\ -*- 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