branch: externals/parser-generator commit b072fdd1035db5bc2ec898c31e7d1082bb779e46 Author: Christian Johansson <christ...@cvj.se> Commit: Christian Johansson <christ...@cvj.se>
Passed test for trailing e-identifier in EFF function --- parser-generator.el | 120 ++++++++++++++++++++++++------------------ test/parser-generator-test.el | 19 ++++++- 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/parser-generator.el b/parser-generator.el index 7c24819..020d604 100644 --- a/parser-generator.el +++ b/parser-generator.el @@ -580,6 +580,58 @@ "For sentential string Α, Calculate e-free-first k terminals in grammar." (parser-generator--first α t)) +(defun parser-generator--generate-f-sets () + "Generate F-sets for grammar." + ;; Generate F-sets only once per grammar + (unless (and + parser-generator--f-sets + parser-generator--f-free-sets) + (let ((productions (parser-generator--get-grammar-productions)) + (k parser-generator--look-ahead-number)) + (let ((i-max (length productions)) + (disallow-set '(nil t))) + (dolist (disallow-e-first disallow-set) + (let ((f-sets (make-hash-table :test 'equal)) + (i 0)) + (while (< i i-max) + (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-generator--debug + (message "Production: %s -> %s" production-lhs production-rhs)) + + ;; Iterate all blocks in RHS + (let ((f-p-set)) + (dolist (rhs-p production-rhs) + (let ((rhs-string rhs-p)) + (let ((rhs-leading-terminals + (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 + (listp rhs-leading-terminals) + (> (length rhs-leading-terminals) 0)) + (dolist (rhs-leading-terminals-element rhs-leading-terminals) + (push rhs-leading-terminals-element f-p-set))))))) + + ;; Make set distinct + (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-generator--f-free-sets f-sets) + (setq parser-generator--f-sets f-sets))))) + (parser-generator--debug + (message "Generated F-sets"))))) + ;; p. 358 (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." @@ -705,8 +757,10 @@ ((equal rhs-type 'EMPTY) (if disallow-e-first - (when (= leading-terminals-count 0) - (setq all-leading-terminals-p nil)) + (if (= leading-terminals-count 0) + (setq all-leading-terminals-p nil) + (setq leading-terminals (append leading-terminals rhs-element)) + (setq leading-terminals-count (1+ leading-terminals-count))) (when (and (= leading-terminals-count 0) (= input-tape-index (1- input-tape-length))) @@ -736,54 +790,7 @@ (let ((i-max (length productions))) ;; Generate F-sets only once per grammar - (when (or - (and - (not disallow-e-first) - (not parser-generator--f-sets)) - (and - disallow-e-first - (not parser-generator--f-free-sets))) - (let ((f-sets (make-hash-table :test 'equal)) - (i 0)) - (while (< i i-max) - (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-generator--debug - (message "Production: %s -> %s" production-lhs production-rhs)) - - ;; Iterate all blocks in RHS - (let ((f-p-set)) - (dolist (rhs-p production-rhs) - (let ((rhs-string rhs-p)) - (let ((rhs-leading-terminals - (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 - (listp rhs-leading-terminals) - (> (length rhs-leading-terminals) 0)) - (dolist (rhs-leading-terminals-element rhs-leading-terminals) - (push rhs-leading-terminals-element f-p-set))))))) - - ;; Make set distinct - (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-generator--f-free-sets f-sets) - (setq parser-generator--f-sets f-sets)))) - - (parser-generator--debug - (message "Generated F-sets")) + (parser-generator--generate-f-sets) (let ((first-list nil)) ;; Iterate each symbol in β using a PDA algorithm @@ -806,6 +813,15 @@ (parser-generator--debug (message "symbol index: %s from %s is: %s" input-tape-index input-tape symbol)) (cond + ((parser-generator--valid-e-p symbol) + (if disallow-e-first + (when (> first-length 0) + (setq first (append first (list symbol))) + (setq first-length (1+ first-length))) + (setq first (append first (list symbol))) + (setq first-length (1+ first-length))) + (setq keep-looking nil)) + ((parser-generator--valid-terminal-p symbol) (setq first (append first (list symbol))) (setq first-length (1+ first-length))) @@ -814,7 +830,9 @@ (parser-generator--debug (message "non-terminal symbol: %s" symbol)) (let ((symbol-f-set)) - (if disallow-e-first + (if (and + disallow-e-first + (= first-length 0)) (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 diff --git a/test/parser-generator-test.el b/test/parser-generator-test.el index bb9f33e..a355942 100644 --- a/test/parser-generator-test.el +++ b/test/parser-generator-test.el @@ -324,13 +324,28 @@ (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 + (should (equal nil (parser-generator--e-free-first '(S b a)))) (message "Passed empty-free-first 1 with complex grammar 2") - ;; TODO Test cases with trailing e-identifier here + (parser-generator-set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp)) + (parser-generator-set-look-ahead-number 2) + (parser-generator-process-grammar) + (should + (equal + '((a b)) + (parser-generator--e-free-first '(a b)))) + (should + (equal + '((a e)) + (parser-generator--e-free-first '(a e)))) + (should + (equal + '((a e)) + (parser-generator--e-free-first '(a S)))) + (message "Passed empty-free-first 2 with trailing e-identifier") (message "Passed tests for (parser-generator--empty-free-first)"))