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