[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/parser-generator af3740c46a 59/82: More refactoring
From: |
Christian Johansson |
Subject: |
[elpa] externals/parser-generator af3740c46a 59/82: More refactoring |
Date: |
Thu, 12 May 2022 13:28:18 -0400 (EDT) |
branch: externals/parser-generator
commit af3740c46a1e3fafe33311ae6527ad02aba4a504
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>
More refactoring
---
parser-generator-ll.el | 97 ++++++++++----
test/parser-generator-ll-test.el | 265 ++++++++++++++++++++-------------------
2 files changed, 211 insertions(+), 151 deletions(-)
diff --git a/parser-generator-ll.el b/parser-generator-ll.el
index 55eaeaecef..05d4fcbd1d 100644
--- a/parser-generator-ll.el
+++ b/parser-generator-ll.el
@@ -17,9 +17,9 @@
(defvar
- parser-generator-ll--parsing-table
+ parser-generator-ll--table
nil
- "Parsing-table for grammar.")
+ "Table for grammar.")
;;; Functions
@@ -27,11 +27,14 @@
(defun parser-generator-ll-generate-tables ()
"Generate tables for grammar."
- (message "\n;; Starting generation of LL(k) tables..\n")
(if (> parser-generator--look-ahead-number 1)
- (parser-generator-ll--generate-parser-tables-k-gt-1)
- (parser-generator-ll--generate-parser-tables-k-eq-1))
- (message "\n;; Completed generation of LL(k) tables.\n"))
+ (progn
+ (message "\n;; Starting generation of LL(k) tables..\n")
+ (parser-generator-ll--generate-tables-k-gt-1)
+ (message "\n;; Completed generation of LL(k) tables.\n"))
+ (message "\n;; Starting generation of LL(1) tables..\n")
+ (parser-generator-ll--generate-tables-k-eq-1)
+ (message "\n;; Completed generation of LL(1) tables.\n")))
;; Generally described at .p 339
(defun parser-generator-ll-parse ()
@@ -59,7 +62,7 @@
(state-action-table
(gethash
(format "%S" state)
- parser-generator-ll--parsing-table))
+ parser-generator-ll--table))
(look-ahead-list
(parser-generator-lex-analyzer--peek-next-look-ahead))
(look-ahead))
@@ -142,16 +145,28 @@
;;; Algorithms
-(defun parser-generator-ll--generate-parser-tables-k-gt-1 ()
- "Generate parsing tables for grammar k > 1."
- (message "\n;; Starting generation of LL(k) parser-tables..\n")
- (unless (parser-generator-ll--valid-grammar-p-k-gt-1)
- (error "Invalid grammar specified!"))
+(defun parser-generator-ll--generate-table-k-eq-1 ()
+ "Generate table for LL(1) grammar."
+ (message "\n;; Starting generation of LL(1) table..\n")
+ (unless (parser-generator-ll--valid-grammar-p-k-eq-1)
+ (error "Invalid LL(1) grammar specified!"))
+ (let (hash-parsing-table (make-hash-table :test 'equal))
+ ;; TODO Iterate all non-terminals here
+ ;; TODO Add non-terminal -> FIRST(non-terminal) -> reduce RHS,
production-number
+ ;; TODO Iterate all possible look-aheds
+ ;; TODO Added EOF symbol
+ (setq
+ parser-generator-ll--table
+ hash-parsing-table)))
+
+(defun parser-generator-ll--generate-table-k-gt-1 ()
+ "Generate table for LL(k) grammar."
+ (message "\n;; Starting generation of LL(k) table..\n")
+ (unless (parser-generator-ll--valid-grammar-k-gt-1-p)
+ (error "Invalid LL(k) grammar specified!"))
(let ((list-parsing-table
- (if (> parser-generator--look-ahead-number 1)
- (parser-generator-ll--generate-parsing-table-k-gt-1
- (parser-generator-ll--generate-tables-k-gt-1))
- (parser-generator-ll--generate-parsing-table-k-eq-1)))
+ (parser-generator-ll--generate-action-table-k-gt-1
+ (parser-generator-ll--generate-goto-table-k-gt-1)))
(hash-parsing-table (make-hash-table :test 'equal)))
(dolist (state-list list-parsing-table)
(let ((state-key (nth 0 state-list))
@@ -181,12 +196,12 @@
state-hash-table
hash-parsing-table)))
(setq
- parser-generator-ll--parsing-table
+ parser-generator-ll--table
hash-parsing-table)))
;; Algorithm 5.2 p. 350
-(defun parser-generator-ll--generate-tables-k-gt-1 ()
- "Construction of LL(k)-tables were k > 1. Output the set of LL(k) tables
needed to construct a parsing table for the grammar G."
+(defun parser-generator-ll--generate-goto-table-k-gt-1 ()
+ "Construction of LL(k) GOTO-table. Output the set of LL(k) tables needed to
construct a action table for the grammar G."
(let ((tables (make-hash-table :test 'equal))
(distinct-item-p (make-hash-table :test 'equal))
(stack)
@@ -395,8 +410,8 @@
sorted-tables)))
;; Algorithm 5.3 p. 351
-(defun parser-generator-ll--generate-parsing-table-k-gt-1 (tables)
- "Generate a parsing table for an LL(k) grammar G and TABLES. Output M, a
valid parsing table for G."
+(defun parser-generator-ll--generate-action-table-k-gt-1 (tables)
+ "Generate a action table for an LL(k) grammar G and TABLES. Output M, a
valid parsing table for G."
(let ((parsing-table))
;; (3) M($, e) = accept
@@ -503,9 +518,45 @@
parsing-table))
+(defun parser-generator-ll--valid-grammar-k-eq-1-p ()
+ "Test for LL(1)-ness. Output t if grammar is LL(1), nil otherwise."
+ (let* ((non-terminals (parser-generator--get-grammar-non-terminals))
+ (non-terminal-length (length non-terminals))
+ (non-terminal-index 0)
+ (non-terminal)
+ (valid t))
+ (while (and
+ valid
+ (< non-terminal-index non-terminal-length))
+ (setq non-terminal (nth non-terminal-index non-terminals))
+ (let* ((rhss (parser-generator--get-grammar-rhs non-terminals))
+ (rhss-length (length rhss))
+ (rhss-index 0)
+ (rhs)
+ (look-aheads (make-hash-table :test 'equal)))
+ (while (and
+ valid
+ (< rhss-index rhss-length))
+ (setq rhs (nth rhss-index rhss))
+ (let* ((firsts-rhs (parser-generator--first rhs))
+ (firsts-rhs-length (length firsts-rhs))
+ (firsts-index 0))
+ (while (and
+ valid
+ (< firsts-index firsts-rhs-length))
+ (setq first-rhs (nth firsts-index firsts-rhs))
+ (let ((first-rhs-hash (format "%S" first-rhs)))
+ (if (gethash first-rhs-hash look-aheads)
+ (setq valid nil)
+ (puthash first-rhs-hash t look-aheads)))
+ (setq firsts-index (1+ firsts-index))))
+ (setq rhss-index (1+ rhss-index))))
+ (setq non-terminal-index (1+ non-terminal-index)))
+ valid))
+
;; Algorithm 5.4 p. 357
-(defun parser-generator-ll--valid-grammar-p-k-gt-1 ()
- "Test for LL(k)-ness. Output t if grammar is LL(k). nil otherwise."
+(defun parser-generator-ll--valid-grammar-k-gt-1-p ()
+ "Test for LL(k)-ness. Output t if grammar is LL(k), nil otherwise."
(let ((stack)
(stack-item)
(distinct-production-p (make-hash-table :test 'equal))
diff --git a/test/parser-generator-ll-test.el b/test/parser-generator-ll-test.el
index e9026532a0..785362e46f 100644
--- a/test/parser-generator-ll-test.el
+++ b/test/parser-generator-ll-test.el
@@ -12,9 +12,9 @@
(require 'parser-generator-ll)
(require 'ert)
-(defun parser-generator-ll-test--generate-tables-k-gt-1 ()
- "Test `parser-generator-ll--generate-tables-k-gt-1'."
- (message "Started tests for (parser-generator-ll--generate-tables-k-gt-1)")
+(defun parser-generator-ll-test--generate-goto-table-k-gt-1 ()
+ "Test `parser-generator-ll--generate-goto-table-k-gt-1'."
+ (message "Started tests for
(parser-generator-ll--generate-goto-table-k-gt-1)")
(parser-generator-set-e-identifier 'e)
(parser-generator-set-look-ahead-number 2)
@@ -30,7 +30,7 @@
)
)
(parser-generator-process-grammar)
- (let ((tables (parser-generator-ll--generate-tables-k-gt-1)))
+ (let ((tables (parser-generator-ll--generate-goto-table-k-gt-1)))
;; (message "tables: %S" tables)
(should
(equal
@@ -79,7 +79,7 @@
)
(parser-generator-process-grammar)
(let* ((tables
- (parser-generator-ll--generate-tables-k-gt-1)))
+ (parser-generator-ll--generate-goto-table-k-gt-1)))
;; (message "tables: %S" tables)
(should
(equal
@@ -138,7 +138,7 @@
)
(parser-generator-process-grammar)
(let* ((tables
- (parser-generator-ll--generate-tables)))
+ (parser-generator-ll--generate-goto-table-k-gt-1)))
;; (message "tables: %S" tables)
(should
(equal
@@ -181,7 +181,7 @@
)
)
(parser-generator-process-grammar)
- (let ((tables (parser-generator-ll--generate-tables)))
+ (let ((tables (parser-generator-ll--generate-goto-table-k-gt-1)))
;; (message "tables: %S" tables)
(should
(equal
@@ -225,13 +225,11 @@
tables)))
(message "Passed Example 5.12 p. 346-347")
- (message "Passed tests for (parser-generator-ll--generate-tables-k-gt-1)"))
+ (message "Passed tests for
(parser-generator-ll--generate-goto-table-k-gt-1)"))
-(defun parser-generator-ll-test--generate-parsing-table-k-gt-1 ()
- "Test `parser-generator-ll--generate-parsing-table'."
- (message "Started tests for
(parser-generator-ll--generate-parsing-table-k-gt-1)")
-
- ;; TODO Need to make this tests pass, RHS after reduction should be single
dimension list
+(defun parser-generator-ll-test--generate-action-table-k-gt-1 ()
+ "Test `parser-generator-ll--generate-action-table-k-gt-1'."
+ (message "Started tests for
(parser-generator-ll--generate-action-table-k-gt-1)")
(parser-generator-set-e-identifier 'e)
(parser-generator-set-look-ahead-number 2)
@@ -248,8 +246,8 @@
)
(parser-generator-process-grammar)
(let ((parser-tables
- (parser-generator-ll--generate-parsing-table-k-gt-1
- (parser-generator-ll--generate-tables))))
+ (parser-generator-ll--generate-action-table-k-gt-1
+ (parser-generator-ll--generate-goto-table-k-gt-1))))
;; (message "parser-tables: %S" parser-tables)
(should
(equal
@@ -299,9 +297,9 @@
)
(parser-generator-process-grammar)
(let* ((tables
- (parser-generator-ll--generate-tables))
+ (parser-generator-ll--generate-goto-table-k-gt-1))
(parser-tables
- (parser-generator-ll--generate-parsing-table-k-gt-1
+ (parser-generator-ll--generate-action-table-k-gt-1
tables)))
;; (message "tables: %S" tables)
;; (message "parser-tables: %S" parser-tables)
@@ -345,105 +343,7 @@
parser-tables)))
(message "Passed Example 5.17 p. 356")
- ;; TODO Move below to separate test
-
- (parser-generator-set-eof-identifier '$)
- (parser-generator-set-e-identifier 'e)
- (parser-generator-set-look-ahead-number 1)
- (parser-generator-set-grammar
- '(
- (E E2 T T2 F)
- ("a" "(" ")" "+" "*")
- (
- (E (T E2))
- (E2 ("+" T E2) e)
- (T (F T2))
- (T2 ("*" F T2) e)
- (F ("(" E ")") "a")
- )
- E
- )
- )
- (parser-generator-process-grammar)
- (parser-generator-process-grammar)
- (let* ((tables
- (parser-generator-ll--generate-tables))
- (parser-tables
- (parser-generator-ll--generate-parsing-table-k-gt-1
- tables)))
- ;; (message "tables: %S" tables)
- ;; (message "parser-tables: %S" parser-tables)
- (should
- (equal
- '(
- (
- ((E) ($))
- (
- (("a") reduce (((T) ($)) ((T) ("+")) ((E2) ($))) 0)
- (("(") reduce (((T) ($)) ((T) ("+")) ((E2) ($))) 0)
- )
- )
- (
- ((E2) ($))
- (
- (("+") reduce ("+" ((T) ($)) ((T) ("+")) ((E2) ($))) 1)
- (($) reduce (e) 2)
- )
- )
- (
- ((T) ("+"))
- (
- (("a") reduce (((F) ("*")) ((F) ("+")) ((T2) ("+"))) 3)
- (("(") reduce (((F) ("*")) ((F) ("+")) ((T2) ("+"))) 3)
- )
- )
- (
- ((T2) ("+"))
- (
- (("+") reduce (e) 5)
- (("*") reduce ("*" ((F) ("*")) ((F) ("+")) ((T2) ("+"))) 4)
- )
- )
- (
- ((F) ("+"))
- (
- (("a") reduce ("a") 7)
- (("(") reduce ("(" ((E) (")")) ")") 6)
- )
- )
- (
- ((E) (")"))
- (
- (("a") reduce (((T) (")")) ((T) ("+")) ((E2) (")"))) 0)
- (("(") reduce (((T) (")")) ((T) ("+")) ((E2) (")"))) 0)
- )
- )
- (
- ((E2) (")"))
- (
- (("+") reduce ("+" ((T) (")")) ((T) ("+")) ((E2) (")"))) 1)
- ((")") reduce (e) 2)
- )
- )
- (((T) (")")) ((("a") reduce (((F) (")")) ((F) ("*")) ((T2) (")"))) 3)
(("(") reduce (((F) (")")) ((F) ("*")) ((T2) (")"))) 3)))
- (((T2) (")")) ((("*") reduce ("*" ((F) (")")) ((F) ("*")) ((T2)
(")"))) 4) ((")") reduce (e) 5)))
- (((F) (")")) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")"))
")") 6)))
- (((F) ("*")) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")"))
")") 6)))
- (((T) ($)) ((("a") reduce (((F) ($)) ((F) ("*")) ((T2) ($))) 3) (("(")
reduce (((F) ($)) ((F) ("*")) ((T2) ($))) 3)))
- (((T2) ($)) ((("*") reduce ("*" ((F) ($)) ((F) ("*")) ((T2) ($))) 4)
(($) reduce (e) 5)))
- (((F) ($)) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")")) ")")
6)))
- ("a" ((("a") pop)))
- ("+" ((("+") pop)))
- ("*" ((("*") pop)))
- (")" (((")") pop)))
- ("(" ((("(") pop)))
- ($ ((($) accept)))
- )
- parser-tables)))
- ;; TODO Verify above
- (message "Passed Example 5.12 p. 346-347")
-
- (message "Passed tests for (parser-generator-ll--generate-parsing-table)"))
+ (message "Passed tests for
(parser-generator-ll--generate-action-table-k-gt-1)"))
(defun parser-generator-ll-test--parse ()
"Test `parser-generator-ll-parse'."
@@ -678,9 +578,9 @@
(message "Passed tests for (parser-generator-ll-generate-tables)"))
-(defun parser-generator-ll-test--valid-grammar-p-k-gt-1 ()
- "Test `parser-generator-ll--valid-grammar-p-k-gt-1'."
- (message "Started tests for (parser-generator-ll--valid-grammar-p-k-gt-1)")
+(defun parser-generator-ll-test--valid-grammar-k-gt-1-p ()
+ "Test `parser-generator-ll--valid-grammar-k-gt-1-p'."
+ (message "Started tests for (parser-generator-ll--valid-grammar-k-gt-1-p)")
;; Example 5.14 p. 350
;; Example 5.15 p. 351
@@ -700,7 +600,7 @@
(parser-generator-process-grammar)
(should
(equal
- (parser-generator-ll--valid-grammar-p-k-gt-1)
+ (parser-generator-ll--valid-grammar-k-gt-1-p)
t))
(message "Passed first valid test")
@@ -720,24 +620,133 @@
(parser-generator-process-grammar)
(should
(equal
- (parser-generator-ll--valid-grammar-p-k-gt-1)
+ (parser-generator-ll--valid-grammar-k-gt-1-p)
nil))
(message "Passed second valid test")
- ;; TODO Example 5.19
+ (message "Passed tests for (parser-generator-ll--valid-grammar-k-gt-1-p)"))
- (message "Passed tests for (parser-generator-ll--valid-grammar-p-k-gt-1)"))
+(defun parser-generator-ll-test--generate-table-k-eq-1 ()
+ "Test `parser-generator-ll--generate-table-k-eq-1'."
+ (message "Started tests for (parser-generator-ll--generate-table-k-eq-1)")
+
+ ;; TODO Implement this
+
+ (parser-generator-set-eof-identifier '$)
+ (parser-generator-set-e-identifier 'e)
+ (parser-generator-set-look-ahead-number 1)
+ (parser-generator-set-grammar
+ '(
+ (E E2 T T2 F)
+ ("a" "(" ")" "+" "*")
+ (
+ (E (T E2))
+ (E2 ("+" T E2) e)
+ (T (F T2))
+ (T2 ("*" F T2) e)
+ (F ("(" E ")") "a")
+ )
+ E
+ )
+ )
+ (parser-generator-process-grammar)
+ (parser-generator-process-grammar)
+ (let ((parser-tables (parser-generator-ll--generate-action-table-k-eq-1)))
+ ;; (message "parser-tables: %S" parser-tables)
+ (should
+ (equal
+ '(
+ (
+ ((E) ($))
+ (
+ (("a") reduce (((T) ($)) ((T) ("+")) ((E2) ($))) 0)
+ (("(") reduce (((T) ($)) ((T) ("+")) ((E2) ($))) 0)
+ )
+ )
+ (
+ ((E2) ($))
+ (
+ (("+") reduce ("+" ((T) ($)) ((T) ("+")) ((E2) ($))) 1)
+ (($) reduce (e) 2)
+ )
+ )
+ (
+ ((T) ("+"))
+ (
+ (("a") reduce (((F) ("*")) ((F) ("+")) ((T2) ("+"))) 3)
+ (("(") reduce (((F) ("*")) ((F) ("+")) ((T2) ("+"))) 3)
+ )
+ )
+ (
+ ((T2) ("+"))
+ (
+ (("+") reduce (e) 5)
+ (("*") reduce ("*" ((F) ("*")) ((F) ("+")) ((T2) ("+"))) 4)
+ )
+ )
+ (
+ ((F) ("+"))
+ (
+ (("a") reduce ("a") 7)
+ (("(") reduce ("(" ((E) (")")) ")") 6)
+ )
+ )
+ (
+ ((E) (")"))
+ (
+ (("a") reduce (((T) (")")) ((T) ("+")) ((E2) (")"))) 0)
+ (("(") reduce (((T) (")")) ((T) ("+")) ((E2) (")"))) 0)
+ )
+ )
+ (
+ ((E2) (")"))
+ (
+ (("+") reduce ("+" ((T) (")")) ((T) ("+")) ((E2) (")"))) 1)
+ ((")") reduce (e) 2)
+ )
+ )
+ (((T) (")")) ((("a") reduce (((F) (")")) ((F) ("*")) ((T2) (")"))) 3)
(("(") reduce (((F) (")")) ((F) ("*")) ((T2) (")"))) 3)))
+ (((T2) (")")) ((("*") reduce ("*" ((F) (")")) ((F) ("*")) ((T2)
(")"))) 4) ((")") reduce (e) 5)))
+ (((F) (")")) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")"))
")") 6)))
+ (((F) ("*")) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")"))
")") 6)))
+ (((T) ($)) ((("a") reduce (((F) ($)) ((F) ("*")) ((T2) ($))) 3) (("(")
reduce (((F) ($)) ((F) ("*")) ((T2) ($))) 3)))
+ (((T2) ($)) ((("*") reduce ("*" ((F) ($)) ((F) ("*")) ((T2) ($))) 4)
(($) reduce (e) 5)))
+ (((F) ($)) ((("a") reduce ("a") 7) (("(") reduce ("(" ((E) (")")) ")")
6)))
+ ("a" ((("a") pop)))
+ ("+" ((("+") pop)))
+ ("*" ((("*") pop)))
+ (")" (((")") pop)))
+ ("(" ((("(") pop)))
+ ($ ((($) accept)))
+ )
+ parser-tables)))
+ ;; TODO Verify above
+ (message "Passed Example 5.12 p. 346-347")
+
+ (message "Passed tests for (parser-generator-ll--generate-table-k-eq-1)"))
+
+(defun parser-generator-ll-test--valid-grammar-k-eq-1-p ()
+ "Test `parser-generator-ll--valid-grammar-k-eq-1-p'."
+ (message "Started tests for (parser-generator-ll--valid-grammar-k-eq-1-p)")
+
+ ;; TODO Implement this
+
+ (message "Passed tests for (parser-generator-ll--valid-grammar-k-eq-1-p)"))
(defun parser-generator-ll-test ()
"Run test."
;; Helpers
- (parser-generator-ll-test--generate-tables-k-gt-1)
- (parser-generator-ll-test--generate-parsing-table-k-gt-1)
- ;; TODO Generate tables k eq 1
- (parser-generator-ll-test--valid-grammar-p-k-gt-1)
- ;; TODO Validate grammar k eq 1
+
+ ;; k > 1
+ (parser-generator-ll-test--generate-goto-table-k-gt-1)
+ (parser-generator-ll-test--generate-action-table-k-gt-1)
+ (parser-generator-ll-test--valid-grammar-k-gt-1-p)
+
+ ;; k = 1
+ (parser-generator-ll-test--generate-table-k-eq-1)
+ (parser-generator-ll-test--valid-grammar-k-eq-1-p)
;; Main stuff
(parser-generator-ll-test-generate-tables)
- [elpa] externals/parser-generator bab123bdda 17/82: Added reference to PHP 8.1, (continued)
- [elpa] externals/parser-generator bab123bdda 17/82: Added reference to PHP 8.1, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator a2a629c16d 18/82: More work on data structure for LL-tables, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 542a50d9c1 20/82: Remove usage of a hash-table, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 221446d647 24/82: Started implementation of LLk validation, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator ab4ce4d668 25/82: Tests for validating LLk grammar passing, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 04eb4d066c 27/82: Started on test for Example 5.17, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 5c0bcd5f9a 36/82: Passing test for LL-table generation example 5.17, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 1290048b84 39/82: Improved documentation, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 57c6fdda2f 43/82: Passing test for generating LL-parser hash-table, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator b37ba1eddf 52/82: Created TODO item, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator af3740c46a 59/82: More refactoring,
Christian Johansson <=
- [elpa] externals/parser-generator 3d373f4dfa 60/82: Updated docs, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 020969094c 61/82: More refactoring, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 08ed55d35a 62/82: More work on k=1, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 4f85cc5616 66/82: Passes byte-compilation tests, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 7a265c9a84 67/82: LL-tests now runs on make tests command, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator a046c8584d 73/82: Started on documentation for LL(k) and LL(1), Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator f07939a440 76/82: Added example from Wikipedia and passing test, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 03a11c4369 14/82: Started test for LL(k) parser-table generation, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 9d6ca94d0e 02/82: More work on LL(k) parser, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 6ce0dd9429 04/82: Improved function to calculate merge max terminal sets, Christian Johansson, 2022/05/12