home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / runtime / rgxcmp.scm < prev    next >
Text File  |  2001-06-15  |  25KB  |  846 lines

  1. ;;; -*-Scheme-*-
  2. ;;;
  3. ;;; $Id: rgxcmp.scm,v 1.115 2001/06/15 21:20:48 cph Exp $
  4. ;;;
  5. ;;; Copyright (c) 1986, 1989-2001 Massachusetts Institute of Technology
  6. ;;;
  7. ;;; This program is free software; you can redistribute it and/or
  8. ;;; modify it under the terms of the GNU General Public License as
  9. ;;; published by the Free Software Foundation; either version 2 of the
  10. ;;; License, or (at your option) any later version.
  11. ;;;
  12. ;;; This program is distributed in the hope that it will be useful,
  13. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. ;;; General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with this program; if not, write to the Free Software
  19. ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  20. ;;; 02111-1307, USA.
  21.  
  22. ;;;; Regular Expression Pattern Compiler
  23. ;;;  Translated from GNU (thank you RMS!)
  24.  
  25. (declare (usual-integrations))
  26.  
  27. ;;;; Compiled Opcodes
  28.  
  29. (define-macro (define-enumeration name prefix . suffixes)
  30.   `(BEGIN
  31.      ,@(let loop ((n 0) (suffixes suffixes))
  32.      (if (null? suffixes)
  33.          '()
  34.          (cons `(DEFINE-INTEGRABLE ,(symbol-append prefix (car suffixes))
  35.               ,n)
  36.            (loop (1+ n) (cdr suffixes)))))
  37.      (DEFINE ,name
  38.        (VECTOR ,@(map (lambda (suffix) `',suffix) suffixes)))))
  39.  
  40. (define-enumeration re-codes re-code:
  41.  
  42.   ;; Zero bytes may appear in the compiled regular expression.
  43.   unused
  44.  
  45.   ;; Followed by a single literal byte.
  46.   exact-1
  47.  
  48.   ;; Followed by one byte giving n, and then by n literal bytes.
  49.   exact-n
  50.  
  51.   line-start        ;Fails unless at start of line.
  52.   line-end        ;Fails unless at end of line.
  53.  
  54.   ;; Followed by two bytes giving relative address to jump to.
  55.   jump
  56.  
  57.   ;; Followed by two bytes giving relative address of place to result
  58.   ;; at in case of failure.
  59.   on-failure-jump
  60.  
  61.   ;; Throw away latest failure point and then jump to address.
  62.   finalize-jump
  63.  
  64.   ;; Like jump but finalize if safe to do so.  This is used to jump
  65.   ;; back to the beginning of a repeat.  If the command that follows
  66.   ;; this jump is clearly incompatible with the one at the beginning
  67.   ;; of the repeat, such that we can be sure that there is no use
  68.   ;; backtracing out of repetitions already completed, then we
  69.   ;; finalize.
  70.   maybe-finalize-jump
  71.  
  72.   ;; Jump, and push a dummy failure point.  This failure point will be
  73.   ;; thrown away if an attempt is made to use it for a failure.  A +
  74.   ;; construct makes this before the first repeat.
  75.   dummy-failure-jump
  76.  
  77.   ;; Matches any one character except for newline.
  78.   any-char
  79.  
  80.   ;; Matches any one char belonging to specified set. First following
  81.   ;; byte is # bitmap bytes.  Then come bytes for a bit-map saying
  82.   ;; which chars are in.  Bits in each byte are ordered low-bit-first.
  83.   ;; A character is in the set if its bit is 1.  A character too large
  84.   ;; to have a bit in the map is automatically not in the set.
  85.   char-set
  86.  
  87.   ;; Similar but match any character that is NOT one of those
  88.   ;; specified.
  89.   not-char-set
  90.  
  91.   ;; Starts remembering the text that is matches and stores it in a
  92.   ;; memory register.  Followed by one byte containing the register
  93.   ;; number.  Register numbers must be in the range 0 through
  94.   ;; re-number-of-registers.
  95.   start-memory
  96.  
  97.   ;; Stops remembering the text that is matched and stores it in a
  98.   ;; memory register.  Followed by one byte containing the register
  99.   ;; number.  Register numbers must be in the range 0 through
  100.   ;; re-number-of-registers.
  101.   stop-memory
  102.  
  103.   ;; Match a duplicate of something remembered.  Followed by one byte
  104.   ;; containing the index of the memory register.
  105.   duplicate
  106.  
  107.   buffer-start        ;Succeeds if at beginning of buffer.
  108.   buffer-end        ;Succeeds if at end of buffer.
  109.   word-char        ;Matches any word-constituent character.
  110.   not-word-char        ;Matches any char that is not a word-constituent.
  111.   word-start        ;Succeeds if at word beginning.
  112.   word-end        ;Succeeds if at word end.
  113.   word-bound        ;Succeeds if at a word boundary.
  114.   not-word-bound    ;Succeeds if not at a word boundary.
  115.  
  116.   ;; Matches any character whose syntax is specified.  Followed by a
  117.   ;; byte which contains a syntax code.
  118.   syntax-spec
  119.  
  120.   ;; Matches any character whose syntax differs from the specified.
  121.   not-syntax-spec
  122.   )
  123.  
  124. ;;;; Cache
  125.  
  126. (define (cached-procedure size procedure)
  127.   (let ((cache (make-cache size)))
  128.     (lambda (key1 key2)
  129.       (cache-result cache procedure key1 key2))))
  130.  
  131. (define (make-cache size)
  132.   (let ((items (make-list size)))
  133.     (do ((items items (cdr items)))
  134.     ((null? items))
  135.       (set-car! items (cons (cons #f #f) #f)))
  136.     (set-cdr! (last-pair items) items)
  137.     (cons 'CACHE items)))
  138.  
  139. (define (cache-result cache procedure key1 key2)
  140.   (let* ((tail (cdr cache))
  141.      (head (cdr tail)))
  142.     (let loop ((items head) (prev tail))
  143.       (let ((item (car items)))
  144.     (cond ((and (eq? key1 (caar item))
  145.             (eq? key2 (cdar item)))
  146.            (cond ((eq? tail items)
  147.               (set-cdr! cache prev))
  148.              ((not (eq? head items))
  149.               (without-interrupts
  150.                (lambda ()
  151.              (set-cdr! prev (cdr items))
  152.              (set-cdr! items head)
  153.              (set-cdr! tail items)))))
  154.            (cdr item))
  155.           ((eq? tail items)
  156.            (let ((result (procedure key1 key2)))
  157.          (without-interrupts
  158.           (lambda ()
  159.             (set-car! (car item) key1)
  160.             (set-cdr! (car item) key2)
  161.             (set-cdr! item result)
  162.             (set-cdr! cache prev)))
  163.          result))
  164.           (else
  165.            (loop (cdr items) items)))))))
  166.  
  167. ;;;; String Compiler
  168.  
  169. (define (re-compile-char char case-fold?)
  170.   (let ((result (string-allocate 2)))
  171.     (vector-8b-set! result 0 re-code:exact-1)
  172.     (string-set! result 1 (if case-fold? (char-upcase char) char))
  173.     (make-compiled-regexp result case-fold?)))
  174.  
  175. (define re-compile-string
  176.   (cached-procedure 16
  177.     (lambda (string case-fold?)
  178.       (let ((string (if case-fold? (string-upcase string) string)))
  179.     (let ((n (string-length string)))
  180.       (if (fix:zero? n)
  181.           (make-compiled-regexp string case-fold?)
  182.           (let ((result
  183.              (string-allocate 
  184.               (let ((qr (integer-divide n 255)))
  185.             (fix:+ (fix:* 257 (integer-divide-quotient qr))
  186.                    (let ((r (integer-divide-remainder qr)))
  187.                  (cond ((fix:zero? r) 0)
  188.                        ((fix:= 1 r) 2)
  189.                        (else (fix:+ r 2)))))))))
  190.         (let loop ((n n) (i 0) (p 0))
  191.           (cond ((fix:= n 1)
  192.              (vector-8b-set! result p re-code:exact-1)
  193.              (vector-8b-set! result
  194.                      (fix:1+ p)
  195.                      (vector-8b-ref string i))
  196.              (make-compiled-regexp result case-fold?))
  197.             ((fix:< n 256)
  198.              (vector-8b-set! result p re-code:exact-n)
  199.              (vector-8b-set! result (fix:1+ p) n)
  200.              (substring-move! string i (fix:+ i n)
  201.                       result (fix:+ p 2))
  202.              (make-compiled-regexp result case-fold?))
  203.             (else
  204.              (vector-8b-set! result p re-code:exact-n)
  205.              (vector-8b-set! result (fix:1+ p) 255)
  206.              (let ((j (fix:+ i 255)))
  207.                (substring-move! string i j result (fix:+ p 2))
  208.                (loop (fix:- n 255) j (fix:+ p 257)))))))))))))
  209.  
  210. (define re-quote-string
  211.   (let ((special (char-set #\[ #\] #\* #\. #\\ #\? #\+ #\^ #\$)))
  212.     (lambda (string)
  213.       (let ((end (string-length string)))
  214.     (let ((n
  215.            (let loop ((start 0) (n 0))
  216.          (let ((index
  217.             (substring-find-next-char-in-set string start end
  218.                              special)))
  219.            (if index
  220.                (loop (1+ index) (1+ n))
  221.                n)))))
  222.       (if (zero? n)
  223.           string
  224.           (let ((result (string-allocate (+ end n))))
  225.         (let loop ((start 0) (i 0))
  226.           (let ((index
  227.              (substring-find-next-char-in-set string start end
  228.                               special)))
  229.             (if index
  230.             (begin
  231.               (substring-move! string start index result i)
  232.               (let ((i (+ i (- index start))))
  233.                 (string-set! result i #\\)
  234.                 (string-set! result
  235.                      (1+ i)
  236.                      (string-ref string index))
  237.                 (loop (1+ index) (+ i 2))))
  238.             (substring-move! string start end result i))))
  239.         result)))))))
  240.  
  241. ;;;; Char-Set Compiler
  242.  
  243. ;;; Special characters:
  244. ;;; #\] must appear as first character.
  245. ;;; #\- must appear as first or last character, or it may appear
  246. ;;;     immediately after a range.
  247. ;;; #\^ must appear anywhere except as the first character in the set.
  248.  
  249. (define (re-compile-char-set pattern negate?)
  250.   (let ((length (string-length pattern))
  251.     (table (string-allocate 256)))
  252.     (let ((kernel
  253.        (lambda (start background foreground)
  254.          (let ((adjoin!
  255.             (lambda (ascii)
  256.               (vector-8b-set! table ascii foreground))))
  257.            (vector-8b-fill! table 0 256 background)
  258.            (let loop
  259.            ((pattern (substring->list pattern start length)))
  260.          (if (pair? pattern)
  261.              (if (and (pair? (cdr pattern))
  262.                   (char=? (cadr pattern) #\-)
  263.                   (pair? (cddr pattern)))
  264.              (begin
  265.                (let ((end (char->ascii (caddr pattern))))
  266.                  (let loop
  267.                  ((index (char->ascii (car pattern))))
  268.                    (if (fix:<= index end)
  269.                    (begin
  270.                      (vector-8b-set! table
  271.                              index
  272.                              foreground)
  273.                      (loop (fix:+ index 1))))))
  274.                (loop (cdddr pattern)))
  275.              (begin
  276.                (adjoin! (char->ascii (car pattern)))
  277.                (loop (cdr pattern))))))))))
  278.       (if (and (not (fix:zero? length))
  279.            (char=? (string-ref pattern 0) #\^))
  280.       (if negate?
  281.           (kernel 1 0 1)
  282.           (kernel 1 1 0))
  283.       (if negate?
  284.           (kernel 0 1 0)
  285.           (kernel 0 0 1))))
  286.     (make-char-set table)))
  287.  
  288. ;;;; Translation Tables
  289.  
  290. (define re-translation-table
  291.   (let ((normal-table (make-string 256)))
  292.     (let loop ((n 0))
  293.       (if (< n 256)
  294.       (begin
  295.         (vector-8b-set! normal-table n n)
  296.         (loop (1+ n)))))
  297.     (let ((upcase-table (string-copy normal-table)))
  298.       (let loop ((n #x61))
  299.     (if (< n #x7B)
  300.         (begin
  301.           (vector-8b-set! upcase-table n (- n #x20))
  302.           (loop (1+ n)))))
  303.       (lambda (case-fold?)
  304.     (if case-fold? upcase-table normal-table)))))
  305.  
  306. ;;;; Pattern Compiler
  307.  
  308. (define re-number-of-registers
  309.   10)
  310.  
  311. (define-integrable stack-maximum-length
  312.   re-number-of-registers)
  313.  
  314. (define condition-type:re-compile-pattern
  315.   (make-condition-type 'RE-COMPILE-PATTERN condition-type:error
  316.       '(MESSAGE)
  317.     (lambda (condition port)
  318.       (write-string "Error compiling regular expression: " port)
  319.       (write-string (access-condition condition 'MESSAGE) port))))
  320.  
  321. (define compilation-error
  322.   (condition-signaller condition-type:re-compile-pattern
  323.                '(MESSAGE)
  324.                standard-error-handler))
  325.  
  326. (define-structure (compiled-regexp
  327.            (constructor %make-compiled-regexp)
  328.            (conc-name compiled-regexp/))
  329.   (byte-stream #f read-only #t)
  330.   (translation-table #f read-only #t))
  331.  
  332. (define (make-compiled-regexp byte-stream case-fold?)
  333.   (%make-compiled-regexp byte-stream (re-translation-table case-fold?)))
  334.  
  335. (define input-list)
  336. (define current-byte)
  337. (define translation-table)
  338. (define output-head)
  339. (define output-tail)
  340. (define output-length)
  341. (define stack)
  342.  
  343. (define fixup-jump)
  344. (define register-number)
  345. (define begin-alternative)
  346. (define pending-exact)
  347. (define last-start)
  348.  
  349. (define re-compile-pattern
  350.   (cached-procedure 16
  351.     (lambda (pattern case-fold?)
  352.       (let ((output (list 'OUTPUT)))
  353.     (fluid-let ((input-list (map char->ascii (string->list pattern)))
  354.             (current-byte)
  355.             (translation-table (re-translation-table case-fold?))
  356.             (output-head output)
  357.             (output-tail output)
  358.             (output-length 0)
  359.             (stack '())
  360.             (fixup-jump #f)
  361.             (register-number 1)
  362.             (begin-alternative)
  363.             (pending-exact #f)
  364.             (last-start #f))
  365.       (set! begin-alternative (output-pointer))
  366.       (let loop ()
  367.         (if (input-end?)
  368.         (begin
  369.           (if fixup-jump
  370.               (store-jump! fixup-jump re-code:jump (output-position)))
  371.           (if (not (stack-empty?))
  372.               (compilation-error "Unmatched \\("))
  373.           (make-compiled-regexp
  374.            (list->string (map ascii->char (cdr output-head)))
  375.            case-fold?))
  376.         (begin
  377.           (compile-pattern-char)
  378.           (loop)))))))))
  379.  
  380. ;;;; Input
  381.  
  382. (define-integrable (input-end?)
  383.   (null? input-list))
  384.  
  385. (define-integrable (input-end+1?)
  386.   (null? (cdr input-list)))
  387.  
  388. (define-integrable (input-peek)
  389.   (vector-8b-ref translation-table (car input-list)))
  390.  
  391. (define-integrable (input-peek+1)
  392.   (vector-8b-ref translation-table (cadr input-list)))
  393.  
  394. (define-integrable (input-discard!)
  395.   (set! input-list (cdr input-list))
  396.   unspecific)
  397.  
  398. (define-integrable (input!)
  399.   (set! current-byte (input-peek))
  400.   (input-discard!))
  401.  
  402. (define-integrable (input-raw!)
  403.   (set! current-byte (car input-list))
  404.   (input-discard!))
  405.  
  406. (define-integrable (input-peek-1)
  407.   current-byte)
  408.  
  409. (define-integrable (input-read!)
  410.   (if (input-end?)
  411.       (premature-end)
  412.       (let ((char (input-peek)))
  413.     (input-discard!)
  414.     char)))
  415.  
  416. (define (input-match? byte . chars)
  417.   (memv (ascii->char byte) chars))
  418.  
  419. ;;;; Output
  420.  
  421. (define-integrable (output! byte)
  422.   (let ((tail (list byte)))
  423.     (set-cdr! output-tail tail)
  424.     (set! output-tail tail))
  425.   (set! output-length (fix:1+ output-length))
  426.   unspecific)
  427.  
  428. (define-integrable (output-re-code! code)
  429.   (set! pending-exact #f)
  430.   (output! code))
  431.  
  432. (define-integrable (output-start! code)
  433.   (set! last-start (output-pointer))
  434.   (output-re-code! code))
  435.  
  436. (define-integrable (output-position)
  437.   output-length)
  438.  
  439. (define-integrable (output-pointer)
  440.   (cons output-length output-tail))
  441.  
  442. (define-integrable (pointer-position pointer)
  443.   (car pointer))
  444.  
  445. (define-integrable (pointer-ref pointer)
  446.   (caddr pointer))
  447.  
  448. (define-integrable (pointer-operate! pointer operator)
  449.   (set-car! (cddr pointer) (operator (caddr pointer)))
  450.   unspecific)
  451.  
  452. (define (store-jump! from opcode to)
  453.   (let ((p (cddr from)))
  454.     (set-car! p opcode)
  455.     (compute-jump (pointer-position from) to
  456.       (lambda (low high)
  457.     (set-car! (cdr p) low)
  458.     (set-car! (cddr p) high)
  459.     unspecific))))
  460.  
  461. (define (insert-jump! from opcode to)
  462.   (compute-jump (pointer-position from) to
  463.     (lambda (low high)
  464.       (set-cdr! (cdr from)
  465.         (cons* opcode low high (cddr from)))
  466.       (set! output-length (fix:+ output-length 3))
  467.       unspecific)))
  468.  
  469. (define (compute-jump from to receiver)
  470.   (let ((n (fix:- to (fix:+ from 3))))
  471.     (let ((qr
  472.        (integer-divide (if (fix:negative? n) (fix:+ n #x10000) n)
  473.                #x100)))
  474.       (receiver (integer-divide-remainder qr)
  475.         (integer-divide-quotient qr)))))
  476.  
  477. ;;;; Stack
  478.  
  479. (define-integrable (stack-empty?)
  480.   (null? stack))
  481.  
  482. (define-integrable (stack-full?)
  483.   (not (fix:< (stack-length) stack-maximum-length)))
  484.  
  485. (define-integrable (stack-length)
  486.   (length stack))
  487.  
  488. (define (stack-push! . args)
  489.   (set! stack (cons args stack))
  490.   unspecific)
  491.  
  492. (define (stack-pop! receiver)
  493.   (let ((frame (car stack)))
  494.     (set! stack (cdr stack))
  495.     (apply receiver frame)))
  496.  
  497. (define-integrable (stack-ref-register-number i)
  498.   (caddr (list-ref stack i)))
  499.  
  500. (define (ascii->syntax-entry ascii)
  501.   ((ucode-primitive string->syntax-entry) (char->string (ascii->char ascii))))
  502.  
  503. ;;;; Pattern Dispatch
  504.  
  505. (define-integrable (compile-pattern-char)
  506.   (input!)
  507.   ((vector-ref pattern-chars (input-peek-1))))
  508.  
  509. (define (premature-end)
  510.   (compilation-error "Premature end of regular expression"))
  511.  
  512. (define (normal-char)
  513.   (if (if (input-end?)
  514.       (not pending-exact)
  515.       (input-match? (input-peek) #\* #\+ #\? #\^))
  516.       (begin
  517.     (output-start! re-code:exact-1)
  518.     (output! (input-peek-1)))
  519.       (begin
  520.     (if (or (not pending-exact)
  521.         (fix:= (pointer-ref pending-exact) #x7F))
  522.         (begin
  523.           (set! last-start (output-pointer))
  524.           (output! re-code:exact-n)
  525.           (set! pending-exact (output-pointer))
  526.           (output! 0)))
  527.     (output! (input-peek-1))
  528.     (pointer-operate! pending-exact 1+))))
  529.  
  530. (define (define-pattern-char char procedure)
  531.   (vector-set! pattern-chars (char->ascii char) procedure)
  532.   unspecific)
  533.  
  534. (define pattern-chars
  535.   (make-vector 256 normal-char))
  536.  
  537. (define-pattern-char #\\
  538.   (lambda ()
  539.     (if (input-end?)
  540.     (premature-end)
  541.     (begin
  542.       (input-raw!)
  543.       ((vector-ref backslash-chars (input-peek-1)))))))
  544.  
  545. (define (define-backslash-char char procedure)
  546.   (vector-set! backslash-chars (char->ascii char) procedure)
  547.   unspecific)
  548.  
  549. (define backslash-chars
  550.   (make-vector 256 normal-char))
  551.  
  552. (define-pattern-char #\$
  553.   ;; $ means succeed if at end of line, but only in special contexts.
  554.   ;; If randomly in the middle of a pattern, it is a normal character.
  555.   (lambda ()
  556.     (if (or (input-end?)
  557.         (input-end+1?)
  558.         (and (input-match? (input-peek) #\\)
  559.          (input-match? (input-peek+1) #\) #\|)))
  560.     (output-re-code! re-code:line-end)
  561.     (normal-char))))
  562.  
  563. (define-pattern-char #\^
  564.   ;; ^ means succeed if at beginning of line, but only if no preceding
  565.   ;; pattern.
  566.   (lambda ()
  567.     (if (not last-start)
  568.     (output-re-code! re-code:line-start)
  569.     (normal-char))))
  570.  
  571. (define-pattern-char #\.
  572.   (lambda ()
  573.     (output-start! re-code:any-char)))
  574.  
  575. (define (define-trivial-backslash-char char code)
  576.   (define-backslash-char char
  577.     (lambda ()
  578.       (output-re-code! code))))
  579.  
  580. (define-trivial-backslash-char #\< re-code:word-start)
  581. (define-trivial-backslash-char #\> re-code:word-end)
  582. (define-trivial-backslash-char #\b re-code:word-bound)
  583. (define-trivial-backslash-char #\B re-code:not-word-bound)
  584. (define-trivial-backslash-char #\` re-code:buffer-start)
  585. (define-trivial-backslash-char #\' re-code:buffer-end)
  586.  
  587. (define (define-starter-backslash-char char code)
  588.   (define-backslash-char char
  589.     (lambda ()
  590.       (output-start! code))))
  591.  
  592. (define-starter-backslash-char #\w re-code:word-char)
  593. (define-starter-backslash-char #\W re-code:not-word-char)
  594.  
  595. (define-backslash-char #\s
  596.   (lambda ()
  597.     (output-start! re-code:syntax-spec)
  598.     (output! (ascii->syntax-entry (input-read!)))))
  599.  
  600. (define-backslash-char #\S
  601.   (lambda ()
  602.     (output-start! re-code:not-syntax-spec)
  603.     (output! (ascii->syntax-entry (input-read!)))))
  604.  
  605. ;;;; Repeaters
  606.  
  607. (define (define-repeater-char char zero? many?)
  608.   (define-pattern-char char
  609.     ;; If there is no previous pattern, char not special.
  610.     (lambda ()
  611.       (if (not last-start)
  612.       (normal-char)
  613.       (repeater-loop zero? many?)))))
  614.  
  615. (define (repeater-loop zero? many?)
  616.   ;; If there is a sequence of repetition chars, collapse it down to
  617.   ;; equivalent to just one.
  618.   (cond ((input-end?)
  619.      (repeater-finish zero? many?))
  620.     ((input-match? (input-peek) #\*)
  621.      (input-discard!)
  622.      (repeater-loop zero? many?))
  623.     ((input-match? (input-peek) #\+)
  624.      (input-discard!)
  625.      (repeater-loop #f many?))
  626.     ((input-match? (input-peek) #\?)
  627.      (input-discard!)
  628.      (repeater-loop zero? #f))
  629.     (else
  630.      (repeater-finish zero? many?))))
  631.  
  632. (define (repeater-finish zero? many?)
  633.   (if many?
  634.       ;; More than one repetition allowed: put in a backward jump at
  635.       ;; the end.
  636.       (compute-jump (output-position)
  637.             (fix:- (pointer-position last-start) 3)
  638.     (lambda (low high)
  639.       (output-re-code! re-code:maybe-finalize-jump)
  640.       (output! low)
  641.       (output! high))))
  642.   (insert-jump! last-start
  643.         re-code:on-failure-jump
  644.         (fix:+ (output-position) 3))
  645.   (if (not zero?)
  646.       ;; At least one repetition required: insert before the loop a
  647.       ;; skip over the initial on-failure-jump instruction.
  648.       (insert-jump! last-start
  649.             re-code:dummy-failure-jump
  650.             (fix:+ (pointer-position last-start) 6))))
  651.  
  652. (define-repeater-char #\* #t #t)
  653. (define-repeater-char #\+ #f #t)
  654. (define-repeater-char #\? #t #f)
  655.  
  656. ;;;; Character Sets
  657.  
  658. (define-pattern-char #\[
  659.   (lambda ()
  660.     (if (input-end?)
  661.     (premature-end))
  662.     (let ((invert?
  663.        (and (input-match? (input-peek) #\^)
  664.         (begin (input-discard!) #t)))
  665.       (charset (make-string 32 (ascii->char 0))))
  666.       (let loop
  667.       ((chars
  668.         (if (input-match? (input-peek) #\])
  669.         (begin (input-discard!) '(#\]))
  670.         '())))
  671.     (if (input-end?)
  672.         (premature-end))
  673.     (let ((char (input-read!)))
  674.       (if (input-match? char #\])
  675.           (begin
  676.         (for-each
  677.          (lambda (char)
  678.            ((ucode-primitive re-char-set-adjoin!) charset
  679.                               (char->ascii char)))
  680.          (char-set-members
  681.           (re-compile-char-set (list->string (reverse! chars)) #f))))
  682.           (loop (cons char chars)))))
  683.       (output-start! (if invert? re-code:not-char-set re-code:char-set))
  684.       ;; Discard any bitmap bytes that are all 0 at the end of
  685.       ;; the map.  Decrement the map-length byte too.
  686.       (let loop ((n 31))
  687.     (cond ((not (fix:= 0 (vector-8b-ref charset n)))
  688.            (output! (fix:+ n 1))
  689.            (let loop ((i 0))
  690.          (output! (vector-8b-ref charset i))
  691.          (if (fix:< i n)
  692.              (loop (fix:+ i 1)))))
  693.           ((fix:= 0 n)
  694.            (output! 0))
  695.           (else
  696.            (loop (fix:- n 1))))))))
  697.  
  698. ;;;; Alternative Groups
  699.  
  700. (define-backslash-char #\(
  701.   (lambda ()
  702.     (if (stack-full?)
  703.     (compilation-error "Nesting too deep"))
  704.     (if (fix:< register-number re-number-of-registers)
  705.     (begin
  706.       (output-re-code! re-code:start-memory)
  707.       (output! register-number)))
  708.     (stack-push! (output-pointer)
  709.          fixup-jump
  710.          register-number
  711.          begin-alternative)
  712.     (set! last-start #f)
  713.     (set! fixup-jump #f)
  714.     (set! register-number (fix:1+ register-number))
  715.     (set! begin-alternative (output-pointer))
  716.     unspecific))
  717.  
  718. (define-backslash-char #\)
  719.   (lambda ()
  720.     (if (stack-empty?)
  721.     (compilation-error "Unmatched close paren"))
  722.     (if fixup-jump
  723.     (store-jump! fixup-jump re-code:jump (output-position)))
  724.     (stack-pop!
  725.      (lambda (op fj rn bg)
  726.        (set! last-start op)
  727.        (set! fixup-jump fj)
  728.        (set! begin-alternative bg)
  729.        (if (fix:< rn re-number-of-registers)
  730.        (begin
  731.          (output-re-code! re-code:stop-memory)
  732.          (output! rn)))))))
  733.  
  734. (define-backslash-char #\|
  735.   (lambda ()
  736.     (insert-jump! begin-alternative
  737.           re-code:on-failure-jump
  738.           (fix:+ (output-position) 6))
  739.     (if fixup-jump
  740.     (store-jump! fixup-jump re-code:jump (output-position)))
  741.     (set! fixup-jump (output-pointer))
  742.     (output! re-code:unused)
  743.     (output! re-code:unused)
  744.     (output! re-code:unused)
  745.     (set! pending-exact #f)
  746.     (set! last-start #f)
  747.     (set! begin-alternative (output-pointer))
  748.     unspecific))
  749.  
  750. (define (define-digit-char digit)
  751.   (let ((char (digit->char digit)))
  752.     (define-backslash-char char
  753.       (lambda ()
  754.     (if (fix:< digit register-number)
  755.         (let ((n (stack-length)))
  756.           (let search-stack ((i 0))
  757.         (cond ((not (fix:< i n))
  758.                (output-start! re-code:duplicate)
  759.                (output! digit))
  760.               ((fix:= (stack-ref-register-number i) digit)
  761.                (normal-char))
  762.               (else
  763.                (search-stack (fix:1+ i))))))
  764.         (normal-char))))))
  765.  
  766. (for-each define-digit-char '(1 2 3 4 5 6 7 8 9))
  767.  
  768. ;;;; Compiled Pattern Disassembler
  769.  
  770. (define (hack-fastmap pattern)
  771.   (let ((compiled-pattern (re-compile-pattern pattern #f))
  772.     (cs (char-set)))
  773.     ((ucode-primitive re-compile-fastmap)
  774.      compiled-pattern
  775.      (re-translation-table #f)
  776.      (get-char-syntax standard-char-syntax-table)
  777.      cs)
  778.     (char-set-members cs)))
  779.  
  780. (define (re-disassemble-pattern compiled-pattern)
  781.   (let ((n (string-length compiled-pattern)))
  782.     (let loop ((i 0))
  783.       (newline)
  784.       (write i)
  785.       (write-string " (")
  786.       (if (< i n)
  787.       (case (let ((re-code-name
  788.                (vector-ref re-codes
  789.                    (vector-8b-ref compiled-pattern i))))
  790.           (write re-code-name)
  791.           re-code-name)
  792.         ((UNUSED LINE-START LINE-END ANY-CHAR BUFFER-START BUFFER-END
  793.           WORD-CHAR NOT-WORD-CHAR WORD-START WORD-END WORD-BOUND
  794.           NOT-WORD-BOUND)
  795.          (write-string ")")
  796.          (loop (1+ i)))
  797.         ((EXACT-1)
  798.          (write-string " ")
  799.          (let ((end (+ i 2)))
  800.            (write (substring compiled-pattern (1+ i) end))
  801.            (write-string ")")
  802.            (loop end)))
  803.         ((EXACT-N)
  804.          (write-string " ")
  805.          (let ((start (+ i 2))
  806.            (n (vector-8b-ref compiled-pattern (1+ i))))
  807.            (let ((end (+ start n)))
  808.          (write (substring compiled-pattern start end))
  809.          (write-string ")")
  810.          (loop end))))
  811.         ((JUMP ON-FAILURE-JUMP MAYBE-FINALIZE-JUMP DUMMY-FAILURE-JUMP)
  812.          (write-string " ")
  813.          (let ((end (+ i 3))
  814.            (offset
  815.             (+ (* 256 (vector-8b-ref compiled-pattern (+ i 2)))
  816.                (vector-8b-ref compiled-pattern (1+ i)))))
  817.            (write (+ end (if (< offset #x8000) offset (- offset #x10000))))
  818.            (write-string ")")
  819.            (loop end)))
  820.         ((CHAR-SET NOT-CHAR-SET)
  821.          (let ((end (+ (+ i 2) (vector-8b-ref compiled-pattern (1+ i)))))
  822.            (let spit ((i (+ i 2)))
  823.          (if (< i end)
  824.              (begin
  825.                (write-string " ")
  826.                (let ((n (vector-8b-ref compiled-pattern i)))
  827.              (if (< n 16) (write-char #\0))
  828.              (write-string (number->string n 16)))
  829.                (spit (1+ i)))
  830.              (begin
  831.                (write-string ")")
  832.                (loop i))))))
  833.         ((START-MEMORY STOP-MEMORY DUPLICATE)
  834.          (write-string " ")
  835.          (write (vector-8b-ref compiled-pattern (1+ i)))
  836.          (write-string ")")
  837.          (loop (+ i 2)))
  838.         ((SYNTAX-SPEC NOT-SYNTAX-SPEC)
  839.          (write-string " ")
  840.          (write (string-ref " .w_()'\"$\\/<>"
  841.                 (vector-8b-ref compiled-pattern (1+ i))))
  842.          (write-string ")")
  843.          (loop (+ i 2))))
  844.       (begin
  845.         (write 'end)
  846.         (write-string ")"))))))