\ -*- mode: forth -*-
\ $Id: regexmatch.gforth,v 1.1 2001/05/26 15:59:44 doug Exp $
\ http://www.bagley.org/~doug/shootout/
\ from Anton Ertl:
\ this uses the Gray parser generator, which is probably too big a
\ cannon for this problem (it also needs a lot of setup code).
\ Writing a recursive descent parser by hand is probably both smaller
\ and faster in this case.
0. argc @ 1- arg >number 2drop drop constant NUM
warnings off \ Gray is a little wordy
require gray.fs
: slurp-fid { fid -- addr u }
    0 0 begin 
    dup 1024 + dup >r extend-mem 
    rot r@ fid read-file throw 
    r> 2dup =
    while 
    2drop
    repeat
    - + dup >r resize throw r> ;
: bit-equiv 
    \ w3=~w1^w2
    invert xor ;
: set-complement 
    empty ['] bit-equiv binary-set-operation ;
variable input \ pointer to next character to be scanned
variable end-input \ pointer to end of input
-1 constant eof-char
: start 
    input @ ;
: end 
    input @ over - ;
: get-input 
    start end-input @ = if
    eof-char
    else
    start c@
    endif ;
256 max-member
s" scan failed" exception constant scanfail
: ?nextchar 
    0= scanfail and throw
    1 chars input +! ;
    
: testchar? 
    get-input member? ;
' testchar? test-vector !
: .. 
 
 empty copy-set
 swap 1+ rot do
  i over add-member
 loop ;
: ` 
    \ creates anonymous terminal for the character c )
    char singleton ['] ?nextchar make-terminal ;
char 0 char 9 .. dup  ' ?nextchar  terminal digit
set-complement        ' ?nextchar  terminal nondigit
bl singleton          ' ?nextchar  terminal lspace
2variable areacode
2variable exchange
2variable last4
)
<- area-code
 || area-code ))
   lspace {{ start }} digit digit digit {{ end exchange 2! }}
   )
   {{ start }} digit digit digit digit {{ end last4 2! }}
   nondigit
)) <- telnum 
telnum parser scan-telnum 
: scan-for-nondigit 
    begin
    count  >r
    r@ '0 < r@ '9 > or  r> '( <>  and
    over end-input @ u>= or
    until ;
variable count  0 count !
: scanfile 
    over + end-input !
    begin 
    dup input !
    ['] scan-telnum catch
    dup dup scanfail <> and throw
    if 
        scan-for-nondigit
    else
        1 count +! count @ 1 u.r ." : "
        ."  " exchange 2@ type ." -" last4 2@ type
        cr
        end-input @ over - #lf scan drop \ skip rest of line
    endif
    dup end-input @ u>=
    until
    drop ;
: mainloop 
    ['] 2drop [is] type
    NUM 1 +do
    2dup scanfile
    loop
    [']  [is] type
    scanfile ;
    
stdin slurp-fid mainloop bye