"I think programmers like to write interpreters.
They like to do these elaborate difficult things."
-- Chuck Moore (in Thinking Forth)
Bradford J. Rodriguez BNF Parser in Forth http://www.bradrodriguez.com/papers/bnfparse.htm).
Updated at https://github.com/letoh/fina-forth/blob/master/bnf.fs
expr: <(>/exp1 expr operator expr <)> = { 3 1 2 };
exp1: ident = { < LOAD > 1 };
operator:
op0: <+>/op1 = { < ADD > };
op1: <->/op2 = { < SUB > };
op2: <*>/op3 = { < MPY > };
op3: </> = { < DIV > };
exp: NUM { $$ = $1; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
: @token ( -- n )
source nip >in @ = if
0
else
source >in @ /string drop c@
then ;
: +token ( f -- ) if 1 >in +! then ;
variable success
: =token ( n -- )
success @ if
@token = dup success ! +token
else drop then ;
char + token '+' char - token '-'
tok + '+' tok - '-'
:noname t' + t' * ;
:noname t" keyword"
: token ( n -- ) create c, does> ( a -- ) c@ =token ;
: t" [char] " parse 0 ?do
dup c@ postpone literal
postpone =token 1+ loop drop ; immediate
: t' char postpone literal
postpone =token ; immediate
: tok char token ;
0 token <EOL>
<NUMBER> ::= <DIGIT> <NUMBER> | <DIGIT>
bnf: <NUMBER> <DIGIT> <NUMBER> | <DIGIT> ;bnf
: bnf: ( -- colon-sys )
: postpone recursive
postpone <bnf ; immediate
: ;bnf ( colon-sys -- )
postpone bnf>
postpone ; ; immediate
: <bnf ( -- )
success @ if
r> >in @ >r here >r >r ( stash old >in & here )
else
r> drop ( bail out of caller, failure! )
then ;
: bnf> ( -- )
success @ if
r> r> r> 2drop >r ( ditch old >in & here )
else
r> r> dp! r> >in ! >r ( restore old >in & here )
then ;
<NUMBER> ::= <DIGIT> <NUMBER> | <DIGIT>
bnf: <NUMBER> <DIGIT> <NUMBER> | <DIGIT> ;bnf
: | ( -- )
success @ if
r> r> r> 2drop drop ( bail out of caller, success! )
else
r> r> r> 2dup >r >r ( pull out old state )
>in ! dp! ( restore old state )
1 success ! >r ( back in action )
then ;
E → E + T | T
T → T * F | F
F → ( E ) | id
E → TE'
E' → +TE' | ε
T → FT'
T' → *FT' | ε
F → (E) | id
exp: NUM { $$ = $1; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
: pow ( x n -- n ) 1 swap 0 ?do over * loop nip ;
bnf: <FACTOR> <PRIMARY> t' ^ <FACTOR> {{ pow }}
| <PRIMARY> ;bnf
bnf: {DIGIT} t' 0 | t' 1 | t' 2 | t' 3 | t' 4 |
t' 5 | t' 6 | t' 7 | t' 8 | t' 9 ;bnf
bnf: <DIGIT> @token 48 - {DIGIT} $$ ! {{ 10 * $$ @ + }} ;bnf
bnf: <NUMBER'> <DIGIT> <NUMBER'> | <DIGIT> ;bnf
bnf: <NUMBER> {{ 0 }} <NUMBER'> ;bnf
variable $$
: {{ postpone ahead
chainer3 ! chainer2 ! chainer1 ! ( stash orig )
postpone ;
noname : latestxt chainer !
; immediate
: }} postpone ; noname :
chainer1 @ chainer2 @ chainer3 @ ( restore orig )
postpone then
postpone $$ postpone @ postpone , ( store state var )
chainer @ postpone literal postpone , ( store xt )
; immediate
Source
and
slides
at:
github.com/flagxor