[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/parser-generator 53fb785 395/434: Verified examples in
From: |
ELPA Syncer |
Subject: |
[elpa] externals/parser-generator 53fb785 395/434: Verified examples in documentation, added infix notation calculator example |
Date: |
Mon, 29 Nov 2021 16:00:23 -0500 (EST) |
branch: externals/parser-generator
commit 53fb7850be60912db15b1bab3c887cf408ef07de
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>
Verified examples in documentation, added infix notation calculator example
---
docs/Syntax-Analysis/LR0.md | 175 ++++++++++++++++-----------
docs/Syntax-Analysis/LRk-Infix-Calculator.md | 120 ++++++++++++++++++
docs/Syntax-Analysis/LRk.md | 3 +
test/parser-generator-lr-export-test.el | 58 +++++++++
4 files changed, 285 insertions(+), 71 deletions(-)
diff --git a/docs/Syntax-Analysis/LR0.md b/docs/Syntax-Analysis/LR0.md
index fed7694..e031b2f 100644
--- a/docs/Syntax-Analysis/LR0.md
+++ b/docs/Syntax-Analysis/LR0.md
@@ -26,6 +26,8 @@ Example with grammar with production: S -> SaSb and S is
non-terminal and a, b a
You can set global symbol operator precedence and also context-sensitive
precedence, like in GNU Bison. Example
``` emacs-lisp
+(require 'parser-generator-lr)
+
(setq
parser-generator--global-attributes
'(%left %precedence %right))
@@ -66,42 +68,53 @@ Perform a right-parse of input-stream. Example from
[Wikipedia](https://en.wikip
(require 'ert)
(let ((buffer (generate-new-buffer "*a*")))
- (switch-to-buffer buffer)
- (kill-region (point-min) (point-max))
- (insert "1+1")
-
- (parser-generator-set-grammar
- '((S E B) ("*" "+" "0" "1") ((S (E $)) (E (E "*" B) (E "+" B) (B)) (B ("0")
("1"))) S))
- (parser-generator-set-look-ahead-number 0)
- (parser-generator-process-grammar)
- (parser-generator-lr-generate-parser-tables)
-
- ;; Setup lex-analyzer
- (setq
- parser-generator-lex-analyzer--function
- (lambda (index)
- (with-current-buffer buffer
- (when (<= (+ index 1) (point-max))
- (let ((start index)
- (end (+ index 1)))
- (let ((token (buffer-substring-no-properties start end)))
- `(,token ,start . ,end)))))))
- (setq
- parser-generator-lex-analyzer--get-function
- (lambda (token)
- (with-current-buffer buffer
- (let ((start (car (cdr token)))
- (end (cdr (cdr token))))
- (when (<= end (point-max))
- (buffer-substring-no-properties
- start
- end))))))
-
- (should
- (equal
- '(5 3 5 2)
- (parser-generator-lr-parse)))
- (message "Passed parse with k = 0 # 1")
+ (switch-to-buffer buffer)
+ (kill-region (point-min) (point-max))
+ (insert "1+1")
+
+ (parser-generator-set-grammar
+ '((S E B) ("*" "+" "0" "1") ((S (E $)) (E (E "*" B) (E "+" B) (B)) (B
("0") ("1"))) S))
+ (parser-generator-set-look-ahead-number 0)
+ (parser-generator-process-grammar)
+ (parser-generator-lr-generate-parser-tables)
+
+ ;; Setup lex-analyzer
+ (setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+ (with-current-buffer buffer
+ (when (<= (+ index 1) (point-max))
+ (let ((start index)
+ (end (+ index 1)))
+ (let ((token (buffer-substring-no-properties start end)))
+ `(,token ,start . ,end)))))))
+ (setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+ (with-current-buffer buffer
+ (let ((start (car (cdr token)))
+ (end (cdr (cdr token))))
+ (when (<= end (point-max))
+ (buffer-substring-no-properties
+ start
+ end))))))
+
+ (should
+ (equal
+ '(5 3 5 2)
+ (parser-generator-lr-parse)))
+ (message "Passed parse with k = 0 # 1")
+
+ (switch-to-buffer buffer)
+ (kill-region (point-min) (point-max))
+ (insert "1+1*1")
+
+ (should
+ (equal
+ '(5 3 5 2 5 1)
+ (parser-generator-lr-parse)))
+ (message "Passed parse with k = 0 # 2")
+ (kill-buffer))
```
## Translate
@@ -109,42 +122,59 @@ Perform a right-parse of input-stream. Example from
[Wikipedia](https://en.wikip
Each production RHS can optionally contain a lambda-expression that will be
called if specified when a reduction is made, example:
```emacs-lisp
-(let ((buffer (generate-new-buffer "*a*")))
- (switch-to-buffer buffer)
- (kill-region (point-min) (point-max))
- (insert "1+1")
-
- (parser-generator-set-grammar
- '((S E B) ("*" "+" "0" "1") ((S (E $)) (E (E "*" B (lambda(args) (let ((ret
(list (nth 0 args)))) (when (nth 2 args) (setq ret (append ret `(" x " ,(nth 2
args))))) ret))) (E "+" B (lambda(args) (let ((ret (list (nth 0 args)))) (when
(nth 2 args) (setq ret (append ret `(" . " ,(nth 2 args))))) ret))) (B)) (B
("0") ("1"))) S))
- (parser-generator-set-look-ahead-number 0)
- (parser-generator-process-grammar)
- (parser-generator-lr-generate-parser-tables)
-
- ;; Setup lex-analyzer
- (setq
- parser-generator-lex-analyzer--function
- (lambda (index)
- (with-current-buffer buffer
- (when (<= (+ index 1) (point-max))
- (let ((start index)
- (end (+ index 1)))
- (let ((token (buffer-substring-no-properties start end)))
- `(,token ,start . ,end)))))))
- (setq
- parser-generator-lex-analyzer--get-function
- (lambda (token)
- (with-current-buffer buffer
- (let ((start (car (cdr token)))
- (end (cdr (cdr token))))
- (when (<= end (point-max))
- (buffer-substring-no-properties start end))))))
+(require 'parser-generator-lr)
+(require 'ert)
- (should
- (equal
- '((("1")) " . " ("1"))
- (parser-generator-lr-translate)))
- (message "Passed translation k=0")
- (kill-buffer))
+(let ((buffer (generate-new-buffer "*a*")))
+ (switch-to-buffer buffer)
+ (kill-region (point-min) (point-max))
+ (insert "1+1")
+
+ (parser-generator-set-grammar
+ '(
+ (S E B)
+ ("*" "+" "0" "1")
+ (
+ (S (E $))
+ (E
+ (E "*" B (lambda(args) (let ((ret (list (nth 0 args)))) (when (nth 2
args) (setq ret (append ret `(" x " ,(nth 2 args))))) ret)))
+ (E "+" B (lambda(args) (let ((ret (list (nth 0 args)))) (when (nth 2
args) (setq ret (append ret `(" . " ,(nth 2 args))))) ret)))
+ (B)
+ )
+ (B
+ ("0")
+ ("1"))
+ )
+ S))
+ (parser-generator-set-look-ahead-number 0)
+ (parser-generator-process-grammar)
+ (parser-generator-lr-generate-parser-tables)
+
+ ;; Setup lex-analyzer
+ (setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+ (with-current-buffer buffer
+ (when (< index (point-max))
+ (let ((start index)
+ (end (+ index 1)))
+ (let ((token (buffer-substring-no-properties start end)))
+ `(,token ,start . ,end)))))))
+ (setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+ (with-current-buffer buffer
+ (let ((start (car (cdr token)))
+ (end (cdr (cdr token))))
+ (when (<= end (point-max))
+ (buffer-substring-no-properties start end))))))
+
+ (should
+ (equal
+ '("1" " . " "1")
+ (parser-generator-lr-translate)))
+ (message "Passed translation k=0")
+ (kill-buffer))
```
## Export
@@ -152,6 +182,9 @@ Each production RHS can optionally contain a
lambda-expression that will be call
The export should be executed after a parser has been generated, example:
```emacs-lisp
+(require 'parser-generator-lr)
+(require 'ert)
+
(let ((buffer (generate-new-buffer "*a*")))
(switch-to-buffer buffer)
(kill-region (point-min) (point-max))
diff --git a/docs/Syntax-Analysis/LRk-Infix-Calculator.md
b/docs/Syntax-Analysis/LRk-Infix-Calculator.md
new file mode 100644
index 0000000..e0ef3e0
--- /dev/null
+++ b/docs/Syntax-Analysis/LRk-Infix-Calculator.md
@@ -0,0 +1,120 @@
+# Example LR(k) Infix Calculator
+
+Example reproduced from GNU Bison manual [Infix Notation
Calculator](https://www.gnu.org/software/bison/manual/html_node/Infix-Calc.html).
+
+``` emacs-lisp
+(require 'parser-generator-lr)
+(require 'ert)
+
+(setq
+ parser-generator--e-identifier
+ '%empty)
+(parser-generator-set-look-ahead-number 1)
+(setq
+ parser-generator--global-attributes
+ '(%left %precedence %right))
+(setq
+ parser-generator--context-sensitive-attributes
+ '(%prec))
+(setq
+ parser-generator-lr--global-precedence-attributes
+ '(%left %precedence %right))
+(setq
+ parser-generator-lr--context-sensitive-precedence-attribute
+ '%prec)
+(setq
+ parser-generator--global-declaration
+ '(
+ (%left "-" "+")
+ (%left "*" "/")
+ (%precedence NEG)
+ (%right "^")))
+(parser-generator-set-grammar
+ '(
+ (start input line exp)
+ ("+" "-" "*" "/" "^" "(" ")" "\n" NUM)
+ (
+ (start input)
+ (input
+ %empty
+ (input line (lambda(args) (nth 1 args))))
+ (line
+ "\n"
+ (exp "\n" (lambda(args) (nth 0 args))))
+ (exp
+ NUM
+ (exp "+" exp (lambda(args) (+ (float (nth 0 args)) (nth 2 args))))
+ (exp "-" exp (lambda(args) (- (float (nth 0 args)) (nth 2 args))))
+ (exp "*" exp (lambda(args) (* (float (nth 0 args)) (nth 2 args))))
+ (exp "/" exp (lambda(args) (/ (float (nth 0 args)) (nth 2 args))))
+ ("-" exp %prec NEG (lambda(args) (- (float (nth 1 args)))))
+ (exp "^" exp (lambda(args) (expt (float (nth 0 args)) (nth 2 args))))
+ ("(" exp ")" (lambda(args) (nth 1 args)))))
+ start))
+(setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+ (with-current-buffer "*buffer*"
+ (let ((token))
+ (when
+ (<
+ index
+ (point-max))
+ (goto-char
+ index)
+
+ ;; Skip white-space(s)
+ (when (looking-at-p "[\t ]+")
+ (when
+ (search-forward-regexp "[^\t ]" nil t)
+ (forward-char -1)))
+
+ (cond
+ ((looking-at "\\([0-9]+\\.[0-9]+\\|[0-9]+\\)")
+ (setq
+ token
+ `(NUM ,(match-beginning 0) . ,(match-end 0))))
+ ((looking-at "\\(\\+\\|-\\|*\\|/\\|\\^\\|)\\|(\\|\n\\)")
+ (let ((symbol
+ (buffer-substring-no-properties
+ (match-beginning 0)
+ (match-end 0))))
+ (setq
+ token
+ `(,symbol ,(match-beginning 0) . ,(match-end 0)))))
+ (t (error "Unexpected input at %d!" index))))
+ token))))
+
+(setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+ (with-current-buffer "*buffer*"
+ (let ((start (car (cdr token)))
+ (end (cdr (cdr token))))
+ (when (<= end (point-max))
+ (let ((symbol
+ (buffer-substring-no-properties start end)))
+ (when
+ (string-match-p "^\\([0-9]+\\.[0-9]+\\|[0-9]+\\)$" symbol)
+ (setq
+ symbol
+ (string-to-number symbol)))
+ symbol))))))
+
+(parser-generator-process-grammar)
+(parser-generator-lr-generate-parser-tables)
+
+(let ((buffer (generate-new-buffer "*buffer*")))
+ (switch-to-buffer buffer)
+ (insert "4 + 4.5 - (34/(8*3+-3))\n")
+ (let ((translate (parser-generator-lr-translate)))
+ (should
+ (equal
+ 6.880952380952381
+ translate)))
+ (message "Passed correct precedence of 4 + 4.5 - (34/(8*3+-3)) =
6.880952380952381")
+ (kill-buffer))
+```
+
+[Back to LR(k) Parser](../LRk.md)
+[Back to syntax analysis](../Syntax-Analysis.md)
diff --git a/docs/Syntax-Analysis/LRk.md b/docs/Syntax-Analysis/LRk.md
index db12254..484012e 100644
--- a/docs/Syntax-Analysis/LRk.md
+++ b/docs/Syntax-Analysis/LRk.md
@@ -27,6 +27,7 @@ Example with grammar with production: S -> SaSb and S is
non-terminal and a, b a
You can set global symbol operator precedence and also context-sensitive
precedence, like in GNU Bison. Example
``` emacs-lisp
+(require 'parser-generator-lr)
(setq
parser-generator--global-attributes
'(%left %precedence %right))
@@ -63,6 +64,7 @@ You can set global symbol operator precedence and also
context-sensitive precede
Calculate the set of LR items valid for any viable prefix S.
``` emacs-lisp
+(require 'parser-generator-lr)
(require 'ert)
(parser-set-grammar '((Sp S) (a b) ((Sp S) (S (S a S b)) (S e)) Sp))
@@ -276,5 +278,6 @@ The export should be executed after a parser has been
generated, example:
(message "Passed parse for exported parser")))
```
+[Example LR(k) Infix Calculator](../LRk-Infix-Calculator.md)
[Back to syntax analysis](../Syntax-Analysis.md)
diff --git a/test/parser-generator-lr-export-test.el
b/test/parser-generator-lr-export-test.el
index c2f0b68..53127b0 100644
--- a/test/parser-generator-lr-export-test.el
+++ b/test/parser-generator-lr-export-test.el
@@ -250,6 +250,64 @@
(fa-translate))))
(message "Passed translate for exported parser")))
+
+ ;; Test exported LR(0) Parser
+ (generate-new-buffer "*a*")
+ (switch-to-buffer "*a*")
+ (kill-region (point-min) (point-max))
+ (insert "1+1")
+
+ (parser-generator-set-grammar
+ '((S E B) ("*" "+" "0" "1") ((S (E $)) (E (E "*" B) (E "+" B) (B)) (B ("0")
("1"))) S))
+ (parser-generator-set-look-ahead-number 0)
+ (parser-generator-process-grammar)
+ (parser-generator-lr-generate-parser-tables)
+
+ ;; Setup lex-analyzer
+ (setq
+ parser-generator-lex-analyzer--function
+ (lambda (index)
+ (with-current-buffer "*a*"
+ (when (<= (+ index 1) (point-max))
+ (let ((start index)
+ (end (+ index 1)))
+ (let ((token (buffer-substring-no-properties start end)))
+ `(,token ,start . ,end)))))))
+ (setq
+ parser-generator-lex-analyzer--get-function
+ (lambda (token)
+ (with-current-buffer "*a*"
+ (let ((start (car (cdr token)))
+ (end (cdr (cdr token))))
+ (when (<= end (point-max))
+ (buffer-substring-no-properties
+ start
+ end))))))
+
+ (should
+ (equal
+ '(5 3 5 2)
+ (parser-generator-lr-parse)))
+
+ ;; Export parser
+ (let ((export (parser-generator-lr-export-to-elisp "e--")))
+
+ (with-temp-buffer
+ (insert export)
+ (eval-buffer)
+ (should
+ (equal
+ t
+ (fboundp 'e---parse)))
+
+ (when (fboundp 'e---parse)
+ (should
+ (equal
+ '(5 3 5 2)
+ (e---parse))))
+ (message "Passed parse for exported LR(0) parser")))
+ (kill-buffer)
+
(message "Passed parse tests"))
(defun parser-generator-lr-export-test-translate ()
- [elpa] externals/parser-generator f0f2daa 364/434: Started refactor of context-sensitive attributes, (continued)
- [elpa] externals/parser-generator f0f2daa 364/434: Started refactor of context-sensitive attributes, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 7e1d2fb 368/434: Added TODO notes, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 5a1f09a 369/434: More work on adding support for production number related precedence, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator e4658d9 372/434: LR action-table generation is now using context-sensitive precedence resolution for reduce/reduce conflicts, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 6aff9d0 373/434: Made TODO notes, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 831a6e6 379/434: Made a commentary audit of parse according to GOTO and ACTION tables, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator bff0e63 380/434: Added TODO note, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 97b5e59 381/434: Comparing precedence of last symbol of production with look-ahead, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 5ff13d2 382/434: Improvements in test for precedence, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 9c30f34 385/434: More work on refactoring conflict resolution, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 53fb785 395/434: Verified examples in documentation, added infix notation calculator example,
ELPA Syncer <=
- [elpa] externals/parser-generator e447145 402/434: Added notes about setting to allow default conflict resolution, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 201bcb1 405/434: Improved notes, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator aad1a17 404/434: Removed unnecessary logic in LR(0) action-table generation, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 1b2a150 403/434: Added failing test for e-identifier in the middle of a rule, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator aa8a2bf 391/434: Work on the tests for the exported lr-parser, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator a8c092d 386/434: More work on precedence logic, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 7a3e653 390/434: Added test for testing precedence of context-sensitive attribute, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator 5cb63eb 399/434: Improve error message of invalid global declaration, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator f9223ea 400/434: Added a flag to use shift conflict resolution in cases were precedence is missing, ELPA Syncer, 2021/11/29
- [elpa] externals/parser-generator ded7700 387/434: Added more test for infix precedence, ELPA Syncer, 2021/11/29