;;; Code stored as: {turing}<3-lisp.problem-sets>general-recognizer.3-lisp ;;; {phylum}<3-lisp>course>problem-sets>general-recognizer.3-lisp ;;; ======================================================================= ;;; ;;; RECURSIVE DESCENT RECOGNIZER ;;; ;;; ======================================================================= ;;; Grammars are to be represented as a sequence of rules, where each rule is ;;; a sequence of a left-hand side and one or more right-hand side symbols. ;;; For example: ;;; ;;; (set *sample* [['s 'np 'vp] ;;; ['vp 'v 'np] ;;; ['vp 'v] ;;; ['v "slept"] ;;; ['v "loved"] ;;; ['v "wielded"] ;;; ['np "arthur"] ;;; ['np "gwen"] ;;; ['np "excalibur"]]) ;;; ;;; then: (recognize "arthur slept" 's *sample*) => "accepted" ;;; (recognize "arthur wielded excalibur" 's *sample*) => "accepted" ;;; (recognize "arthur gwen" 's *sample*) => "rejected" (define RECOGNIZE-1 (lambda [expression start-symbol grammar] (if (recognize-frontier-1 (lexical-analysis expression) [start-symbol] grammar) "accepted" "rejected"))) (define RECOGNIZE-FRONTIER-1 (lambda [tokens frontier grammar] (cond [(null frontier) (null tokens)] [(terminal (first frontier)) (and (not (null tokens)) (match (first frontier) (first tokens)) (recognize-frontier-1 (rest tokens) (rest frontier) grammar))] [(nonterminal (first frontier)) (some (lambda [rhs] (recognize-frontier-1 tokens (append rhs (rest frontier)) grammar)) (rhsides (first frontier) grammar))]))) (define TERMINAL (lambda [symbol] (or (= symbol 'identifier-expression) (= symbol 'numeral-expression) (string symbol)))) (define NONTERMINAL (compose not terminal)) (define MATCH (lambda [nonterm token] (cond [(= nonterm 'identifier-expression) (identifier-expression token)] [(= nonterm 'numeral-expression) (numeral-expression token)] [$true (= nonterm token)]))) (define RHSIDES (lambda [nonterm grammar] (filtered-map rest (lambda [rule] (= nonterm (first rule))) grammar))) ;;; ====================================================================== ;;; ANOTHER VERSION ;;; ====================================================================== (define RECOGNIZE-2 (lambda [expression start-symbol grammar] (if (some null (recognize-symbol-2 (lexical-analysis expression) start-symbol grammar)) "accepted" "rejected"))) (define RECOGNIZE-SYMBOL-2 (lambda [tokens symbol grammar] (cond [(null tokens) (nothing)] [(match symbol (first tokens)) (singleton (rest tokens))] [$t (collect (lambda [rhs] (recognize-frontier-2 tokens rhs grammar)) (rhsides symbol grammar))]))) (define RECOGNIZE-FRONTIER-2 (lambda [tokens frontier grammar] (cond [(null frontier) (singleton tokens)] [(null tokens) (nothing)] [$t (collect (lambda [fragment] (recognize-frontier-2 fragment (rest frontier) grammar)) (recognize-symbol-2 tokens (first frontier) grammar))]))) ;;; ====================================================================== ;;; YET A THIRD VERSION (even more compact) ;;; ====================================================================== (define RECOGNIZE-3 (lambda [expression start-symbol grammar] (if (some null (recognize-frontier-3 (lexical-analysis expression) [start-symbol] grammar)) "accepted" "rejected"))) (define RECOGNIZE-FRONTIER-3 (lambda [tokens frontier grammar] (cond [(null frontier) (singleton tokens)] [(null tokens) (nothing)] [$t (collect (lambda [fragment] (recognize-frontier-3 fragment (rest frontier) grammar)) (if (match (first frontier) (first tokens)) (singleton (rest tokens)) (collect (lambda [rhs] (recognize-frontier-3 tokens rhs grammar)) (rhsides (first frontier) grammar))))]))) ;;; ====================================================================== ;;; TESTS ;;; ====================================================================== (set *3g* [['exp 'identifier-expression] ['exp "(" 'exp "." 'exp ")"] ['exp "[" 'exps "]"] ['exp "[" "]"] ['exps 'exp 'exps] ['exps 'exp]]) (==> (recognize-1 "" 'exp *3g*) "rejected") (==> (recognize-1 "a" 'exp *3g*) "accepted") (==> (recognize-1 "(a.b)" 'exp *3g*) "accepted") (==> (recognize-1 "(a b )" 'exp *3g*) "rejected") (==> (recognize-1 "[]" 'exp *3g*) "accepted") (==> (recognize-1 "[a (b . b) a]" 'exp *3g*) "accepted") (set *3-epsilon* [['exp 'identifier-expression] ['exp "(" 'exp "." 'exp ")"] ['exp "[" 'exps "]"] ['exps 'exp 'exps] ['exps]])