[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/parser-generator 020969094c 61/82: More refactoring
From: |
Christian Johansson |
Subject: |
[elpa] externals/parser-generator 020969094c 61/82: More refactoring |
Date: |
Thu, 12 May 2022 13:28:18 -0400 (EDT) |
branch: externals/parser-generator
commit 020969094c94614601ee353b1ba06cb931ec9e58
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>
More refactoring
---
parser-generator-ll.el | 201 +++++++++++++++++++++++-----------
parser-generator.el | 2 +-
test/parser-generator-ll-test.el | 231 ++++++++++++++++++++-------------------
3 files changed, 253 insertions(+), 181 deletions(-)
diff --git a/parser-generator-ll.el b/parser-generator-ll.el
index 05d4fcbd1d..c33f8082f1 100644
--- a/parser-generator-ll.el
+++ b/parser-generator-ll.el
@@ -25,16 +25,67 @@
;;; Functions
-(defun parser-generator-ll-generate-tables ()
- "Generate tables for grammar."
- (if (> parser-generator--look-ahead-number 1)
- (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")))
+(defun parser-generator-ll-generate-table ()
+ "Generate table for grammar."
+ (let ((list-parsing-table)
+ (hash-parsing-table (make-hash-table :test 'equal)))
+
+ (if (> parser-generator--look-ahead-number 1)
+ (progn
+ (message "\n;; Starting generation of LL(k) tables..\n")
+
+ (unless (parser-generator-ll--valid-grammar-k-gt-1-p)
+ (error "Invalid LL(k) grammar specified!"))
+
+ (setq
+ list-parsing-table
+ (parser-generator-ll--generate-action-table-k-gt-1
+ (parser-generator-ll--generate-goto-table-k-gt-1))))
+
+ (message "\n;; Starting generation of LL(1) tables..\n")
+
+ (unless (parser-generator-ll--valid-grammar-p-k-eq-1)
+ (error "Invalid LL(1) grammar specified!"))
+
+ (setq
+ list-parsing-table
+ (parser-generator-ll--generate-table-k-eq-1)))
+
+ ;; Convert list-structure to hash-map
+ (dolist (state-list list-parsing-table)
+ (let ((state-key (nth 0 state-list))
+ (state-look-aheads (nth 1 state-list))
+ (state-hash-table (make-hash-table :test 'equal)))
+ (dolist (state-look-ahead-list state-look-aheads)
+ (let ((state-look-ahead-string (nth 0 state-look-ahead-list))
+ (state-look-ahead-action (nth 1 state-look-ahead-list)))
+ (if (equal state-look-ahead-action 'reduce)
+ (let ((state-look-ahead-reduction
+ (nth 2 state-look-ahead-list))
+ (state-look-ahead-production-number
+ (nth 3 state-look-ahead-list)))
+ (puthash
+ (format "%S" state-look-ahead-string)
+ (list
+ state-look-ahead-action
+ state-look-ahead-reduction
+ state-look-ahead-production-number)
+ state-hash-table))
+ (puthash
+ (format "%S" state-look-ahead-string)
+ state-look-ahead-action
+ state-hash-table))))
+ (puthash
+ (format "%S" state-key)
+ state-hash-table
+ hash-parsing-table)))
+ (setq
+ parser-generator-ll--table
+ hash-parsing-table)
+
+ (if (> parser-generator--look-ahead-number 1)
+ (message "\n;; Completed generation of LL(k) tables.\n")
+ (message "\n;; Completed generation of LL(1) tables.\n"))))
;; Generally described at .p 339
(defun parser-generator-ll-parse ()
@@ -147,57 +198,77 @@
(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
- (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))
- (state-look-aheads (nth 1 state-list))
- (state-hash-table (make-hash-table :test 'equal)))
- (dolist (state-look-ahead-list state-look-aheads)
- (let ((state-look-ahead-string (nth 0 state-look-ahead-list))
- (state-look-ahead-action (nth 1 state-look-ahead-list)))
- (if (equal state-look-ahead-action 'reduce)
- (let ((state-look-ahead-reduction
- (nth 2 state-look-ahead-list))
- (state-look-ahead-production-number
- (nth 3 state-look-ahead-list)))
- (puthash
- (format "%S" state-look-ahead-string)
- (list
- state-look-ahead-action
- state-look-ahead-reduction
- state-look-ahead-production-number)
- state-hash-table))
- (puthash
- (format "%S" state-look-ahead-string)
- state-look-ahead-action
- state-hash-table))))
- (puthash
- (format "%S" state-key)
- state-hash-table
- hash-parsing-table)))
- (setq
- parser-generator-ll--table
- hash-parsing-table)))
+ (let ((parsing-table))
+
+ ;; Iterate all possible look-aheads
+ ;; Add EOF symbol look-ahead
+ (let ((eof-look-ahead
+ (parser-generator--generate-list-of-symbol
+ parser-generator--look-ahead-number
+ parser-generator--eof-identifier))
+ (terminal-mutations
+ (parser-generator--get-grammar-look-aheads))
+ (terminal-buffer)
+ (last-terminal))
+ (dolist (terminal-mutation terminal-mutations)
+ (if (equal terminal-mutation eof-look-ahead)
+ (push
+ (list
+ parser-generator--eof-identifier
+ (list
+ (list
+ eof-look-ahead
+ 'accept)))
+ parsing-table)
+ (let ((stack-item (nth 0 terminal-mutation)))
+ (when (and
+ last-terminal
+ (not (equal last-terminal stack-item)))
+ (push
+ (list
+ last-terminal
+ terminal-buffer)
+ parsing-table)
+ (setq
+ terminal-buffer
+ nil))
+ (push
+ (list terminal-mutation 'pop)
+ terminal-buffer)
+ (setq
+ last-terminal
+ stack-item))))
+ (when (and
+ last-terminal
+ terminal-buffer)
+ (push
+ (list
+ last-terminal
+ terminal-buffer)
+ parsing-table)))
+
+ ;; Add non-terminal -> FIRST(non-terminal) -> reduce RHS, production-number
+ (let ((non-terminals (parser-generator--get-grammar-non-terminals)))
+ (dolist (non-terminal non-terminals)
+ (let ((non-terminal-buffer))
+ (let ((rhss (parser-generator--get-grammar-rhs non-terminal)))
+ (dolist (rhs rhss)
+ (let ((firsts-rhs (parser-generator--first rhs))
+ (production-number
+ (parser-generator--get-grammar-production-number
+ (list (list non-terminal) rhs))))
+ (dolist (first-rhs firsts-rhs)
+ (push
+ (list first-rhs 'reduce rhs production-number)
+ non-terminal-buffer)))))
+ (when non-terminal-buffer
+ (push
+ (list
+ non-terminal
+ non-terminal-buffer)
+ parsing-table)))))
+
+ parsing-table))
;; Algorithm 5.2 p. 350
(defun parser-generator-ll--generate-goto-table-k-gt-1 ()
@@ -308,13 +379,13 @@
'error
(list
(format
- "There are more than one follow set in state! %S -> %S
+ %S"
+ "There are more than one possible follow set in state!
%S -> %S + %S"
sub-symbol
production-rhs
- follow-set)
+ local-follow-set)
sub-symbol
production-rhs
- follow-set)))
+ local-follow-set)))
(setq
local-follow
(car local-follow-set))
@@ -529,7 +600,7 @@
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))
+ (let* ((rhss (parser-generator--get-grammar-rhs non-terminal))
(rhss-length (length rhss))
(rhss-index 0)
(rhs)
diff --git a/parser-generator.el b/parser-generator.el
index dfd698663e..4b749f7f31 100644
--- a/parser-generator.el
+++ b/parser-generator.el
@@ -45,7 +45,7 @@
(defvar
parser-generator--debug
- t
+ nil
"Whether to print debug messages or not.")
(defvar
diff --git a/test/parser-generator-ll-test.el b/test/parser-generator-ll-test.el
index 785362e46f..a03fc43558 100644
--- a/test/parser-generator-ll-test.el
+++ b/test/parser-generator-ll-test.el
@@ -120,111 +120,6 @@
)
(message "Passed Example 5.17 p. 354")
- ;; 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
- '(
- (S A)
- (a b)
- (
- (S (a A S) b)
- (A a (b S A))
- )
- S
- )
- )
- (parser-generator-process-grammar)
- (let* ((tables
- (parser-generator-ll--generate-goto-table-k-gt-1)))
- ;; (message "tables: %S" tables)
- (should
- (equal
- tables
- '(
- (
- (A)
- (
- ((a) (a))
- ((b) (b S A))
- )
- )
- (
- (S)
- (
- ((a) (a A S))
- ((b) (b))
- )
- )
- )
- )
- ))
- (message "Passed Example 5.5 p. 340")
-
- (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)
- (let ((tables (parser-generator-ll--generate-goto-table-k-gt-1)))
- ;; (message "tables: %S" tables)
- (should
- (equal
- '(
- (
- (F)
- (
- (("(") ("(" E ")"))
- (("a") ("a"))
- )
- )
- (
- (T2)
- (
- (($) (e))
- (("*") ("*" F T2))
- )
- )
- (
- (T)
- (
- (("(") (F T2))
- (("a") (F T2))
- )
- )
- (
- (E2)
- (
- ((")") (e))
- (("+") ("+" T E2))
- )
- )
- (
- (E)
- (
- (("(") (T E2))
- (("a") (T E2))
- )
- )
- )
- tables)))
- (message "Passed Example 5.12 p. 346-347")
-
(message "Passed tests for
(parser-generator-ll--generate-goto-table-k-gt-1)"))
(defun parser-generator-ll-test--generate-action-table-k-gt-1 ()
@@ -248,7 +143,7 @@
(let ((parser-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)
+ (message "parser-tables: %S" parser-tables)
(should
(equal
'(
@@ -383,7 +278,7 @@
(lambda (token)
(car token)))
(message "parsing-table: %S" (parser-generator--hash-to-list
- parser-generator-ll--parsing-table
+ parser-generator-ll--table
t))
(should
(equal
@@ -516,9 +411,9 @@
(message "Passed tests for (parser-generator-ll-parse)"))
-(defun parser-generator-ll-test-generate-tables ()
- "Test `parser-generator-ll-generate-tables'."
- (message "Started tests for (parser-generator-ll-generate-tables)")
+(defun parser-generator-ll-test-generate-table ()
+ "Test `parser-generator-ll-generate-table'."
+ (message "Started tests for (parser-generator-ll-generate-table)")
(parser-generator-set-eof-identifier '$)
(parser-generator-set-e-identifier 'e)
@@ -535,8 +430,8 @@
)
)
(parser-generator-process-grammar)
- (parser-generator-ll-generate-tables)
- ;; (message "parsing-table: %S" (parser-generator--hash-to-list
parser-generator-ll--parsing-table t))
+ (parser-generator-ll-generate-table)
+ ;; (message "parsing-table: %S" (parser-generator--hash-to-list
parser-generator-ll--table t))
(should
(equal
'(
@@ -571,12 +466,12 @@
("$" (("($ $)" accept)))
)
(parser-generator--hash-to-list
- parser-generator-ll--parsing-table
+ parser-generator-ll--table
t)))
;; TODO Should test k = 1 here as well
- (message "Passed tests for (parser-generator-ll-generate-tables)"))
+ (message "Passed tests for (parser-generator-ll-generate-table)"))
(defun parser-generator-ll-test--valid-grammar-k-gt-1-p ()
"Test `parser-generator-ll--valid-grammar-k-gt-1-p'."
@@ -632,6 +527,112 @@
;; TODO Implement this
+ ;; 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
+ '(
+ (S A)
+ (a b)
+ (
+ (S (a A S) b)
+ (A a (b S A))
+ )
+ S
+ )
+ )
+ (parser-generator-process-grammar)
+ (let* ((tables
+ (parser-generator-ll--generate-table-k-eq-1)))
+ (message "tables: %S" tables)
+ (should
+ (equal
+ tables
+ '(
+ (
+ (A)
+ (
+ ((a) (a))
+ ((b) (b S A))
+ )
+ )
+ (
+ (S)
+ (
+ ((a) (a A S))
+ ((b) (b))
+ )
+ )
+ )
+ )
+ ))
+ (message "Passed Example 5.5 p. 340")
+
+ (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)
+ (let ((tables (parser-generator-ll--generate-table-k-eq-1)))
+ (message "tables: %S" tables)
+ (should
+ (equal
+ '(
+ (
+ (F)
+ (
+ (("(") ("(" E ")"))
+ (("a") ("a"))
+ )
+ )
+ (
+ (T2)
+ (
+ (($) (e))
+ (("*") ("*" F T2))
+ )
+ )
+ (
+ (T)
+ (
+ (("(") (F T2))
+ (("a") (F T2))
+ )
+ )
+ (
+ (E2)
+ (
+ ((")") (e))
+ (("+") ("+" T E2))
+ )
+ )
+ (
+ (E)
+ (
+ (("(") (T E2))
+ (("a") (T E2))
+ )
+ )
+ )
+ tables)))
+ (message "Passed Example 5.12 p. 346-347")
+
+
(parser-generator-set-eof-identifier '$)
(parser-generator-set-e-identifier 'e)
(parser-generator-set-look-ahead-number 1)
@@ -749,7 +750,7 @@
(parser-generator-ll-test--valid-grammar-k-eq-1-p)
;; Main stuff
- (parser-generator-ll-test-generate-tables)
+ (parser-generator-ll-test-generate-table)
(parser-generator-ll-test-parse))
- [elpa] externals/parser-generator 542a50d9c1 20/82: Remove usage of a hash-table, (continued)
- [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, 2022/05/12
- [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 <=
- [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
- [elpa] externals/parser-generator 52734d7160 16/82: Updated TODO items, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 7b77032f71 22/82: Parser table generation for LLk now works for productions, Christian Johansson, 2022/05/12