;;;========================================================================== ;;; Simple 3-LISP Expression Reader ;;;========================================================================== ;;; ;;; Reads 3-LISP expressions including rails, pairs and simple symbols. ;;; Does not handle numerals, handles, strings, or booleans. ;;; Builds internal structure for the expression. ;;; Assumed grammar: (<token> is the primitive lexical item) ;;; ;;; <expression> ::= <rail> | <pair> | <symbol> ;;; <rail> ::= "[" <expression>* "]" ;;; <pair> ::= "(" <expression>* ")" ;;; <symbol> ::= <token> ;;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;;; NOTE: SHOULD BE MODIFIED TO CORRESPOND TO THE 3-LISP EXPRESSION RECOGNIZER. ;;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;;; READ-3-LISP reads from STRING, building the corresponding 3-LISP ;;; =========== internal structure. (define read-3-lisp (lambda [string] (init-lex string) (let [[answer (catch recognition-error (begin (define error-in-recognition (lambda [] (recognition-error $false))) (read-expression)))]] (if (and (not (= answer $false)) (= (next-token) 'eot)) answer $false)))) ;;; Ancillary read functions: ;;; ;;; All the following read functions are responsible for ;;; reading just one type of 3-LISP expression. They use ;;; GET-TOKEN etc. from the lexical-analyser package, which are set ;;; up by a call to INIT-LEX. Thus they require a call to INIT-LEX ;;; before running (as is done by RECOGNIZE above). They also assume ;;; that the procedure ERROR-IN-RECOGNITION is bound. This is ;;; called immediately upon finding a syntactic error of any sort. ;;; It should not return, as the procedures below are not guaranteed to ;;; do anything sensible about continuing from errors. Thus the logical ;;; thing to do is to have ERROR-IN-RECOGNITION bound to some THROW ;;; procedure (see CATCH in the 3-LISP reference manual) as is done in ;;; RECOGNIZE above. ;;; ;;; All of the procedures return handles to the 3-LISP structure built. ;;; READ-EXPRESSION attempts to read an arbitrary 3-LISP ;;; =============== expression, returning the corresponding structure. (define read-expression (lambda [] (select (next-token) ["[" (read-rail)] ["(" (read-pair)] [$true (read-symbol)]))) ;;; READ-RAIL attempts to read a 3-LISP rail expression ;;; ========= (define read-rail (lambda [] (get-token) ; skip the open bracket (let [[answer (read-exp-list "]")]] (get-token) ; skip the close bracket (rcons . answer)))) ;;; READ-EXP-LIST attempts to read a list of 3-LISP expressions ;;; ============= delimited by (but not including) the token ;;; ENDING-TOKEN, returning a rail of handles ;;; designating the structures notated by the various elements in the ;;; list read. (Whew.) (define read-exp-list (lambda [ending-token] (if (= (next-token) ending-token) [] (cons (read-expression) (read-exp-list ending-token))))) ;;; READ-PAIR attempts to read a 3-LISP pair expression ;;; ========= (define read-pair (lambda [] (get-token) ; skip the open parenthesis (let [[answer (read-exp-list ")")]] (get-token) ; skip the close parenthesis (pcons (first answer) (rcons . (rest answer)))))) ;;; READ-SYMBOL attempts to read a 3-LISP symbol ;;; =========== (define read-symbol (lambda [] (let [[tok (get-token)]] (if (member tok ['eot "[" "]" "(" ")"]) (error-in-recognition) (atom-notated tok)))))