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

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

[elpa] externals/parser-generator 6726c5231e 24/29: Fixed conflict


From: Christian Johansson
Subject: [elpa] externals/parser-generator 6726c5231e 24/29: Fixed conflict
Date: Sat, 12 Feb 2022 02:24:45 -0500 (EST)

branch: externals/parser-generator
commit 6726c5231e1c73ec7d7a49a9a2aeb6b0c6b59e5c
Merge: add9d0072f 98dc561880
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>

    Fixed conflict
---
 parser-generator-lr.el           |   11 +-
 parser-generator.el              | 1409 +++++++++++++++++++-------------------
 test/parser-generator-lr-test.el |   27 +-
 test/parser-generator-test.el    |   34 +-
 4 files changed, 755 insertions(+), 726 deletions(-)

diff --git a/parser-generator-lr.el b/parser-generator-lr.el
index 3718857c28..1f72ae7dd9 100644
--- a/parser-generator-lr.el
+++ b/parser-generator-lr.el
@@ -682,6 +682,11 @@
         (parser-generator--debug
          (message "%s actions %s" goto-index action-table))
         (when action-table
+          (setq
+           action-table
+           (sort
+            action-table
+            'parser-generator--sort-list))
           (message
            "ACTION-TABLE (%d): %S\n"
            goto-index
@@ -689,11 +694,13 @@
           (push
            (list
             goto-index
-            (sort action-table 'parser-generator--sort-list))
+            action-table)
            action-tables))))
     (unless found-accept
       (error "Failed to find an accept action in the generated 
action-tables!"))
-    (setq action-tables (nreverse action-tables))
+    (setq
+     action-tables
+     (nreverse action-tables))
     (setq
      parser-generator-lr--action-tables
      (make-hash-table :test 'equal))
diff --git a/parser-generator.el b/parser-generator.el
index 6a3befc48a..0a2575efae 100644
--- a/parser-generator.el
+++ b/parser-generator.el
@@ -45,7 +45,7 @@
 
 (defvar
   parser-generator--debug
-  t
+  nil
   "Whether to print debug messages or not.")
 
 (defvar
@@ -78,11 +78,6 @@
   nil
   "Generated F-sets for grammar.")
 
-(defvar
-  parser-generator--f-free-sets
-  nil
-  "Generated e-free F-sets for grammar.")
-
 (defvar
   parser-generator--look-ahead-number
   nil
@@ -161,9 +156,6 @@
   (setq
    parser-generator--f-sets
    nil)
-  (setq
-   parser-generator--f-free-sets
-   nil)
   (setq
    parser-generator--table-firsts
    (make-hash-table :test 'equal)))
@@ -700,6 +692,7 @@
       (parser-generator--valid-look-ahead-number-p
        parser-generator--look-ahead-number)
     (error "Invalid look-ahead number k!"))
+  (message "k = %d" parser-generator--look-ahead-number)
   (unless parser-generator--grammar
     (error "No grammar defined!"))
   (unless
@@ -1051,220 +1044,183 @@
 (defun parser-generator--generate-f-sets ()
   "Generate F-sets for grammar."
   ;; Generate F-sets only once per grammar
-  (unless (and
-           parser-generator--f-sets
-           parser-generator--f-free-sets)
+  (unless parser-generator--f-sets
     (parser-generator--debug
      (message "(parser-generator--generate-f-sets)"))
     (let ((productions
            (parser-generator--get-grammar-productions))
-          (k
-           (max
-            1
-            parser-generator--look-ahead-number)))
-      (let ((disallow-set '(nil t)))
-        (parser-generator--debug
-         (message "disallow-set: %s" disallow-set))
-        (dolist (disallow-e-first disallow-set)
+          (k (max 1 parser-generator--look-ahead-number)))
+      (let ((f-sets (make-hash-table :test 'equal))
+            (i 0)
+            (max-i 100)
+            (expanded-all))
+
+        (while (not expanded-all)
+          (when (> i max-i)
+            (error "Endless loop!"))
           (parser-generator--debug
-           (message "disallow-e-first: %s" disallow-e-first))
-          (let ((f-sets (make-hash-table :test 'equal))
-                (i 0)
-                (expanded-all nil)
-                (expanded-all-second nil))
-
-            (while (or
-                    (not expanded-all)
-                    (not expanded-all-second))
-              ;; Make one iteration after everything has been expanded
-              (when expanded-all
-                (setq
-                 expanded-all-second
-                 t))
-              (when (> i 100)
-                (error "Endless loop!"))
-              (parser-generator--debug
-               (message "i = %s" i))
+           (message "i = %s" i))
+          (let ((f-set
+                 (make-hash-table :test 'equal))
+                (distinct-lhs)
+                (distinct-lhs-p
+                 (make-hash-table :test 'equal))
+                (previous-f-set))
+            (when (> i 0)
               (setq
                expanded-all
                t)
-              (let ((f-set (make-hash-table :test 'equal)))
-
-                ;; Iterate all productions, set F_i
-                (dolist (p productions)
-                  (let ((production-lhs (car p))
-                        (production-rhs (cdr p)))
-                    (parser-generator--debug
-                     (message
-                      "Production: %s -> %s"
-                      production-lhs
-                      production-rhs))
-
-                    ;; Iterate all blocks in RHS
-                    (let ((f-p-set)
-                          (rhs-expanded-full t))
-                      (dolist (rhs-p production-rhs)
-                        (let ((rhs-string rhs-p))
-                          (let ((rhs-leading-terminals)
-                                (f-set-return
-                                 (parser-generator--f-set
-                                  rhs-string
-                                  `(
-                                    ,k
-                                    ,i
-                                    ,f-sets
-                                    ,disallow-e-first
-                                    ,production-lhs)
-                                  '((nil t 0)))))
-
-                            (parser-generator--debug
-                             (message
-                              "f-set-return: %s = %s"
-                              rhs-string
-                              f-set-return))
-
-                            (unless (nth 0 f-set-return)
-                              (let ((unexpanded-non-terminal
-                                     (nth 1 f-set-return)))
-                                (cond
-                                 ((equal
-                                   unexpanded-non-terminal
-                                   production-lhs)
-                                  (parser-generator--debug
-                                   (message
-                                    "Production '%S' unexpanded due to 
self-reference, ignore flag."
-                                    production-lhs)))
-                                 ((gethash
-                                   unexpanded-non-terminal
-                                   f-set)
-                                  (parser-generator--debug
-                                   (message
-                                    "Production '%S' is un-expanded due to 
reference to previously processed production '%S', ignore flag."
-                                    production-lhs
-                                    unexpanded-non-terminal
-                                    )))
-                                 (t
-                                  (parser-generator--debug
-                                   (message
-                                    "Expanded-all negative set because 
f-set-return '%s' is not fully expanded because '%s' is unexpanded"
-                                    f-set-return
-                                    (nth 1 f-set-return)))
-                                  (setq
-                                   rhs-expanded-full
-                                   nil)
-                                  (setq
-                                   expanded-all
-                                   nil)))))
-
-                            (setq
-                             rhs-leading-terminals
-                             (nth 2 f-set-return))
+              (setq
+               previous-f-set
+               (gethash
+                (1- i)
+                f-sets)))
 
-                            (parser-generator--debug
-                             (message
-                              "Leading %d terminals at index %s: %s -> %s = %s"
-                              k
-                              i
-                              production-lhs
-                              rhs-string
-                              rhs-leading-terminals))
-                            (parser-generator--debug
-                             (message
-                              "expanded-all: %s"
-                              expanded-all))
-
-                            (when rhs-leading-terminals
-                              (when (and
-                                     (listp rhs-leading-terminals)
-                                     (> (length rhs-leading-terminals) 0))
-                                (dolist
-                                    (rhs-leading-terminals-element
-                                     rhs-leading-terminals)
-                                  (push
-                                   rhs-leading-terminals-element
-                                   f-p-set)))))))
-
-                      ;; If we have multiple equal LHS
-                      ;; merge them
-                      (when (
-                             gethash
-                             production-lhs
-                             f-set)
-                        (let ((existing-f-set
-                               (gethash
-                                production-lhs
-                                f-set)))
-
-                          ;; If another RHS has not been fully expanded
-                          ;; mark LHS as not fully expanded
-                          (unless (nth 0 existing-f-set)
-                            (parser-generator--debug
-                             (message
-                              "Expanded-all negative set for LHS '%s' because 
a alternative RHS '%s' is not fully expanded"
-                              production-lhs
-                              existing-f-set))
-                            (setq
-                             expanded-all
-                             nil)
-                            (setq
-                             rhs-expanded-full
-                             nil))
+            ;; Iterate all productions, set F_i
+            (dolist (p productions)
+              (let ((production-lhs (car p))
+                    (production-rhs (cdr p)))
+                (parser-generator--debug
+                 (message
+                  "Production: %s -> %s"
+                  production-lhs
+                  production-rhs))
+
+                ;; Iterate all blocks in RHS
+                (dolist (rhs-p production-rhs)
+                  (let ((rhs-string rhs-p))
+                    (let ((rhs-leading-symbols
+                           (parser-generator--f-set
+                            rhs-string
+                            `(
+                              ,k
+                              ,i
+                              ,f-sets
+                              ,production-lhs)
+                            '((nil nil 0)))))
 
-                          (setq f-p-set
-                                (append
-                                 f-p-set
-                                 (nth 1 existing-f-set)))))
+                      (parser-generator--debug
+                       (message
+                        "\nrhs-leading-symbols: %S = %S"
+                        rhs-string
+                        rhs-leading-symbols))
 
-                      ;; Make set distinct
-                      (setq
-                       f-p-set
-                       (parser-generator--distinct
-                        f-p-set))
-                      (puthash
-                       production-lhs
-                       (list
-                        rhs-expanded-full
-                        (reverse f-p-set))
-                       f-set)
                       (parser-generator--debug
                        (message
-                        "F_%s%s = %s"
+                        "Leading %d symbols at index %s: %s -> %s = %s"
+                        k
                         i
                         production-lhs
-                        (gethash
-                         production-lhs
-                         f-set))))))
+                        rhs-string
+                        rhs-leading-symbols))
 
-                (puthash
-                 i
-                 f-set
-                 f-sets)
-                (setq
-                 i
-                 (+ i 1))))
+                      (when rhs-leading-symbols
+                        (if (gethash
+                             production-lhs
+                             f-set)
+                            (puthash
+                             production-lhs
+                             (append
+                              (gethash
+                               production-lhs
+                               f-set)
+                              rhs-leading-symbols)
+                             f-set)
+                          (puthash
+                           production-lhs
+                           rhs-leading-symbols
+                           f-set))
+
+                        (unless (gethash
+                                 production-lhs
+                                 distinct-lhs-p)
+                          (puthash
+                           production-lhs
+                           t
+                           distinct-lhs-p)
+                          (push
+                           production-lhs
+                           distinct-lhs))))))))
 
-            (if disallow-e-first
-                (progn
-                  (setq
-                   parser-generator--f-free-sets
+            ;; Iterate productions again
+            ;; make distinct sets and check if we found anything new
+            (dolist (production-lhs distinct-lhs)
+              (when (gethash
+                     production-lhs
+                     f-set)
+
+                ;; Make set distinct
+                (puthash
+                 production-lhs
+                 (parser-generator--distinct
+                  (gethash
+                   production-lhs
+                   f-set))
+                 f-set)
+
+                ;; Sort it for a more deterministic result
+                (puthash
+                 production-lhs
+                 (sort
+                  (parser-generator--distinct
                    (gethash
-                    (1- i)
-                    f-sets))
+                    production-lhs
+                    f-set))
+                  'parser-generator--sort-list)
+                 f-set)
+
+                ;; If this set differs from the last, keep expanding
+                (when (and
+                       expanded-all
+                       previous-f-set
+                       (not
+                        (equal
+                         (gethash
+                          production-lhs
+                          f-set)
+                         (gethash
+                          production-lhs
+                          previous-f-set))))
                   (parser-generator--debug
                    (message
-                    "E-FREE-FIRST max-index: %s, contents: %s"
+                    "F_%s%s = %S is new compared to F_%s%s = %S"
+                    i
+                    production-lhs
+                    (gethash
+                     production-lhs
+                     f-set)
                     (1- i)
-                    parser-generator--f-free-sets)))
-              (setq
-               parser-generator--f-sets
-               (gethash
-                (1- i)
-                f-sets))
-              (parser-generator--debug
-               (message
-                "FIRST max-index: %s, contents: %s"
-                (1- i)
-                parser-generator--f-sets)))))))
+                    production-lhs
+                    (gethash
+                     production-lhs
+                     previous-f-set)))
+                  (setq
+                   expanded-all
+                   nil))))
+
+            (puthash
+             i
+             f-set
+             f-sets)
+            (parser-generator--debug
+             (message
+              "F_%s = %s"
+              i
+              f-set))
+            (setq
+             i
+             (1+ i))))
+
+        (setq
+         parser-generator--f-sets
+         (gethash
+          (1- i)
+          f-sets))
+        (parser-generator--debug
+         (message
+          "FIRST max-index: %s, contents: %s"
+          (1- i)
+          parser-generator--f-sets))))
     (parser-generator--debug
      (message "Generated F-sets"))))
 
@@ -1319,54 +1275,59 @@
   (unless (listp input-tape)
     (setq input-tape (list input-tape)))
   (parser-generator--debug
-   (message "(parser-generator--f-set)")
+   (message "\n(parser-generator--f-set)")
    (message "input-tape: %s" input-tape)
-   (message "stack: %s" stack))
+   (message "stack: %s" stack)
+   (message "state: %S" state))
 
   (let ((f-set)
         (input-tape-length (length input-tape))
         (k (nth 0 state))
         (i (nth 1 state))
-        (f-sets (nth 2 state))
-        (disallow-e-first (nth 3 state))
-        (lhs (nth 4 state))
-        (expanded-all t)
-        (unexpanded-non-terminal nil))
+        (f-sets (nth 2 state)))
     (parser-generator--debug
-     (message "disallow-3-first: %s" disallow-e-first)
-     (message "input-tape-length: %s" input-tape-length)
+     (message
+      "input-tape-length: %s"
+      input-tape-length)
      (message "k: %s" k)
      (message "i: %s" i))
 
     (while stack
       (let ((stack-symbol (pop stack)))
         (parser-generator--debug
-         (message "Stack-symbol: %s" stack-symbol))
-        (let ((leading-terminals (nth 0 stack-symbol))
-              (all-leading-terminals-p (nth 1 stack-symbol))
+         (message
+          "Stack-symbol: %s"
+          stack-symbol))
+        (let ((leading-symbols (nth 0 stack-symbol))
+              (leading-terminals (nth 1 stack-symbol))
               (input-tape-index (nth 2 stack-symbol)))
           (parser-generator--debug
-           (message "leading-terminals 0: %s" leading-terminals)
-           (message "all-leading-terminals-p: %s" all-leading-terminals-p)
-           (message "input-tape-index: %s" input-tape-index))
-
-          (when (and
-                 all-leading-terminals-p
-                 leading-terminals
-                 (parser-generator--valid-e-p
-                  (nth (1- (length leading-terminals)) leading-terminals)))
-            (message "Not leading terminals: %s" leading-terminals)
-            (setq all-leading-terminals-p nil))
-
-          (let ((leading-terminals-count (length leading-terminals)))
+           (message
+            "leading-symbols 0: %s"
+            leading-symbols)
+           (message
+            "leading-terminals 0: %s"
+            leading-terminals)
+           (message
+            "input-tape-index: %s"
+            input-tape-index))
+
+          (let ((leading-terminals-count
+                 (length leading-terminals))
+                (leading-symbols-count
+                 (length leading-symbols))
+                (keep-iterating t))
             (parser-generator--debug
-             (message "leading-terminals-count: %s" leading-terminals-count))
+             (message
+              "leading-terminals-count: %s"
+              leading-terminals-count))
 
             (while (and
+                    keep-iterating
                     (< input-tape-index input-tape-length)
-                    (< leading-terminals-count k)
-                    all-leading-terminals-p)
-              (let ((rhs-element (nth input-tape-index input-tape))
+                    (< leading-terminals-count k))
+              (let ((rhs-element
+                     (nth input-tape-index input-tape))
                     (rhs-type))
                 (parser-generator--debug
                  (message
@@ -1381,7 +1342,9 @@
                   (setq rhs-type 'E-IDENTIFIER))
                  ((parser-generator--valid-terminal-p rhs-element)
                   (setq rhs-type 'TERMINAL))
-                 (t (error (format "Invalid symbol %s" rhs-element))))
+                 ((parser-generator--valid-eof-p rhs-element)
+                  (setq rhs-type 'EOF))
+                 (t (error (format "Invalid symbol %s!" rhs-element))))
                 (parser-generator--debug
                  (message
                   "rhs-type: %s"
@@ -1391,9 +1354,7 @@
 
                  ((equal rhs-type 'NON-TERMINAL)
                   (if (> i 0)
-                      (let ((sub-terminal-sets)
-                            (sub-terminal-expanded)
-                            (sub-terminal-data
+                      (let ((sub-terminal-sets
                              (gethash
                               (list rhs-element)
                               (gethash
@@ -1401,36 +1362,9 @@
                                f-sets))))
                         (parser-generator--debug
                          (message
-                          "sub-terminal-data: %s = %s"
-                          rhs-element
-                          sub-terminal-data))
-                        
-                        (setq
-                         sub-terminal-expanded
-                         (nth 0 sub-terminal-data))
-                        (setq
-                         sub-terminal-sets
-                         (nth 1 sub-terminal-data))
-
-                        ;; When sub-set has not been fully expanded mark this 
set
-                        ;; as not fully expanded either
-                        (when (and
-                               sub-terminal-data
-                               (not sub-terminal-expanded))
-                          (parser-generator--debug
-                           (message
-                            "Expanded-all negative set for '%s' because 
sub-terminals of '%s' has not been fully expanded"
-                            lhs
-                            rhs-element))
-                          (setq
-                           unexpanded-non-terminal
-                           (list rhs-element))
-                          (setq
-                           all-leading-terminals-p
-                           nil)
-                          (setq
-                           expanded-all
-                           nil))
+                          "sub-terminal-sets: %s = %s"
+                          (list rhs-element)
+                          sub-terminal-sets))
 
                         (if sub-terminal-sets
                             (progn
@@ -1441,148 +1375,89 @@
                                 rhs-element
                                 sub-terminal-sets
                                 (length sub-terminal-sets)))
-                              (let ((sub-terminal-set (car sub-terminal-sets)))
-
-                                (unless (= (length sub-terminal-sets) 1)
-
-                                  ;; Should branch off here, each unique 
permutation should be included in set
-                                  ;; Follow the first alternative in this 
scope but follow the rest in separate scopes
-                                  (let ((sub-terminal-index 0))
-                                    (dolist (sub-terminal-alternative-set 
sub-terminal-sets)
-                                      (unless (= sub-terminal-index 0)
-                                        (let 
((alternative-all-leading-terminals-p all-leading-terminals-p))
-                                          (parser-generator--debug
-                                           (message 
"Sub-terminal-alternative-set: %s" sub-terminal-alternative-set))
-
-                                          ;; When sub-set only contains the e 
identifier
-                                          (if (parser-generator--valid-e-p
-                                               (car 
sub-terminal-alternative-set))
-                                              (progn
-                                                (parser-generator--debug
-                                                 (message "alternative-set is 
the e identifier"))
-
-                                                ;; Branch off here in two 
separate tracks, one with the e-identifier appended and one without
-                                                (if disallow-e-first
-                                                    (progn
-                                                      (when (and
-                                                             
all-leading-terminals-p
-                                                             (> 
leading-terminals-count 0))
-                                                        (let ((branch `(
-                                                                        
,leading-terminals
-                                                                        
,all-leading-terminals-p
-                                                                        ,(1+ 
input-tape-index))))
-                                                          
(parser-generator--debug (message "branched off 2: %s" branch))
-                                                          ;; Branch off here 
with a separate track where this e-identifier is ignored
-                                                          (push branch 
stack))))
-
-                                                  (when all-leading-terminals-p
-                                                    (let ((branch
-                                                           `(
-                                                             ,leading-terminals
-                                                             
,all-leading-terminals-p
-                                                             ,(1+ 
input-tape-index))))
-                                                      (parser-generator--debug 
(message "branched off 1: %s" branch))
-                                                      ;; Branch off here with 
a separate track where this e-identifier is ignored
-                                                      (push branch stack))))
-
-                                                (when all-leading-terminals-p
-                                                  (let 
((alternative-leading-terminals
-                                                         (append
-                                                          leading-terminals
-                                                          (list 
parser-generator--e-identifier)))
-                                                        
(alternative-all-leading-terminals-p nil))
-                                                    (let ((branch
-                                                           `(
-                                                             
,alternative-leading-terminals
-                                                             
,alternative-all-leading-terminals-p
-                                                             ,(1+ 
input-tape-index))))
-                                                      (parser-generator--debug 
(message "branched off 0: %s" branch))
-                                                      ;; Branch off here with 
a separate track where this e-identifier is ignored
-                                                      (push branch stack)))))
-
-                                            (let ((sub-terminal-index 0)
-                                                  (sub-terminal-length (length 
sub-terminal-alternative-set))
-                                                  (sub-terminal-leading-p 
alternative-all-leading-terminals-p)
-                                                  (sub-terminal)
-                                                  (sub-terminals (reverse 
leading-terminals)))
-                                              (while (and
-                                                      sub-terminal-leading-p
-                                                      (< sub-terminal-index 
sub-terminal-length)
-                                                      (< (length 
sub-terminals) k))
-                                                (setq sub-terminal (nth 
sub-terminal-index sub-terminal-alternative-set))
-                                                (when 
(parser-generator--valid-e-p sub-terminal)
-                                                  (setq sub-terminal-leading-p 
nil))
-                                                (push sub-terminal 
sub-terminals)
-                                                (setq sub-terminal-index (1+ 
sub-terminal-index)))
-                                              (setq sub-terminals (reverse 
sub-terminals))
-                                              ;; (message "sub-terminals: %s 
from %s (%s) + %s (%s)" sub-terminals leading-terminals (length 
leading-terminals) sub-terminal-alternative-set (length 
sub-terminal-alternative-set))
-                                              (let ((branch
-                                                     `(
-                                                       ,sub-terminals
-                                                       ,sub-terminal-leading-p
-                                                       ,(1+ 
input-tape-index))))
-                                                (parser-generator--debug 
(message "branched off 3: %s" branch))
-                                                (push branch stack))))))
-                                      (setq sub-terminal-index (1+ 
sub-terminal-index)))))
-
-                                (parser-generator--debug
-                                 (message "Sub-terminal-set: %s" 
sub-terminal-set))
-
-                                ;; When sub-set only contains the e identifier
-                                (if (parser-generator--valid-e-p
-                                     (car sub-terminal-set))
-                                    (progn
+
+                              ;; Should branch off here, each unique 
permutation should be included in set
+                              ;; Follow the first alternative in this scope 
but follow the rest in separate scopes
+                              (let ((sub-symbols-set-index 0)
+                                    (original-leading-symbols
+                                     leading-symbols)
+                                    (original-leading-terminals
+                                     leading-terminals))
+                                (dolist (sub-symbol-alternative-set 
sub-terminal-sets)
+                                  (parser-generator--debug
+                                   (message
+                                    "sub-symbol-alternative-set: %s"
+                                    sub-symbol-alternative-set))
+
+                                  (let ((sub-symbol-index 0)
+                                        (sub-symbol-length
+                                         (length
+                                          sub-symbol-alternative-set))
+                                        (sub-symbol)
+                                        (sub-symbols
+                                         (reverse original-leading-symbols))
+                                        (sub-terminals
+                                         (reverse original-leading-terminals)))
+                                    (while (and
+                                            (< sub-symbol-index 
sub-symbol-length)
+                                            (< (length sub-terminals) k))
+                                      (setq
+                                       sub-symbol
+                                       (nth
+                                        sub-symbol-index
+                                        sub-symbol-alternative-set))
                                       (parser-generator--debug
-                                       (message "sub-terminal-set is the e 
identifier"))
-
-                                      ;; Branch off here in two separate 
tracks, one with the e-identifier appended and one without
-                                      (if disallow-e-first
-                                          (progn
-                                            (when (and
-                                                   all-leading-terminals-p
-                                                   (> leading-terminals-count 
0))
-                                              (let ((branch
-                                                     `(
-                                                       ,leading-terminals
-                                                       ,all-leading-terminals-p
-                                                       ,(1+ 
input-tape-index))))
-                                                ;; Branch off here with a 
separate track where this e-identifier is ignored
-                                                (parser-generator--debug 
(message "branched off 4: %s" branch))
-                                                (push branch stack)))
-
-                                            (setq all-leading-terminals-p nil))
-
-                                        ;; Add e-identifier to leading 
terminals when
-                                        ;; we have not found any leading 
terminals
-                                        ;; and we are at the last symbol in 
input-tape
-
-                                        (when all-leading-terminals-p
-                                          (let ((branch
-                                                 `(
-                                                   ,leading-terminals
-                                                   ,all-leading-terminals-p
-                                                   ,(1+ input-tape-index))))
-                                            ;; Branch off here with a separate 
track where this e-identifier is ignored
-                                            (parser-generator--debug (message 
"branched off 5: %s" branch))
-                                            (push branch stack)))
-
-                                        (parser-generator--debug (message 
"leading-terminals-1: %s" leading-terminals))
-                                        (setq leading-terminals 
(parser-generator--merge-max-terminals leading-terminals sub-terminal-set k))
-                                        (parser-generator--debug (message 
"leading-terminals-2: %s" leading-terminals))
-                                        (setq leading-terminals-count (length 
leading-terminals))
-                                        (setq all-leading-terminals-p nil)))
-
-                                  (parser-generator--debug (message 
"leading-terminals-3: %s" leading-terminals))
-                                  (setq leading-terminals 
(parser-generator--merge-max-terminals leading-terminals sub-terminal-set k))
-                                  (parser-generator--debug (message 
"leading-terminals-4: %s" leading-terminals))
-                                  (setq leading-terminals-count (length 
leading-terminals))
-
-                                  (when
-                                      (parser-generator--valid-e-p
-                                       (nth (1- (length leading-terminals)) 
leading-terminals))
-                                    (parser-generator--debug
-                                     (message "after merge leading-terminals 
end in e-identifier"))
-                                    (setq all-leading-terminals-p nil)))))
+                                       (message
+                                        "sub-symbol: %S"
+                                        sub-symbol))
+                                      (push
+                                       sub-symbol
+                                       sub-symbols)
+                                      (unless (parser-generator--valid-e-p 
sub-symbol)
+                                        (push
+                                         sub-symbol
+                                         sub-terminals))
+                                      (setq
+                                       sub-symbol-index
+                                       (1+ sub-symbol-index)))
+                                    (setq
+                                     sub-symbols
+                                     (reverse sub-symbols))
+                                    (setq
+                                     sub-terminals
+                                     (reverse sub-terminals))
+
+                                    ;; The first iteration does not branch off
+                                    (if (= sub-symbols-set-index 0)
+                                        (progn
+                                          (setq
+                                           leading-symbols
+                                           sub-symbols)
+                                          (setq
+                                           leading-symbols-count
+                                           (length leading-symbols))
+                                          (setq
+                                           leading-terminals
+                                           sub-terminals)
+                                          (setq
+                                           leading-terminals-count
+                                           (length leading-terminals)))
+                                      (let (
+                                            (branch
+                                             `(
+                                               ,sub-symbols
+                                               ,sub-terminals
+                                               ,(1+ input-tape-index))))
+                                        (parser-generator--debug
+                                         (message
+                                          "branched off 3: %s"
+                                          branch))
+                                        (push
+                                         branch
+                                         stack))))
+                                  (setq
+                                   sub-symbols-set-index
+                                   (1+ sub-symbols-set-index)))))
 
                           (parser-generator--debug
                            (message
@@ -1590,344 +1465,456 @@
                             rhs-element
                             (1- i)))
                           (setq
-                           unexpanded-non-terminal
-                           (list rhs-element))
-                          (setq
-                           all-leading-terminals-p
+                           keep-iterating
                            nil)))
-
-                    (parser-generator--debug
-                     (message
-                      "Expanded-all negative set for '%s' because symbol '%s' 
is a non-terminal and i is zero"
-                      lhs
-                      rhs-element))
-                    (setq
-                     expanded-all
-                     nil)
-                    (setq
-                     unexpanded-non-terminal
-                     (list rhs-element))
                     (setq
-                     all-leading-terminals-p
+                     keep-iterating
                      nil)))
 
                  ((equal rhs-type 'E-IDENTIFIER)
-                  (if disallow-e-first
-                      (progn
-                        (when (and
-                               all-leading-terminals-p
-                               (> leading-terminals-count 0))
-                          ;; Branch off here with a separate track where this 
e-identifier is ignored
-                          (let ((branch
-                                 `(
-                                   ,leading-terminals
-                                   ,all-leading-terminals-p
-                                   ,(1+ input-tape-index))))
-                            (parser-generator--debug (message "branched off 6: 
%s" branch))
-                            (push branch stack)))
-
-                        (setq all-leading-terminals-p nil))
-                    ;; Add e-identifier to leading terminals when
-                    ;; we have not found any leading terminals
-                    ;; and we are at the last symbol in input-tape
-
-                    (when all-leading-terminals-p
-                      ;; Branch off here with a separate track where this 
e-identifier is ignored
-                      (let ((branch
-                             `(
-                               ,leading-terminals
-                               ,all-leading-terminals-p
-                               ,(1+ input-tape-index))))
-                        (parser-generator--debug (message "branched off 7: %s" 
branch))
-                        (push branch stack)))
-
-                    (setq leading-terminals (append leading-terminals 
rhs-element))
-                    (setq leading-terminals-count (1+ leading-terminals-count))
-                    (setq all-leading-terminals-p nil)))
-
-                 ((equal rhs-type 'TERMINAL)
-                  (setq leading-terminals (append leading-terminals (list 
rhs-element)))
-                  (setq leading-terminals-count (1+ leading-terminals-count)))
-
-                 ))
-              (setq input-tape-index (1+ input-tape-index)))
-
-            (when (> leading-terminals-count 0)
-              (unless (listp leading-terminals)
-                (setq leading-terminals (list leading-terminals)))
+                  (setq
+                   leading-symbols
+                   (append
+                    leading-symbols
+                    rhs-element))
+                  (setq
+                   leading-symbols-count
+                   (1+ leading-symbols-count)))
+
+                 ((or
+                   (equal rhs-type 'TERMINAL)
+                   (equal rhs-type 'EOF))
+                  (setq
+                   leading-symbols
+                   (append
+                    leading-symbols
+                    (list rhs-element)))
+                  (setq
+                   leading-symbols-count
+                   (1+ leading-symbols-count))
+                  (setq
+                   leading-terminals
+                   (append
+                    leading-terminals
+                    (list rhs-element)))
+                  (setq
+                   leading-terminals-count
+                   (1+ leading-terminals-count)))))
+
+              (setq
+               input-tape-index
+               (1+ input-tape-index)))
+
+            (when (> leading-symbols-count 0)
+              (unless (listp leading-symbols)
+                (setq
+                 leading-symbols
+                 (list leading-symbols)))
               (parser-generator--debug
+               (message "leading-symbols 5: %s" leading-symbols)
                (message "leading-terminals 5: %s" leading-terminals))
               (push
-               leading-terminals
+               leading-symbols
                f-set))))))
-    (list
-     expanded-all
-     unexpanded-non-terminal
-     f-set)))
+    f-set))
 
 ;; Algorithm 5.5, p. 357
 (defun parser-generator--first
-    (
-     β
-     &optional
-     disallow-e-first
-     ignore-validation
-     skip-sorting)
+    (β &optional disallow-e-first ignore-validation skip-sorting)
   "For sentential-form Β, calculate first terminals, optionally 
DISALLOW-E-FIRST, IGNORE-VALIDATION and SKIP-SORTING."
-  (let ((hash-key
-         (format
-          "%S-%s"
-          β
-          disallow-e-first)))
-    (unless
-        (gethash
-         hash-key
-         parser-generator--table-firsts)
-      (unless (listp β)
-        (setq β (list β)))
+
+  ;; Make sure we are dealing with a list of symbols
+  (unless (listp β)
+    (setq β (list β)))
+
+  (parser-generator--debug
+   (if disallow-e-first
+       (message
+        "\nE-FREE-FIRST%S"
+        β)
+     (message
+      "\nFIRST%S"
+      β)))
+
+  ;; Cache first calculation
+  (let ((hash-key (format "%S-%s" β disallow-e-first)))
+    (unless (gethash
+             hash-key
+             parser-generator--table-firsts)
+
+      ;; Perform optional validation of inpuit
       (unless (or
                ignore-validation
                (parser-generator--valid-sentential-form-p β))
         (error "Invalid sentential form β! %s" β))
-      (let ((k
-             (max
-              1
-              parser-generator--look-ahead-number)))
-
-        ;; Generate F-sets only once per grammar
-        (parser-generator--generate-f-sets)
-
-        (let ((first-list nil)
-              (first-items (make-hash-table :test 'equal)))
-          ;; Iterate each symbol in β using a PDA algorithm
-          (let ((input-tape β)
-                (input-tape-length (length β))
-                (stack '((0 0 nil))))
-            (while stack
-              (let ((stack-topmost (pop stack)))
+
+      ;; Generate F-sets only once per grammar
+      (parser-generator--generate-f-sets)
+
+      ;; Algorithm
+      ;; 1. Iterate each symbol of input and expand into list of lists of 
terminals and the e-identifier
+      ;;     if input symbol is a terminal, the e-identifier or the 
EOF-identifier push it to each expanded list
+      ;;     if input symbol is a non-terminal, expand it and push each 
possible expansion onto each expanded list
+      ;; 2. Reverse each expanded list and place each list on a stack of 
unprocessed lists each with a input-index to zero
+      ;; 3. Process each unprocessed list and expand into a list of lists of 
terminals and the e-identifier
+      ;;        pop a unprocessed list from the stack of unprocessed lists
+      ;;            create a new empty list
+      ;;            set skip-flag to false
+      ;;            set loop-flag to true
+      ;;            loop while index is below length and skip-flag is false 
and loop-flag is true
+      ;;                if a list starts with the e-identifier and it is 
disallowed, set skip-flag to true to stop iterating
+      ;;                if a symbol on a list is a terminal push it onto the 
new list
+      ;;                if a symbol on a the list is the e-identifier
+      ;;                    push a copy of the new list on the unprocessed 
stack but increase it's input-index by one
+      ;;                    push the e-identifier onto the new list and set 
loop-flag to false to stop iterating
+      ;;                increase index with one
+      ;;            if skip-flag is false place new list onto the list of 
processed lists
+      ;; 4. Reverse each processed list
+      ;; 5. Return processed lists
+
+      (let ((expanded-lists nil)
+            (processed-lists))
+
+        ;; 1. Iterate each symbol of input and expand into list of lists of 
terminals and the e-identifier
+        (let ((input-tape β)
+              (input-tape-index 0)
+              (input-tape-length (length β))
+              (input-symbol))
+
+          (parser-generator--debug
+           (message
+            "\nExpanding symbols.. %S"
+            input-tape)
+           (message
+            "Length: %S"
+            input-tape-length))
+
+          (while (< input-tape-index input-tape-length)
+            (setq
+             input-symbol
+             (nth input-tape-index input-tape))
+            (parser-generator--debug
+             (message
+              "\ninput-symbol: %S"
+              input-symbol))
+            (cond
+
+             ;; if input symbol is a non-terminal, expand it and push each 
possible expansion onto each expanded list
+             ((parser-generator--valid-non-terminal-p input-symbol)
+              (parser-generator--debug
+               (message
+                "input-symbol is non-terminal"))
+              (let ((expanded-non-terminal-lists
+                     (gethash
+                      (list input-symbol)
+                      parser-generator--f-sets)))
+                (let ((expanded-list-index)
+                      (expanded-list-count
+                       (length expanded-lists)))
+                  (parser-generator--debug
+                   (message
+                    "non-terminal expands into: %S with count: %d"
+                    expanded-non-terminal-lists
+                    (length expanded-non-terminal-lists)))
+
+                  (if (= expanded-list-count 0)
+                      (dolist (expanded-non-terminal-list 
expanded-non-terminal-lists)
+                        (push
+                         (reverse expanded-non-terminal-list)
+                         expanded-lists))
+
+                    (let ((new-expanded-lists))
+                      (dolist (expanded-non-terminal-list 
expanded-non-terminal-lists)
+                        (setq expanded-list-index 0)
+                        (let ((reversed-expanded-non-terminal-list
+                               (reverse expanded-non-terminal-list)))
+                          (while (< expanded-list-index expanded-list-count)
+                            (push
+                             (append
+                              reversed-expanded-non-terminal-list
+                              (nth expanded-list-index expanded-lists))
+                             new-expanded-lists)
+                            (setq
+                             expanded-list-index
+                             (1+ expanded-list-index)))))
+                      (setq
+                       expanded-lists
+                       new-expanded-lists)))
+                  (parser-generator--debug
+                   (message
+                    "expanded-lists after adding: %S"
+                    expanded-lists)))))
+
+             ;; if input symbol is a terminal
+             ;; or the e-identifier
+             ;; or the eof-identifier
+             ;; push it to each expanded list
+             ((or
+               (parser-generator--valid-e-p input-symbol)
+               (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"))
+              (let ((expanded-list-index 0)
+                    (expanded-list-count
+                     (length expanded-lists)))
+                (if (= expanded-list-count 0)
+                    (setq
+                     expanded-lists
+                     (list (list input-symbol)))
+                  (while (< expanded-list-index expanded-list-count)
+                    (setf
+                     (nth expanded-list-index expanded-lists)
+                     (append
+                      (list input-symbol)
+                      (nth expanded-list-index expanded-lists)))
+                    (setq
+                     expanded-list-index
+                     (1+ expanded-list-index))))
                 (parser-generator--debug
                  (message
-                  "stack-topmost: %s"
-                  stack-topmost))
-                (let ((input-tape-index (car stack-topmost))
-                      (first-length (car (cdr stack-topmost)))
-                      (first (car (cdr (cdr stack-topmost))))
-                      (keep-looking t))
-                  (while (and
-                          keep-looking
-                          (< input-tape-index input-tape-length)
-                          (< first-length k))
-                    (let ((symbol (nth input-tape-index input-tape)))
-                      (parser-generator--debug
-                       (message
-                        "symbol index: %s from %s is: %s"
-                        input-tape-index
-                        input-tape symbol))
-                      (cond
-
-                       ((parser-generator--valid-e-p symbol)
+                  "expanded-lists after adding: %S"
+                  expanded-lists)))))
+            (setq
+             input-tape-index
+             (1+ input-tape-index))))
 
-                        ;; When there a symbols left on stack, make 
alternative trail by skipping this symbol
-                        (unless (or
-                                 disallow-e-first
-                                 (= input-tape-index (1- input-tape-length)))
-                          (parser-generator--debug
-                           (message
-                            "Pushed alternative trail to stack since symbol is 
e-identifier: %s"
-                            `(,(1+ input-tape-index) ,first-length ,first)))
-                          (push
-                           `(,(1+ input-tape-index) ,first-length ,first)
-                           stack))
+        (if expanded-lists
+            (let ((unprocessed-lists)
+                  (k (max 1 parser-generator--look-ahead-number))
+                  (distinct-processed-lists (make-hash-table :test 'equal)))
+              (parser-generator--debug
+               (message
+                "\nExpanded symbols: %S (in reverse order)"
+                expanded-lists))
+
+              ;; 2. Place each expanded list on a stack of unprocessed lists
+              ;; each with a input-index to zero and an empty processed list
+              (let ((expanded-list-index 0)
+                    (expanded-list-count
+                     (length expanded-lists)))
+                (while (< expanded-list-index expanded-list-count)
+                  (push
+                   (list
+                    (reverse (nth expanded-list-index expanded-lists))
+                    0
+                    nil)
+                   unprocessed-lists)
+                  (setq
+                   expanded-list-index
+                   (1+ expanded-list-index))))
+
+              ;; 3. Process each unprocessed list and expand into a list of 
lists of terminals and the e-identifier
+              (let ((unprocessed-data)
+                    (unprocessed-list)
+                    (unprocessed-list-length)
+                    (unprocessed-list-index)
+                    (processed-list))
+                (while unprocessed-lists
+                  (setq
+                   unprocessed-data
+                   (pop unprocessed-lists))
+                  (setq
+                   unprocessed-list
+                   (nth 0 unprocessed-data))
+                  (setq
+                   unprocessed-list-index
+                   (nth 1 unprocessed-data))
+                  (setq
+                   unprocessed-list-length
+                   (length unprocessed-list))
+                  (setq
+                   processed-list
+                   (nth 2 unprocessed-data))
+                  (parser-generator--debug
+                   (message
+                    "\nunprocessed-list: %S"
+                    unprocessed-list)
+                   (message
+                    "unprocessed-list-index: %S"
+                    unprocessed-list-index)
+                   (message
+                    "unprocessed-list-length: %S"
+                    unprocessed-list-length))
+
+                  (let ((skip-flag)
+                        (loop-flag t))
+                    (while (and
+                            (not skip-flag)
+                            loop-flag
+                            (< unprocessed-list-index unprocessed-list-length))
+                      (let ((unprocessed-list-symbol
+                             (nth unprocessed-list-index unprocessed-list)))
+
+                        ;; if a list starts with the e-identifier and it is 
disallowed
+                        ;; set skip-flag to true to stop iterating
+                        (if (and
+                             disallow-e-first
+                             (= unprocessed-list-index 0)
+                             (parser-generator--valid-e-p
+                              unprocessed-list-symbol))
+                            (progn
+                              (setq
+                               skip-flag
+                               t)
+                              (parser-generator--debug
+                               (message
+                                "Unprocessed list starts with e-identifier, 
skipping")))
 
-                        (if disallow-e-first
-                            (when (> first-length 0)
-                              (setq first (append first (list symbol)))
-                              (setq first-length (1+ first-length)))
-                          (setq first (append first (list symbol)))
-                          (setq first-length (1+ first-length)))
+                          (cond
 
-                        (setq keep-looking nil))
+                           ;; if a symbol on a the list is the e-identifier
+                           ((parser-generator--valid-e-p
+                             unprocessed-list-symbol)
 
-                       ((parser-generator--valid-eof-p symbol)
-                        (setq first (append first (list symbol)))
-                        (setq first-length (1+ first-length)))
+                            ;; push a copy of the new list on the unprocessed 
stack but increase it's input-index by one
+                            (let ((unprocessed-branch
+                                   (list
+                                    unprocessed-list
+                                    (1+ unprocessed-list-index)
+                                    processed-list)))
+                              (parser-generator--debug
+                               (message
+                                "Pushed unprocessed-branch to 
unprocessed-lists: %S"
+                                unprocessed-branch))
+                              (push
+                               unprocessed-branch
+                               unprocessed-lists))
 
-                       ((parser-generator--valid-terminal-p symbol)
-                        (setq first (append first (list symbol)))
-                        (setq first-length (1+ first-length)))
+                            (parser-generator--debug
+                             (message
+                              "Added e-identifier to processed list: %S"
+                              processed-list))
+                            (push
+                             unprocessed-list-symbol
+                             processed-list)
+                            (setq
+                             loop-flag
+                             nil))
 
-                       ((parser-generator--valid-non-terminal-p symbol)
-                        (parser-generator--debug
-                         (message "non-terminal symbol: %s" symbol))
-                        (setq
-                         symbol
-                         (list symbol))
-                        (parser-generator--debug
-                         (message "non-terminal symbol production: %s" symbol))
-                        (let ((symbol-f-set))
-
-                          ;; Load the pre-generated F-set
-                          ;; if it's the first symbol and we are using
-                          ;; E-FREE-FIRST then use separate hash-table
-                          (if (and
-                               disallow-e-first
-                               (= first-length 0))
-                              (progn
-                                (parser-generator--debug
-                                 (message
-                                  "gethash: %s"
-                                  (gethash
-                                   symbol
-                                   parser-generator--f-free-sets)))
-                                (setq
-                                 symbol-f-set
-                                 (nth
-                                  1
-                                  (gethash
-                                   symbol
-                                   parser-generator--f-free-sets))))
+                           (t
+                            (push
+                             unprocessed-list-symbol
+                             processed-list)
                             (parser-generator--debug
                              (message
-                              "gethash: %s"
-                              (gethash
-                               symbol
-                               parser-generator--f-sets)))
+                              "Added terminal %S to processed list: %S"
+                              unprocessed-list-symbol
+                              processed-list)))))
+
+                        (setq
+                         unprocessed-list-index
+                         (1+ unprocessed-list-index))))
+
+                    ;; if skip-flag is false place reversed new list onto the 
list of processed lists
+                    (if skip-flag
+                        (progn
+                          (parser-generator--debug
+                           (message
+                            "Skip flag is set, ignoring resulted list: %S with 
length: %d"
+                            processed-list
+                            (length processed-list))))
+
+                      (parser-generator--debug
+                       (message
+                        "Skip flag is not set, proceeding with resulted list: 
%S with length: %d"
+                        processed-list
+                        (length processed-list)))
+
+                      ;; If length of a set is below K fill it up with 
e-identifiers
+                      (when (< (length processed-list) k)
+                        (let ((missing-symbol-count
+                               (- k (length processed-list)))
+                              (missing-symbol-index 0))
+                          (while (< missing-symbol-index missing-symbol-count)
+                            (push
+                             parser-generator--e-identifier
+                             processed-list)
                             (setq
-                             symbol-f-set
-                             (nth
-                              1
-                              (gethash
-                               symbol
-                               parser-generator--f-sets))))
+                             missing-symbol-index
+                             (1+ missing-symbol-index)))
                           (parser-generator--debug
                            (message
-                            "symbol-f-set: %s"
-                            symbol-f-set))
-
-                          (if (and
-                               (not symbol-f-set)
-                               disallow-e-first
-                               (= first-length 0))
-                              (progn
-                                (parser-generator--debug
-                                 (message
-                                  "stopped looking since non-terminal starts 
with e-identifier: %s"
-                                  symbol-f-set))
-                                (setq
-                                 keep-looking
-                                 nil))
-
-                            ;; Handle this scenario here were a non-terminal 
can result in different FIRST sets
-                            (let ((symbol-f-set-index 0)
-                                  (symbol-f-set-length
-                                   (length symbol-f-set))
-                                  (found-e-trail)
-                                  (e-trail-is-viable-p
-                                   (< input-tape-index (1- input-tape-length)))
-                                  (original-first first)
-                                  (original-first-length first-length))
-                              (while (< symbol-f-set-index symbol-f-set-length)
-                                (let ((symbol-f-set-element (nth 
symbol-f-set-index symbol-f-set)))
-                                  (let ((alternative-first-length
-                                         (+ original-first-length (length 
symbol-f-set-element)))
-                                        (alternative-first
-                                         (append original-first 
symbol-f-set-element))
-                                        (alternative-tape-index
-                                         (1+ input-tape-index)))
-                                    (parser-generator--debug
-                                     (message
-                                      "alternative-first: %s"
-                                      alternative-first))
-
-                                    ;; When the e-identifier is an alternative 
trail
-                                    ;; and there a symbols left on stack
-                                    ;; make alternative trail by skipping this 
symbol
-                                    ;; but only if there are more symbols in 
the input tape
-                                    (when (and
-                                           e-trail-is-viable-p
-                                           (not found-e-trail)
-                                           (or
-                                            (not disallow-e-first)
-                                            (> original-first-length 0))
-                                           (parser-generator--valid-e-p
-                                            (car alternative-first)))
-                                      (push
-                                       `(,(1+ input-tape-index) 
,original-first-length ,original-first)
-                                       stack)
-                                      (parser-generator--debug
-                                       (message
-                                        "Pushed alternative trail from 
non-terminal expansion to stack since first symbol is the e-identifier: %s"
-                                        `(,(1+ input-tape-index) 
,original-first-length ,original-first)))
-                                      (setq
-                                       found-e-trail
-                                       t))
+                            "Added %d trailing e-identifiers to set"
+                            missing-symbol-count))))
+
+                      (when (> (length processed-list) k)
+                        (let ((obsolete-symbol-count
+                               (- (length processed-list) k))
+                              (obsolete-symbol-index 0))
+                          (while (< obsolete-symbol-index 
obsolete-symbol-count)
+                            (pop
+                             processed-list)
+                            (setq
+                             obsolete-symbol-index
+                             (1+ obsolete-symbol-index)))
+                          (parser-generator--debug
+                           (message
+                            "Stripped away %d trailing symbols from set"
+                            obsolete-symbol-count))))
 
-                                    (if (= symbol-f-set-index 0)
-                                        (progn
-                                          (setq
-                                           first-length
-                                           (+ original-first-length (length 
alternative-first)))
-                                          (setq
-                                           first
-                                           (append original-first 
alternative-first)))
-                                      (push
-                                       `(
-                                         ,alternative-tape-index
-                                         ,alternative-first-length
-                                         ,alternative-first)
-                                       stack))))
-                                (setq
-                                 symbol-f-set-index
-                                 (1+ symbol-f-set-index)))))))))
-                    (setq
-                     input-tape-index
-                     (1+ input-tape-index)))
-                  (when (> first-length 0)
-
-                    ;; If length exceeds k, strip trailing symbols
-                    (when (> (length first) k)
-                      (setq first (reverse first))
-                      (while (> (length first) k)
-                        (pop first))
-                      (setq first (reverse first)))
-
-                    ;; When length of terminals list is below K
-                    ;; fill up with e-identifiers
-                    (when (and
-                           (< (length first) k))
-                      ;; (message "first-before-fill: %s" first)
-                      (setq first (reverse first))
-                      (while (< (length first) k)
-                        (push parser-generator--e-identifier first))
-                      (setq first (reverse first))
-                      ;; (message "first-after-fill: %s" first)
-                      )
-                    (unless
-                        (gethash
-                         first
-                         first-items)
                       (parser-generator--debug
                        (message
-                        "push to first-list: %s to %s"
-                        first
-                        first-list))
-                      (puthash
-                       first
-                       t
-                       first-items)
-                      (push
-                       first
-                       first-list)))))))
-          (unless skip-sorting
-            (setq
-             first-list
-             (sort
-              first-list
-              'parser-generator--sort-list)))
-          (puthash
-           hash-key
-           first-list
-           parser-generator--table-firsts))))
+                        "processed-list: %S"
+                        processed-list))
+
+                      ;; Reverse list
+                      (setq
+                       processed-list
+                       (reverse
+                        processed-list))
+
+                      ;; Make sure only distinct sets are added to list
+                      (let ((processed-list-hash-key
+                             (format
+                              "%S"
+                              processed-list)))
+                        (if (gethash
+                             processed-list-hash-key
+                             distinct-processed-lists)
+                            (progn
+                              (parser-generator--debug
+                               (message
+                                "Processed list already existed in set, 
skipping %S"
+                                processed-list)))
+
+                          (push
+                           processed-list
+                           processed-lists)
+                          (puthash
+                           processed-list-hash-key
+                           t
+                           distinct-processed-lists)
+                          (parser-generator--debug
+                           (message
+                            "Processed list is new, added to set %S"
+                            processed-list)))))))))
+
+          (parser-generator--debug
+           (message
+            "\nFailed to expand symbols!")))
+
+        ;; Optional sorting
+        (when (and
+               processed-lists
+               (not skip-sorting))
+          (setq
+           processed-lists
+           (sort
+            processed-lists
+            'parser-generator--sort-list)))
+
+        (parser-generator--debug
+         (message
+          "processed-lists: %S"
+          processed-lists))
+
+        ;; Store in memory cache
+        (puthash
+         hash-key
+         processed-lists
+         parser-generator--table-firsts)))
     (gethash
      hash-key
      parser-generator--table-firsts)))
diff --git a/test/parser-generator-lr-test.el b/test/parser-generator-lr-test.el
index 316b1b1f93..8fc8fbae76 100644
--- a/test/parser-generator-lr-test.el
+++ b/test/parser-generator-lr-test.el
@@ -1165,7 +1165,7 @@
       (message "Passed test PHP 8.0 match grammar 2")
       ))
 
-  ;; TODO Test another left-recursive grammar from PHP 8.0 here
+  ;; Test another left-recursive grammar from PHP 8.0 here
   (parser-generator-set-look-ahead-number 1)
   (parser-generator-set-e-identifier '%empty)
   (parser-generator-set-grammar
@@ -1281,7 +1281,6 @@
 
   (message "Passed tests for (parser-generator-lr--parse)"))
 
-;; TODO Make these pass again
 (defun parser-generator-lr-test-parse-k-2 ()
   "Test `parser-generator-lr-parse' with k = 2."
   (message "Started tests for (parser-generator-lr-parse) k = 2")
@@ -1486,19 +1485,18 @@
      lr-items)
     (parser-generator--debug
      (message
-      "Action-tables k = 2: %s"
+      "Action-tables k = 2: %S"
       (parser-generator-lr--get-expanded-action-tables)))
-
     (should
      (equal
       '(
         (0 (((a b) shift)))
         (1 ((($ $) reduce 2) ((a b) shift)))
         (2 ((($ $) accept)))
-        (3 (((b $) shift) ((b c) shift) ((b a) shift)))
-        (4 ((($ $) reduce 6) ((a b) reduce 6) ((a $) shift) ((a c) shift) ((a 
a) shift) ((c a) shift) ((c $) shift)))
+        (3 (((b c) shift) ((b a) shift) ((b $) shift)))
+        (4 ((($ $) reduce 6) ((a b) reduce 6) ((a c) shift) ((a a) shift) ((a 
$) shift) ((c a) shift) ((c $) shift)))
         (5 ((($ $) reduce 3) ((a b) reduce 3)))
-        (6 ((($ $) reduce 6) ((a b) reduce 6) ((a $) shift) ((a c) shift) ((a 
a) shift) ((c a) shift) ((c $) shift)))
+        (6 ((($ $) reduce 6) ((a b) reduce 6) ((a c) shift) ((a a) shift) ((a 
$) shift) ((c a) shift) ((c $) shift)))
         (7 ((($ $) reduce 5) ((a b) reduce 5)))
         (8 ((($ $) reduce 4) ((a b) reduce 4)))
         (9 ((($ $) reduce 1)))
@@ -1624,7 +1622,18 @@
   ;; (5) B → 1
 
   (parser-generator-set-grammar
-   '((S E B) ("*" "+" "0" "1") ((S (E $)) (E (E "*" B) (E "+" B) (B)) (B ("0") 
("1"))) S))
+   '(
+     (S E B)
+     ("*" "+" "0" "1")
+     (
+      (S (E $))
+      (E (E "*" B) (E "+" B) (B))
+      (B ("0") ("1"))
+      )
+     S
+     )
+   )
+  (parser-generator-set-e-identifier nil)
   (parser-generator-set-look-ahead-number 0)
   (parser-generator-process-grammar)
 
@@ -1736,7 +1745,7 @@
         (7 nil)
         (8 nil))
       (parser-generator-lr--get-expanded-goto-tables)))
-    (message "Passed GOTO-tables k = 2")
+    (message "Passed GOTO-tables k = 0")
 
     ;;         *       +       0       1       $
     ;; 0                       s1      s2      
diff --git a/test/parser-generator-test.el b/test/parser-generator-test.el
index 437a4aa76e..6a13070990 100644
--- a/test/parser-generator-test.el
+++ b/test/parser-generator-test.el
@@ -191,6 +191,24 @@
 
   (message "Passed tests for (parser-generator--follow)"))
 
+(defun parser-generator-test--generate-f-sets ()
+  "Test `parser-generator--first'."
+  (message "Starting tests for (parser-generator-test--generate-f-sets)")
+
+  (parser-generator-set-e-identifier 'e)
+  (parser-generator-set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) 
Sp))
+  (parser-generator-set-look-ahead-number 1)
+  (parser-generator-process-grammar)
+  (parser-generator--generate-f-sets)
+  (should
+   (equal
+    '((e a) (e))
+    (gethash
+     (list 'S)
+     parser-generator--f-sets)))
+
+  (message "Passed tests for (parser-generator-test--generate-f-sets)"))
+
 (defun parser-generator-test--first ()
   "Test `parser-generator--first'."
   (message "Starting tests for (parser-generator--first)")
@@ -279,6 +297,14 @@
   (parser-generator-set-grammar '((S A B) ("c" "d") ((S A) (A B) (B "c" "d")) 
S))
   (parser-generator-set-look-ahead-number 1)
   (parser-generator-process-grammar)
+  (should
+   (equal
+    '(("c") ("d"))
+    (parser-generator--first 'B)))
+  (should
+   (equal
+    '(("c") ("d"))
+    (parser-generator--first 'A)))
   (should
    (equal
     '(("c") ("d"))
@@ -372,7 +398,7 @@
   (parser-generator-process-grammar)
   (should
    (equal
-    '((a a b) (a a e) (a b a) (a b e) (a e e) (e e e))
+    '((a a a) (a a b) (a a e) (a b a) (a b e) (a e e) (e e e))
     (parser-generator--first 'S)))
   (message "Passed first 8 with complex grammar with starting e-identifier 
variant 2")
 
@@ -381,7 +407,7 @@
   (parser-generator-process-grammar)
   (should
    (equal
-    '((a a b b) (a a e e) (a b a a) (a b a b) (a b a e) (a b e e) (a e e e) (e 
e e e))
+    '((a a a a) (a a a b) (a a a e) (a a b a) (a a b b) (a a e e) (a b a a) (a 
b a b) (a b a e) (a b e e) (a e e e) (e e e e))
     (parser-generator--first 'S)))
   (message "Passed first 9 with complex grammar with starting e-identifier 
variant 2")
 
@@ -541,11 +567,10 @@
   (message "Passed empty-free-first 2 with trailing e-identifier 2")
   (should
    (equal
-    '((a a) (a e))
+    '((a a) (a b) (a e))
     (parser-generator--e-free-first '(a S b))))
   (message "Passed empty-free-first 2 with trailing e-identifier 1")
 
-  ;; TODO Make this pass
   (parser-generator-set-grammar
    '((Sp S R T) (a b c) ((Sp S) (S (R S) (R)) (R (a b T)) (T (a T) (c) (e))) 
Sp))
   (parser-generator-set-look-ahead-number 2)
@@ -1048,6 +1073,7 @@
   (parser-generator-test--valid-production-p)
   (parser-generator-test--valid-sentential-form-p)
   (parser-generator-test--valid-terminal-p)
+  (parser-generator-test--generate-f-sets)
 
   ;; Algorithms
   (parser-generator-test--first)



reply via email to

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