branch: externals/parser-generator commit 58e58068f5e1eebbba1548aede2956d34094a2f9 Author: Christian Johansson <christ...@cvj.se> Commit: Christian Johansson <christ...@cvj.se>
Renamed plugin from parser to parser-generator --- Makefile | 6 +- README.md | 30 +- parser-lr.el => parser-generator-lr.el | 190 +++---- parser.el => parser-generator.el | 338 ++++++------- ...rser-lr-test.el => parser-generator-lr-test.el} | 144 +++--- test/parser-generator-test.el | 543 +++++++++++++++++++++ test/parser-test.el | 543 --------------------- 7 files changed, 897 insertions(+), 897 deletions(-) diff --git a/Makefile b/Makefile index 951c98d..0cd694e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ifdef emacs endif EMACS_CMD := $(EMACS) -Q -batch -L . -L test/ -EL := parser.el test/parser-test.el +EL := parser-generator.el parser-generator-lr.el test/parser-generator-test.el test/parser-generator-lr-test.el ELC := $(EL:.el=.elc) .PHONY: clean @@ -17,11 +17,11 @@ compile: .PHONY: test test: - $(EMACS_CMD) -l test/parser-test.el -f "parser-test" + $(EMACS_CMD) -l test/parser-generator-test.el -f "parser-generator-test" .PHONY: test-lr test-lr: - $(EMACS_CMD) -l test/parser-lr-test.el -f "parser-lr-test" + $(EMACS_CMD) -l test/parser-generator-lr-test.el -f "parser-generator-lr-test" .PHONY: tests tests: test test-lr diff --git a/README.md b/README.md index 1a51a16..cbff6e6 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,12 @@ Grammar consists of `N`, `T`, `P` and `S`, where `N` is non-terminals, `T` is te * S = `'S` ``` emacs-lisp -(parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) +(parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) ``` ### e -The symbol defined in variable `parser--e-identifier`, with default-value: 'e`, symbolizes the e symbol. The symbol is allowed in some grammars and not in others. +The symbol defined in variable `parser-generator--e-identifier`, with default-value: 'e`, symbolizes the e symbol. The symbol is allowed in some grammars and not in others. ### Non-terminals @@ -87,7 +87,7 @@ The start symbol is the entry-point of the grammar and should be either a string ### Look-ahead number -Is a simple integer above zero. You set it like this: `(parser--set-look-ahead-number 1)` for `1` number look-ahead. +Is a simple integer above zero. You set it like this: `(parser-generator--set-look-ahead-number 1)` for `1` number look-ahead. ### Syntax-directed-translation (SDT) @@ -106,14 +106,14 @@ Calculate the first look-ahead number of terminals of the sentential-form `S`, e ``` emacs-lisp (require 'ert) -(parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) -(parser--set-look-ahead-number 2) -(parser--process-grammar) +(parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) +(parser-generator--set-look-ahead-number 2) +(parser-generator--process-grammar) (should (equal '((a) (a c) (a b) (c a) (b a) (e) (c) (b) (c b)) - (parser--first 'S))) + (parser-generator--first 'S))) ``` ### E-FREE-FIRST(S) @@ -123,14 +123,14 @@ Calculate the e-free-first look-ahead number of terminals of sentential-form `S` ``` emacs-lisp (require 'ert) -(parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) -(parser--set-look-ahead-number 2) -(parser--process-grammar) +(parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) +(parser-generator--set-look-ahead-number 2) +(parser-generator--process-grammar) (should (equal '((c b) (c a)) - (parser--e-free-first 'S))) + (parser-generator--e-free-first 'S))) ``` ### FOLLOW(S) @@ -140,14 +140,14 @@ Calculate the look-ahead number of terminals possibly following S. ``` emacs-lisp (require 'ert) -(parser--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) -(parser--set-look-ahead-number 2) -(parser--process-grammar) +(parser-generator--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) +(parser-generator--set-look-ahead-number 2) +(parser-generator--process-grammar) (should (equal '((a)) - (parser--follow 'A))) + (parser-generator--follow 'A))) ``` ## Test diff --git a/parser-lr.el b/parser-generator-lr.el similarity index 80% rename from parser-lr.el rename to parser-generator-lr.el index 5a1b9f4..1b3b4c8 100644 --- a/parser-lr.el +++ b/parser-generator-lr.el @@ -1,4 +1,4 @@ -;;; parser-el.el --- LR(k) Parser -*- lexical-binding: t -*- +;;; parser-generator-lr.el --- LR(k) Parser Generator -*- lexical-binding: t -*- ;;; Commentary: @@ -7,20 +7,21 @@ ;;; Code: -(require 'parser) +(require 'parser-generator) ;;; Variables: -(defvar parser-lr--action-tables + +(defvar parser-generator-lr--action-tables nil "Action-tables for grammar.") -(defvar parser-lr--goto-tables +(defvar parser-generator-lr--goto-tables nil "Goto-tables for grammar.") -(defvar parser-lr--items +(defvar parser-generator-lr--items nil "Hash-table for distinct LR-items in grammar.") @@ -28,30 +29,29 @@ ;; Helper Functions -(defun parser-lr--reset () +(defun parser-generator-lr--reset () "Reset variables." - (setq parser-lr--action-tables nil) - (setq parser-lr--goto-tables nil) - (setq parser-lr--items nil)) + (setq parser-generator-lr--action-tables nil) + (setq parser-generator-lr--goto-tables nil) + (setq parser-generator-lr--items nil)) ;; Main Algorithms ;; Algorithm 5.11, p. 393 -(defun parser-lr--generate-action-tables () +(defun parser-generator-lr--generate-action-tables () "Generate action-tables for lr-grammar." - (unless parser-lr--action-tables + (unless parser-generator-lr--action-tables (let ((action-tables) (states '(shift reduce error)) (added-actions (make-hash-table :test 'equal)) - (goto-tables (parser--hash-to-list parser-lr--goto-tables))) + (goto-tables (parser-generator--hash-to-list parser-generator-lr--goto-tables))) (dolist (goto-table goto-tables) (let ((goto-index (car goto-table)) - (gotos (car (cdr goto-table))) (found-action nil) (action-table)) - (let ((lr-items (gethash goto-index parser-lr--items))) + (let ((lr-items (gethash goto-index parser-generator-lr--items))) (let ((lr-items-length (length lr-items))) ;; Where u is in (T U e)*k (dolist (state states) @@ -71,7 +71,7 @@ (v (nth 3 lr-item))) (let ((Cv (append C v))) (when Cv - (let ((eff (parser--e-free-first Cv))) + (let ((eff (parser-generator--e-free-first Cv))) (when eff ;; Go through eff-items and see if any item is a valid look-ahead of grammar ;; in that case save in action table a shift action here @@ -83,7 +83,7 @@ searching-match (< eff-index eff-length)) (setq eff-item (nth eff-index eff)) - (when (parser--valid-look-ahead-p eff-item) + (when (parser-generator--valid-look-ahead-p eff-item) (let ((hash-key (format "%s-%s-%s" goto-index state eff-item))) (unless (gethash hash-key added-actions) (puthash hash-key t added-actions) @@ -103,20 +103,20 @@ (B (nth 1 lr-item)) (u (nth 3 lr-item))) (unless B - (setq B (list parser--e-identifier))) - (when (parser--valid-look-ahead-p u) + (setq B (list parser-generator--e-identifier))) + (when (parser-generator--valid-look-ahead-p u) (let ((hash-key (format "%s-%s-%s" goto-index state u))) (unless (gethash hash-key added-actions) (puthash hash-key t added-actions) (let ((production (list A B))) - (let ((production-number (parser--get-grammar-production-number production))) + (let ((production-number (parser-generator--get-grammar-production-number production))) (unless production-number (error "Expecting production number for %s from LR-item %s!" production lr-item)) (if (and (= production-number 0) (= (length u) 1) - (parser--valid-e-p (car u))) + (parser-generator--valid-e-p (car u))) (progn ;; Reduction by first production ;; of empty look-ahead means grammar has been accepted @@ -132,33 +132,33 @@ (error (format "Failed to find any action in set %s" lr-items))) (setq continue-loop nil))) (setq lr-item-index (1+ lr-item-index))))))) - (parser--debug + (parser-generator--debug (message "%s actions %s" goto-index action-table)) (when action-table - (push (list goto-index (sort action-table 'parser--sort-list)) action-tables)))) + (push (list goto-index (sort action-table 'parser-generator--sort-list)) action-tables)))) (setq action-tables (nreverse action-tables)) - (setq parser-lr--action-tables (make-hash-table :test 'equal)) + (setq parser-generator-lr--action-tables (make-hash-table :test 'equal)) (let ((table-length (length action-tables)) (table-index 0)) (while (< table-index table-length) - (puthash table-index (car (cdr (nth table-index action-tables))) parser-lr--action-tables) + (puthash table-index (car (cdr (nth table-index action-tables))) parser-generator-lr--action-tables) (setq table-index (1+ table-index))))))) ;; Algorithm 5.9, p. 389 -(defun parser-lr--generate-goto-tables () +(defun parser-generator-lr--generate-goto-tables () "Calculate set of valid LR(k) items for grammar and a GOTO-table." (unless (or - parser-lr--goto-tables - parser-lr--items) - (setq parser-lr--goto-tables nil) - (setq parser-lr--items (make-hash-table :test 'equal)) + parser-generator-lr--goto-tables + parser-generator-lr--items) + (setq parser-generator-lr--goto-tables nil) + (setq parser-generator-lr--items (make-hash-table :test 'equal)) (let ((lr-item-set-new-index 0) (goto-table) (unmarked-lr-item-sets) (marked-lr-item-sets (make-hash-table :test 'equal)) - (symbols (append (parser--get-grammar-non-terminals) (parser--get-grammar-terminals)))) + (symbols (append (parser-generator--get-grammar-non-terminals) (parser-generator--get-grammar-terminals)))) - (let ((e-set (parser-lr--items-for-prefix parser--e-identifier))) + (let ((e-set (parser-generator-lr--items-for-prefix parser-generator--e-identifier))) ;;(1) Place V(e) in S. The set V(e) is initially unmarked. (push `(,lr-item-set-new-index ,e-set) unmarked-lr-item-sets) (setq lr-item-set-new-index (1+ lr-item-set-new-index))) @@ -174,7 +174,7 @@ (setq popped-item (pop unmarked-lr-item-sets)) (setq lr-item-set-index (car popped-item)) (setq lr-items (car (cdr popped-item))) - (parser--debug + (parser-generator--debug (message "lr-item-set-index: %s" lr-item-set-index) (message "lr-items: %s" lr-items) (message "popped-item: %s" popped-item)) @@ -182,32 +182,32 @@ ;; (2) Mark a (puthash lr-items lr-item-set-index marked-lr-item-sets) - (puthash lr-item-set-index lr-items parser-lr--items) + (puthash lr-item-set-index lr-items parser-generator-lr--items) (setq goto-table-table nil) ;; (2) By computing for each X in N u E, GOTO (a, X). (Algorithm 5.8 can be used here.) ;; V(X1,...,Xi) = GOTO(V(X1,...,Xi-1), Xi) (dolist (symbol symbols) - (parser--debug + (parser-generator--debug (message "symbol: %s" symbol)) - (let ((prefix-lr-items (parser-lr--items-for-goto lr-items symbol))) + (let ((prefix-lr-items (parser-generator-lr--items-for-goto lr-items symbol))) ;; If a' = GOTO(a, X) is nonempty (when prefix-lr-items - (parser--debug + (parser-generator--debug (message "GOTO(%s, %s) = %s" lr-items symbol prefix-lr-items)) ;; and is not already in S (let ((goto (gethash prefix-lr-items marked-lr-item-sets))) (if goto (progn - (parser--debug + (parser-generator--debug (message "Set already exists in: %s" goto)) (push `(,symbol ,goto) goto-table-table)) - (parser--debug + (parser-generator--debug (message "Set is new")) ;; Note that GOTO(a, X) will always be empty if all items in a @@ -218,25 +218,25 @@ (push `(,lr-item-set-new-index ,prefix-lr-items) unmarked-lr-item-sets) (setq lr-item-set-new-index (1+ lr-item-set-new-index))))))) - (setq goto-table-table (sort goto-table-table 'parser--sort-list)) + (setq goto-table-table (sort goto-table-table 'parser-generator--sort-list)) (push `(,lr-item-set-index ,goto-table-table) goto-table))) - (setq goto-table (sort goto-table 'parser--sort-list)) - (setq parser-lr--goto-tables (make-hash-table :test 'equal)) + (setq goto-table (sort goto-table 'parser-generator--sort-list)) + (setq parser-generator-lr--goto-tables (make-hash-table :test 'equal)) (let ((table-length (length goto-table)) (table-index 0)) (while (< table-index table-length) - (puthash table-index (car (cdr (nth table-index goto-table))) parser-lr--goto-tables) + (puthash table-index (car (cdr (nth table-index goto-table))) parser-generator-lr--goto-tables) (setq table-index (1+ table-index))))) (unless - (parser-lr--items-valid-p - (parser--hash-values-to-list parser-lr--items t)) ;; TODO Should not use this debug function + (parser-generator-lr--items-valid-p + (parser-generator--hash-values-to-list parser-generator-lr--items t)) ;; TODO Should not use this debug function (error "Inconsistent grammar!")))) ;; Algorithm 5.10, p. 391 -(defun parser-lr--items-valid-p (lr-item-sets) +(defun parser-generator-lr--items-valid-p (lr-item-sets) "Return whether the set collection LR-ITEM-SETS is valid or not." - (parser--debug + (parser-generator--debug (message "lr-item-sets: %s" lr-item-sets)) (let ((valid-p t) (set-index 0) @@ -259,7 +259,7 @@ valid-p (< set-index sets-length)) (setq set (nth set-index lr-item-sets)) - (parser--debug + (parser-generator--debug (message "set: %s" set)) ;; Iterate each set @@ -272,7 +272,7 @@ (setq a (nth a-index set)) (setq a-look-ahead (nth 2 a)) - (parser--debug + (parser-generator--debug (message "a: %s" a) (message "a-look-ahead: %s" a-look-ahead)) @@ -282,7 +282,7 @@ (not a-look-ahead)) (setq a-follow (nth 3 a)) - (parser--debug + (parser-generator--debug (message "a-follow: %s" a-follow)) ;; Iterate each set again @@ -294,9 +294,9 @@ (setq b-suffix (nth 2 b)) (setq b-follow (nth 3 b)) (setq b-suffix-follow (append b-suffix b-follow)) - (setq b-suffix-follow-eff (parser--e-free-first b-suffix-follow)) + (setq b-suffix-follow-eff (parser-generator--e-free-first b-suffix-follow)) - (parser--debug + (parser-generator--debug (message "b: %s" b) (message "b-suffix: %s" b-suffix) (message "b-follow: %s" b-follow) @@ -305,7 +305,7 @@ (dolist (b-suffix-follow-eff-item b-suffix-follow-eff) (when (equal a-follow b-suffix-follow-eff-item) - (parser--debug + (parser-generator--debug (message "Inconsistent grammar! %s conflicts with %s" a b)) (setq valid-p nil)))) (setq b-index (1+ b-index)))) @@ -315,12 +315,12 @@ valid-p)) ;; Algorithm 5.8, p. 386 -(defun parser-lr--items-for-prefix (γ) +(defun parser-generator-lr--items-for-prefix (γ) "Calculate valid LR-items for the viable prefix Γ." - (let ((start (parser--get-grammar-start))) + (let ((start (parser-generator--get-grammar-start))) (unless (listp γ) (setq γ (list γ))) - (unless (parser--valid-sentential-form-p γ) + (unless (parser-generator--valid-sentential-form-p γ) (error "Invalid sentential form γ!")) (let ((lr-item-exists (make-hash-table :test 'equal))) @@ -329,13 +329,13 @@ ;; Iterate all productions in grammar (let ((lr-items-e) - (start-productions (parser--get-grammar-rhs start))) + (start-productions (parser-generator--get-grammar-rhs start))) ;; (a) (dolist (rhs start-productions) ;; Add [S -> . α] to V(e) (push `(,start nil ,rhs (e)) lr-items-e) - (puthash `(,parser--e-identifier ,start nil ,rhs (,parser--e-identifier)) t lr-item-exists)) + (puthash `(,parser-generator--e-identifier ,start nil ,rhs (,parser-generator--e-identifier)) t lr-item-exists)) ;; (b) Iterate every item in v-set(e), if [A -> . Bα, u] is an item and B -> β is in P ;; then for each x in FIRST(αu) add [B -> . β, x] to v-set(e), provided it is not already there @@ -356,17 +356,17 @@ ;; Check if RHS starts with a non-terminal (let ((rhs-first (car rhs))) - (parser--debug + (parser-generator--debug (message "rhs-first: %s" rhs-first)) - (when (parser--valid-non-terminal-p rhs-first) + (when (parser-generator--valid-non-terminal-p rhs-first) (let ((rhs-rest (append (cdr rhs) suffix))) - (let ((rhs-rest-first (parser--first rhs-rest))) - (parser--debug + (let ((rhs-rest-first (parser-generator--first rhs-rest))) + (parser-generator--debug (message "rhs-rest-first: %s" rhs-rest-first)) (unless rhs-rest-first - (setq rhs-rest-first `((,parser--e-identifier)))) - (let ((sub-production (parser--get-grammar-rhs rhs-first))) - (parser--debug + (setq rhs-rest-first `((,parser-generator--e-identifier)))) + (let ((sub-production (parser-generator--get-grammar-rhs rhs-first))) + (parser-generator--debug (message "sub-production: %s" sub-production)) ;; For each production with B as LHS @@ -375,15 +375,15 @@ ;; Set follow to nil if it's the e-identifier (when (and (= (length sub-rhs) 1) - (parser--valid-e-p (car sub-rhs))) + (parser-generator--valid-e-p (car sub-rhs))) (setq sub-rhs nil)) - (parser--debug + (parser-generator--debug (message "sub-rhs: %s" sub-rhs)) ;; For each x in FIRST(αu) (dolist (f rhs-rest-first) - (parser--debug + (parser-generator--debug (message "f: %s" f)) ;; Add [B -> . β, x] to V(e), provided it is not already there @@ -394,37 +394,37 @@ ;; (c) Repeat (b) until no more items can be added to V(e) (setq found-new t)))))))))))))) - (parser--debug + (parser-generator--debug (message "V(e) = %s" lr-items-e)) - (setq lr-items-e (sort lr-items-e 'parser--sort-list)) + (setq lr-items-e (sort lr-items-e 'parser-generator--sort-list)) ;; 2 Suppose that we have constructed V(X1,X2,...,Xi-1) we construct V(X1,X2,...,Xi) as follows: ;; Only do this step if prefix is not the e-identifier (let ((prefix-previous lr-items-e)) (unless (and (= (length γ) 1) - (parser--valid-e-p (car γ))) + (parser-generator--valid-e-p (car γ))) (dolist (prefix γ) (let ((lr-new-item)) - (setq lr-new-item (parser-lr--items-for-goto prefix-previous prefix)) + (setq lr-new-item (parser-generator-lr--items-for-goto prefix-previous prefix)) - (parser--debug + (parser-generator--debug (message "prefix: %s" prefix) (message "prefix-previous: %s" prefix-previous) (message "lr-new-item: %s" lr-new-item)) (setq prefix-previous lr-new-item)))) - (parser--debug + (parser-generator--debug (message "γ: %s" γ)) prefix-previous))))) -(defun parser-lr--items-for-goto (previous-lr-item x) +(defun parser-generator-lr--items-for-goto (previous-lr-item x) "Calculate LR-items for GOTO(PREVIOUS-LR-ITEM, X)." (let ((lr-new-item) (lr-item-exists (make-hash-table :test 'equal))) - (parser--debug (message "x: %s" x)) + (parser-generator--debug (message "x: %s" x)) (dolist (lr-item previous-lr-item) (let ((lr-item-lhs (nth 0 lr-item)) @@ -439,7 +439,7 @@ ;; Add [A -> aXi . B, u] to V(X1,...,Xi) (let ((combined-prefix (append lr-item-prefix (list x)))) - (parser--debug + (parser-generator--debug (message "lr-new-item-1: %s" `(,lr-item-lhs ,combined-prefix ,lr-item-suffix-rest ,lr-item-look-ahead))) (push `(,lr-item-lhs ,combined-prefix ,lr-item-suffix-rest ,lr-item-look-ahead) lr-new-item)))))) @@ -454,12 +454,12 @@ ;; (b) If [A -> a . Bb, u] has been placed in V(X1,...,Xi) ;; and B -> D is in P - (when (parser--valid-non-terminal-p lr-item-suffix-first) + (when (parser-generator--valid-non-terminal-p lr-item-suffix-first) - (let ((lr-item-suffix-rest-first (parser--first lr-item-suffix-rest))) + (let ((lr-item-suffix-rest-first (parser-generator--first lr-item-suffix-rest))) (unless lr-item-suffix-rest-first (setq lr-item-suffix-rest-first (list nil))) - (let ((sub-production (parser--get-grammar-rhs lr-item-suffix-first))) + (let ((sub-production (parser-generator--get-grammar-rhs lr-item-suffix-first))) ;; For each production with B as LHS (dolist (sub-rhs sub-production) @@ -467,7 +467,7 @@ ;; Transform e-productions into nil (when (and (= (length sub-rhs) 1) - (parser--valid-e-p (car sub-rhs))) + (parser-generator--valid-e-p (car sub-rhs))) (setq sub-rhs nil)) ;; For each x in FIRST(αu) @@ -478,11 +478,11 @@ (let ((lr-item-to-add `(,lr-item-suffix-first nil ,sub-rhs ,f))) (unless (gethash lr-item-to-add lr-item-exists) (setq added-new t) - (parser--debug (message "lr-item-to-add: %s" lr-item-to-add)) + (parser-generator--debug (message "lr-item-to-add: %s" lr-item-to-add)) (puthash lr-item-to-add t lr-item-exists) (push lr-item-to-add lr-new-item))))))))))))) - (setq lr-new-item (sort lr-new-item 'parser--sort-list)) + (setq lr-new-item (sort lr-new-item 'parser-generator--sort-list)) lr-new-item)) ;; Algorithm 5.7, p. 375 @@ -490,7 +490,7 @@ ;; TODO Add support for SDT ;; TODO Add support for semantic-actions ;; TODO Consider case with 2 character look-ahead -(defun parser-lr--parse (input-tape &optional input-tape-index pushdown-list) +(defun parser-generator-lr--parse (input-tape &optional input-tape-index pushdown-list) "Perform a LR-parse of INPUT-TAPE optionally at INPUT-TAPE-INDEX with PUSHDOWN-LIST." (unless input-tape-index (setq input-tape-index 0)) @@ -498,8 +498,8 @@ (push 0 pushdown-list)) ;; Make sure tables exists - (parser-lr--generate-goto-tables) - (parser-lr--generate-action-tables) + (parser-generator-lr--generate-goto-tables) + (parser-generator-lr--generate-action-tables) (let ((accept nil) (input-tape-length (length input-tape)) @@ -515,20 +515,20 @@ (while (and (< look-ahead-input-tape-index input-tape-length) - (< look-ahead-length parser--look-ahead-number)) + (< look-ahead-length parser-generator--look-ahead-number)) (push (nth look-ahead-input-tape-index input-tape) look-ahead) (setq look-ahead-length (1+ look-ahead-length)) (setq look-ahead-input-tape-index (1+ look-ahead-input-tape-index))) ;; If we reached end of input-tape and look-ahead is too small, append e-identifiers - (while (< look-ahead-length parser--look-ahead-number) - (push parser--e-identifier look-ahead) + (while (< look-ahead-length parser-generator--look-ahead-number) + (push parser-generator--e-identifier look-ahead) (setq look-ahead-length (1+ look-ahead-length))) (setq look-ahead (nreverse look-ahead)) (let ((table-index (car pushdown-list))) - (let ((action-table (gethash table-index parser-lr--action-tables))) + (let ((action-table (gethash table-index parser-generator-lr--action-tables))) (let ((action-match nil) (action-table-length (length action-table)) @@ -568,7 +568,7 @@ ;; and declare error. (let ((a (car look-ahead))) - (let ((goto-table (gethash table-index parser-lr--goto-tables))) + (let ((goto-table (gethash table-index parser-generator-lr--goto-tables))) (let ((goto-table-length (length goto-table)) (goto-index 0) (searching-match t) @@ -608,10 +608,10 @@ ;; the pushdown list and return to step (1) (let ((production-number (car (cdr action-match)))) - (let ((production (parser--get-grammar-production-by-number production-number))) + (let ((production (parser-generator--get-grammar-production-by-number production-number))) (let ((production-lhs (car production)) (production-rhs (car (cdr production)))) - (unless (equal production-rhs (list parser--e-identifier)) + (unless (equal production-rhs (list parser-generator--e-identifier)) (let ((pop-items (* 2 (length production-rhs))) (popped-items 0)) (while (< popped-items pop-items) @@ -620,7 +620,7 @@ (push production-number output) (let ((new-table-index (car pushdown-list))) - (let ((goto-table (gethash new-table-index parser-lr--goto-tables))) + (let ((goto-table (gethash new-table-index parser-generator-lr--goto-tables))) (let ((goto-table-length (length goto-table)) (goto-index 0) (searching-match t) @@ -655,6 +655,6 @@ (error "Parsed entire string without getting accepting!")) (nreverse output))) -(provide 'parser-lr) +(provide 'parser-generator-lr) -;;; parser-lr.el ends here +;;; parser-generator-lr.el ends here diff --git a/parser.el b/parser-generator.el similarity index 72% rename from parser.el rename to parser-generator.el index 90a73f2..3467008 100644 --- a/parser.el +++ b/parser-generator.el @@ -1,4 +1,4 @@ -;;; parser.el --- Parser library -*- lexical-binding: t -*- +;;; parser-generator.el --- Parser Generator library -*- lexical-binding: t -*- ;;; Commentary: @@ -9,59 +9,59 @@ ;;; Variables: -(defvar parser--allow-e-productions +(defvar parser-generator--allow-e-productions nil "Flag whether e-productions is allowed or not.") -(defvar parser--debug +(defvar parser-generator--debug nil "Whether to print debug messages or not.") -(defvar parser--e-identifier +(defvar parser-generator--e-identifier 'e "The identifier used for e-symbol. Default value 'e.") -(defvar parser--grammar +(defvar parser-generator--grammar nil "Current grammar used in parser.") -(defvar parser--f-sets +(defvar parser-generator--f-sets nil "Generated F-sets for grammar.") -(defvar parser--f-free-sets +(defvar parser-generator--f-free-sets nil "Generated e-free F-sets for grammar.") -(defvar parser--lex-analyzer-function +(defvar parser-generator--lex-analyzer-function nil "Function used as lex-analyzer.") -(defvar parser--look-ahead-number +(defvar parser-generator--look-ahead-number nil "Current look-ahead number used.") -(defvar parser--table-look-aheads-p +(defvar parser-generator--table-look-aheads-p nil "Hash-table of look-aheads for quick checking.") -(defvar parser--table-non-terminal-p +(defvar parser-generator--table-non-terminal-p nil "Hash-table of terminals for quick checking.") -(defvar parser--table-productions-rhs +(defvar parser-generator--table-productions-rhs nil "Hash-table of productions RHS indexed by LHS for quick retrieving.") -(defvar parser--table-productions-number +(defvar parser-generator--table-productions-number nil "Hash-table indexed by production and value is production-number.") -(defvar parser--table-productions-number-reverse +(defvar parser-generator--table-productions-number-reverse nil "Hash-table indexed by production-number and value is production.") -(defvar parser--table-terminal-p +(defvar parser-generator--table-terminal-p nil "Hash-table of non-terminals for quick checking.") @@ -69,21 +69,21 @@ ;; Macros -(defmacro parser--debug (&rest message) +(defmacro parser-generator--debug (&rest message) "Output MESSAGE but only if debug is enabled." - `(when parser--debug + `(when parser-generator--debug ,@message)) ;; Helper Functions -(defun parser--clear-cache () +(defun parser-generator--clear-cache () "Clear cache." - (setq parser--f-sets nil) - (setq parser--f-free-sets nil)) + (setq parser-generator--f-sets nil) + (setq parser-generator--f-free-sets nil)) -(defun parser--distinct (elements) +(defun parser-generator--distinct (elements) "Return distinct of ELEMENTS." (let ((processed (make-hash-table :test 'equal)) (new-elements)) @@ -93,13 +93,13 @@ (push element new-elements))) (nreverse new-elements))) -(defun parser--get-grammar-look-aheads () +(defun parser-generator--get-grammar-look-aheads () "Return all possible look-ahead set." - (unless parser--look-ahead-number + (unless parser-generator--look-ahead-number (error "No look-ahead number defined!")) - (let ((terminals (parser--get-grammar-terminals)) + (let ((terminals (parser-generator--get-grammar-terminals)) (look-aheads) - (k parser--look-ahead-number) + (k parser-generator--look-ahead-number) (stack '((0 0 nil))) (marked-paths (make-hash-table :test 'equal)) (added-look-aheads (make-hash-table :test 'equal))) @@ -137,70 +137,70 @@ (setq look-ahead-to-add (reverse look-ahead))) (when (= look-ahead-length (1- k)) - (push parser--e-identifier look-ahead) + (push parser-generator--e-identifier look-ahead) (setq look-ahead-to-add (reverse look-ahead)))) (when (= k 1) - (setq look-ahead-to-add `(,parser--e-identifier)))) + (setq look-ahead-to-add `(,parser-generator--e-identifier)))) (when (and look-ahead-to-add (not (gethash look-ahead-to-add added-look-aheads))) (puthash look-ahead-to-add t added-look-aheads) (push look-ahead-to-add look-aheads)))))) - (sort look-aheads 'parser--sort-list))) + (sort look-aheads 'parser-generator--sort-list))) -(defun parser--get-grammar-non-terminals (&optional G) +(defun parser-generator--get-grammar-non-terminals (&optional G) "Return non-terminals of grammar G." (unless G - (if parser--grammar - (setq G parser--grammar) + (if parser-generator--grammar + (setq G parser-generator--grammar) (error "No grammar G defined!"))) (nth 0 G)) -(defun parser--get-grammar-production-number (production) +(defun parser-generator--get-grammar-production-number (production) "If PRODUCTION exist, return it's number." - (unless parser--table-productions-number + (unless parser-generator--table-productions-number (error "Table for production-numbers is undefined!")) - (gethash production parser--table-productions-number)) + (gethash production parser-generator--table-productions-number)) -(defun parser--get-grammar-production-by-number (production-number) +(defun parser-generator--get-grammar-production-by-number (production-number) "If PRODUCTION-NUMBER exist, return it's production." - (unless parser--table-productions-number-reverse + (unless parser-generator--table-productions-number-reverse (error "Table for reverse production-numbers is undefined!")) - (gethash production-number parser--table-productions-number-reverse)) + (gethash production-number parser-generator--table-productions-number-reverse)) -(defun parser--get-grammar-productions (&optional G) +(defun parser-generator--get-grammar-productions (&optional G) "Return productions of grammar G." (unless G - (if parser--grammar - (setq G parser--grammar) + (if parser-generator--grammar + (setq G parser-generator--grammar) (error "No grammar G defined!"))) (nth 2 G)) -(defun parser--get-grammar-rhs (lhs) +(defun parser-generator--get-grammar-rhs (lhs) "Return right hand sides of LHS if there is any." - (unless parser--table-productions-rhs + (unless parser-generator--table-productions-rhs (error "Table for productions RHS indexed by LHS is undefined!")) - (gethash lhs parser--table-productions-rhs)) + (gethash lhs parser-generator--table-productions-rhs)) -(defun parser--get-grammar-start (&optional G) +(defun parser-generator--get-grammar-start (&optional G) "Return start of grammar G." (unless G - (if parser--grammar - (setq G parser--grammar) + (if parser-generator--grammar + (setq G parser-generator--grammar) (error "No grammar G defined!"))) (nth 3 G)) -(defun parser--get-grammar-terminals (&optional G) +(defun parser-generator--get-grammar-terminals (&optional G) "Return terminals of grammar G." (unless G - (if parser--grammar - (setq G parser--grammar) + (if parser-generator--grammar + (setq G parser-generator--grammar) (error "No grammar G defined!"))) (nth 1 G)) -(defun parser--hash-to-list (hash-table &optional un-sorted) +(defun parser-generator--hash-to-list (hash-table &optional un-sorted) "Return a list that represent the HASH-TABLE. Each element is a list: (list key value), optionally UN-SORTED." (let (result) (if (hash-table-p hash-table) @@ -213,7 +213,7 @@ (sort (nreverse result) (lambda (a b) (< (car a) (car b)))))) nil))) -(defun parser--hash-values-to-list (hash-table &optional un-sorted) +(defun parser-generator--hash-values-to-list (hash-table &optional un-sorted) "Return a list that represent the HASH-TABLE. Each element is a list: (list key value), optionally UN-SORTED." (let (result) (if (hash-table-p hash-table) @@ -226,32 +226,32 @@ (sort (nreverse result) (lambda (a b) (< (car a) (car b)))))) nil))) -(defun parser--load-symbols () +(defun parser-generator--load-symbols () "Load terminals and non-terminals in grammar." - (let ((terminals (parser--get-grammar-terminals))) - (setq parser--table-terminal-p (make-hash-table :test 'equal)) + (let ((terminals (parser-generator--get-grammar-terminals))) + (setq parser-generator--table-terminal-p (make-hash-table :test 'equal)) (dolist (terminal terminals) - (puthash terminal t parser--table-terminal-p))) + (puthash terminal t parser-generator--table-terminal-p))) - (let ((non-terminals (parser--get-grammar-non-terminals))) - (setq parser--table-non-terminal-p (make-hash-table :test 'equal)) + (let ((non-terminals (parser-generator--get-grammar-non-terminals))) + (setq parser-generator--table-non-terminal-p (make-hash-table :test 'equal)) (dolist (non-terminal non-terminals) - (puthash non-terminal t parser--table-non-terminal-p))) + (puthash non-terminal t parser-generator--table-non-terminal-p))) - (let ((productions (parser--get-grammar-productions))) - (setq parser--table-productions-rhs (make-hash-table :test 'equal)) + (let ((productions (parser-generator--get-grammar-productions))) + (setq parser-generator--table-productions-rhs (make-hash-table :test 'equal)) (dolist (p productions) (let ((lhs (car p)) (rhs (cdr p))) - (let ((new-value (gethash lhs parser--table-productions-rhs))) + (let ((new-value (gethash lhs parser-generator--table-productions-rhs))) (dolist (rhs-element rhs) (unless (listp rhs-element) (setq rhs-element (list rhs-element))) (push rhs-element new-value)) - (puthash lhs (nreverse new-value) parser--table-productions-rhs)))) + (puthash lhs (nreverse new-value) parser-generator--table-productions-rhs)))) - (setq parser--table-productions-number (make-hash-table :test 'equal)) - (setq parser--table-productions-number-reverse (make-hash-table :test 'equal)) + (setq parser-generator--table-productions-number (make-hash-table :test 'equal)) + (setq parser-generator--table-productions-number-reverse (make-hash-table :test 'equal)) (let ((production-index 0)) (dolist (p productions) (let ((lhs (car p)) @@ -261,53 +261,53 @@ (unless (listp rhs-element) (setq rhs-element (list rhs-element))) (setq production (list lhs rhs-element)) - (parser--debug + (parser-generator--debug (message "Production %s: %s" production-index production)) - (puthash production production-index parser--table-productions-number) - (puthash production-index production parser--table-productions-number-reverse) + (puthash production production-index parser-generator--table-productions-number) + (puthash production-index production parser-generator--table-productions-number-reverse) (setq production-index (1+ production-index))))))) - (let ((look-aheads (parser--get-grammar-look-aheads))) - (setq parser--table-look-aheads-p (make-hash-table :test 'equal)) + (let ((look-aheads (parser-generator--get-grammar-look-aheads))) + (setq parser-generator--table-look-aheads-p (make-hash-table :test 'equal)) (dolist (look-ahead look-aheads) - (puthash look-ahead t parser--table-look-aheads-p)))) + (puthash look-ahead t parser-generator--table-look-aheads-p)))) -(defun parser--set-look-ahead-number (k) +(defun parser-generator--set-look-ahead-number (k) "Set look-ahead number K." - (unless (parser--valid-look-ahead-number-p k) + (unless (parser-generator--valid-look-ahead-number-p k) (error "Invalid look-ahead number k!")) - (setq parser--look-ahead-number k)) + (setq parser-generator--look-ahead-number k)) -(defun parser--set-allow-e-productions (flag) +(defun parser-generator--set-allow-e-productions (flag) "Set FLAG whether e-productions is allowed or not." - (setq parser--allow-e-productions flag)) + (setq parser-generator--allow-e-productions flag)) -(defun parser--set-grammar (G) +(defun parser-generator--set-grammar (G) "Set grammar G.." - (unless (parser--valid-grammar-p G) + (unless (parser-generator--valid-grammar-p G) (error "Invalid grammar G!")) - (setq parser--grammar G)) + (setq parser-generator--grammar G)) -(defun parser--process-grammar () +(defun parser-generator--process-grammar () "Process grammar." - (parser--clear-cache) - (parser--load-symbols)) + (parser-generator--clear-cache) + (parser-generator--load-symbols)) -(defun parser--load-next-look-ahead () +(defun parser-generator--load-next-look-ahead () "Load next look-ahead number of tokens via lex-analyzer." - (unless parser--lex-analyzer-function + (unless parser-generator--lex-analyzer-function (error "Missing lex-analyzer function!")) - (let ((left parser--look-ahead-number) + (let ((left parser-generator--look-ahead-number) (look-ahead)) (while (> left 0) - (let ((token (funcall parser--lex-analyzer-function))) + (let ((token (funcall parser-generator--lex-analyzer-function))) (if token (push token look-ahead) - (push parser--e-identifier look-ahead))) + (push parser-generator--e-identifier look-ahead))) (setq left (1- left))) look-ahead)) -(defun parser--sort-list (a b) +(defun parser-generator--sort-list (a b) "Return non-nil if a element in A is greater than a element in B in lexicographic order." (let ((length (min (length a) (length b))) (index 0) @@ -349,11 +349,11 @@ (setq index (1+ index))) response)) -(defun parser--valid-e-p (symbol) +(defun parser-generator--valid-e-p (symbol) "Return whether SYMBOL is the e identifier or not." - (eq symbol parser--e-identifier)) + (eq symbol parser-generator--e-identifier)) -(defun parser--valid-grammar-p (G) +(defun parser-generator--valid-grammar-p (G) "Return if grammar G is valid or not. Grammar should contain list with 4 elements: non-terminals (N), terminals (T), productions (P), start (S) where N, T and P are lists containing symbols and/or strings and S is a symbol or string." (let ((valid-p t)) (unless (listp G) @@ -410,7 +410,7 @@ valid-p (< production-index production-count)) (let ((production (nth production-index productions))) - (unless (parser--valid-production-p production) + (unless (parser-generator--valid-production-p production) (setq valid-p nil))) (setq production-index (1+ production-index))))) @@ -422,27 +422,27 @@ (setq valid-p nil)))) valid-p)) -(defun parser--valid-look-ahead-p (symbol) +(defun parser-generator--valid-look-ahead-p (symbol) "Return whether SYMBOL is a look-ahead in grammar or not." - (unless parser--table-look-aheads-p + (unless parser-generator--table-look-aheads-p (error "Table for look-aheads is undefined!")) (unless (listp symbol) (setq symbol (list symbol))) - (gethash symbol parser--table-look-aheads-p)) + (gethash symbol parser-generator--table-look-aheads-p)) -(defun parser--valid-look-ahead-number-p (k) +(defun parser-generator--valid-look-ahead-number-p (k) "Return if look-ahead number K is valid or not." (and (integerp k) (>= k 0))) -(defun parser--valid-non-terminal-p (symbol) +(defun parser-generator--valid-non-terminal-p (symbol) "Return whether SYMBOL is a non-terminal in grammar or not." - (unless parser--table-non-terminal-p + (unless parser-generator--table-non-terminal-p (error "Table for non-terminals is undefined!")) - (gethash symbol parser--table-non-terminal-p)) + (gethash symbol parser-generator--table-non-terminal-p)) -(defun parser--valid-production-p (production) +(defun parser-generator--valid-production-p (production) "Return whether PRODUCTION is valid or not." (let ((is-valid t)) (unless (listp production) @@ -502,7 +502,7 @@ (setq rhs-index (1+ rhs-index))))))) is-valid)) -(defun parser--valid-sentential-form-p (symbols) +(defun parser-generator--valid-sentential-form-p (symbols) "Return whether SYMBOLS is a valid sentential form in grammar or not." (let ((is-valid t)) (let ((symbols-length (length symbols)) @@ -511,43 +511,43 @@ is-valid (< symbol-index symbols-length)) (let ((symbol (nth symbol-index symbols))) - (unless (parser--valid-symbol-p symbol) + (unless (parser-generator--valid-symbol-p symbol) (setq is-valid nil))) (setq symbol-index (1+ symbol-index)))) is-valid)) -(defun parser--valid-symbol-p (symbol) +(defun parser-generator--valid-symbol-p (symbol) "Return whether SYMBOL is valid or not." (let ((is-valid t)) (unless (or - (parser--valid-e-p symbol) - (parser--valid-non-terminal-p symbol) - (parser--valid-terminal-p symbol)) + (parser-generator--valid-e-p symbol) + (parser-generator--valid-non-terminal-p symbol) + (parser-generator--valid-terminal-p symbol)) (setq is-valid nil)) is-valid)) -(defun parser--valid-terminal-p (symbol) +(defun parser-generator--valid-terminal-p (symbol) "Return whether SYMBOL is a terminal in grammar or not." - (unless parser--table-terminal-p + (unless parser-generator--table-terminal-p (error "Table for terminals is undefined!")) - (gethash symbol parser--table-terminal-p)) + (gethash symbol parser-generator--table-terminal-p)) ;; Main Algorithms ;; p. 381 -(defun parser--e-free-first (α) +(defun parser-generator--e-free-first (α) "For sentential string Α, Calculate e-free-first k terminals in grammar." - (parser--first α t)) + (parser-generator--first α t)) ;; p. 358 -(defun parser--f-set (input-tape state stack) +(defun parser-generator--f-set (input-tape state stack) "A deterministic push-down transducer (DPDT) for building F-sets from INPUT-TAPE, STATE and STACK." (unless (listp input-tape) (setq input-tape (list input-tape))) - (parser--debug - (message "(parser--f-set)") + (parser-generator--debug + (message "(parser-generator--f-set)") (message "input-tape: %s" input-tape) (message "state: %s" state) (message "stack: %s" stack)) @@ -558,58 +558,58 @@ (i (nth 1 state)) (f-sets (nth 2 state)) (disallow-e-first (nth 3 state))) - (parser--debug + (parser-generator--debug (message "disallow-e-first: %s" disallow-e-first) (message "input-tape-length: %s" input-tape-length) (message "k: %s" k) (message "i: %s" i)) (while stack (let ((stack-symbol (pop stack))) - (parser--debug + (parser-generator--debug (message "Stack-symbol: %s" stack-symbol)) (let ((leading-terminals (nth 0 stack-symbol)) (all-leading-terminals-p (nth 1 stack-symbol)) (input-tape-index (nth 2 stack-symbol)) (e-first-p)) - (parser--debug + (parser-generator--debug (message "leading-terminals: %s" leading-terminals) (message "all-leading-terminals-p: %s" all-leading-terminals-p) (message "input-tape-index: %s" input-tape-index)) ;; Flag whether leading-terminal is empty or not - (when (parser--valid-e-p leading-terminals) + (when (parser-generator--valid-e-p leading-terminals) (setq e-first-p t)) - (parser--debug (message "e-first-p: %s" e-first-p)) + (parser-generator--debug (message "e-first-p: %s" e-first-p)) ;; If leading terminal is empty and we have input-tape left, disregard it (when (and (not disallow-e-first) e-first-p (< input-tape-index input-tape-length)) - (parser--debug (message "Disregarding empty first terminal")) + (parser-generator--debug (message "Disregarding empty first terminal")) (setq leading-terminals nil)) (let ((leading-terminals-count (length leading-terminals))) - (parser--debug (message "leading-terminals-count: %s" leading-terminals-count)) + (parser-generator--debug (message "leading-terminals-count: %s" leading-terminals-count)) (while (and (< input-tape-index input-tape-length) (< leading-terminals-count k) all-leading-terminals-p) (let ((rhs-element (nth input-tape-index input-tape)) (rhs-type)) - (parser--debug (message "rhs-element: %s" rhs-element)) + (parser-generator--debug (message "rhs-element: %s" rhs-element)) ;; Determine symbol type (cond - ((parser--valid-non-terminal-p rhs-element) + ((parser-generator--valid-non-terminal-p rhs-element) (setq rhs-type 'NON-TERMINAL)) - ((parser--valid-e-p rhs-element) + ((parser-generator--valid-e-p rhs-element) (setq rhs-type 'EMPTY)) - ((parser--valid-terminal-p rhs-element) + ((parser-generator--valid-terminal-p rhs-element) (setq rhs-type 'TERMINAL)) (t (error (format "Invalid symbol %s" rhs-element)))) - (parser--debug (message "rhs-type: %s" rhs-type)) + (parser-generator--debug (message "rhs-type: %s" rhs-type)) (cond @@ -618,7 +618,7 @@ (let ((sub-terminal-sets (gethash rhs-element (gethash (1- i) f-sets)))) (if sub-terminal-sets (progn - (parser--debug + (parser-generator--debug (message "Sub-terminal-sets F_%s_%s(%s) = %s (%d)" (1- i) k rhs-element sub-terminal-sets (length sub-terminal-sets))) (let ((sub-terminal-set (car sub-terminal-sets))) @@ -629,11 +629,11 @@ (dolist (sub-terminal-alternative-set sub-terminal-sets) (unless (= sub-terminal-index 0) (let ((alternative-all-leading-terminals-p all-leading-terminals-p)) - (parser--debug (message "Sub-terminal-alternative-set: %s" sub-terminal-alternative-set)) + (parser-generator--debug (message "Sub-terminal-alternative-set: %s" sub-terminal-alternative-set)) ;; When sub-set only contains the e symbol - (when (parser--valid-e-p (car sub-terminal-alternative-set)) - (parser--debug (message "alternative-set is e symbol")) + (when (parser-generator--valid-e-p (car sub-terminal-alternative-set)) + (parser-generator--debug (message "alternative-set is e symbol")) (if disallow-e-first (when (= leading-terminals-count 0) (setq alternative-all-leading-terminals-p nil)) @@ -641,25 +641,25 @@ (> leading-terminals-count 0) (< input-tape-index (1- input-tape-length))) (setq sub-terminal-alternative-set nil) - (parser--debug (message "Cleared sub-terminal-alternative-set"))))) + (parser-generator--debug (message "Cleared sub-terminal-alternative-set"))))) (let ((sub-rhs-leading-terminals (append leading-terminals sub-terminal-alternative-set))) - (parser--debug (message "sub-rhs-leading-terminals: %s" sub-rhs-leading-terminals)) + (parser-generator--debug (message "sub-rhs-leading-terminals: %s" sub-rhs-leading-terminals)) (when (> (length sub-rhs-leading-terminals) k) (setq sub-rhs-leading-terminals (butlast sub-rhs-leading-terminals (- (length sub-rhs-leading-terminals) k)))) (push `(,sub-rhs-leading-terminals ,alternative-all-leading-terminals-p ,(1+ input-tape-index)) stack)))) (setq sub-terminal-index (1+ sub-terminal-index))))) - (parser--debug (message "Sub-terminal-set: %s" sub-terminal-set)) + (parser-generator--debug (message "Sub-terminal-set: %s" sub-terminal-set)) (when (or - (not (parser--valid-e-p (car sub-terminal-set))) + (not (parser-generator--valid-e-p (car sub-terminal-set))) (= input-tape-index (1- input-tape-length))) (setq leading-terminals (append leading-terminals sub-terminal-set)) (setq leading-terminals-count (+ leading-terminals-count (length sub-terminal-set))) (when (> leading-terminals-count k) (setq leading-terminals (butlast leading-terminals (- leading-terminals-count k))) (setq leading-terminals-count k))))) - (parser--debug + (parser-generator--debug (message "Found no subsets for %s %s" rhs-element (1- i))) (setq all-leading-terminals-p nil))) (setq all-leading-terminals-p nil))) @@ -686,35 +686,35 @@ f-set)) ;; Algorithm 5.5, p. 357 -(defun parser--first (β &optional disallow-e-first) +(defun parser-generator--first (β &optional disallow-e-first) "For sentential-form Β, calculate first terminals, optionally DISALLOW-E-FIRST." (unless (listp β) (setq β (list β))) - (unless (parser--valid-sentential-form-p β) + (unless (parser-generator--valid-sentential-form-p β) (error "Invalid sentential form β!")) - (let ((productions (parser--get-grammar-productions)) - (k parser--look-ahead-number)) + (let ((productions (parser-generator--get-grammar-productions)) + (k parser-generator--look-ahead-number)) (let ((i-max (length productions))) ;; Generate F-sets only once per grammar (when (or (and (not disallow-e-first) - (not parser--f-sets)) + (not parser-generator--f-sets)) (and disallow-e-first - (not parser--f-free-sets))) + (not parser-generator--f-free-sets))) (let ((f-sets (make-hash-table :test 'equal)) (i 0)) (while (< i i-max) - (parser--debug (message "i = %s" i)) + (parser-generator--debug (message "i = %s" i)) (let ((f-set (make-hash-table :test 'equal))) ;; Iterate all productions, set F_i (dolist (p productions) (let ((production-lhs (car p)) (production-rhs (cdr p))) - (parser--debug + (parser-generator--debug (message "Production: %s -> %s" production-lhs production-rhs)) ;; Iterate all blocks in RHS @@ -722,8 +722,8 @@ (dolist (rhs-p production-rhs) (let ((rhs-string rhs-p)) (let ((rhs-leading-terminals - (parser--f-set rhs-string `(,k ,i ,f-sets ,disallow-e-first) '(("" t 0))))) - (parser--debug + (parser-generator--f-set rhs-string `(,k ,i ,f-sets ,disallow-e-first) '(("" t 0))))) + (parser-generator--debug (message "Leading %d terminals at index %s (%s) -> %s = %s" k i production-lhs rhs-string rhs-leading-terminals)) (when rhs-leading-terminals (when (and @@ -733,17 +733,17 @@ (push rhs-leading-terminals-element f-p-set))))))) ;; Make set distinct - (setq f-p-set (parser--distinct f-p-set)) - (parser--debug + (setq f-p-set (parser-generator--distinct f-p-set)) + (parser-generator--debug (message "F_%s_%s(%s) = %s" i k production-lhs f-p-set)) (puthash production-lhs (nreverse f-p-set) f-set)))) (puthash i f-set f-sets) (setq i (+ i 1)))) (if disallow-e-first - (setq parser--f-free-sets f-sets) - (setq parser--f-sets f-sets)))) + (setq parser-generator--f-free-sets f-sets) + (setq parser-generator--f-sets f-sets)))) - (parser--debug + (parser-generator--debug (message "Generated F-sets")) (let ((first-list nil)) @@ -753,7 +753,7 @@ (stack '((0 0 nil)))) (while stack (let ((stack-topmost (pop stack))) - (parser--debug + (parser-generator--debug (message "stack-topmost: %s" stack-topmost)) (let ((input-tape-index (car stack-topmost)) (first-length (car (cdr stack-topmost))) @@ -764,25 +764,25 @@ (< input-tape-index input-tape-length) (< first-length k)) (let ((symbol (nth input-tape-index input-tape))) - (parser--debug + (parser-generator--debug (message "symbol index: %s from %s is: %s" input-tape-index input-tape symbol)) (cond - ((parser--valid-terminal-p symbol) + ((parser-generator--valid-terminal-p symbol) (setq first (append first (list symbol))) (setq first-length (1+ first-length))) - ((parser--valid-non-terminal-p symbol) - (parser--debug + ((parser-generator--valid-non-terminal-p symbol) + (parser-generator--debug (message "non-terminal symbol: %s" symbol)) (let ((symbol-f-set)) (if disallow-e-first - (setq symbol-f-set (gethash symbol (gethash (1- i-max) parser--f-free-sets))) - (setq symbol-f-set (gethash symbol (gethash (1- i-max) parser--f-sets)))) - (parser--debug + (setq symbol-f-set (gethash symbol (gethash (1- i-max) parser-generator--f-free-sets))) + (setq symbol-f-set (gethash symbol (gethash (1- i-max) parser-generator--f-sets)))) + (parser-generator--debug (message "symbol-f-set: %s" symbol-f-set)) (if (not symbol-f-set) (progn - (parser--debug + (parser-generator--debug (message "empty symbol-f-set, so stop looking")) (setq keep-looking nil)) @@ -795,26 +795,26 @@ (let ((alternative-first-length (+ first-length (length symbol-f-set-element))) (alternative-first (append first symbol-f-set-element)) (alternative-tape-index (1+ input-tape-index))) - (parser--debug + (parser-generator--debug (message "alternative-first: %s" alternative-first)) (push `(,alternative-tape-index ,alternative-first-length ,alternative-first) stack))) (setq symbol-f-set-index (1+ symbol-f-set-index))))) - (parser--debug + (parser-generator--debug (message "main-symbol-f-set: %s" (car symbol-f-set))) (setq first-length (+ first-length (length (car symbol-f-set)))) (setq first (append first (car symbol-f-set)))))))) (setq input-tape-index (1+ input-tape-index))) (when (> first-length 0) - (parser--debug + (parser-generator--debug (message "push to first-list: %s to %s" first first-list)) (push first first-list)))))) - (setq first-list (sort first-list 'parser--sort-list)) + (setq first-list (sort first-list 'parser-generator--sort-list)) first-list)))) ;; Definition at p. 343 -(defun parser--follow (β) +(defun parser-generator--follow (β) "Calculate follow-set of Β. FOLLOW(β) = w, w is the set {w | S =>* αβγ and w is in FIRST(γ)}." ;; Make sure argument is a list (unless (listp β) @@ -822,7 +822,7 @@ (let ((follow-set nil) (match-length (length β))) ;; Iterate all productions in grammar - (let ((productions (parser--get-grammar-productions))) + (let ((productions (parser-generator--get-grammar-productions))) (dolist (p productions) ;; Iterate all RHS of every production (let ((production-rhs (cdr p)) @@ -847,19 +847,19 @@ (when (= match-index match-length) (if (= rhs-index (1- rhs-count)) ;; If rest of RHS is empty add e in follow-set - (push `(,parser--e-identifier) follow-set) + (push `(,parser-generator--e-identifier) follow-set) ;; Otherwise add FOLLOW(rest) to follow-set (let ((rest (nthcdr (1+ rhs-index) rhs))) - (let ((first-set (parser--first rest))) + (let ((first-set (parser-generator--first rest))) (setq follow-set (append first-set follow-set))))) (setq match-index 0))) (when (> match-index 0) (setq match-index 0)))) (setq rhs-index (1+ rhs-index)))))))) (when (> (length follow-set) 0) - (setq follow-set (parser--distinct follow-set))) + (setq follow-set (parser-generator--distinct follow-set))) follow-set)) -(provide 'parser) +(provide 'parser-generator) -;;; parser.el ends here +;;; parser-generator.el ends here diff --git a/test/parser-lr-test.el b/test/parser-generator-lr-test.el similarity index 51% rename from test/parser-lr-test.el rename to test/parser-generator-lr-test.el index 79f8a49..37b4de8 100644 --- a/test/parser-lr-test.el +++ b/test/parser-generator-lr-test.el @@ -1,4 +1,4 @@ -;;; parser-lr-test.el --- Tests for LR(k) Parser -*- lexical-binding: t -*- +;;; parser-generator-lr-test.el --- Tests for LR(k) Parser Generator -*- lexical-binding: t -*- ;;; Commentary: @@ -6,21 +6,21 @@ ;;; Code: -(require 'parser-lr) +(require 'parser-generator-lr) (require 'ert) -(defun parser-lr-test--generate-action-tables () - "Test `parser-lr--generate-action-tables'." - (message "Starting tests for (parser-lr--generate-action-tables)") +(defun parser-generator-lr-test--generate-action-tables () + "Test `parser-generator-lr--generate-action-tables'." + (message "Starting tests for (parser-generator-lr--generate-action-tables)") ;; Example 5.32 p. 393 - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) - (parser-lr--reset) - (parser-lr--generate-goto-tables) - (parser-lr--generate-action-tables) + (parser-generator-lr--reset) + (parser-generator-lr--generate-goto-tables) + (parser-generator-lr--generate-action-tables) (should (equal @@ -32,7 +32,7 @@ (5 nil) (6 ((a 4) (b 7))) (7 nil)) - (parser--hash-to-list parser-lr--goto-tables))) + (parser-generator--hash-to-list parser-generator-lr--goto-tables))) (should (equal @@ -44,7 +44,7 @@ (5 ((S (S a S b) nil (a)) (S (S a S b) nil (e)))) (6 ((S (S) (a S b) (a)) (S (S) (a S b) (b)) (S (S a S) (b) (a)) (S (S a S) (b) (b)))) (7 ((S (S a S b) nil (a)) (S (S a S b) nil (b))))) - (parser--hash-to-list parser-lr--items))) + (parser-generator--hash-to-list parser-generator-lr--items))) ;; Fig. 5.9 p. 374 (should @@ -57,24 +57,24 @@ (5 (((a) reduce 1) ((e) reduce 1))) (6 (((a) shift) ((b) shift))) (7 (((a) reduce 1) ((b) reduce 1)))) - (parser--hash-to-list parser-lr--action-tables))) + (parser-generator--hash-to-list parser-generator-lr--action-tables))) - (message "Ended tests for (parser-lr--generate-action-tables)")) + (message "Ended tests for (parser-generator-lr--generate-action-tables)")) -(defun parser-lr-test--generate-goto-tables () - "Test `parser-lr--generate-goto-tables'." - (message "Starting tests for (parser-lr--generate-goto-tables)") +(defun parser-generator-lr-test--generate-goto-tables () + "Test `parser-generator-lr--generate-goto-tables'." + (message "Starting tests for (parser-generator-lr--generate-goto-tables)") ;; Example 5.30, p. 389 - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) - (parser-lr--reset) - (parser-lr--generate-goto-tables) + (parser-generator-lr--reset) + (parser-generator-lr--generate-goto-tables) - ;; (message "GOTO-table: %s" parser-lr--goto-tables) - ;; (message "LR-items: %s" (parser--hash-to-list parser-lr--items)) + ;; (message "GOTO-table: %s" parser-generator-lr--goto-tables) + ;; (message "LR-items: %s" (parser-generator--hash-to-list parser-generator-lr--items)) (should (equal @@ -86,7 +86,7 @@ (5 nil) (6 ((a 4) (b 7))) (7 nil)) - (parser--hash-to-list parser-lr--goto-tables))) + (parser-generator--hash-to-list parser-generator-lr--goto-tables))) (should (equal @@ -98,22 +98,22 @@ (5 ((S (S a S b) nil (a)) (S (S a S b) nil (e)))) (6 ((S (S) (a S b) (a)) (S (S) (a S b) (b)) (S (S a S) (b) (a)) (S (S a S) (b) (b)))) (7 ((S (S a S b) nil (a)) (S (S a S b) nil (b))))) - (parser--hash-to-list parser-lr--items))) + (parser-generator--hash-to-list parser-generator-lr--items))) (message "Passed LR-items for example 5.30") (message "Passed tests for (parser-r--generate-goto-tables)")) -(defun parser-lr-test--items-for-prefix () - "Test `parser-lr--items-for-prefix'." - (message "Starting tests for (parser-lr--items-for-prefix)") +(defun parser-generator-lr-test--items-for-prefix () + "Test `parser-generator-lr--items-for-prefix'." + (message "Starting tests for (parser-generator-lr--items-for-prefix)") ;; Example 5.29 p 387 - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) - (parser-lr--reset) + (parser-generator-lr--reset) (should (equal @@ -122,7 +122,7 @@ (S nil nil (a)) (S nil nil (e)) (Sp nil (S) (e))) - (parser-lr--items-for-prefix 'e))) + (parser-generator-lr--items-for-prefix 'e))) (message "Passed V(e)") (should @@ -130,19 +130,19 @@ '((S (S) (a S b) (a)) (S (S) (a S b) (e)) (Sp (S) nil (e))) - (parser-lr--items-for-prefix 'S))) + (parser-generator-lr--items-for-prefix 'S))) (message "Passed V(S)") (should (equal nil - (parser-lr--items-for-prefix 'a))) + (parser-generator-lr--items-for-prefix 'a))) (message "Passed V(a)") (should (equal nil - (parser-lr--items-for-prefix 'b))) + (parser-generator-lr--items-for-prefix 'b))) (message "Passed V(b)") (should @@ -153,19 +153,19 @@ (S nil (S a S b) (b)) (S nil nil (a)) (S nil nil (b))) - (parser-lr--items-for-prefix '(S a)))) + (parser-generator-lr--items-for-prefix '(S a)))) (message "Passed V(Sa)") (should (equal nil - (parser-lr--items-for-prefix '(S S)))) + (parser-generator-lr--items-for-prefix '(S S)))) (message "Passed V(SS)") (should (equal nil - (parser-lr--items-for-prefix '(S b)))) + (parser-generator-lr--items-for-prefix '(S b)))) (message "Passed V(Sb)") ;; a3 p. 390 @@ -175,72 +175,72 @@ (S (S) (a S b) (b)) (S (S a S) (b) (a)) (S (S a S) (b) (e))) - (parser-lr--items-for-prefix '(S a S)))) + (parser-generator-lr--items-for-prefix '(S a S)))) (message "Passed V(SaS)") (should (equal nil - (parser-lr--items-for-prefix '(S a a)))) + (parser-generator-lr--items-for-prefix '(S a a)))) (message "Passed V(Saa)") (should (equal nil - (parser-lr--items-for-prefix '(S a b)))) + (parser-generator-lr--items-for-prefix '(S a b)))) (message "Passed V(Sab)") - (message "Passed tests for (parser-lr--items-for-prefix)")) + (message "Passed tests for (parser-generator-lr--items-for-prefix)")) -(defun parser-lr-test--items-valid-p () - "Test `parser-lr--items-valid-p'." - (message "Started tests for (parser-lr--items-valid-p)") +(defun parser-generator-lr-test--items-valid-p () + "Test `parser-generator-lr--items-valid-p'." + (message "Started tests for (parser-generator-lr--items-valid-p)") - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) - (parser-lr--reset) - (parser-lr--generate-goto-tables) + (parser-generator-lr--reset) + (parser-generator-lr--generate-goto-tables) (should (equal t - (parser-lr--items-valid-p (parser--hash-values-to-list parser-lr--items t)))) + (parser-generator-lr--items-valid-p (parser-generator--hash-values-to-list parser-generator-lr--items t)))) (message "Passed first") (should (equal nil - (parser-lr--items-valid-p + (parser-generator-lr--items-valid-p '(((S nil (S a S b) (a)) (S nil (S a S b) (e)) (S nil nil (a)) (S nil nil (e)) (Sp nil (S) (e))) ((S (S) (a S b) (a)) (S (S) (a S b) (e)) (Sp (S) nil (e))) ((S (S a) (S b) (a)) (S (S a) (S b) (e)) (S nil (S a S b) (a)) (S nil (S a S b) (b)) (S nil nil (a)) (S nil nil (b))) ((S (S) (a S b) (a)) (S (S) (a S b) (b)) (S (S a S) (b) (a)) (S (S a S) (b) (e))) ((S (S a S b) nil (a)) (S (S a S b) (a) (a)) (S (S a S b) nil (e))) ((S (S a) (S b) (a)) (S (S a) (S b) (b)) (S nil (S a S b) (a)) [...] - (message "Passed tests for (parser-lr--items-valid-p)")) + (message "Passed tests for (parser-generator-lr--items-valid-p)")) -(defun parser-lr-test--parse () - "Test `parser-lr--parse'." - (message "Started tests for (parser-lr--parse)") +(defun parser-generator-lr-test--parse () + "Test `parser-generator-lr--parse'." + (message "Started tests for (parser-generator-lr--parse)") - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) (should (equal '(2 2 2 1 1) - (parser-lr--parse '(a a b b)))) + (parser-generator-lr--parse '(a a b b)))) - (message "Passed tests for (parser-lr--parse)")) + (message "Passed tests for (parser-generator-lr--parse)")) -(defun parser-lr-test () +(defun parser-generator-lr-test () "Run test." ;; (setq debug-on-error t) - (parser-lr-test--items-for-prefix) - (parser-lr-test--items-valid-p) - (parser-lr-test--generate-goto-tables) - (parser-lr-test--generate-action-tables) - (parser-lr-test--parse)) + (parser-generator-lr-test--items-for-prefix) + (parser-generator-lr-test--items-valid-p) + (parser-generator-lr-test--generate-goto-tables) + (parser-generator-lr-test--generate-action-tables) + (parser-generator-lr-test--parse)) -(provide 'parser-lr-test) +(provide 'parser-generator-lr-test) -;;; parser-lr-test.el ends here +;;; parser-generator-lr-test.el ends here diff --git a/test/parser-generator-test.el b/test/parser-generator-test.el new file mode 100644 index 0000000..824bced --- /dev/null +++ b/test/parser-generator-test.el @@ -0,0 +1,543 @@ +;;; parser-generator-test.el --- Tests for Parser Generator -*- lexical-binding: t -*- + + +;;; Commentary: + + +;;; Code: + +(require 'parser-generator) +(require 'ert) + +(defun parser-generator-test--valid-look-ahead-p () + "Test `parser-generator--valid-look-ahead-p'." + (message "Starting tests for (parser-generator--valid-look-ahead-p)") + + (parser-generator--set-look-ahead-number 1) + (parser-generator--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should + (equal + t + (parser-generator--valid-look-ahead-p "a"))) + (should + (equal + t + (parser-generator--valid-look-ahead-p "b"))) + (should + (equal + nil + (parser-generator--valid-look-ahead-p "c"))) + (should + (equal + nil + (parser-generator--valid-look-ahead-p "d"))) + (should + (equal + t + (parser-generator--valid-look-ahead-p 'e))) + + (message "Passed tests for (parser-generator--valid-look-ahead-p)")) + +(defun parser-generator-test--get-grammar-look-aheads () + "Test `parser-generator--get-look-aheads'." + (message "Starting tests for (parser-generator--get-grammar-look-aheads)") + + (parser-generator--set-look-ahead-number 1) + (parser-generator--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should + (equal + '(("a") ("b") (e)) + (parser-generator--get-grammar-look-aheads))) + (message "Passed ((a) (b) (e))") + + (parser-generator--set-look-ahead-number 2) + + (should + (equal + '(("a" "a") ("a" "b") ("a" e) ("b" "a") ("b" "b") ("b" e)) + (parser-generator--get-grammar-look-aheads))) + + (message "Passed tests for (parser-generator--get-grammar-look-aheads)")) + +(defun parser-generator-test--sort-list () + "Test `parser-generator--sort-list'." + (message "Starting tests for (parser-generator-test--sort-list)") + + (should + (equal + '((a b c) (b c d) (c e f)) + (sort '((a b c) (c e f) (b c d)) 'parser-generator--sort-list))) + + (should + (equal + '((a b c) (a c c) (c e f)) + (sort '((a c c) (a b c) (c e f)) 'parser-generator--sort-list))) + + (should + (equal + '((a b) (a c c) (c e f g h)) + (sort '((a c c) (a b) (c e f g h)) 'parser-generator--sort-list))) + + (should + (equal + '((a) (b) (c)) + (sort '((a) (c) (b)) 'parser-generator--sort-list))) + + (message "Passed tests for (parser-generator--distinct)")) + +(defun parser-generator-test--distinct () + "Test `parser-generator--distinct'." + (message "Starting tests for (parser-generator--distinct)") + + (should + (equal + '(a b c) + (parser-generator--distinct '(a a b c)))) + + (should + (equal + '("aa" "b" "cc" "c" "a") + (parser-generator--distinct '("aa" "b" "cc" "c" "b" "a" "aa")))) + (message "Passed tests for (parser-generator--distinct)")) + +(defun parser-generator-test--follow () + "Test `parser-generator--follow'." + (message "Starting tests for (parser-generator--follow)") + + (parser-generator--set-grammar '((S A) (b) ((S A) (A b)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((e)) + (parser-generator--follow 'A))) + (message "Passed follow 1 with intermediate grammar") + + (parser-generator--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((a)) + (parser-generator--follow 'A))) + (message "Passed follow 2 with intermediate grammar") + + (parser-generator--set-grammar '((S A B) (a c d f) ((S (A a)) (A (B c d)) (B (c f) d)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((c d)) + (parser-generator--follow 'B))) + (message "Passed follow 3 with intermediate grammar") + + (message "Passed tests for (parser-generator--follow)")) + +(defun parser-generator-test--first () + "Test `parser-generator--first'." + (message "Starting tests for (parser-generator--first)") + + (parser-generator--set-grammar '((S) (a) ((S a)) S)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + + (should + (equal + '((a)) + (parser-generator--first 'S))) + (message "Passed first 1 with rudimentary grammar") + + (parser-generator--set-grammar '((S) (a) ((S a)) S)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + + (should + (equal + '((a)) + (parser-generator--first '(S a)))) + (message "Passed first 1b with rudimentary grammar") + + (parser-generator--set-grammar '((S) (a) ((S a)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((a a)) + (parser-generator--first '(S a)))) + (message "Passed first 1c with rudimentary grammar") + + (parser-generator--set-grammar '((S) (a) ((S a)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((a)) + (parser-generator--first '(a)))) + (message "Passed first 1d with rudimentary grammar") + + (parser-generator--set-grammar '((S) ("a" "b" "c") ((S ("a" "b" "c"))) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '(("a" "b")) + (parser-generator--first 'S))) + (message "Passed first 2 with rudimentary grammar") + + (parser-generator--set-grammar '((S) ("a" b "c") ((S ("a" b "c"))) S)) + (parser-generator--set-look-ahead-number 3) + (parser-generator--process-grammar) + + (should + (equal + '(("a" b "c")) + (parser-generator--first 'S))) + (message "Passed first 3 with rudimentary grammar") + + (parser-generator--set-grammar '((S A) (b) ((S A) (A b)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((b)) + (parser-generator--first 'S))) + (message "Passed first 1 with intermediate grammar") + + (parser-generator--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '(("b" "a")) + (parser-generator--first 'S))) + (message "Passed first 2 with intermediate grammar") + + (parser-generator--set-grammar '((S A) ("a" "b" "c" "d") ((S A) (A ("b" "a" "c" "d"))) S)) + (parser-generator--set-look-ahead-number 3) + (parser-generator--process-grammar) + + (should + (equal + '(("b" "a" "c")) + (parser-generator--first 'S))) + (message "Passed first 3 with intermediate grammar") + + (parser-generator--set-grammar '((S A B) ("c" "d") ((S A) (A B) (B "c" "d")) S)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + + (should + (equal + '(("c") ("d")) + (parser-generator--first 'S))) + (message "Passed first 1 with semi-complex grammar") + + (parser-generator--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((c f) (d a)) + (parser-generator--first 'S))) + (message "Passed first 2 with semi-complex grammar") + + (parser-generator--set-grammar '((S A B) ("a" "c" "d" "m") ((S A) (A (B "a" "m")) (B "c" "d")) S)) + (parser-generator--set-look-ahead-number 3) + (parser-generator--process-grammar) + + (should + (equal + '(("c" "a" "m") ("d" "a" "m")) + (parser-generator--first 'S))) + (message "Passed first 3 with semi-complex grammar") + + (parser-generator--set-grammar '((S A B C) (a b c) ((S A B) (A (B a) e) (B (C b) C) (C c e)) S)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + + (should + (equal + '((a) (b) (c) (e)) + (parser-generator--first 'S))) + (message "Passed first 1 with complex grammar") + + ;; Example 5.28 p 382 + (parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((a b) (a c) (a) (b a) (b) (c a) (c) (c b) (e)) + (parser-generator--first 'S))) + (message "Passed first 2 with complex grammar") + + (parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) + (parser-generator--set-look-ahead-number 3) + (parser-generator--process-grammar) + + (should + (equal + '((a) (a b) (a c) (a c b) (b a) (b a b) (b a c) (b) (c a) (c a b) (c a c) (c b) (c) (c b a) (e)) + (parser-generator--first 'S))) + (message "Passed first 3 with complex grammar") + + (message "Passed tests for (parser-generator--first)")) + +;; Example 5.28 page 402 +(defun parser-generator-test--e-free-first () + "Test `parser-generator--e-free-first'." + (message "Starting tests for (parser-generator--e-free-first)") + + ;; Example 5.28 p 402 + (parser-generator--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) + (parser-generator--set-look-ahead-number 2) + (parser-generator--process-grammar) + + (should + (equal + '((c a) (c b)) + (parser-generator--e-free-first 'S))) + (message "Passed empty-free-first 2 with complex grammar") + + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + (should + (equal + '((c)) + (parser-generator--e-free-first '(S b a)))) + (message "Passed empty-free-first 1 with complex grammar") + + (parser-generator--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator--set-look-ahead-number 1) + (parser-generator--process-grammar) + (should + (equal + nil + (parser-generator--e-free-first '(S b a)))) + (message "Passed empty-free-first 1 with complex grammar 2") + + (message "Passed tests for (parser-generator--empty-free-first)")) + +(defun parser-generator-test--valid-grammar-p () + "Test function `parser-generator--valid-grammar-p'." + (message "Starting tests for (parser-generator--valid-grammar-p)") + + (should (equal + t + (parser-generator--valid-grammar-p '((A B C) ("a" "b" "c") ((A "a")) A)))) + + (should (equal + nil + (parser-generator--valid-grammar-p '((A B C) ("a" "b" "c") ((A "a")) (A))))) + + (should (equal + nil + (parser-generator--valid-grammar-p '((A B C) (("a" "b") "c") ((A "a")) A)))) + + (should (equal + nil + (parser-generator--valid-grammar-p '(((A B) C) ("a" "b" "c") ((A "a")) A)))) + + (should (equal + nil + (parser-generator--valid-grammar-p '(((A B) C) ("a" "b" "c") ((A)) A)))) + + (should (equal + nil + (parser-generator--valid-grammar-p "A"))) + + (should (equal + nil + (parser-generator--valid-grammar-p '(A B C)))) + + (should (equal + nil + (parser-generator--valid-grammar-p '((A B))))) + + (should (equal + nil + (parser-generator--valid-grammar-p '((A B C) (a (b c) "c") (A ("a" "b") (a b)) (B b) (C "c"))))) + + (message "Passed tests for (parser-generator--valid-grammar-p)")) + +(defun parser-generator-test--valid-look-ahead-number-p () + "Test function `parser-generator--valid-look-ahead-number-p'." + (message "Starting tests for (parser-generator--valid-look-ahead-number-p)") + + (should (equal + nil + (parser-generator--valid-look-ahead-number-p 'A))) + + (should (equal + nil + (parser-generator--valid-look-ahead-number-p "A"))) + + (should (equal + nil + (parser-generator--valid-look-ahead-number-p -2))) + + (should (equal + nil + (parser-generator--valid-look-ahead-number-p 3.3))) + + (should (equal + t + (parser-generator--valid-look-ahead-number-p 2))) + + (should (equal + t + (parser-generator--valid-look-ahead-number-p 1))) + + (message "Passed tests for (parser-generator--valid-look-ahead-number-p)")) + +(defun parser-generator-test--valid-sentential-form-p () + "Test `parser-generator--valid-sentential-form-p'." + (message "Starting tests for (parser-generator--valid-sentential-form-p)") + + ;; TODO Add tests for this + + (message "Passed tests for (parser-generator--valid-sentential-form-p)")) + +(defun parser-generator-test--valid-production-p () + "Test `parser-generator--valid-production-p'." + (message "Starting tests for (parser-generator--valid-production-p)") + + (should (equal + t + (parser-generator--valid-production-p '(A a)))) + + (should (equal + nil + (parser-generator--valid-production-p "A"))) + + (should (equal + nil + (parser-generator--valid-production-p '((A a))))) + + (message "Passed tests for (parser-generator--valid-production-p)")) + +(defun parser-generator-test--get-grammar-rhs () + "Test `parser-generator--get-grammar-rhs'." + (message "Started tests for (parser-generator--get-grammar-rhs)") + + (parser-generator--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should (equal + '((A)) + (parser-generator--get-grammar-rhs 'S))) + (should (equal + '(("b" "a")) + (parser-generator--get-grammar-rhs 'A))) + + (parser-generator--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should (equal + '((A) (B)) + (parser-generator--get-grammar-rhs 'S))) + (should (equal + '(("a") ("b" "a")) + (parser-generator--get-grammar-rhs 'A))) + + (message "Passed tests for (parser-generator--get-grammar-rhs)")) + +(defun parser-generator-test--valid-non-terminal-p () + "Test `parser-generator--valid-non-terminal-p'." + (message "Starting tests for (parser-generator--valid-non-terminal-p)") + + (parser-generator--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should + (equal + t + (parser-generator--valid-non-terminal-p 'S))) + (should + (equal + t + (parser-generator--valid-non-terminal-p 'A))) + (should + (equal + t + (parser-generator--valid-non-terminal-p 'B))) + (should + (equal + nil + (parser-generator--valid-non-terminal-p 'C))) + (should + (equal + nil + (parser-generator--valid-non-terminal-p "a"))) + + (message "Passed tests for (parser-generator--valid-non-terminal-p)")) + +(defun parser-generator-test--valid-terminal-p () + "Test `parser-generator--valid-terminal-p'." + (message "Starting tests for (parser-generator--valid-terminal-p)") + + (parser-generator--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) + (parser-generator--process-grammar) + + (should + (equal + t + (parser-generator--valid-terminal-p "a"))) + (should + (equal + t + (parser-generator--valid-terminal-p "b"))) + (should + (equal + t + (parser-generator--valid-terminal-p "a"))) + (should + (equal + nil + (parser-generator--valid-terminal-p 'S))) + (should + (equal + nil + (parser-generator--valid-terminal-p 'A))) + + (message "Passed tests for (parser-generator--valid-terminal-p)")) + +(defun parser-generator-test () + "Run test." + ;; (setq debug-on-error t) + + ;; Helpers + (parser-generator-test--valid-look-ahead-p) + (parser-generator-test--valid-look-ahead-number-p) + (parser-generator-test--valid-production-p) + (parser-generator-test--valid-grammar-p) + (parser-generator-test--valid-non-terminal-p) + (parser-generator-test--valid-sentential-form-p) + (parser-generator-test--valid-terminal-p) + (parser-generator-test--distinct) + (parser-generator-test--sort-list) + (parser-generator-test--get-grammar-rhs) + (parser-generator-test--get-grammar-look-aheads) + + ;; Algorithms + (parser-generator-test--first) + (parser-generator-test--e-free-first) + (parser-generator-test--follow)) + +(provide 'parser-generator-test) + +;;; parser-generator-test.el ends here diff --git a/test/parser-test.el b/test/parser-test.el deleted file mode 100644 index 1ebe13b..0000000 --- a/test/parser-test.el +++ /dev/null @@ -1,543 +0,0 @@ -;;; parser-test.el --- Tests for Parser -*- lexical-binding: t -*- - - -;;; Commentary: - - -;;; Code: - -(require 'parser) -(require 'ert) - -(defun parser-test--valid-look-ahead-p () - "Test `parser--valid-look-ahead-p'." - (message "Starting tests for (parser--valid-look-ahead-p)") - - (parser--set-look-ahead-number 1) - (parser--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) - (parser--process-grammar) - - (should - (equal - t - (parser--valid-look-ahead-p "a"))) - (should - (equal - t - (parser--valid-look-ahead-p "b"))) - (should - (equal - nil - (parser--valid-look-ahead-p "c"))) - (should - (equal - nil - (parser--valid-look-ahead-p "d"))) - (should - (equal - t - (parser--valid-look-ahead-p 'e))) - - (message "Passed tests for (parser--valid-look-ahead-p)")) - -(defun parser-test--get-grammar-look-aheads () - "Test `parser--get-look-aheads'." - (message "Starting tests for (parser--get-grammar-look-aheads)") - - (parser--set-look-ahead-number 1) - (parser--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) - (parser--process-grammar) - - (should - (equal - '(("a") ("b") (e)) - (parser--get-grammar-look-aheads))) - (message "Passed ((a) (b) (e))") - - (parser--set-look-ahead-number 2) - - (should - (equal - '(("a" "a") ("a" "b") ("a" e) ("b" "a") ("b" "b") ("b" e)) - (parser--get-grammar-look-aheads))) - - (message "Passed tests for (parser--get-grammar-look-aheads)")) - -(defun parser-test--sort-list () - "Test `parser--sort-list'." - (message "Starting tests for (parser-test--sort-list)") - - (should - (equal - '((a b c) (b c d) (c e f)) - (sort '((a b c) (c e f) (b c d)) 'parser--sort-list))) - - (should - (equal - '((a b c) (a c c) (c e f)) - (sort '((a c c) (a b c) (c e f)) 'parser--sort-list))) - - (should - (equal - '((a b) (a c c) (c e f g h)) - (sort '((a c c) (a b) (c e f g h)) 'parser--sort-list))) - - (should - (equal - '((a) (b) (c)) - (sort '((a) (c) (b)) 'parser--sort-list))) - - (message "Passed tests for (parser--distinct)")) - -(defun parser-test--distinct () - "Test `parser--distinct'." - (message "Starting tests for (parser--distinct)") - - (should - (equal - '(a b c) - (parser--distinct '(a a b c)))) - - (should - (equal - '("aa" "b" "cc" "c" "a") - (parser--distinct '("aa" "b" "cc" "c" "b" "a" "aa")))) - (message "Passed tests for (parser--distinct)")) - -(defun parser-test--follow () - "Test `parser--follow'." - (message "Starting tests for (parser--follow)") - - (parser--set-grammar '((S A) (b) ((S A) (A b)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((e)) - (parser--follow 'A))) - (message "Passed follow 1 with intermediate grammar") - - (parser--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((a)) - (parser--follow 'A))) - (message "Passed follow 2 with intermediate grammar") - - (parser--set-grammar '((S A B) (a c d f) ((S (A a)) (A (B c d)) (B (c f) d)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((c d)) - (parser--follow 'B))) - (message "Passed follow 3 with intermediate grammar") - - (message "Passed tests for (parser--follow)")) - -(defun parser-test--first () - "Test `parser--first'." - (message "Starting tests for (parser--first)") - - (parser--set-grammar '((S) (a) ((S a)) S)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) - - (should - (equal - '((a)) - (parser--first 'S))) - (message "Passed first 1 with rudimentary grammar") - - (parser--set-grammar '((S) (a) ((S a)) S)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) - - (should - (equal - '((a)) - (parser--first '(S a)))) - (message "Passed first 1b with rudimentary grammar") - - (parser--set-grammar '((S) (a) ((S a)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((a a)) - (parser--first '(S a)))) - (message "Passed first 1c with rudimentary grammar") - - (parser--set-grammar '((S) (a) ((S a)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((a)) - (parser--first '(a)))) - (message "Passed first 1d with rudimentary grammar") - - (parser--set-grammar '((S) ("a" "b" "c") ((S ("a" "b" "c"))) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '(("a" "b")) - (parser--first 'S))) - (message "Passed first 2 with rudimentary grammar") - - (parser--set-grammar '((S) ("a" b "c") ((S ("a" b "c"))) S)) - (parser--set-look-ahead-number 3) - (parser--process-grammar) - - (should - (equal - '(("a" b "c")) - (parser--first 'S))) - (message "Passed first 3 with rudimentary grammar") - - (parser--set-grammar '((S A) (b) ((S A) (A b)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((b)) - (parser--first 'S))) - (message "Passed first 1 with intermediate grammar") - - (parser--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '(("b" "a")) - (parser--first 'S))) - (message "Passed first 2 with intermediate grammar") - - (parser--set-grammar '((S A) ("a" "b" "c" "d") ((S A) (A ("b" "a" "c" "d"))) S)) - (parser--set-look-ahead-number 3) - (parser--process-grammar) - - (should - (equal - '(("b" "a" "c")) - (parser--first 'S))) - (message "Passed first 3 with intermediate grammar") - - (parser--set-grammar '((S A B) ("c" "d") ((S A) (A B) (B "c" "d")) S)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) - - (should - (equal - '(("c") ("d")) - (parser--first 'S))) - (message "Passed first 1 with semi-complex grammar") - - (parser--set-grammar '((S A B) (a c d f) ((S (A a)) (A B) (B (c f) d)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((c f) (d a)) - (parser--first 'S))) - (message "Passed first 2 with semi-complex grammar") - - (parser--set-grammar '((S A B) ("a" "c" "d" "m") ((S A) (A (B "a" "m")) (B "c" "d")) S)) - (parser--set-look-ahead-number 3) - (parser--process-grammar) - - (should - (equal - '(("c" "a" "m") ("d" "a" "m")) - (parser--first 'S))) - (message "Passed first 3 with semi-complex grammar") - - (parser--set-grammar '((S A B C) (a b c) ((S A B) (A (B a) e) (B (C b) C) (C c e)) S)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) - - (should - (equal - '((a) (b) (c) (e)) - (parser--first 'S))) - (message "Passed first 1 with complex grammar") - - ;; Example 5.28 p 382 - (parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((a b) (a c) (a) (b a) (b) (c a) (c) (c b) (e)) - (parser--first 'S))) - (message "Passed first 2 with complex grammar") - - (parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) - (parser--set-look-ahead-number 3) - (parser--process-grammar) - - (should - (equal - '((a) (a b) (a c) (a c b) (b a) (b a b) (b a c) (b) (c a) (c a b) (c a c) (c b) (c) (c b a) (e)) - (parser--first 'S))) - (message "Passed first 3 with complex grammar") - - (message "Passed tests for (parser--first)")) - -;; Example 5.28 page 402 -(defun parser-test--e-free-first () - "Test `parser--e-free-first'." - (message "Starting tests for (parser--e-free-first)") - - ;; Example 5.28 p 402 - (parser--set-grammar '((S A B C) (a b c) ((S (A B)) (A (B a) e) (B (C b) C) (C c e)) S)) - (parser--set-look-ahead-number 2) - (parser--process-grammar) - - (should - (equal - '((c a) (c b)) - (parser--e-free-first 'S))) - (message "Passed empty-free-first 2 with complex grammar") - - (parser--set-look-ahead-number 1) - (parser--process-grammar) - (should - (equal - '((c)) - (parser--e-free-first '(S b a)))) - (message "Passed empty-free-first 1 with complex grammar") - - (parser--set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) - (parser--set-look-ahead-number 1) - (parser--process-grammar) - (should - (equal - nil - (parser--e-free-first '(S b a)))) - (message "Passed empty-free-first 1 with complex grammar 2") - - (message "Passed tests for (parser--empty-free-first)")) - -(defun parser-test--valid-grammar-p () - "Test function `parser--valid-grammar-p'." - (message "Starting tests for (parser--valid-grammar-p)") - - (should (equal - t - (parser--valid-grammar-p '((A B C) ("a" "b" "c") ((A "a")) A)))) - - (should (equal - nil - (parser--valid-grammar-p '((A B C) ("a" "b" "c") ((A "a")) (A))))) - - (should (equal - nil - (parser--valid-grammar-p '((A B C) (("a" "b") "c") ((A "a")) A)))) - - (should (equal - nil - (parser--valid-grammar-p '(((A B) C) ("a" "b" "c") ((A "a")) A)))) - - (should (equal - nil - (parser--valid-grammar-p '(((A B) C) ("a" "b" "c") ((A)) A)))) - - (should (equal - nil - (parser--valid-grammar-p "A"))) - - (should (equal - nil - (parser--valid-grammar-p '(A B C)))) - - (should (equal - nil - (parser--valid-grammar-p '((A B))))) - - (should (equal - nil - (parser--valid-grammar-p '((A B C) (a (b c) "c") (A ("a" "b") (a b)) (B b) (C "c"))))) - - (message "Passed tests for (parser--valid-grammar-p)")) - -(defun parser-test--valid-look-ahead-number-p () - "Test function `parser--valid-look-ahead-number-p'." - (message "Starting tests for (parser--valid-look-ahead-number-p)") - - (should (equal - nil - (parser--valid-look-ahead-number-p 'A))) - - (should (equal - nil - (parser--valid-look-ahead-number-p "A"))) - - (should (equal - nil - (parser--valid-look-ahead-number-p -2))) - - (should (equal - nil - (parser--valid-look-ahead-number-p 3.3))) - - (should (equal - t - (parser--valid-look-ahead-number-p 2))) - - (should (equal - t - (parser--valid-look-ahead-number-p 1))) - - (message "Passed tests for (parser--valid-look-ahead-number-p)")) - -(defun parser-test--valid-sentential-form-p () - "Test `parser--valid-sentential-form-p'." - (message "Starting tests for (parser--valid-sentential-form-p)") - - ;; TODO Add tests for this - - (message "Passed tests for (parser--valid-sentential-form-p)")) - -(defun parser-test--valid-production-p () - "Test `parser--valid-production-p'." - (message "Starting tests for (parser--valid-production-p)") - - (should (equal - t - (parser--valid-production-p '(A a)))) - - (should (equal - nil - (parser--valid-production-p "A"))) - - (should (equal - nil - (parser--valid-production-p '((A a))))) - - (message "Passed tests for (parser--valid-production-p)")) - -(defun parser-test--get-grammar-rhs () - "Test `parser--get-grammar-rhs'." - (message "Started tests for (parser--get-grammar-rhs)") - - (parser--set-grammar '((S A) ("a" "b") ((S A) (A ("b" "a"))) S)) - (parser--process-grammar) - - (should (equal - '((A)) - (parser--get-grammar-rhs 'S))) - (should (equal - '(("b" "a")) - (parser--get-grammar-rhs 'A))) - - (parser--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) - (parser--process-grammar) - - (should (equal - '((A) (B)) - (parser--get-grammar-rhs 'S))) - (should (equal - '(("a") ("b" "a")) - (parser--get-grammar-rhs 'A))) - - (message "Passed tests for (parser--get-grammar-rhs)")) - -(defun parser-test--valid-non-terminal-p () - "Test `parser--valid-non-terminal-p'." - (message "Starting tests for (parser--valid-non-terminal-p)") - - (parser--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) - (parser--process-grammar) - - (should - (equal - t - (parser--valid-non-terminal-p 'S))) - (should - (equal - t - (parser--valid-non-terminal-p 'A))) - (should - (equal - t - (parser--valid-non-terminal-p 'B))) - (should - (equal - nil - (parser--valid-non-terminal-p 'C))) - (should - (equal - nil - (parser--valid-non-terminal-p "a"))) - - (message "Passed tests for (parser--valid-non-terminal-p)")) - -(defun parser-test--valid-terminal-p () - "Test `parser--valid-terminal-p'." - (message "Starting tests for (parser--valid-terminal-p)") - - (parser--set-grammar '((S A B) ("a" "b") ((S A) (S (B)) (B "a") (A "a") (A ("b" "a"))) S)) - (parser--process-grammar) - - (should - (equal - t - (parser--valid-terminal-p "a"))) - (should - (equal - t - (parser--valid-terminal-p "b"))) - (should - (equal - t - (parser--valid-terminal-p "a"))) - (should - (equal - nil - (parser--valid-terminal-p 'S))) - (should - (equal - nil - (parser--valid-terminal-p 'A))) - - (message "Passed tests for (parser--valid-terminal-p)")) - -(defun parser-test () - "Run test." - ;; (setq debug-on-error t) - - ;; Helpers - (parser-test--valid-look-ahead-p) - (parser-test--valid-look-ahead-number-p) - (parser-test--valid-production-p) - (parser-test--valid-grammar-p) - (parser-test--valid-non-terminal-p) - (parser-test--valid-sentential-form-p) - (parser-test--valid-terminal-p) - (parser-test--distinct) - (parser-test--sort-list) - (parser-test--get-grammar-rhs) - (parser-test--get-grammar-look-aheads) - - ;; Algorithms - (parser-test--first) - (parser-test--e-free-first) - (parser-test--follow)) - -(provide 'parser-test) - -;;; parser-test.el ends here