\ recognizer-based interpreter 05oct2011py \ Recognizer are words that take a string and try to figure out \ what to do with it. I want to separate the parse action from \ the interpret/compile/postpone action, so that recognizers \ are more general than just be used for the interpreter. \ The "design pattern" used here is the *factory*, even though \ the recognizer does not return a full-blown object. \ A recognizer has the stack effect \ ( addr u -- token table true | addr u false ) \ where the token is the result of the parsing action (can be more than \ one stack or live on other stacks, e.g. on the FP stack) \ and the table contains for actions (as array of four xts: \ interpret it, compile interpretation semantics \ compile it, compile it as literal. : recognizer: ( xt1 xt2 xt3 -- ) Create rot , swap , , ; (field) r>int ( r-addr -- addr ) 0 cells , (field) r>comp ( r-addr -- addr ) 1 cells , (field) r>lit ( r-addr -- addr ) 2 cells , ' no.extensions dup dup Create r:fail A, A, A, : lit, ( n -- ) postpone Literal ; : 2lit, ( n -- ) postpone 2Literal ; : nt, ( nt -- ) name>comp execute ; ' name>int :noname ( ... nt -- ... xt ) ['] nt, ; :noname ( ... nt -- xt ) ['] lit, ; Create r:word rot A, swap A, A, : word-recognizer ( addr u -- nt r:word | addr u r:fail ) 2dup find-name [ [IFDEF] prelude-mask ] run-prelude [ [THEN] ] dup IF nip nip r:word ELSE drop r:fail THEN ; :noname ['] noop ; :noname ['] lit, ; dup Create r:num rot A, swap A, A, :noname ['] noop ; :noname ['] 2lit, ; dup Create r:2num rot A, swap A, A, \ snumber? should be implemented as recognizer stack : num-recognizer ( addr u -- n/d table | addr u r:fail ) 2dup 2>r snumber? dup IF 2rdrop 0> IF r:2num ELSE r:num THEN EXIT THEN drop 2r> r:fail ; \ recognizer stack $10 Constant max-rec# : get-recognizers ( rec-addr -- xt1 .. xtn n ) dup swap @ dup >r cells bounds swap ?DO I @ cell -LOOP r> ; : set-recognizers ( xt1 .. xtn n rec-addr -- ) over max-rec# u>= abort" Too many recognizers" 2dup ! cell+ swap cells bounds ?DO I ! cell +LOOP ; Variable forth-recognizer ' word-recognizer A, ' num-recognizer A, max-rec# 2 - cells allot 2 forth-recognizer ! \ ' num-recognizer ' word-recognizer 2 forth-recognizer set-recognizers \ recognizer loop : do-recognizer ( addr u rec-addr -- token table ) dup cell+ swap @ cells bounds ?DO I perform dup r:fail <> IF UNLOOP EXIT THEN drop cell +LOOP r:fail ; \ nested recognizer helper \ : nest-recognizer ( addr u -- token table | addr u r:fail ) \ xxx-recognizer do-recognizer ; : interpreter-r ( addr u -- ... xt ) forth-recognizer do-recognizer r>int perform ; ' interpreter-r IS parser1 : compiler-r ( addr u -- ... xt ) forth-recognizer do-recognizer r>comp perform ; : [ ( -- ) \ core left-bracket \G Enter interpretation state. Immediate word. ['] interpreter-r IS parser1 state off ; immediate : ] ( -- ) \ core right-bracket \G Enter compilation state. ['] compiler-r IS parser1 state on ; : >int ( token table -- ) r>int perform execute ; : >comp ( token table -- ) r>comp perform execute ; : >postpone ( token table -- ) >r r@ r>lit perform execute r> r>comp perform compile, ; : postpone ( "name" -- ) \ core \g Compiles the compilation semantics of @i{name}. parse-name forth-recognizer do-recognizer >postpone ; immediate