emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/parser-generator 75323b10e5 81/82: Merge branch 'featur


From: Christian Johansson
Subject: [elpa] externals/parser-generator 75323b10e5 81/82: Merge branch 'feature/llk-parser'
Date: Thu, 12 May 2022 13:28:20 -0400 (EDT)

branch: externals/parser-generator
commit 75323b10e549448f3debbe2a0bbabcaf8f3848de
Merge: bf7229332f 5be162966b
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>

    Merge branch 'feature/llk-parser'
---
 Makefile                                |   12 +-
 README.md                               |    2 +-
 TODO.md                                 |    8 +-
 docs/Syntax-Analysis.md                 |    5 +-
 docs/Syntax-Analysis/LL1.md             |  174 ++++++
 docs/Syntax-Analysis/LLk.md             |  178 ++++++
 parser-generator-ll-export.el           |  816 +++++++++++++++++++++++++
 parser-generator-ll.el                  | 1004 +++++++++++++++++++++++++++++++
 parser-generator-lr.el                  |    4 +-
 parser-generator.el                     |  276 ++++++++-
 test/parser-generator-ll-export-test.el |  176 ++++++
 test/parser-generator-ll-test.el        |  943 +++++++++++++++++++++++++++++
 test/parser-generator-test.el           |  128 +++-
 13 files changed, 3676 insertions(+), 50 deletions(-)

diff --git a/Makefile b/Makefile
index 4965a61a20..86a23ae36f 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ ifdef emacs
 endif
 EMACS_CMD := $(EMACS) -Q -batch -L . -L test/
 
-EL  := parser-generator.el parser-generator-lex-analyzer.el 
parser-generator-lr.el parser-generator-lr-export.el 
test/parser-generator-test.el test/parser-generator-lex-analyzer-test.el 
test/parser-generator-lr-export-test.el test/parser-generator-lr-test.el 
+EL  := parser-generator.el parser-generator-lex-analyzer.el 
parser-generator-ll.el parser-generator-ll-export.el parser-generator-lr.el 
parser-generator-lr-export.el test/parser-generator-test.el 
test/parser-generator-lex-analyzer-test.el 
test/parser-generator-lr-export-test.el test/parser-generator-ll-test.el 
test/parser-generator-ll-export-test.el test/parser-generator-lr-test.el 
 ELC := $(EL:.el=.elc)
 
 .PHONY: clean
@@ -31,5 +31,13 @@ test-lr:
 test-lr-export:
        $(EMACS_CMD) -l test/parser-generator-lr-export-test.el -f 
"parser-generator-lr-export-test"
 
+.PHONY: test-ll
+test-ll:
+       $(EMACS_CMD) -l test/parser-generator-ll-test.el -f 
"parser-generator-ll-test"
+
+.PHONY: test-ll-export
+test-ll-export:
+       $(EMACS_CMD) -l test/parser-generator-ll-export-test.el -f 
"parser-generator-ll-export-test"
+
 .PHONY: tests
-tests: test test-lex-analyzer test-lr test-lr-export
+tests: test test-lex-analyzer test-lr test-lr-export test-ll test-ll-export
diff --git a/README.md b/README.md
index 5432ef4407..777cb89246 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 
 The idea of this plugin is to provide functions for various kinds of 
context-free grammar parser generations with support for 
syntax-directed-translations (SDT) and semantic actions (SA) and the 
possibility of exporting parsers and translators (as generated stand-alone 
elisp code) to enable Emacs plugin-agnostic usage. This project is also about 
implementing algorithms described in the book `The Theory of Parsing, 
Translation and Compiling (Volume 1)` by `Alfred V. Aho and Jeffrey D. Ull [...]
 
-At the moment it is possible to generate canonical LR(k) parsers using this 
library for complex languages like PHP 8.0.
+At the moment it is possible to generate canonical LR(k) parsers using this 
library for complex languages like PHP 8.1.
 
 ## Lexical Analysis
 
diff --git a/TODO.md b/TODO.md
index 54a3e26d94..952c7d226e 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,17 +2,17 @@
 
 ## Main
 
-Functions (with validations) to set global variables
+Functions (with validations) to set global variables:
 
-* parser-generator--global-attributes
 * parser-generator--context-sensitive-attributes
+* parser-generator--global-attributes
 * parser-generator--global-declaration
 
 ## LR-Parser
 
-Functions (with validations) to set global variables
+Functions (with validations) to set global variables:
 
-* parser-generator-lr--global-precedence-attributes
 * parser-generator-lr--context-sensitive-precedence-attribute
+* parser-generator-lr--global-precedence-attributes
 
 [Back to start](../../)
diff --git a/docs/Syntax-Analysis.md b/docs/Syntax-Analysis.md
index 6f639d7b1f..c391d346f0 100644
--- a/docs/Syntax-Analysis.md
+++ b/docs/Syntax-Analysis.md
@@ -11,7 +11,8 @@ We use push down transducer (PDT) based algorithms.
 
 ## Without Backtracking
 
-* LL(k) *WIP*
+* [LL(1)](Syntax-Analysis/LL1.md)
+* [LL(k)](Syntax-Analysis/LLk.md)
 * [LR(k)](Syntax-Analysis/LRk.md)
 * [LR(0)](Syntax-Analysis/LR0.md)
 * Formal Shift-Reduce Parsing Algorithms *WIP*
@@ -156,7 +157,7 @@ Calculate the first look-ahead number of terminals of the 
sentential-form `S`, e
 
 ### E-FREE-FIRST(S)
 
-Calculate the e-free-first look-ahead number of terminals of sentential-form 
`S`, if you have multiple symbols the e-free-first will only affect the first 
symbol, the rest will be treated via first-function (above). Example:
+Calculate the e-free-first look-ahead number of terminals of sentential-form 
`S`, if you have multiple symbols the e-free-first will only affect the first 
symbol, the rest will be treated via the first-function (above). Example:
 
 ``` emacs-lisp
 (require 'parser-generator)
diff --git a/docs/Syntax-Analysis/LL1.md b/docs/Syntax-Analysis/LL1.md
new file mode 100644
index 0000000000..0d0e5d9db2
--- /dev/null
+++ b/docs/Syntax-Analysis/LL1.md
@@ -0,0 +1,174 @@
+# LL(1) Parser
+
+LL(1) parser is a Left-to-right, Leftmost derivation with look-ahead number k 
= 1.
+
+This library contains functions to parse, translate, validate grammars.
+
+## Parse
+
+Perform a left-parse of input-stream.
+
+```emacs-lisp
+(require 'parser-generator-ll)
+(require 'ert)
+
+(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 (lambda(a b) (format "alfa %s %s" (nth 1 a) (nth 2 a))))
+     (b (lambda(a b) "beta"))
+     )
+    (A
+     (a (lambda(a b) "delta"))
+     (b S A (lambda(a b) (format "gamma %s %s" (nth 1 a) (nth 2 a))))
+     )
+    )
+   S
+   )
+ )
+(parser-generator-process-grammar)
+(parser-generator-ll-generate-table)
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+   (let* ((string '((a 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5) (b 5 . 6)))
+          (string-length (length string))
+          (max-index index)
+          (tokens))
+     (while (and
+             (< (1- index) string-length)
+             (< (1- index) max-index))
+       (push (nth (1- index) string) tokens)
+       (setq index (1+ index)))
+     (nreverse tokens))))
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+   (car token)))
+(should
+ (equal
+  "beta"
+  (parser-generator-ll-translate)))
+(message "Passed translation test 3")
+```
+
+## Translate
+
+Each production RHS can optionally contain a lambda-expression that will be 
called if specified when stack is reduced:
+
+```emacs-lisp
+(require 'parser-generator-ll)
+(require 'ert)
+
+(parser-generator-set-eof-identifier '$)
+(parser-generator-set-e-identifier 'e)
+(parser-generator-set-look-ahead-number 2)
+(parser-generator-set-grammar
+ '(
+   (S A)
+   (a b)
+   (
+    (S
+     (a A a a (lambda(a b) (format "alfa %s laval" (nth 1 a))))
+     (b A b a (lambda(a b) (format "delta %s laval" (nth 1 a))))
+     )
+    (A
+     (b (lambda(a b) "sven"))
+     (e (lambda(a b) "ingrid"))
+     )
+    )
+   S
+   )
+ )
+(parser-generator-process-grammar)
+(parser-generator-ll-generate-table)
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+   (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+          (string-length (length string))
+          (max-index index)
+          (tokens))
+     (while (and
+             (< (1- index) string-length)
+             (< (1- index) max-index))
+       (push (nth (1- index) string) tokens)
+       (setq index (1+ index)))
+     (nreverse tokens))))
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+   (car token)))
+(should
+ (equal
+  "delta ingrid laval"
+  (parser-generator-ll-translate)))
+(message "Passed translation test 1")
+```
+
+## Export
+
+```emacs-lisp
+(require 'parser-generator-ll)
+(require 'ert)
+
+(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)
+(parser-generator-ll-generate-table)
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+   (let* ((string '((a 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5) (b 5 . 6)))
+          (string-length (length string))
+          (max-index index)
+          (tokens))
+     (while (and
+             (< (1- index) string-length)
+             (< (1- index) max-index))
+       (push (nth (1- index) string) tokens)
+       (setq index (1+ index)))
+     (nreverse tokens))))
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+   (car token)))
+(let ((export (parser-generator-ll-export-to-elisp "ba3")))
+  (with-temp-buffer
+    (insert export)
+    (eval-buffer)
+    (should
+     (equal
+      t
+      (fboundp 'ba3-parse)))
+    (should
+     (equal
+      t
+      (fboundp 'ba3-translate)))
+    (when (fboundp 'ba3-parse)
+      (should
+       (equal
+        '(0 3 1 2 1)
+        (ba3-parse))))))
+(message "Passed exported test for example 5.5 p. 340")
+```
+
+[Back to syntax analysis](../Syntax-Analysis.md)
diff --git a/docs/Syntax-Analysis/LLk.md b/docs/Syntax-Analysis/LLk.md
new file mode 100644
index 0000000000..bf7130b452
--- /dev/null
+++ b/docs/Syntax-Analysis/LLk.md
@@ -0,0 +1,178 @@
+# LL(k) Parser
+
+LL(k) parser is a Left-to-right, Leftmost derivation with look-ahead number k 
> 1.
+
+This library contains functions to parse, translate, validate grammars.
+
+## Parse
+
+Perform a left-parse of input-stream.
+
+```emacs-lisp
+(require 'parser-generator-ll)
+(require 'ert)
+
+(parser-generator-set-eof-identifier '$)
+(parser-generator-set-e-identifier 'e)
+(parser-generator-set-look-ahead-number 2)
+(parser-generator-set-grammar
+ '(
+   (S A)
+   (a b)
+   (
+    (S (a A a a) (b A b a))
+    (A b e)
+    )
+   S
+   )
+ )
+(parser-generator-process-grammar)
+(parser-generator-ll-generate-table)
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+   (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+          (string-length (length string))
+          (max-index index)
+          (tokens))
+     (while (and
+             (< (1- index) string-length)
+             (< (1- index) max-index))
+       (push (nth (1- index) string) tokens)
+       (setq index (1+ index)))
+     (nreverse tokens))))
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+   (car token)))
+
+(should
+ (equal
+  '(1 3) ;; Example is indexed from 1 so that is why they have '(2 4)
+  (parser-generator-ll-parse)))
+(message "Passed example 5.16 p. 352")
+```
+
+## Translate
+
+Each production RHS can optionally contain a lambda-expression that will be 
called if specified when stack is reduced:
+
+```emacs-lisp
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S
+       (a A a a (lambda(a b) (format "alfa %s laval" (nth 1 a))))
+       (b A b a (lambda(a b) (format "delta %s laval" (nth 1 a))))
+       )
+      (A
+       (b (lambda(a b) "sven"))
+       (e (lambda(a b) "ingrid"))
+       )
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    "delta ingrid laval"
+    (parser-generator-ll-translate)))
+  (message "Passed translation test 1")
+```
+
+## Export
+
+```emacs-lisp
+(require 'parser-generator-ll)
+(require 'ert)
+
+(parser-generator-set-eof-identifier '$)
+(parser-generator-set-e-identifier 'e)
+(parser-generator-set-look-ahead-number 2)
+(parser-generator-set-grammar
+ '(
+   (S A)
+   (a b)
+   (
+    (S
+     (a A a a (lambda(a b) (format "alfa %s laval" (nth 1 a))))
+     (b A b a (lambda(a b) (format "delta %s laval" (nth 1 a))))
+     )
+    (A
+     (b (lambda(a b) "sven"))
+     (e (lambda(a b) "ingrid"))
+     )
+    )
+   S
+   )
+ )
+(parser-generator-process-grammar)
+(parser-generator-ll-generate-table)
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+   (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+          (string-length (length string))
+          (max-index index)
+          (tokens))
+     (while (and
+             (< (1- index) string-length)
+             (< (1- index) max-index))
+       (push (nth (1- index) string) tokens)
+       (setq index (1+ index)))
+     (nreverse tokens))))
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+   (car token)))
+(let ((export (parser-generator-ll-export-to-elisp "ba")))
+  (with-temp-buffer
+    (insert export)
+    (eval-buffer)
+    (should
+     (equal
+      t
+      (fboundp 'ba-parse)))
+    (should
+     (equal
+      t
+      (fboundp 'ba-translate)))
+    (when (fboundp 'ba-parse)
+      (should
+       (equal
+        '(1 3)
+        (ba-parse))))
+    (when (fboundp 'ba-translate)
+      (should
+       (equal
+        "delta ingrid laval"
+        (ba-translate))))))
+(message "Passed exported test for example 5.16 p. 352")
+```
+
+
+[Back to syntax analysis](../Syntax-Analysis.md)
diff --git a/parser-generator-ll-export.el b/parser-generator-ll-export.el
new file mode 100644
index 0000000000..80fef9cac2
--- /dev/null
+++ b/parser-generator-ll-export.el
@@ -0,0 +1,816 @@
+;;; parser-generator-ll-export.el --- Export LL(k) Parser -*- lexical-binding: 
t -*-
+
+;; Copyright (C) 2020-2022  Free Software Foundation, Inc.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(require 'parser-generator-ll)
+
+(defun parser-generator-ll-export-to-elisp (namespace &optional header 
copyright)
+  "Export parser with NAMESPACE and a optional HEADER and COPYRIGHT."
+  (message "\n;; Starting generation of elips..\n")
+
+  ;; Make sure all requisites are defined
+  (unless parser-generator-ll--table
+    (error "Missing generated table!"))
+  (unless parser-generator--table-productions-number-reverse
+    (error "Table for reverse production-numbers is undefined!"))
+  (unless parser-generator--table-look-aheads-p
+    (error "Table for valid look-aheads is undefined!"))
+  (unless parser-generator--look-ahead-number
+    (error "Missing a look-ahead number!"))
+  (unless parser-generator--e-identifier
+    (error "Missing definition for e-identifier!"))
+  (unless parser-generator--eof-identifier
+    (error "Missing definition for EOF-identifier!"))
+  (unless parser-generator--table-non-terminal-p
+    (error "Table for non-terminals is undefined!"))
+  (unless parser-generator--table-terminal-p
+    (error "Table for terminals is undefined!"))
+  (unless parser-generator--table-translations
+    (error "Table for translations by production-number is undefined!"))
+  (unless parser-generator-lex-analyzer--get-function
+    (error "Missing lex-analyzer get function!"))
+  (unless parser-generator-lex-analyzer--function
+    (error "Missing lex-analyzer function!"))
+
+  (let ((code))
+    (with-temp-buffer
+      (goto-char (point-min))
+
+      ;; Header
+      (insert
+       (format
+        ";;; %s.el --- Exported Emacs Parser Generator -*- lexical-binding: t 
-*-\n\n"
+        namespace))
+
+      ;; Optional copyright
+      (when copyright
+        (insert copyright))
+
+      (insert ";;; Commentary:\n\n\n;;; Code:\n\n")
+
+      ;; Optional header
+      (when header
+        (insert header))
+
+      (insert "\n;;; Variables:\n\n\n")
+
+      ;; Grammar start
+      (insert
+       (format
+        "(defvar\n  %s--grammar-start\n %s\n  \"The start of grammar.\")\n\n"
+        namespace
+        (if (symbolp (parser-generator--get-grammar-start))
+            (format "'%s" (parser-generator--get-grammar-start))
+          (format "\"%s\"" (parser-generator--get-grammar-start)))))
+
+      ;; Generated table
+      (insert
+       (format
+        "(defvar\n  %s--table\n  %S\n  \"The generated table.\")\n\n"
+        namespace
+        parser-generator-ll--table))
+
+      ;; Table production-number
+      (insert
+       (format
+        "(defvar\n  %s--table-productions-number-reverse\n  %S\n  \"The 
hash-table indexed by production-number and value is production.\")\n\n"
+        namespace
+        parser-generator--table-productions-number-reverse))
+
+      ;; Table terminals
+      (insert
+       (format
+        "(defvar\n  %s--table-terminal-p\n  %S\n  \"The hash-table of valid 
terminals.\")\n\n"
+        namespace
+        parser-generator--table-terminal-p))
+
+      ;; Table non-terminals
+      (insert
+       (format
+        "(defvar\n  %s--table-non-terminal-p\n  %S\n  \"The hash-table of 
valid non-terminals.\")\n\n"
+        namespace
+        parser-generator--table-non-terminal-p))
+
+      ;; Table translations
+      (insert
+       (format
+        "(defvar\n  %s--table-translations\n  %S\n  \"The hash-table of 
translations.\")\n\n"
+        namespace
+        parser-generator--table-translations))
+
+      ;; E-identifier
+      (insert
+       (format
+        "(defvar\n  %s--e-identifier\n  '%S\n  \"The e-identifier.\")\n\n"
+        namespace
+        parser-generator--e-identifier))
+
+      ;; EOF-identifier
+      (insert
+       (format
+        "(defvar\n  %s--eof-identifier\n  '%S\n  \"The 
end-of-file-identifier.\")\n\n"
+        namespace
+        parser-generator--eof-identifier))
+
+      ;; Look-ahead number
+      (insert
+       (format
+        "(defvar\n  %s--look-ahead-number\n  %S\n  \"The look-ahead 
number.\")\n\n"
+        namespace
+        parser-generator--look-ahead-number))
+
+      (insert "\n;;; Local Variables:\n\n")
+
+      ;; Index
+      (insert
+       (format
+        "(defvar-local\n  %s-lex-analyzer--index\n  0\n  \"The current index 
of the lex-analyzer.\")\n\n"
+        namespace))
+
+      ;; Move to index flag
+      (insert
+       (format
+        "(defvar-local\n  %s-lex-analyzer--move-to-index-flag\n  nil\n  
\"Non-nil means move index to value.\")\n\n"
+        namespace))
+
+      (insert "\n;;; Variable Functions:\n\n")
+
+      ;; Lex-Analyzer Get Function
+      (insert
+       (format
+        "(defvar\n  %s-lex-analyzer--get-function\n  (lambda %S %S)\n  \"The 
lex-analyzer get function.\")\n\n"
+        namespace
+        (nth 2 parser-generator-lex-analyzer--get-function)
+        (nth 3 parser-generator-lex-analyzer--get-function)))
+
+      ;; Lex-Analyzer Function
+      (insert
+       (format
+        "(defvar\n  %s-lex-analyzer--function\n  (lambda %S %S)\n  \"The 
lex-analyzer function.\")\n\n"
+        namespace
+        (nth 2 parser-generator-lex-analyzer--function)
+        (nth 3 parser-generator-lex-analyzer--function)))
+
+      ;; Lex-Analyzer Reset Function
+      (insert
+       (format
+        "(defvar\n  %s-lex-analyzer--reset-function\n  "
+        namespace))
+      (if parser-generator-lex-analyzer--reset-function
+          (insert
+           (format
+            "(lambda %S %S)\n"
+            (nth 2 parser-generator-lex-analyzer--reset-function)
+            (nth 3 parser-generator-lex-analyzer--reset-function)))
+        (insert "nil\n"))
+      (insert "  \"The lex-analyzer reset function.\")\n\n")
+
+      (insert "\n;;; Functions:\n\n")
+
+      (insert "\n;;; Functions for Lex-Analyzer:\n\n")
+
+      ;; Lex-Analyzer Get Function
+      (insert
+       (format
+        "(defun
+  %s-lex-analyzer--get-function (token)
+  \"Get information about TOKEN.\"
+  (let ((meta-information))
+    (condition-case
+      error
+      (progn
+        (setq
+          meta-information
+          (funcall
+            %s-lex-analyzer--get-function
+            token)))"
+        namespace
+        namespace))
+      (insert "
+      (error (error
+        \"Lex-analyze failed to get token meta-data of %s, error: %s\"
+        token
+        (car (cdr error)))))
+    (unless meta-information
+      (error \"Could not find any token meta-information for: %s\" token))
+    meta-information))\n")
+
+      ;; Lex-Analyzer Reset Function
+      (insert
+       (format "
+(defun
+  %s-lex-analyzer--reset
+  ()
+  \"Reset Lex-Analyzer.\"
+  (setq
+    %s-lex-analyzer--index
+    1)
+  (when
+    %s-lex-analyzer--reset-function
+    (funcall
+      %s-lex-analyzer--reset-function)))\n"
+               namespace
+               namespace
+               namespace
+               namespace))
+
+      ;; Lex-Analyzer Peek Next Look Ahead
+      (insert
+       (format "
+(defun
+  %s-lex-analyzer--peek-next-look-ahead
+  ()
+  \"Peek next look-ahead number of tokens via lex-analyzer.\"
+  (let ((look-ahead)
+        (look-ahead-length 0)
+        (index %s-lex-analyzer--index)
+        (k (max
+            1
+            %s--look-ahead-number)))
+    (while (<
+            look-ahead-length
+            k)
+      (condition-case error
+          (progn
+            (setq-local
+              %s-lex-analyzer--move-to-index-flag
+              nil)
+            (let ((next-look-ahead
+                   (funcall
+                    %s-lex-analyzer--function
+                    index)))
+                  (if %s-lex-analyzer--move-to-index-flag
+                    (setq
+                     index
+                     %s-lex-analyzer--move-to-index-flag)
+              (if next-look-ahead
+                  (progn
+                    (unless (listp (car next-look-ahead))
+                      (setq next-look-ahead (list next-look-ahead)))
+                    (dolist (next-look-ahead-item next-look-ahead)
+                      (when (<
+                             look-ahead-length
+                             k)
+                        (push next-look-ahead-item look-ahead)
+                        (setq look-ahead-length (1+ look-ahead-length))
+                        (setq index (cdr (cdr next-look-ahead-item))))))
+                (push (list %s--eof-identifier) look-ahead)
+                (setq look-ahead-length (1+ look-ahead-length))
+                (setq index (1+ index))))))"
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace))
+      (insert "
+        (error
+         (error
+          \"Lex-analyze failed to peek next look-ahead at %s, error: %s\"
+          index
+          error))))
+    (nreverse look-ahead)))\n")
+
+      ;; Lex-Analyzer Pop Token
+      (insert
+       (format "
+(defun
+  %s-lex-analyzer--pop-token ()
+  \"Pop next token via lex-analyzer.\"
+  (let ((continue t)
+        (tokens))
+    (while continue
+      (condition-case error
+          (progn
+            (setq-local
+              %s-lex-analyzer--move-to-index-flag
+              nil)
+            (let ((token
+                   (funcall
+                    %s-lex-analyzer--function
+                    %s-lex-analyzer--index)))
+              (if %s-lex-analyzer--move-to-index-flag
+                  (progn
+                    (setq-local
+                     %s-lex-analyzer--index
+                     %s-lex-analyzer--move-to-index-flag))
+              (when token
+                (unless (listp (car token))
+                  (setq token (list token)))
+                (let ((first-token (car token)))
+                  (setq
+                   %s-lex-analyzer--index
+                   (cdr (cdr first-token)))
+                  (push 
+                   first-token 
+                   tokens)))
+                (setq
+                 continue
+                 nil))))"
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace))
+      (insert "
+        (error (error
+                \"Lex-analyze failed to pop token at %s, error: %s\"")
+      (insert (format "
+                %s-lex-analyzer--index
+                (car (cdr error))))))
+    (nreverse tokens)))\n"
+                      namespace))
+
+      (insert "\n\n;;; Functions for Syntax-Analyzer / Parser:\n\n");
+
+      ;; Get grammar production by number
+      (insert
+       (format "
+(defun
+  %s--get-grammar-production-by-number
+  (production-number)
+  \"If PRODUCTION-NUMBER exist, return it's production.\"
+  (gethash
+   production-number
+   %s--table-productions-number-reverse))\n"
+               namespace
+               namespace))
+
+      ;; Valid symbol p
+      (insert
+       (format "
+(defun
+  %s--valid-symbol-p
+  (symbol)
+  \"Return whether SYMBOL is valid or not.\"
+  (let ((is-valid t))
+    (unless (or
+             (%s--valid-e-p symbol)
+             (%s--valid-eof-p symbol)
+             (%s--valid-non-terminal-p symbol)
+             (%s--valid-terminal-p symbol))
+      (setq is-valid nil))
+    is-valid))\n"
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace))
+
+      ;; Valid e-p
+      (insert
+       (format "
+(defun
+  %s--valid-e-p
+  (symbol)
+  \"Return whether SYMBOL is the e identifier or not.\"
+  (eq
+   symbol
+   %s--e-identifier))\n"
+               namespace
+               namespace))
+
+      ;; Valid EOF-p
+      (insert
+       (format "
+(defun
+  %s--valid-eof-p
+  (symbol)
+  \"Return whether SYMBOL is the EOF identifier or not.\"
+  (eq
+    symbol
+    %s--eof-identifier))\n"
+               namespace
+               namespace))
+
+      ;; Valid non-terminal-p
+      (insert
+       (format "
+(defun
+  %s--valid-non-terminal-p (symbol)
+  \"Return whether SYMBOL is a non-terminal in grammar or not.\"
+  (gethash
+   symbol
+   %s--table-non-terminal-p))\n"
+               namespace
+               namespace))
+
+      ;; Valid terminal-p
+      (insert
+       (format "
+(defun
+  %s--valid-terminal-p (symbol)
+  \"Return whether SYMBOL is a terminal in grammar or not.\"
+  (gethash
+   symbol
+   %s--table-terminal-p))\n"
+               namespace
+               namespace))
+
+      ;; Generate list of symbol
+      (insert
+       (format "
+(defun %s--generate-list-of-symbol (k symbol)
+  \"Generate list of K number of SYMBOL.\"
+  (let ((list-index 0)
+        (list))
+    (while (< list-index k)
+      (push symbol list)
+      (setq list-index (1+ list-index)))
+    list))
+"
+  namespace))
+
+      ;; Get grammar translation by number
+      (insert
+       (format "
+(defun
+  %s--get-grammar-translation-by-number
+  (production-number)
+  \"If translation for PRODUCTION-NUMBER exist, return it.\"
+  (gethash
+    production-number
+    %s--table-translations))\n"
+               namespace
+               namespace))
+
+      ;; Parse / translate function
+      (insert
+       (format "
+(defun %s--parse (&optional translate-p)
+  \"Parse input via lex-analyzer and return parse trail.\"
+  (let ((accept)
+        (stack
+         (if (> %s--look-ahead-number 1)
+             (list
+              (list
+               (list
+                %s--grammar-start)
+               (%s--generate-list-of-symbol
+                %s--look-ahead-number
+                %s--eof-identifier))
+              %s--eof-identifier)
+           (list
+            %s--grammar-start
+            %s--eof-identifier)))
+        (output)
+        (eof-look-ahead
+         (%s--generate-list-of-symbol
+          %s--look-ahead-number
+          %s--eof-identifier))
+        (e-reduction
+         (list %s--e-identifier))
+        (translation)
+        (translation-stack)
+        (translation-symbol-table
+         (make-hash-table :test 'equal))
+        (terminal-stack '()))
+    (%s-lex-analyzer--reset)
+    (while (not accept)
+      (let* ((state (car stack))
+             (state-action-table
+              (gethash
+               (format \"%%S\" state)
+               %s--table))
+             (look-ahead-list
+              (%s-lex-analyzer--peek-next-look-ahead))
+             (look-ahead))
+
+        (unless state-action-table
+          (signal
+           'error
+           (list
+            (format
+             \"State action table lacks actions for state: '%%S'!\"
+             state)
+            state)))
+
+        (if look-ahead-list
+            (progn
+              (dolist (look-ahead-list-item look-ahead-list)
+                (push (car look-ahead-list-item) look-ahead))
+              (setq look-ahead (reverse look-ahead)))
+          (setq
+           look-ahead
+           eof-look-ahead))
+
+        (unless (gethash
+                 (format \"%%S\" look-ahead)
+                 state-action-table)
+          (let ((possible-look-aheads))
+            (maphash
+             (lambda (k _v) (push k possible-look-aheads))
+             state-action-table)
+            (signal
+             'error
+             (list
+              (format
+               \"Invalid look-ahead '%%S' in state: '%%S', valid look-aheads: 
'%%S'\"
+               look-ahead
+               state
+               possible-look-aheads)
+              look-ahead
+              state
+              possible-look-aheads))))
+
+        (let* ((action
+                (gethash
+                 (format \"%%S\" look-ahead)
+                 state-action-table))
+               (action-type action))
+          (when (listp action)
+            (setq action-type (car action)))
+          (cond
+
+           ((equal action-type 'pop)
+            (let ((popped-tokens
+                   (%s-lex-analyzer--pop-token)))
+
+              ;; Is it time for SDT?
+              (when (and
+                     translate-p
+                     translation-stack
+                     (string=
+                      (car (car translation-stack))
+                      (format \"%%S\" stack)))
+                (let* ((translation-item (pop translation-stack))
+                       (partial-translation
+                        (%s--perform-translation
+                         (nth 1 translation-item)
+                         translation-symbol-table
+                         (reverse (pop terminal-stack)))))
+                  (setq
+                   translation
+                   partial-translation)))
+
+              (pop stack)
+
+              (when translate-p
+                (let ((token-data)
+                      (old-terminal-stack (car terminal-stack)))
+                  (dolist (popped-token popped-tokens)
+                    (push
+                     popped-token
+                     token-data))
+                  (push
+                   token-data
+                   old-terminal-stack)
+                  (setf
+                   (car terminal-stack)
+                   old-terminal-stack)))
+
+              ;; Is it time for SDT?
+              (when (and
+                     translate-p
+                     translation-stack
+                     (string=
+                      (car (car translation-stack))
+                      (format \"%%S\" stack)))
+                (let* ((translation-item (pop translation-stack))
+                       (partial-translation
+                        (%s--perform-translation
+                         (nth 1 translation-item)
+                         translation-symbol-table
+                         (reverse (pop terminal-stack)))))
+                  (setq
+                   translation
+                   partial-translation)))
+
+              ))
+
+           ((equal action-type 'reduce)
+
+            ;; Is it time for SDT?
+            (when (and
+                   translate-p
+                   translation-stack
+                   (string=
+                    (car (car translation-stack))
+                    (format \"%%S\" stack)))
+              (let* ((translation-item (pop translation-stack))
+                     (partial-translation
+                      (%s--perform-translation
+                       (nth 1 translation-item)
+                       translation-symbol-table
+                       (reverse (pop terminal-stack)))))
+                (setq
+                 translation
+                 partial-translation)))
+
+            (pop stack)
+
+            ;; Is it time for SDT?
+            (when (and
+                   translate-p
+                   translation-stack
+                   (string=
+                    (car (car translation-stack))
+                    (format  \"%%S\" stack)))
+              (let* ((translation-item (pop translation-stack))
+                     (partial-translation
+                      (%s--perform-translation
+                       (nth 1 translation-item)
+                       translation-symbol-table
+                       (reverse (pop terminal-stack)))))
+                (setq
+                 translation
+                 partial-translation)))
+
+            (when translate-p
+              (push
+               (list
+                (format \"%%S\" stack)
+                (nth 2 action))
+               translation-stack)
+              (push
+               '()
+               terminal-stack))
+
+            (unless (equal (nth 1 action) e-reduction)
+              (dolist (reduce-item (reverse (nth 1 action)))
+                (push reduce-item stack)))
+            (push
+             (nth 2 action)
+             output))
+
+           ((equal action-type 'accept)
+            (setq accept t))))))
+    (list
+     (reverse output)
+     translation)))
+
+(defun %s-parse ()
+  (let ((parse (%s--parse)))
+    (car parse)))
+
+(defun %s-translate ()
+  (let ((parse (%s--parse t)))
+    (car (cdr parse))))
+
+(defun %s--perform-translation (production-number symbol-table terminals)
+  \"Perform translation by PRODUCTION-NUMBER, with SYMBOL-TABLE and 
TERMINALS.\"
+  (let* ((production
+          (%s--get-grammar-production-by-number
+           production-number))
+         (production-lhs
+          (car (nth 0 production)))
+         (production-rhs
+          (nth 1 production))
+         (translation)
+         (args-1)
+         (args-2))
+
+    ;; Collect arguments for translation
+    (let ((terminal-index 0))
+      (dolist (rhs-item production-rhs)
+        (cond
+
+         ((%s--valid-non-terminal-p
+           rhs-item)
+          (let* ((non-terminal-value-list
+                  (gethash rhs-item symbol-table))
+                 (non-terminal-value
+                  (pop non-terminal-value-list)))
+            (push
+             (car non-terminal-value)
+             args-1)
+            (push
+             (car (cdr non-terminal-value))
+             args-2)
+            (puthash
+             rhs-item
+             non-terminal-value-list
+             symbol-table)))
+
+         ((%s--valid-terminal-p
+           rhs-item)
+          (push
+           (%s-lex-analyzer--get-function
+            (nth terminal-index terminals))
+           args-1)
+          (push
+           (nth terminal-index terminals)
+           args-2)
+          (setq
+           terminal-index
+           (1+ terminal-index))))))
+    (setq
+     args-1
+     (reverse args-1))
+    (setq
+     args-2
+     (reverse args-2))
+
+    (if (%s--get-grammar-translation-by-number
+         production-number)
+        (let ((partial-translation
+               (funcall
+                (%s--get-grammar-translation-by-number
+                 production-number)
+                args-1
+                args-2))
+              (old-symbol-value
+               (gethash production-lhs symbol-table)))
+          (push
+           (list
+            partial-translation
+            args-2)
+           old-symbol-value)
+          (puthash
+           production-lhs
+           old-symbol-value
+           symbol-table)
+          (setq
+           translation
+           partial-translation))
+
+      ;; When no translation is specified just use popped contents as 
translation
+      (let ((partial-translation
+             (list
+              args-1
+              args-2))
+            (old-symbol-value
+             (gethash production-lhs symbol-table)))
+        (push
+         partial-translation
+         old-symbol-value)
+        (puthash
+         production-lhs
+         old-symbol-value
+         symbol-table)
+        (setq
+         translation
+         (car partial-translation))))
+
+    translation))
+
+"
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               namespace
+               ))
+
+      ;; Footer
+      (insert
+       (format
+        "\n(provide '%s)"
+        namespace))
+
+      (insert
+       (format
+        "\n\n;;; %s.el ends here"
+        namespace))
+
+      (setq
+       code
+       (buffer-substring-no-properties
+        (point-min)
+        (point-max))))
+    (message "\n;; Completed generation of elips.\n")
+    code))
+
+
+(provide 'parser-generator-ll-export)
+
+;;; parser-generator-ll-export.el ends here
diff --git a/parser-generator-ll.el b/parser-generator-ll.el
new file mode 100644
index 0000000000..2696982d35
--- /dev/null
+++ b/parser-generator-ll.el
@@ -0,0 +1,1004 @@
+;;; parser-generator-ll.el --- LL(k) Parser Generator -*- lexical-binding: t 
-*-
+
+;; Copyright (C) 2020-2022  Free Software Foundation, Inc.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(require 'parser-generator)
+(require 'parser-generator-lex-analyzer)
+
+
+;;; Variables:
+
+
+(defvar
+  parser-generator-ll--table
+  nil
+  "Table for grammar.")
+
+
+;;; Functions
+
+
+(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))))
+
+      (message "\n;; Starting generation of LL(1) tables..\n")
+
+      (unless (parser-generator-ll--valid-grammar-k-eq-1-p)
+        (error "Invalid LL(1) grammar specified!"))
+
+      (setq
+       list-parsing-table
+       (parser-generator-ll--generate-action-table-k-eq-1
+        (parser-generator-ll--generate-goto-table))))
+
+    ;; 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"))))
+
+(defun parser-generator-ll-parse ()
+  (let ((parse (parser-generator-ll--parse)))
+    (car parse)))
+
+(defun parser-generator-ll-translate ()
+  (let ((parse (parser-generator-ll--parse t)))
+    (car (cdr parse))))
+
+;; Generally described at .p 339
+(defun parser-generator-ll--parse (&optional translate-p)
+  "Parse input via lex-analyzer and return parse trail."
+  (let ((accept)
+        (stack
+         (if (> parser-generator--look-ahead-number 1)
+             (list
+              (list
+               (list
+                (parser-generator--get-grammar-start))
+               (parser-generator--generate-list-of-symbol
+                parser-generator--look-ahead-number
+                parser-generator--eof-identifier))
+              parser-generator--eof-identifier)
+           (list
+            (parser-generator--get-grammar-start)
+            parser-generator--eof-identifier)))
+        (output)
+        (eof-look-ahead
+         (parser-generator--generate-list-of-symbol
+          parser-generator--look-ahead-number
+          parser-generator--eof-identifier))
+        (e-reduction
+         (list parser-generator--e-identifier))
+        (translation)
+        (translation-stack)
+        (translation-symbol-table
+         (make-hash-table :test 'equal))
+        (terminal-stack '()))
+    (parser-generator-lex-analyzer--reset)
+    (while (not accept)
+      (let* ((state (car stack))
+             (state-action-table
+              (gethash
+               (format "%S" state)
+               parser-generator-ll--table))
+             (look-ahead-list
+              (parser-generator-lex-analyzer--peek-next-look-ahead))
+             (look-ahead))
+        (parser-generator--debug
+         (message "\nstack: %S" stack)
+         (message "translation-stack: %S" translation-stack)
+         (message "output: %S" output)
+         (message "state: %S" state)
+         (message "state-action-table: %S" state-action-table))
+
+        (unless state-action-table
+          (signal
+           'error
+           (list
+            (format
+             "State action table lacks actions for state: '%S'!"
+             state)
+            state)))
+
+        (if look-ahead-list
+            (progn
+              (parser-generator--debug
+               (message "look-ahead-list: %S" look-ahead-list))
+              (dolist (look-ahead-list-item look-ahead-list)
+                (push (car look-ahead-list-item) look-ahead))
+              (setq look-ahead (reverse look-ahead)))
+          (setq
+           look-ahead
+           eof-look-ahead))
+
+        (parser-generator--debug
+         (message "look-ahead: %S" look-ahead))
+
+        (unless (gethash
+                 (format "%S" look-ahead)
+                 state-action-table)
+          (let ((possible-look-aheads))
+            (maphash
+             (lambda (k _v) (push k possible-look-aheads))
+             state-action-table)
+            (signal
+             'error
+             (list
+              (format
+               "Invalid look-ahead '%S' in state: '%S', valid look-aheads: 
'%S'"
+               look-ahead
+               state
+               possible-look-aheads)
+              look-ahead
+              state
+              possible-look-aheads))))
+
+        (let* ((action
+                (gethash
+                 (format "%S" look-ahead)
+                 state-action-table))
+               (action-type action))
+          (parser-generator--debug
+           (message "action: %S" action))
+          (when (listp action)
+            (setq action-type (car action)))
+          (parser-generator--debug
+           (message "action-type: %S" action-type))
+          (cond
+
+           ((equal action-type 'pop)
+            (parser-generator--debug
+             (message "popped: %S" look-ahead))
+            (let ((popped-tokens
+                   (parser-generator-lex-analyzer--pop-token)))
+
+              ;; Is it time for SDT?
+              (when (and
+                     translate-p
+                     translation-stack
+                     (string=
+                      (car (car translation-stack))
+                      (format "%S" stack)))
+                (let* ((translation-item (pop translation-stack))
+                       (partial-translation
+                        (parser-generator-ll--perform-translation
+                         (nth 1 translation-item)
+                         translation-symbol-table
+                         (reverse (pop terminal-stack)))))
+                  (setq
+                   translation
+                   partial-translation)))
+
+              (pop stack)
+
+              (when translate-p
+                (let ((token-data)
+                      (old-terminal-stack (car terminal-stack)))
+                  (dolist (popped-token popped-tokens)
+                    (push
+                     popped-token
+                     token-data))
+                  (push
+                   token-data
+                   old-terminal-stack)
+                  (setf
+                   (car terminal-stack)
+                   old-terminal-stack)))
+
+              ;; Is it time for SDT?
+              (when (and
+                     translate-p
+                     translation-stack
+                     (string=
+                      (car (car translation-stack))
+                      (format "%S" stack)))
+                (let* ((translation-item (pop translation-stack))
+                       (partial-translation
+                        (parser-generator-ll--perform-translation
+                         (nth 1 translation-item)
+                         translation-symbol-table
+                         (reverse (pop terminal-stack)))))
+                  (setq
+                   translation
+                   partial-translation)))
+
+              ))
+
+           ((equal action-type 'reduce)
+            (parser-generator--debug
+             (message "reduced: %S -> %S" state (nth 1 action)))
+
+            ;; Is it time for SDT?
+            (when (and
+                   translate-p
+                   translation-stack
+                   (string=
+                    (car (car translation-stack))
+                    (format "%S" stack)))
+              (let* ((translation-item (pop translation-stack))
+                     (partial-translation
+                      (parser-generator-ll--perform-translation
+                       (nth 1 translation-item)
+                       translation-symbol-table
+                       (reverse (pop terminal-stack)))))
+                (setq
+                 translation
+                 partial-translation)))
+
+            (pop stack)
+
+            ;; Is it time for SDT?
+            (when (and
+                   translate-p
+                   translation-stack
+                   (string=
+                    (car (car translation-stack))
+                    (format "%S" stack)))
+              (let* ((translation-item (pop translation-stack))
+                     (partial-translation
+                      (parser-generator-ll--perform-translation
+                       (nth 1 translation-item)
+                       translation-symbol-table
+                       (reverse (pop terminal-stack)))))
+                (setq
+                 translation
+                 partial-translation)))
+
+            (when translate-p
+              (push
+               (list
+                (format "%S" stack)
+                (nth 2 action))
+               translation-stack)
+              (push
+               '()
+               terminal-stack))
+
+            (unless (equal (nth 1 action) e-reduction)
+              (dolist (reduce-item (reverse (nth 1 action)))
+                (push reduce-item stack)))
+            (push
+             (nth 2 action)
+             output))
+
+           ((equal action-type 'accept)
+            (setq accept t))))))
+    (list
+     (reverse output)
+     translation)))
+
+(defun parser-generator-ll--perform-translation (production-number 
symbol-table terminals)
+  "Perform translation by PRODUCTION-NUMBER, with SYMBOL-TABLE and TERMINALS."
+  (let* ((production
+          (parser-generator--get-grammar-production-by-number
+           production-number))
+         (production-lhs
+          (car (nth 0 production)))
+         (production-rhs
+          (nth 1 production))
+         (translation)
+         (args-1)
+         (args-2))
+    (parser-generator--debug
+     (message
+      "Perform translation %S %S %S = %S"
+      production-number
+      symbol-table
+      terminals
+      production-rhs))
+
+    ;; Collect arguments for translation
+    (let ((terminal-index 0))
+      (dolist (rhs-item production-rhs)
+        (cond
+
+         ((parser-generator--valid-non-terminal-p
+           rhs-item)
+          (let* ((non-terminal-value-list
+                  (gethash rhs-item symbol-table))
+                 (non-terminal-value
+                  (pop non-terminal-value-list)))
+            (push
+             (car non-terminal-value)
+             args-1)
+            (push
+             (car (cdr non-terminal-value))
+             args-2)
+            (puthash
+             rhs-item
+             non-terminal-value-list
+             symbol-table)))
+
+         ((parser-generator--valid-terminal-p
+           rhs-item)
+          (push
+           (parser-generator-lex-analyzer--get-function
+            (nth terminal-index terminals))
+           args-1)
+          (push
+           (nth terminal-index terminals)
+           args-2)
+          (setq
+           terminal-index
+           (1+ terminal-index))))))
+    (setq
+     args-1
+     (reverse args-1))
+    (setq
+     args-2
+     (reverse args-2))
+
+    (parser-generator--debug
+     (message
+      "Perform translation %d: %S -> %S via args-1: %S and args-2: %S"
+      production-number
+      production-lhs
+      production-rhs
+      args-1
+      args-2))
+
+    (if (parser-generator--get-grammar-translation-by-number
+         production-number)
+        (let ((partial-translation
+               (funcall
+                (parser-generator--get-grammar-translation-by-number
+                 production-number)
+                args-1
+                args-2))
+              (old-symbol-value
+               (gethash production-lhs symbol-table)))
+          (parser-generator--debug
+           (message
+            "\ntranslation-symbol-table: %S = %S (processed)\n"
+            production-lhs
+            partial-translation))
+          (push
+           (list
+            partial-translation
+            args-2)
+           old-symbol-value)
+          (puthash
+           production-lhs
+           old-symbol-value
+           symbol-table)
+          (setq
+           translation
+           partial-translation))
+
+      ;; When no translation is specified just use popped contents as 
translation
+      (let ((partial-translation
+             (list
+              args-1
+              args-2))
+            (old-symbol-value
+             (gethash production-lhs symbol-table)))
+        (parser-generator--debug
+         (message
+          "\ntranslation-symbol-table: %S = %S (generic)\n"
+          production-lhs
+          partial-translation))
+        (push
+         partial-translation
+         old-symbol-value)
+        (puthash
+         production-lhs
+         old-symbol-value
+         symbol-table)
+        (setq
+         translation
+         (car partial-translation))))
+
+    translation))
+
+
+;;; Algorithms
+
+
+(defun parser-generator-ll--generate-action-table-k-eq-1 (goto-table)
+  "Generate action-table for LL(1) grammar using GOTO-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-terminal-look-ahead-p (make-hash-table :test 'equal))
+          (non-terminal-look-ahead-list (make-hash-table :test 'equal)))
+      (dolist (goto-row goto-table)
+        (let* ((stack (nth 0 goto-row))
+               (non-terminal (car (nth 0 stack)))
+               (local-follows (nth 1 stack))
+               (look-aheads (nth 1 goto-row)))
+          (parser-generator--debug
+           (message "\nnon-terminal: %S" non-terminal)
+           (message "local-follows: %S" local-follows)
+           (message "look-aheads: %S" look-aheads))
+          (dolist (look-ahead look-aheads)
+            (let* ((rhs
+                    (nth 1 look-ahead))
+                   (production
+                    (list (list non-terminal) rhs))
+                   (production-number
+                    (parser-generator--get-grammar-production-number
+                     production))
+                   (look-ahead-terminal
+                    (nth 0 look-ahead))
+                   (hashmap-key
+                    (format "%S-%S" non-terminal look-ahead-terminal)))
+              (parser-generator--debug
+               (message "\nrhs: %S" rhs)
+               (message "production: %S" production)
+               (message "production-number: %S" production-number)
+               (message "hashmap-key: %S" hashmap-key))
+              (unless (gethash hashmap-key non-terminal-look-ahead-p)
+                (let ((old-non-terminal-look-aheads
+                       (gethash
+                        non-terminal
+                        non-terminal-look-ahead-list)))
+                  (push
+                   (list
+                    look-ahead-terminal
+                    'reduce
+                    rhs
+                    production-number)
+                   old-non-terminal-look-aheads)
+                  (puthash
+                   non-terminal
+                   old-non-terminal-look-aheads
+                   non-terminal-look-ahead-list)
+                  (puthash
+                   hashmap-key
+                   t
+                   non-terminal-look-ahead-p)))))))
+      (maphash
+       (lambda (non-terminal look-ahead)
+         (push
+          (list
+           non-terminal
+           look-ahead)
+          parsing-table))
+       non-terminal-look-ahead-list))
+
+    parsing-table))
+
+;; Algorithm 5.2 p. 350
+(defun parser-generator-ll--generate-goto-table ()
+  "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)
+        (distinct-stack-item-p (make-hash-table :test 'equal))
+        (stack-item))
+
+    ;; (1) Construct T_0, the LL(k) table associated with S {e}
+    (let* ((start (parser-generator--get-grammar-start))
+           (start-rhss (parser-generator--get-grammar-rhs start)))
+      (dolist (start-rhs start-rhss)
+        (let* ((initial-stack-item
+                (list
+                 (list start)
+                 start-rhs
+                 (parser-generator--generate-list-of-symbol
+                  parser-generator--look-ahead-number
+                  parser-generator--eof-identifier))))
+          (puthash
+           initial-stack-item
+           t
+           distinct-stack-item-p)
+          (push
+           initial-stack-item
+           stack))))
+
+    (setq stack (nreverse stack))
+    (parser-generator--debug
+     (message "stack: %S" stack))
+
+    (while stack
+      (setq stack-item (pop stack))
+      (let* ((production-lhs
+              (nth 0 stack-item))
+             (production-rhs
+              (nth 1 stack-item))
+             (parent-follow
+              (nth 2 stack-item))
+             (concatenated-follow
+              (append production-rhs parent-follow))
+             (first-concatenated-follow
+              (parser-generator--first concatenated-follow nil t t))
+             (look-aheads
+              (parser-generator--merge-max-terminal-sets
+               first-concatenated-follow))
+             (sets))
+
+        (parser-generator--debug
+         (message "\nproduction-lhs: %S" production-lhs)
+         (message "production-rhs: %S" production-rhs)
+         (message "parent-follow: %S" parent-follow)
+         (message "concatenated-follow: %S" concatenated-follow)
+         (message "first-concatenated-follow: %S" first-concatenated-follow)
+         (message "look-aheads: %S" look-aheads))
+
+        ;; For each non-terminal in the production right-hand side
+        ;; push a new item to stack with a local-follow
+        ;; and a new left-hand-side
+        (let ((sub-symbol-index 0)
+              (sub-symbol-length (length production-rhs)))
+          (while (< sub-symbol-index sub-symbol-length)
+            (let ((sub-symbol (nth sub-symbol-index production-rhs)))
+              (when (parser-generator--valid-non-terminal-p
+                     sub-symbol)
+                (let* ((follow-set
+                        (nthcdr (1+ sub-symbol-index) production-rhs))
+                       (concatenated-follow-set
+                        (append follow-set parent-follow))
+                       (first-concatenated-follow-set
+                        (parser-generator--first concatenated-follow-set nil t 
t))
+                       (local-follow-set
+                        (parser-generator--merge-max-terminal-sets
+                         first-concatenated-follow-set
+                         nil
+                         t))
+                       (sub-symbol-rhss
+                        (parser-generator--get-grammar-rhs
+                         sub-symbol)))
+                  (parser-generator--debug
+                   (message
+                    "\nnon-terminal sub-symbol: %S" sub-symbol)
+                   (message
+                    "follow-set: %S for %S in %S"
+                    follow-set
+                    (nth sub-symbol-index production-rhs)
+                    production-rhs)
+                   (message
+                    "concatenated-follow-set: %S"
+                    concatenated-follow-set)
+                   (message
+                    "first-concatenated-follow-set: %S"
+                    first-concatenated-follow-set)
+                   (message
+                    "local-follow-set: %S"
+                    local-follow-set)
+                   (message
+                    "sub-symbol-rhss: %S"
+                    sub-symbol-rhss))
+                  (unless local-follow-set
+                    (setq local-follow-set '(nil)))
+
+                  (push
+                   local-follow-set
+                   sets)
+                  (parser-generator--debug
+                   (message
+                    "pushed local follow set to sets: %S"
+                    local-follow-set))
+                  (dolist (local-follow local-follow-set)
+                    (dolist (sub-symbol-rhs sub-symbol-rhss)
+                      (let* ((new-stack-item
+                              (list
+                               (list sub-symbol)
+                               sub-symbol-rhs
+                               local-follow)))
+                        (unless (gethash
+                                 new-stack-item
+                                 distinct-stack-item-p)
+                          (parser-generator--debug
+                           (message
+                            "new-stack-item: %S"
+                            new-stack-item))
+                          (puthash
+                           new-stack-item
+                           t
+                           distinct-stack-item-p)
+                          (push
+                           new-stack-item
+                           stack))))))))
+            (setq
+             sub-symbol-index
+             (1+ sub-symbol-index))))
+
+        (setq sets (reverse sets))
+        (parser-generator--debug
+         (message
+          "\nsets: %S"
+          sets))
+
+        ;; Add all distinct combinations of left-hand-side,
+        ;; look-aheads and parent-follow to tables list here
+        (when look-aheads
+          (dolist (look-ahead look-aheads)
+            (let ((table
+                   (list
+                    look-ahead
+                    production-rhs
+                    sets))
+                  (item-hash-key
+                   (format
+                    "%S-%S-%S"
+                    production-lhs
+                    parent-follow
+                    look-ahead))
+                  (table-hash-key
+                   (list
+                    production-lhs
+                    parent-follow)))
+
+              ;; Only add distinct items
+              (unless (gethash item-hash-key distinct-item-p)
+                (puthash
+                 item-hash-key
+                 t
+                 distinct-item-p)
+                (parser-generator--debug
+                 (message "\nnew table: %S" table))
+                (if (gethash
+                     table-hash-key
+                     tables)
+                    (puthash
+                     table-hash-key
+                     (push
+                      table
+                      (gethash
+                       table-hash-key
+                       tables))
+                     tables)
+                  (puthash
+                   table-hash-key
+                   (list table)
+                   tables))))))))
+
+    (let ((sorted-tables))
+      (maphash
+       (lambda (k v)
+         (push
+          (list k (sort v 'parser-generator--sort-list))
+          sorted-tables))
+       tables)
+      sorted-tables)))
+
+;; Algorithm 5.3 p. 351
+(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
+    ;; (2) M(a, av) = pop for all v in E where |E| = k-1
+    (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)))
+
+    (dolist (table tables)
+      (let* ((key (nth 0 table))
+             (value (nth 1 table))
+             (left-hand-side (nth 0 key))
+             (parse-table))
+        (dolist (look-ahead-row value)
+          (let* ((look-ahead (nth 0 look-ahead-row))
+                 (right-hand-side (nth 1 look-ahead-row))
+                 (local-follow-sets (nth 2 look-ahead-row))
+                 (non-terminal-index 0)
+                 (sub-symbol-index 0)
+                 (sub-symbol-length (length right-hand-side))
+                 (production (list left-hand-side right-hand-side))
+                 (production-number
+                  (parser-generator--get-grammar-production-number
+                   production))
+                 (modified-right-hand-side))
+            (while (< sub-symbol-index sub-symbol-length)
+              (let ((sub-symbol (nth sub-symbol-index right-hand-side)))
+                (if (parser-generator--valid-non-terminal-p
+                     sub-symbol)
+                    (let ((local-follow
+                           (car (nth non-terminal-index local-follow-sets))))
+                      (push
+                       (list
+                        (list sub-symbol)
+                        local-follow)
+                       modified-right-hand-side)
+                      (setq
+                       non-terminal-index
+                       (1+ non-terminal-index)))
+                  (push
+                   sub-symbol
+                   modified-right-hand-side)))
+              (setq
+               sub-symbol-index
+               (1+ sub-symbol-index)))
+            (setq
+             modified-right-hand-side
+             (reverse modified-right-hand-side))
+
+            (push
+             (list
+              look-ahead
+              'reduce
+              modified-right-hand-side
+              production-number)
+             parse-table)))
+        (push
+         (list
+          key
+          parse-table)
+         parsing-table)))
+
+    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-terminal))
+             (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)
+                 (first-rhs))
+            (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-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))
+        (valid t))
+
+    ;; (1) Construct T_0, the LL(k) table associated with S {e}
+    (let* ((start (parser-generator--get-grammar-start))
+           (start-rhss (parser-generator--get-grammar-rhs start)))
+      (dolist (start-rhs start-rhss)
+        (let* ((production (list (list start) start-rhs)))
+          (push
+           production
+           stack)
+          (puthash
+           production
+           t
+           distinct-production-p))))
+    (setq stack (nreverse stack))
+    (parser-generator--debug
+     (message "stack: %S" stack))
+
+    (while (and
+            stack
+            valid)
+      (setq stack-item (pop stack))
+      (let ((production-rhs
+             (nth 1 stack-item)))
+
+        ;; For each non-terminal in the production right-hand side
+        ;; push a new item to stack with a local-follow
+        ;; and a new left-hand-side
+        (let ((sub-symbol-index 0)
+              (sub-symbol-length (length production-rhs)))
+          (while (< sub-symbol-index sub-symbol-length)
+            (let ((sub-symbol (nth sub-symbol-index production-rhs)))
+              (when (parser-generator--valid-non-terminal-p
+                     sub-symbol)
+                (let* ((local-follow
+                        (nthcdr (1+ sub-symbol-index) production-rhs))
+                       (first-local-follow-sets
+                        (parser-generator--first local-follow nil t t))
+                       (sub-symbol-rhss
+                        (parser-generator--get-grammar-rhs sub-symbol))
+                       (distinct-item-p
+                        (make-hash-table :test 'equal)))
+                  (parser-generator--debug
+                   (message "\nsub-symbol: %S" sub-symbol)
+                   (message "local-follow: %S" local-follow)
+                   (message "first-local-follow-sets: %S" 
first-local-follow-sets)
+                   (message "sub-symbol-rhss: %S" sub-symbol-rhss))
+
+                  ;; Calculate following terminals to see if there is a 
conflict
+                  (dolist (sub-symbol-rhs sub-symbol-rhss)
+                    (let ((first-sub-symbol-rhs
+                           (parser-generator--first sub-symbol-rhs nil t t)))
+                      (let ((merged-terminal-sets
+                             (parser-generator--merge-max-terminal-sets
+                              first-sub-symbol-rhs
+                              first-local-follow-sets)))
+                        (parser-generator--debug
+                         (message "sub-symbol-rhs: %S" sub-symbol-rhs)
+                         (message "first-sub-symbol-rhs: %S" 
first-sub-symbol-rhs)
+                         (message "merged-terminal-sets: %S" 
merged-terminal-sets))
+                        (dolist (merged-terminal-set merged-terminal-sets)
+                          (if (gethash
+                               merged-terminal-set
+                               distinct-item-p)
+                              (progn
+                                (setq valid nil)
+                                (parser-generator--debug
+                                 (message
+                                  "merged-terminal-set: %S was not distinct"
+                                  merged-terminal-set)))
+                            (puthash
+                             merged-terminal-set
+                             t
+                             distinct-item-p)))))
+
+                    ;; Add production to stack if it has not been added already
+                    (let ((production
+                           (list
+                            (list sub-symbol)
+                            sub-symbol-rhs)))
+                      (unless
+                          (gethash
+                           production
+                           distinct-production-p)
+                        (push
+                         production
+                         stack)
+                        (puthash
+                         production
+                         t
+                         distinct-production-p)))))))
+            (setq
+             sub-symbol-index
+             (1+ sub-symbol-index))))))
+    valid))
+
+
+(provide 'parser-generator-ll)
+
+;;; parser-generator-ll.el ends here
diff --git a/parser-generator-lr.el b/parser-generator-lr.el
index d57f691906..47c0baa3b3 100644
--- a/parser-generator-lr.el
+++ b/parser-generator-lr.el
@@ -254,13 +254,13 @@
 
 (defun parser-generator-lr-generate-parser-tables ()
   "Generate parsing tables for grammar."
-  (message "\n;; Starting generation of parser-tables..\n")
+  (message "\n;; Starting generation of LR(k) parser-tables..\n")
   (parser-generator-lr--generate-precedence-tables)
   (let ((table-lr-items
          (parser-generator-lr--generate-goto-tables)))
     (parser-generator-lr--generate-action-tables
      table-lr-items)
-    (message "\n;; Completed generation of parser-tables.\n")
+    (message "\n;; Completed generation of LR(k) parser-tables.\n")
     table-lr-items))
 
 (defun parser-generator-lr--get-expanded-action-tables ()
diff --git a/parser-generator.el b/parser-generator.el
index 5ee265c407..2690799da0 100644
--- a/parser-generator.el
+++ b/parser-generator.el
@@ -367,7 +367,10 @@
     (if (hash-table-p hash-table)
         (progn
           (maphash
-           (lambda (k v) (push (list k v) result))
+           (lambda (k v)
+             (if (hash-table-p v)
+                 (push (list k (parser-generator--hash-to-list v un-sorted)) 
result)
+               (push (list k v) result)))
            hash-table)
           (if un-sorted
               (nreverse result)
@@ -662,6 +665,14 @@
     (error "E-identifier must be a symbol or string!"))
   (setq parser-generator--e-identifier e-identifier))
 
+(defun parser-generator-set-eof-identifier (eof-identifier)
+  "Set EOF-IDENTIFIER."
+  (unless (or
+           (stringp eof-identifier)
+           (symbolp eof-identifier))
+    (error "EOF-identifier must be a symbol or string!"))
+  (setq parser-generator--eof-identifier eof-identifier))
+
 (defun parser-generator-set-look-ahead-number (k)
   "Set look-ahead number K."
   (unless (parser-generator--valid-look-ahead-number-p k)
@@ -1230,36 +1241,155 @@
          look-ahead)))
     (nreverse look-ahead)))
 
-(defun parser-generator--merge-max-terminals (a b k)
-  "Merge terminals from A and B to a maximum length of K."
-  (let ((merged)
+(defun parser-generator--merge-max-terminal-sets (a &optional b 
allow-any-length)
+  "Calculate list of all lists of L1 (+) L2 which is a merge of all terminals 
in lists A combined with all terminals in lists B but with maximum length of 
the set look-ahead number."
+  (let ((a-length (length a))
+        (a-index 0)
+        (b-length (length b))
+        (merged-lists))
+    (cond
+     ((and a b)
+      (while (< a-index a-length)
+        (let ((a-element (nth a-index a))
+              (b-index 0))
+          (while (< b-index b-length)
+            (let ((b-element (nth b-index b)))
+              (when-let
+                  ((merged-element
+                    (parser-generator--merge-max-terminals
+                     a-element
+                     b-element
+                     allow-any-length)))
+                (if merged-lists
+                    (setq
+                     merged-lists
+                     (append
+                      merged-lists
+                      (list merged-element)))
+                  (setq
+                   merged-lists
+                   (list merged-element)))))
+            (setq b-index (1+ b-index)))
+          (setq a-index (1+ a-index)))))
+     (a
+      (while (< a-index a-length)
+        (let ((a-element (nth a-index a)))
+          (when-let
+              ((merged-element
+                (parser-generator--merge-max-terminals
+                 a-element
+                 nil
+                 allow-any-length)))
+            (if merged-lists
+                (setq
+                 merged-lists
+                 (append
+                  merged-lists
+                  (list merged-element)))
+              (setq
+               merged-lists
+               (list merged-element)))))
+        (setq a-index (1+ a-index))))
+
+     (b
+      (let ((b-index 0))
+        (while (< b-index b-length)
+          (let ((b-element (nth b-index b)))
+            (when-let
+                ((merged-element
+                  (parser-generator--merge-max-terminals
+                   nil
+                   b-element
+                   allow-any-length)))
+              (if merged-lists
+                  (setq
+                   merged-lists
+                   (append
+                    merged-lists
+                    (list merged-element)))
+                (setq
+                 merged-lists
+                 (list merged-element)))))
+          (setq b-index (1+ b-index))))))
+    (setq
+     merged-lists
+     (parser-generator--distinct
+      merged-lists))
+    (setq
+     merged-lists
+     (sort
+      merged-lists
+      'parser-generator--sort-list))
+    merged-lists))
+
+;; Lemma 5.1 p. 348
+(defun parser-generator--merge-max-terminals (a b &optional allow-any-length)
+  "Calculate L1 (+) L2 which is a merge of all terminals in A and B but with 
exactly length of the set look-ahead number. Optionally ALLOW-ANY-LENGTH."
+  (let ((k (max 1 parser-generator--look-ahead-number))
+        (merged)
         (merge-count 0)
-        (continue t)
         (a-element)
         (a-index 0)
         (a-length (length a))
         (b-element)
         (b-index 0)
-        (b-length (length b)))
+        (b-length (length b))
+        (only-eof))
+
     (while (and
             (< a-index a-length)
-            (< merge-count k)
-            continue)
+            (< merge-count k))
       (setq a-element (nth a-index a))
-      (when (parser-generator--valid-e-p a-element)
-        (setq continue nil))
-      (push a-element merged)
+
+      (when (parser-generator--valid-eof-p
+             a-element)
+        (setq only-eof t))
+
+      (when (or
+             (and
+              only-eof
+              (parser-generator--valid-eof-p
+               a-element))
+             (and
+              (not only-eof)
+              (parser-generator--valid-terminal-p
+               a-element)))
+        (push a-element merged)
+        (setq merge-count (1+ merge-count)))
+
       (setq a-index (1+ a-index)))
+
     (while (and
             (< b-index b-length)
-            (< merge-count k)
-            continue)
+            (< merge-count k))
       (setq b-element (nth b-index b))
-      (when (parser-generator--valid-e-p b-element)
-        (setq continue nil))
-      (push b-element merged)
+
+      (when (parser-generator--valid-eof-p
+             b-element)
+        (setq only-eof t))
+
+      (when (or
+             (and
+              only-eof
+              (parser-generator--valid-eof-p
+               b-element))
+             (and
+              (not only-eof)
+              (parser-generator--valid-terminal-p
+               b-element)))
+        (push b-element merged)
+        (setq merge-count (1+ merge-count)))
+
       (setq b-index (1+ b-index)))
-    (nreverse merged)))
+
+    (if (or
+         (and
+          allow-any-length
+          (> merge-count 0))
+         (and (not allow-any-length)
+              (= merge-count k)))
+        (nreverse merged)
+      nil)))
 
 ;; p. 357
 (defun parser-generator--f-set (input-tape state stack)
@@ -1512,8 +1642,8 @@
 
 ;; Algorithm 5.5, p. 357
 (defun parser-generator--first
-    (β &optional disallow-e-first ignore-validation skip-sorting)
-  "For sentential-form Β, calculate first terminals, optionally 
DISALLOW-E-FIRST, IGNORE-VALIDATION and SKIP-SORTING."
+    (β &optional disallow-e-first ignore-validation skip-sorting 
use-eof-for-trailing-symbols)
+  "For sentential-form Β, calculate first terminals, optionally 
DISALLOW-E-FIRST, IGNORE-VALIDATION, SKIP-SORTING and 
USE-EOF-FOR-TRAILING-SYMBOLS."
 
   ;; Make sure we are dealing with a list of symbols
   (unless (listp β)
@@ -1644,8 +1774,13 @@
            (parser-generator--valid-eof-p input-symbol)
            (parser-generator--valid-terminal-p input-symbol))
           (parser-generator--debug
-           (message
-            "symbol is a terminal, the e-identifier or the EOF-identifier"))
+           (cond
+            ((parser-generator--valid-e-p input-symbol)
+             (message "symbol is the e-identifier"))
+            ((parser-generator--valid-eof-p input-symbol)
+             (message "symbol is the EOF-identifier"))
+            ((parser-generator--valid-terminal-p input-symbol)
+             (message "symbol is a terminal"))))
           (let ((expanded-list-index 0)
                 (expanded-list-count
                  (length expanded-lists)))
@@ -1706,7 +1841,9 @@
             (setq
              expanded-lists-index
              (1+ expanded-lists-index)))
-          (when (>= minimum-terminal-count k)
+          (when (and
+                 minimum-terminal-count
+                 (>= minimum-terminal-count k))
             (setq still-looking nil)
             (parser-generator--debug
              (message
@@ -1866,14 +2003,18 @@
                           (missing-symbol-index 0))
                       (while (< missing-symbol-index missing-symbol-count)
                         (push
-                         parser-generator--e-identifier
+                         (if use-eof-for-trailing-symbols
+                             parser-generator--eof-identifier
+                             parser-generator--e-identifier)
                          processed-list)
                         (setq
                          missing-symbol-index
                          (1+ missing-symbol-index)))
                       (parser-generator--debug
                        (message
-                        "Added %d trailing e-identifiers to set"
+                        (if use-eof-for-trailing-symbols
+                          "Added %d trailing EOF-identifiers to set"
+                          "Added %d trailing e-identifiers to set")
                         missing-symbol-count))))
 
                   (when (> (length processed-list) k)
@@ -1999,6 +2140,93 @@
             (parser-generator--distinct follow-set)))
     follow-set))
 
+(defun parser-generator-generate-terminal-saturated-first-set (first-set)
+  "Generated a set from FIRST-SET with items that does not end with the 
e-identifier if there is alternative items that continues with terminals."
+  (let ((max-terminal-count
+         (parser-generator-calculate-max-terminal-count
+          first-set))
+        (saturated-list))
+    (when (> max-terminal-count 0)
+      (setq
+       saturated-list
+       (parser-generator-generate-sets-of-terminals
+        first-set
+        max-terminal-count)))
+    saturated-list))
+
+(defun parser-generator-generate-sets-of-terminals (sets count)
+  "Generate set of terminals in sequence from SETS with COUNT."
+  (let ((sets-of-terminals)
+        (terminal-set-exists-p (make-hash-table :test 'equal)))
+    (dolist (set sets)
+      (let ((item-count (length set))
+            (item-index 0)
+            (only-terminals t)
+            (terminal-count 0)
+            (terminals))
+        (while (and
+                only-terminals
+                (< terminal-count count)
+                (< item-index item-count))
+          (let ((item (nth item-index set)))
+            (if (parser-generator--valid-terminal-p item)
+                (progn
+                  (push
+                   item
+                   terminals)
+                  (setq
+                   terminal-count
+                   (1+ terminal-count)))
+              (setq
+               only-terminals
+               nil)))
+          (setq
+           item-index
+           (1+ item-index)))
+        (when (and
+               only-terminals
+               (= terminal-count count)
+               (not
+                (gethash
+                 terminals
+                 terminal-set-exists-p)))
+          (puthash
+           terminals
+           t
+           terminal-set-exists-p)
+          (push
+           (reverse terminals)
+           sets-of-terminals))))
+    (reverse sets-of-terminals)))
+
+(defun parser-generator-calculate-max-terminal-count (sets)
+  "Calculate maximum number of terminals in sequence in SETS."
+  (let ((max-terminal-count 0))
+    (dolist (set sets)
+      (let ((item-count (length set))
+            (item-index 0)
+            (only-terminals t)
+            (terminal-count 0))
+        (while (and
+                only-terminals
+                (< item-index item-count))
+          (let ((item (nth item-index set)))
+            (if (parser-generator--valid-terminal-p item)
+                (setq
+                 terminal-count
+                 (1+ terminal-count))
+              (setq
+               only-terminals
+               nil)))
+          (setq
+           item-index
+           (1+ item-index)))
+        (when (> terminal-count max-terminal-count)
+          (setq
+           max-terminal-count
+           terminal-count))))
+    max-terminal-count))
+
 
 (provide 'parser-generator)
 
diff --git a/test/parser-generator-ll-export-test.el 
b/test/parser-generator-ll-export-test.el
new file mode 100644
index 0000000000..17d7ac0468
--- /dev/null
+++ b/test/parser-generator-ll-export-test.el
@@ -0,0 +1,176 @@
+;; parser-generator-ll-export-test.el --- Tests for Exported Generated LL(k) 
Parser -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2022  Free Software Foundation, Inc.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(require 'parser-generator-ll-export)
+(require 'ert)
+
+(defun parser-generator-ll-export-test-to-elisp ()
+  "Test `parser-generator-ll-export-to-elisp'."
+  (message "Started tests for (parser-generator-ll-export-to-elisp)")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S
+       (a A a a (lambda(a b) (format "alfa %s laval" (nth 1 a))))
+       (b A b a (lambda(a b) (format "delta %s laval" (nth 1 a))))
+       )
+      (A
+       (b (lambda(a b) "sven"))
+       (e (lambda(a b) "ingrid"))
+       )
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (let ((export (parser-generator-ll-export-to-elisp "ba")))
+    (with-temp-buffer
+      (insert export)
+      (eval-buffer)
+      (should
+       (equal
+        t
+        (fboundp 'ba-parse)))
+      (should
+       (equal
+        t
+        (fboundp 'ba-translate)))
+      (when (fboundp 'ba-parse)
+        (should
+         (equal
+          '(1 3)
+          (ba-parse))))
+      (when (fboundp 'ba-translate)
+        (should
+         (equal
+          "delta ingrid laval"
+          (ba-translate))))))
+  (message "Passed exported test for example 5.16 p. 352")
+
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (let ((export (parser-generator-ll-export-to-elisp "ba2")))
+    (with-temp-buffer
+      (insert export)
+      (eval-buffer)
+      (should
+       (equal
+        t
+        (fboundp 'ba2-parse)))
+      (should
+       (equal
+        t
+        (fboundp 'ba2-translate)))
+      (when (fboundp 'ba2-translate)
+        (should
+         (equal
+          "delta sven laval"
+          (ba2-translate))))))
+  (message "Passed exported test failing parse")
+
+  (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)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((a 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5) (b 5 . 6)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (let ((export (parser-generator-ll-export-to-elisp "ba3")))
+    (with-temp-buffer
+      (insert export)
+      (eval-buffer)
+      (should
+       (equal
+        t
+        (fboundp 'ba3-parse)))
+      (should
+       (equal
+        t
+        (fboundp 'ba3-translate)))
+      (when (fboundp 'ba3-parse)
+        (should
+         (equal
+          '(0 3 1 2 1)
+          (ba3-parse))))))
+  (message "Passed exported test for example 5.5 p. 340")
+
+  (message "Passed tests for (parser-generator-ll-export-to-elisp)"))
+
+
+(defun parser-generator-ll-export-test ()
+  "Run test."
+  (parser-generator-ll-export-test-to-elisp))
+
+
+(provide 'parser-generator-ll-export-test)
+
+;;; parser-generator-ll-export-test.el ends here
diff --git a/test/parser-generator-ll-test.el b/test/parser-generator-ll-test.el
new file mode 100644
index 0000000000..5e927cbf3f
--- /dev/null
+++ b/test/parser-generator-ll-test.el
@@ -0,0 +1,943 @@
+;; parser-generator-ll-test.el --- Tests for LL(k) Parser Generator -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2020-2022  Free Software Foundation, Inc.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(require 'parser-generator-ll)
+(require 'ert)
+
+(defun parser-generator-ll-test--generate-goto-table ()
+  "Test `parser-generator-ll--generate-goto-table'."
+  (message "Started tests for (parser-generator-ll--generate-goto-table)")
+
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S (a A a a) (b A b a))
+      (A b e)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (let ((tables (parser-generator-ll--generate-goto-table)))
+    ;; (message "tables: %S" tables)
+    (should
+     (equal
+      tables
+      '(
+        (
+         ((A) (b a)) ;; T A,{ba}
+         (
+          ((b b) (b) nil)
+          ((b a) (e) nil)
+          )
+         )
+        (
+         ((A) (a a)) ;; T A,{aa}
+         (
+          ((a a) (e) nil)
+          ((b a) (b) nil)
+          )
+         )
+        (
+         ((S) ($ $)) ;; T0
+         (
+          ((a b) (a A a a) (((a a))))
+          ((a a) (a A a a) (((a a))))
+          ((b b) (b A b a) (((b a))))
+          )
+         )
+        )
+      )
+     ))
+  (message "Passed Example 5.14 p. 350 and 5.15 p. 351")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S e (a b A))
+      (A (S a a) b)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (let* ((tables
+          (parser-generator-ll--generate-goto-table)))
+    ;; (message "tables: %S" tables)
+    (should
+     (equal
+      tables
+      '(
+        (
+         ((A) (a a)) ;; T3
+         (
+          ((a b) (S a a) (((a a))))
+          ((a a) (S a a) (((a a))))
+          ((b a) (b) nil)
+          )
+         )
+        (
+         ((S) (a a)) ;; T2
+         (
+          ((a b) (a b A) (((a a))))
+          ((a a) (e) nil)
+          )
+         )
+        (
+         ((A) ($ $)) ;; T1
+         (
+          ((a b) (S a a) (((a a))))
+          ((a a) (S a a) (((a a))))
+          ((b $) (b) nil)
+          )
+         )
+        (
+         ((S) ($ $)) ;; T0
+         (
+          (($ $) (e) nil)
+          ((a b) (a b A) ((($ $))))
+          )
+         )
+        )
+      ))
+    )
+  (message "Passed Example 5.17 p. 354")
+
+  (message "Passed tests for (parser-generator-ll--generate-goto-table)"))
+
+(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)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S (a A a a) (b A b a))
+      (A b e)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (let* ((goto-table
+          (parser-generator-ll--generate-goto-table))
+         (action-table
+          (parser-generator-ll--generate-action-table-k-gt-1
+           goto-table)))
+    ;; (message "goto-table: %S" goto-table)
+    ;; (message "action-table: %S" action-table)
+    (should
+     (equal
+      '(
+        (
+         ((S) ($ $)) ;; T0
+         (
+          ((b b) reduce (b ((A) (b a)) b a) 1)
+          ((a a) reduce (a ((A) (a a)) a a) 0)
+          ((a b) reduce (a ((A) (a a)) a a) 0)
+          )
+         )
+        (
+         ((A) (a a)) ;; T1
+         (
+          ((b a) reduce (b) 2)
+          ((a a) reduce (e) 3)
+          )
+         )
+        (
+         ((A) (b a)) ;; T2
+         (
+          ((b a) reduce (e) 3)
+          ((b b) reduce (b) 2)
+          )
+         )
+        (b (((b b) pop) ((b a) pop) ((b $) pop)))
+        (a (((a b) pop) ((a a) pop) ((a $) pop)))
+        ($ ((($ $) accept)))
+        )
+      action-table)))
+  (message "Passed Example 5.15 p. 351 and 5.16 p. 352")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S e (a b A))
+      (A (S a a) b)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (let* ((goto-table
+          (parser-generator-ll--generate-goto-table))
+         (action-table
+          (parser-generator-ll--generate-action-table-k-gt-1
+           goto-table)))
+    ;; (message "goto-tables: %S" goto-table)
+    ;; (message "action-table: %S" action-table)
+    (should
+     (equal
+      '(
+        (
+         ((S) ($ $)) ;; T0
+         (
+          ((a b) reduce (a b ((A) ($ $))) 1)
+          (($ $) reduce (e) 0)
+          )
+         )
+        (
+         ((A) ($ $)) ;; T1
+         (
+          ((b $) reduce (b) 3)
+          ((a a) reduce (((S) (a a)) a a) 2)
+          ((a b) reduce (((S) (a a)) a a) 2)
+          )
+         )
+        (
+         ((S) (a a)) ;; T2
+         (
+          ((a a) reduce (e) 0)
+          ((a b) reduce (a b ((A) (a a))) 1)
+          )
+         )
+        (
+         ((A) (a a)) ;; T3
+         (
+          ((b a) reduce (b) 3)
+          ((a a) reduce (((S) (a a)) a a) 2)
+          ((a b) reduce (((S) (a a)) a a) 2)
+          )
+         )
+        (b (((b b) pop) ((b a) pop) ((b $) pop)))
+        (a (((a b) pop) ((a a) pop) ((a $) pop)))
+        ($ ((($ $) accept)))
+        )
+      action-table)))
+  (message "Passed Example 5.17 p. 356")
+
+  (message "Passed tests for 
(parser-generator-ll--generate-action-table-k-gt-1)"))
+
+(defun parser-generator-ll-test-parse ()
+  "Test `parser-generator-ll-parse'."
+  (message "Started tests for (parser-generator-ll-parse)")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S (a A a a) (b A b a))
+      (A b e)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    '(1 3) ;; Example is indexed from 1 so that is why they have '(2 4)
+    (parser-generator-ll-parse)))
+  (message "Passed example 5.16 p. 352")
+
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should-error
+   (parser-generator-ll-parse))
+  (message "Passed failing variant of example 5.16 p. 352")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S e (a b A))
+      (A (S a a) b)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((a 1 . 2) (b 2 . 3) (a 3 . 4) (a 4 . 5)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    '(1 2 0) ;; Example is indexed from 1 so that is why they have '(2 3 1)
+    (parser-generator-ll-parse)))
+  (message "Passed example 5.17 p. 355")
+
+  (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)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((a 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5) (b 5 . 6)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    '(0 3 1 2 1) ;; Example is indexed from 1 so that is why they have '(1 4 2 
3 2)
+    (parser-generator-ll-parse)))
+  (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)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '(("(" 1 . 2) ("a" 2 . 3) ("*" 3 . 4) ("a" 4 . 5) (")" 5 . 
6)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    '(0 3 6 0 3 7 4 7 5 2 5 2) ;; Example is 1-indexed '(1 4 7 1 4 8 5 8 6 3 6 
3)
+    (parser-generator-ll-parse)))
+  (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)
+  (parser-generator-set-grammar
+   '(
+     (S F)
+     ("(" "a" ")" "+")
+     (
+      (S F)
+      (S ("(" S "+" F ")"))
+      (F "a")
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '(("(" 1 . 2) ("a" 2 . 3) ("+" 3 . 4) ("a" 4 . 5) (")" 5 . 
6)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    '(1 0 2 2) ;; Example is 1 indexed '(2 1 3 3)
+    (parser-generator-ll-parse)))
+  (message "Passed example from Wikipedia")
+
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '(("(" 1 . 2) ("a" 2 . 3) ("+" 3 . 4) ("a" 4 . 5)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should-error
+   (parser-generator-ll-parse))
+  (message "Passed failing variant of example from Wikipedia")
+
+  (message "Passed tests for (parser-generator-ll-parse)"))
+
+(defun parser-generator-ll-test-translate ()
+  "Test `parser-generator-ll-translate'."
+  (message "Started tests for (parser-generator-ll-translate)")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S
+       (a A a a (lambda(a b) (format "alfa %s laval" (nth 1 a))))
+       (b A b a (lambda(a b) (format "delta %s laval" (nth 1 a))))
+       )
+      (A
+       (b (lambda(a b) "sven"))
+       (e (lambda(a b) "ingrid"))
+       )
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (a 3 . 4)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    "delta ingrid laval"
+    (parser-generator-ll-translate)))
+  (message "Passed translation test 1")
+
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((b 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (should
+   (equal
+    "delta sven laval"
+    (parser-generator-ll-translate)))
+  (message "Passed translation test 2")
+
+  (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 (lambda(a b) (format "alfa %s %s" (nth 1 a) (nth 2 a))))
+       (b (lambda(a b) "beta"))
+       )
+      (A
+       (a (lambda(a b) "delta"))
+       (b S A (lambda(a b) (format "gamma %s %s" (nth 1 a) (nth 2 a))))
+       )
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  (setq
+   parser-generator-lex-analyzer--function
+   (lambda (index)
+     (let* ((string '((a 1 . 2) (b 2 . 3) (b 3 . 4) (a 4 . 5) (b 5 . 6)))
+            (string-length (length string))
+            (max-index index)
+            (tokens))
+       (while (and
+               (< (1- index) string-length)
+               (< (1- index) max-index))
+         (push (nth (1- index) string) tokens)
+         (setq index (1+ index)))
+       (nreverse tokens))))
+  (setq
+   parser-generator-lex-analyzer--get-function
+   (lambda (token)
+     (car token)))
+  (should
+   (equal
+    "beta"
+    (parser-generator-ll-translate)))
+  (message "Passed translation test 3")
+
+  (message "Passed tests for (parser-generator-ll-translate)"))
+
+(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)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S e (a b A))
+      (A (S a a) b)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (parser-generator-ll-generate-table)
+  ;; (message "parsing-table: %S" (parser-generator--hash-to-list 
parser-generator-ll--table t))
+  (should
+   (equal
+    '(
+      ("((S) ($ $))"
+       (
+        ("(a b)" (reduce (a b ((A) ($ $))) 1))
+        ("($ $)" (reduce (e) 0))
+        )
+       )
+      ("((A) ($ $))"
+       (
+        ("(b $)" (reduce (b) 3))
+        ("(a a)" (reduce (((S) (a a)) a a) 2))
+        ("(a b)" (reduce (((S) (a a)) a a) 2))
+        )
+       )
+      ("((S) (a a))"
+       (
+        ("(a a)" (reduce (e) 0))
+        ("(a b)" (reduce (a b ((A) (a a))) 1))
+        )
+       )
+      ("((A) (a a))"
+       (
+        ("(b a)" (reduce (b) 3))
+        ("(a a)" (reduce (((S) (a a)) a a) 2))
+        ("(a b)" (reduce (((S) (a a)) a a) 2))
+        )
+       )
+      ("b" (("(b b)" pop) ("(b a)" pop) ("(b $)" pop)))
+      ("a" (("(a b)" pop) ("(a a)" pop) ("(a $)" pop)))
+      ("$" (("($ $)" accept)))
+      )
+    (parser-generator--hash-to-list
+     parser-generator-ll--table
+     t)))
+
+  (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)
+  (parser-generator-ll-generate-table)
+  ;; (message "parsing-table: %S" (parser-generator--hash-to-list 
parser-generator-ll--table t))
+  (should
+   (equal
+    '(
+      ("S"
+       (
+        ("(b)" (reduce (b) 1))
+        ("(a)" (reduce (a A S) 0))
+        )
+       )
+      ("A"
+       (
+        ("(b)" (reduce (b S A) 3))
+        ("(a)" (reduce (a) 2))
+        )
+       )
+      ("b" (("(b)" pop)))
+      ("a" (("(a)" pop)))
+      ("$" (("($)" accept)))
+      )
+    (parser-generator--hash-to-list
+     parser-generator-ll--table
+     t)))
+
+  (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'."
+  (message "Started tests for (parser-generator-ll--valid-grammar-k-gt-1-p)")
+
+  ;; Example 5.14 p. 350
+  ;; Example 5.15 p. 351
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S (a A a a) (b A b a))
+      (A b e)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (should
+   (equal
+    (parser-generator-ll--valid-grammar-k-gt-1-p)
+    t))
+  (message "Passed first valid test")
+
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (parser-generator-set-grammar
+   '(
+     (S A)
+     (a b)
+     (
+      (S (a A a a) (b A b a))
+      (A b e a)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (should
+   (equal
+    (parser-generator-ll--valid-grammar-k-gt-1-p)
+    nil))
+  (message "Passed second valid test")
+
+  (message "Passed tests for (parser-generator-ll--valid-grammar-k-gt-1-p)"))
+
+(defun parser-generator-ll-test--generate-action-table-k-eq-1 ()
+  "Test `parser-generator-ll--generate-action-table-k-eq-1'."
+  (message "Started tests for 
(parser-generator-ll--generate-action-table-k-eq-1)")
+
+  (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-action-table-k-eq-1
+           (parser-generator-ll--generate-goto-table))))
+    ;; (message "tables: %S" tables)
+    (should
+     (equal
+      '(
+        (S
+         (
+          ((b) reduce (b) 1)
+          ((a) reduce (a A S) 0)
+          )
+         )
+        (A
+         (
+          ((b) reduce (b S A) 3)
+          ((a) reduce (a) 2)
+          )
+         )
+        (b (((b) pop)))
+        (a (((a) pop)))
+        ($ ((($) accept)))
+        )
+      tables
+     )))
+  (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-action-table-k-eq-1
+          (parser-generator-ll--generate-goto-table))))
+    ;; (message "tables: %S" tables)
+    (should
+     (equal
+      '(
+        (E
+         (
+          (("a") reduce (T E2) 0)
+          (("(") reduce (T E2) 0)
+          )
+         )
+        (E2
+         (
+          (($) reduce (e) 2)
+          (("+") reduce ("+" T E2) 1)
+          ((")") reduce (e) 2)
+          )
+         )
+        (T
+         (
+          (("a") reduce (F T2) 3)
+          (("(") reduce (F T2) 3)
+          )
+         )
+        (T2
+         (
+          (("+") reduce (e) 5)
+          ((")") reduce (e) 5)
+          (("*") reduce ("*" F T2) 4)
+          (($) reduce (e) 5)
+          )
+         )
+        (F
+         (
+          (("a") reduce ("a") 7)
+          (("(") reduce ("(" E ")") 6)
+          )
+         )
+        ("a" ((("a") pop)))
+        ("+" ((("+") pop)))
+        ("*" ((("*") pop)))
+        (")" (((")") pop)))
+        ("(" ((("(") pop)))
+        ($ ((($) accept)))
+        )
+      tables)))
+  (message "Passed Example 5.12 p. 346-347")
+
+  (message "Passed tests for 
(parser-generator-ll--generate-action-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)")
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 1)
+  (parser-generator-set-grammar
+   '(
+     (S A B)
+     (a b)
+     (
+      (S (a A S) b B)
+      (A a (b S A))
+      (B a)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (should
+   (equal
+    nil
+    (parser-generator-ll--valid-grammar-k-eq-1-p)))
+
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 1)
+  (parser-generator-set-grammar
+   '(
+     (S A B)
+     (a b c)
+     (
+      (S (a A S) b B)
+      (A a (b S A))
+      (B c)
+      )
+     S
+     )
+   )
+  (parser-generator-process-grammar)
+  (should
+   (equal
+    t
+    (parser-generator-ll--valid-grammar-k-eq-1-p)))
+
+  (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-goto-table)
+
+  ;; k > 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-action-table-k-eq-1)
+  (parser-generator-ll-test--valid-grammar-k-eq-1-p)
+
+  ;; Main stuff
+  (parser-generator-ll-test-generate-table)
+  (parser-generator-ll-test-parse)
+  (parser-generator-ll-test-translate))
+
+
+(provide 'parser-generator-ll-test)
+
+;;; parser-generator-ll-test.el ends here
diff --git a/test/parser-generator-test.el b/test/parser-generator-test.el
index 1fab673dc2..45dd865238 100644
--- a/test/parser-generator-test.el
+++ b/test/parser-generator-test.el
@@ -967,27 +967,41 @@
 
   (message "Passed tests for (parser-generator--valid-terminal-p)"))
 
-(defun parser-generator-test--merge-max-terminals ()
-  "Test `parser-generator--merge-max-terminals'."
-  (message "Starting tests for (parser-generator--merge-max-terminals)")
+(defun parser-generator-test--merge-max-terminal-sets ()
+  "Test `parser-generator--merge-max-terminal-sets'."
+  (message "Starting tests for (parser-generator--merge-max-terminal-sets)")
 
+  (parser-generator-set-eof-identifier '$)
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-look-ahead-number 2)
+  (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)
+
+  ;; Example 5.13 p. 348
+  (should
+   (equal
+    '((a b) (b) (b a))
+    (parser-generator--merge-max-terminal-sets
+     '((a b b) (e))
+     '((b) (b a b))
+     t)))
+
+  ;; Example 5.14 p. 350
   (should
    (equal
-    '(a b e)
-    (parser-generator--merge-max-terminals
-     '(a)
-     '(b e)
-     3)))
+    '((a a) (a b) (b b))
+    (parser-generator--merge-max-terminal-sets
+     '((a b) (a e a) (b b) (b e b))
+     nil)))
 
   (should
    (equal
-    '(a e)
-    (parser-generator--merge-max-terminals
-     '(a e)
-     '(b e)
-     3)))
+    '(($ $) (a $) (a a))
+    (parser-generator--merge-max-terminal-sets
+     '((a e) ($))
+     '(($ $) (a $)))))
 
-  (message "Passed tests for (parser-generator--merge-max-terminals)"))
+  (message "Passed tests for (parser-generator--merge-max-terminal-sets)"))
 
 (defun parser-generator-test--get-list-permutations ()
   "Test `parser-generator--get-list-permutations'."
@@ -1051,6 +1065,87 @@
 
   (message "Passed tests for 
(parser-generator-test--generate-list-of-symbol)"))
 
+(defun parser-generator-test--calculate-max-terminal-count ()
+  "Test `parser-generator-calculate-max-terminal-count'."
+  (message "Starting tests for 
(parser-generator-calculate-max-terminal-count)")
+
+  (parser-generator-set-look-ahead-number 1)
+  (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
+    (parser-generator-calculate-max-terminal-count
+     '(("a" "a") ("b") ("a" e "b" "c") (B "a" "b" "c")))
+    2))
+  (should
+   (equal
+    (parser-generator-calculate-max-terminal-count
+     '(("a") ("b") ("a" e "b" "c") (B "a" "b" "c")))
+    1))
+
+  (message "Passed tests for (parser-generator-calculate-max-terminal-count)"))
+
+(defun parser-generator-test--generate-sets-of-terminals ()
+  "Test `parser-generator--generate-sets-of-terminals'."
+  (message "Starting tests for (parser-generator--generate-sets-of-terminals)")
+
+  (parser-generator-set-look-ahead-number 1)
+  (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
+    (parser-generator-generate-sets-of-terminals
+     '(("a" "a") ("b") ("b" "a") ("a" "b" "a") ("a" e S "b" "a") ("b" "b" A))
+     2)
+    '(("a" "a") ("b" "a") ("a" "b") ("b" "b"))))
+
+  (should
+   (equal
+    (parser-generator-generate-sets-of-terminals
+     '(("a" "a") ("b") ("b" "a") ("a" "b" "a") ("a" e S "b" "a") ("b" "b" A))
+     1)
+    '(("a") ("b"))))
+
+  (should
+   (equal
+    (parser-generator-generate-sets-of-terminals
+     '(("a" "a") ("b") ("b" "a") ("a" "b" "a") ("a" e S "b" "a") ("b" "b" A))
+     3)
+    '(("a" "b" "a"))))
+
+  (should
+   (equal
+    (parser-generator-generate-sets-of-terminals
+     '(("a" e) ("b") ("b" "a") ("a" "b" "a") ("a" e S "b" "a") ("b" "b" A))
+     1)
+    '(("a") ("b"))))
+
+  (message "Passed tests for (parser-generator--generate-sets-of-terminals)"))
+
+(defun parser-generator-test--generate-terminal-saturated-first-set ()
+  "Test `parser-generator-generate-terminal-saturated-first-set'."
+  (message "Starting tests for 
(parser-generator-generate-terminal-saturated-first-set)")
+
+  (parser-generator-set-look-ahead-number 1)
+  (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
+    (parser-generator-generate-terminal-saturated-first-set
+     '(("a" "b") ("a" "a" e) ("b") ("a" e)))
+    '(("a" "b") ("a" "a"))))
+
+  (should
+   (equal
+    (parser-generator-generate-terminal-saturated-first-set
+     '(("a" "b") ("a" "a" e) ("b" "b") ("a" e)))
+    '(("a" "b") ("a" "a") ("b" "b"))))
+
+  (message "Passed tests for 
(parser-generator-generate-terminal-saturated-first-set)"))
+
 (defun parser-generator-test ()
   "Run test."
   ;; (setq debug-on-error t)
@@ -1061,7 +1156,7 @@
   (parser-generator-test--get-grammar-look-aheads)
   (parser-generator-test--get-grammar-rhs)
   (parser-generator-test--get-list-permutations)
-  (parser-generator-test--merge-max-terminals)
+  (parser-generator-test--merge-max-terminal-sets)
   (parser-generator-test--sort-list)
   (parser-generator-test--valid-context-sensitive-attribute-p)
   (parser-generator-test--valid-context-sensitive-attributes-p)
@@ -1074,6 +1169,9 @@
   (parser-generator-test--valid-sentential-form-p)
   (parser-generator-test--valid-terminal-p)
   (parser-generator-test--generate-f-sets)
+  (parser-generator-test--calculate-max-terminal-count)
+  (parser-generator-test--generate-sets-of-terminals)
+  (parser-generator-test--generate-terminal-saturated-first-set)
 
   ;; Algorithms
   (parser-generator-test--first)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]