;;;========================================================================== ;;; Simple 3-LISP Expression Recognizer ;;;========================================================================== ;;; ;;; Recognizes 3-LISP expressions including rails, pairs and simple symbols. ;;; Does not handle numerals, handles, strings, or booleans. ;;; Assumed grammar: (<token> is the primitive lexical item) ;;; ;;; <expression> ::= <rail-exp> | <pair-exp> | <identifier> ;;; ;;; <rail-exp> ::= "[" <expression>* "]" ;;; <pair-exp> ::= "(" <expression>+ ")" ;;; <identifier> ::= <alphanumeric token> ;;; RECOGNIZE Main recognition routine. Returns a message ;;; ========= identifying whether or not the STRING encodes a single ;;; well-formed 3-LISP expression. This version ignores ;;; the information signaled by an error. (define recognize (lambda [string] (init-lex) (setup-lex string) (let [[answer (error-protect (recognize-expression) (lambda [message] (if (= message "Recognition error") $false (error message 'passed-on))))]] (if (and answer (= (next-token) 'eot)) "Accepted" "Rejected")))) ;;; Ancillary recognition functions: ;;; ;;; All the following recognition functions are responsible for ;;; recognizing 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 SETUP-LEX ;;; before running (as is done by RECOGNIZE above). They all call ;;; the procedure ERROR-IN-RECOGNITION immediately upon finding a ;;; syntactic error of any sort, which should not return, as the ;;; procedures below are not guaranteed to do anything sensible ;;; about continuing from errors. ERROR-IN-RECOGNITION simply ;;; causes an error, which is caught by the ERROR-PROTECT in ;;; RECOGNIZE, above. ;;; RECOGNIZE-EXPRESSION Attempts to recognize an arbitrary 3-LISP ;;; ==================== expression. (define RECOGNIZE-EXPRESSION (lambda [] (select (next-token) ["[" (recognize-rail)] ["(" (recognize-pair)] [$true (recognize-identifier)]))) ;;; RECOGNIZE-RAIL attempts to recognize a 3-LISP rail expression ;;; ============== (define RECOGNIZE-RAIL (lambda [] (get-token) ; skip the open bracket (recognize-exp-list "]") (get-token) ; skip the close bracket $true)) ;;; RECOGNIZE-EXP-LIST attempts to recognize a list of 3-LISP expressions ;;; ================== delimited by (but not including) the token ;;; ENDING-TOKEN. (define RECOGNIZE-EXP-LIST (lambda [ending-token] (if (= (next-token) ending-token) $true (begin (recognize-expression) (recognize-exp-list ending-token))))) ;;; RECOGNIZE-PAIR attempts to recognize a 3-LISP pair expression ;;; ============== (define RECOGNIZE-PAIR (lambda [] (get-token) ; skip the open parenthesis (recognize-expression) ; there must be at least one exp. (recognize-exp-list ")") (get-token) ; skip the close parenthesis $true)) ;;; RECOGNIZE-IDENTIFIER attempts to recognize a 3-LISP identifier ;;; ==================== (define RECOGNIZE-IDENTIFIER (lambda [] (let [[tok (get-token)]] (cond [(member tok ['eot "[" "]" "(" ")"]) (error-in-recognition tok)] [(every-character (lambda [ch] (not (member ch *special-chars*))) tok) $true] [$true (error-in-recognition tok)])))) ;;; ERROR-IN-RECOGNITION Signals an error. ;;; ==================== (define ERROR-IN-RECOGNITION (lambda [string] (error "Recognition error" ↑string))) (define EVERY-CHARACTER (lambda [predicate string] (cond [(string-null string) $true] [(predicate (string-first string)) (every-character predicate (string-rest string))] [$true $false])))