197 lines
8.2 KiB
Markdown
197 lines
8.2 KiB
Markdown
This file contains notes on how the parser implemented in `expr_parser.js` is designed.
|
|
The nominal grammar is as follows:
|
|
|
|
```
|
|
expr := conj
|
|
|
|
exprList := exprList "," expr
|
|
| expr
|
|
|
|
conj := conj "&" disj
|
|
| disj
|
|
|
|
disj := disj "|" cmpEq
|
|
| cmpEq
|
|
|
|
cmpEq := cmpEq "=" cmpRel
|
|
| cmpEq "!=" cmpRel
|
|
| cmpEq "?=" cmpRel
|
|
| cmpRel
|
|
|
|
cmpRel := cmpRel "<=" sum
|
|
| cmpRel "<" sum
|
|
| cmpRel ">" sum
|
|
| cmpRel ">=" sum
|
|
| sum
|
|
|
|
sum := sum "+" prod
|
|
| sum "-" prod
|
|
| prod
|
|
|
|
prod := prod "*" exp
|
|
| prod "/" exp
|
|
| exp
|
|
|
|
exp := exp "^" unary
|
|
| unary
|
|
|
|
unary := "-" unary
|
|
| "!" unary
|
|
| prim
|
|
|
|
prim := nLit
|
|
| bLit
|
|
| sLit
|
|
| ident "(" args ")"
|
|
| ident
|
|
| "(" expr ")"
|
|
|
|
args := exprList
|
|
| ε
|
|
```
|
|
|
|
In order to eliminate left-recursion, the above grammar is transformed into the following:
|
|
|
|
```
|
|
expr := conj
|
|
|
|
exprList := expr exprListTail
|
|
|
|
exprList' := "," expr exprList'
|
|
| ε
|
|
|
|
conj := disj conj'
|
|
|
|
conj' := "&" disj conj'
|
|
| ε
|
|
|
|
disj := cmpEq disj'
|
|
|
|
disj' := "|" cmpEq disj'
|
|
| ε
|
|
|
|
cmpEq := cmpRel cmpEq'
|
|
|
|
cmpEq' := "=" cmpRel cmpEq'
|
|
| "!=" cmpRel cmpEq'
|
|
| "?=" cmpRel cmpEq'
|
|
| ε
|
|
|
|
cmpRel := sum cmpRel'
|
|
|
|
cmpRel' := "<=" sum cmpRel'
|
|
| "<" sum cmpRel'
|
|
| ">" sum cmpRel'
|
|
| ">=" sum cmpRel'
|
|
| ε
|
|
|
|
sum := prod sum'
|
|
|
|
sum' := "+" prod sum'
|
|
| "-" prod sum'
|
|
| ε
|
|
|
|
prod := exp prod'
|
|
|
|
prod' := "*" exp prod'
|
|
| "/" exp prod'
|
|
| ε
|
|
|
|
exp := unary exp'
|
|
|
|
exp' := "^" unary exp'
|
|
| ε
|
|
|
|
unary := "-" unary
|
|
| "!" unary
|
|
| prim
|
|
|
|
prim := nLit
|
|
| bLit
|
|
| sLit
|
|
| ident identTail
|
|
| "(" expr ")"
|
|
|
|
identTail := "(" args ")"
|
|
| ε
|
|
|
|
args := exprList
|
|
| ε
|
|
```
|
|
|
|
The parser itself is a recursive-descent LL(1) parser.
|
|
To build the parsing rules, the following `FIRST` and `FOLLOW` sets are computed for the above grammar:
|
|
|
|
Nonterminal | FIRST
|
|
----------- | -----
|
|
`expr` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`exprList` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`exprList'` | `","`, `ε`
|
|
`conj` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`conj'` | `"&"`, `ε`
|
|
`disj` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`disj'` | `"\|"`, `ε`
|
|
`cmpEq` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`cmpEq'` | `"!="`, `"="`, `"?="`, `ε`
|
|
`cmpRel` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`cmpRel'` | `"<"`, `"<="`, `">"`, `">="`, `ε`
|
|
`sum` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`sum'` | `"+"`, `"-"`, `ε`
|
|
`prod` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`prod'` | `"*"`, `"/"`, `ε`
|
|
`exp` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`exp'` | `"^"`, `ε`
|
|
`unary` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`prim` | `"("`, `bLit`, `ident`, `nLit`, `sLit`
|
|
`identTail` | `"("`, `ε`
|
|
`args` | `"!"`, `"("`, `"-"`, `bLit`, `ident`, `nLit`, `sLit`, `ε`
|
|
|
|
Nonterminal | FOLLOW
|
|
----------- | ------
|
|
`expr` | `")"`, `","`, `$`
|
|
`exprList` | `")"`
|
|
`exprList'` | `")"`
|
|
`conj` | `")"`, `","`
|
|
`conj'` | `")"`, `","`
|
|
`disj` | `"&"`, `")"`, `","`
|
|
`disj'` | `"&"`, `")"`, `","`
|
|
`cmpEq` | `"&"`, `")"`, `","`, `"\|"`
|
|
`cmpEq'` | `"&"`, `")"`, `","`, `"\|"`
|
|
`cmpRel` | `"!="`, `"&"`, `")"`, `","`, `"="`, `"?="`, `"\|"`
|
|
`cmpRel'` | `"!="`, `"&"`, `")"`, `","`, `"="`, `"?="`, `"\|"`
|
|
`sum` | `"!="`, `"&"`, `")"`, `","`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`sum'` | `"!="`, `"&"`, `")"`, `","`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`prod` | `"!="`, `"&"`, `")"`, `"+"`, `","`, `"-"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`prod'` | `"!="`, `"&"`, `")"`, `"+"`, `","`, `"-"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`exp` | `"!="`, `"&"`, `")"`, `"*"`, `"+"`, `","`, `"-"`, `"/"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`exp'` | `"!="`, `"&"`, `")"`, `"*"`, `"+"`, `","`, `"-"`, `"/"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"\|"`
|
|
`unary` | `"!="`, `"&"`, `")"`, `"*"`, `"+"`, `","`, `"-"`, `"/"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"^"`, `"\|"`
|
|
`prim` | `"!="`, `"&"`, `")"`, `"*"`, `"+"`, `","`, `"-"`, `"/"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"^"`, `"\|"`
|
|
`identTail` | `"!="`, `"&"`, `")"`, `"*"`, `"+"`, `","`, `"-"`, `"/"`, `"<"`, `"<="`, `"="`, `">"`, `">="`, `"?="`, `"^"`, `"\|"`
|
|
`args` | `")"`
|
|
|
|
Then, the parsing rule table is as follows, where each table entry refers to the production number for the given nonterminal:
|
|
|
|
Nonterminal | "!" | "!=" | "&" | "(" | ")" | "*" | "+" | "," | "-" | "/" | "<" | "<=" | "=" | ">" | ">=" | "?=" | "^" | "|" | bLit | ident | nLit | sLit | $
|
|
----------- | --- | ---- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---- | --- | --- | ---- | ---- | --- | --- | ---- | ----- | ---- | ---- | ---
|
|
expr | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
exprList | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
exprList' | - | - | - | - | 1 | - | - | 0 | - | - | - | - | - | - | - | - | - | - | - | - | - | - | 1
|
|
conj | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
conj' | - | - | 0 | - | 1 | - | - | 1 | - | - | - | - | - | - | - | - | - | - | - | - | - | - | 1
|
|
disj | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
disj' | - | - | 1 | - | 1 | - | - | 1 | - | - | - | - | - | - | - | - | - | 0 | - | - | - | - | 1
|
|
cmpEq | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
cmpEq' | - | 1 | 3 | - | 3 | - | - | 3 | - | - | - | - | 0 | - | - | 2 | - | 3 | - | - | - | - | 3
|
|
cmpRel | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
cmpRel' | - | 4 | 4 | - | 4 | - | - | 4 | - | - | 1 | 0 | 4 | 2 | 3 | 4 | - | 4 | - | - | - | - | 4
|
|
sum | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
sum' | - | 2 | 2 | - | 2 | - | 0 | 2 | 1 | - | 2 | 2 | 2 | 2 | 2 | 2 | - | 2 | - | - | - | - | 2
|
|
prod | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
prod' | - | 2 | 2 | - | 2 | 0 | 2 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | - | 2 | - | - | - | - | 2
|
|
exp | 0 | - | - | 0 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | -
|
|
exp' | - | 1 | 1 | - | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | - | - | - | - | 1
|
|
unary | 1 | - | - | 2 | - | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 2 | 2 | 2 | 2 | -
|
|
prim | - | - | - | 4 | - | - | - | - | - | - | - | - | - | - | - | - | - | - | 1 | 3 | 0 | 2 | -
|
|
identTail | - | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | - | - | - | - | 1
|
|
args | 0 | - | - | 0 | 1 | - | - | - | 0 | - | - | - | - | - | - | - | - | - | 0 | 0 | 0 | 0 | 1
|