Formats are part of the language
- The problem
- Reading a log, a protocol or a small language usually means a parsing library, or a parser written by hand.
- An example
- A four-function calculator that reads
2 + 3 * (10 - 4) / 2. - What Nikaia checks
- You describe the format as a
grammar, and the compiler builds the parser. Precedence and recursion are rules: the order of the rules is the order of binding. The whole calculator is about 100 lines. - The limit
- A grammar is a large topic, and this page shows only the idea. The full rules are in Part II, chapter 10.
The start of the calculator
grammar Calc {
// A lowercase rule is *syntactic*: whitespace between its parts is skipped,
// so "2+3" and "2 + 3" both parse and no rule mentions blanks.
//
// `a - b - c` means `(a - b) - c`: the tails are collected and folded left to
// right in the action. (`expr = expr "-" term` would never terminate.)
entry rule expr -> i64 =
head:term tail:add_tail* {
let mut value = head
for t in tail { value = value + t }
value
}
// Subtraction is addition of a negation, so the fold above needs no operator.
rule add_tail -> i64 =
"+" t:term { t }
| "-" t:term { -t }
// Division cannot be folded that way, so each operand travels with its
// operator as a pair `(Op, i64)`, and `match` takes the pair apart.
// `term` sits between `expr` and `factor`, which is why `*` binds tighter
// than `+`: precedence is the order of the rules, not a table.
rule term -> i64 =
head:factor tail:mul_tail* {
Go deeper
More under Easy to understand: Code that waits needs no markingReadable errors