[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/parser-generator de7c45c511 78/82: Started with LL-expo
From: |
Christian Johansson |
Subject: |
[elpa] externals/parser-generator de7c45c511 78/82: Started with LL-export functions |
Date: |
Thu, 12 May 2022 13:28:20 -0400 (EDT) |
branch: externals/parser-generator
commit de7c45c51145207c69aecfbc168e8aa8721e2d55
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>
Started with LL-export functions
---
parser-generator-ll-export.el | 779 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 779 insertions(+)
diff --git a/parser-generator-ll-export.el b/parser-generator-ll-export.el
new file mode 100644
index 0000000000..8fff6ed74c
--- /dev/null
+++ b/parser-generator-ll-export.el
@@ -0,0 +1,779 @@
+;;; 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")
+
+ ;; Action-tables
+ (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))
+
+ ;; 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--get-grammar-start))
+ (%s--generate-list-of-symbol
+ %s--look-ahead-number
+ %s--eof-identifier))
+ %s--eof-identifier)
+ (list
+ (%s--get-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
+ (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
+ (%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
+
+ ((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))
+
+")
+
+ ;; 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-lr-export)
+
+;;; parser-generator-lr-export.el ends here
- [elpa] externals/parser-generator 064bd259ff 26/82: Passing LLk validation tests, (continued)
- [elpa] externals/parser-generator 064bd259ff 26/82: Passing LLk validation tests, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator f0de6698b9 29/82: Added todo item, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 97919972a7 35/82: Improved debug message, added TODO item, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator e55a3f8a37 38/82: Updated TODO items, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 7ee5504003 45/82: More work on LLk parser, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator fd2f90dd81 47/82: Added TODO-item, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator b41b2dbffe 68/82: Removed debug output, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 566228f16c 71/82: More work on LLk translation, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 234a6ca2db 70/82: More work on LLk SDT, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator ff261d9a4e 75/82: Using stack for symbols value in SDT, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator de7c45c511 78/82: Started with LL-export functions,
Christian Johansson <=
- [elpa] externals/parser-generator 5be162966b 80/82: Fixed byte-compilation issue in exported LL parser, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 2869417d78 31/82: Made new helper functions to make LL-parsing easier, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 23805731c1 34/82: More work on LL-parser, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 8cc2a5b315 44/82: More work on LLk parsing, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 5aeee49bd0 48/82: Added another todo note, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 4c93e895b3 49/82: Added TODO item, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator ec0711fa84 53/82: Tweaks on internal functions of LLk parsing, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator ed9933eeba 57/82: Passing a lot of LLk tests, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 87ded78c28 63/82: LL(1) parser passes test for generating tables and parsing, Christian Johansson, 2022/05/12
- [elpa] externals/parser-generator 1ccc742678 72/82: LLk parser passes translation tests, Christian Johansson, 2022/05/12