The parsing table tells us for a given non-terminal and a given terminal , which production rule to use to re-write .
If multiple entries appear in a table location, the grammar cannot be parsed by an LL(1) parser, i.e., it’s not an LL(1) grammar.
Construction
Basic idea: for a production in the form , add to the table entry at row and column , for each . Then when , we use .
We follow the algorithm:
- For each production , repeat the following:
- Add to row and column for each .
- If in , add to row and column for each .
- Each undefined entry in the table is an error.
To construct the parsing table, we must understand: what are the parser states, how do we determine the transitions, and how do we determine the actions (shift, reduce, goto
, accept, error)?
Usage
We have states, actions, and goto
. Elements in a parsing table are:
si
— shift and move to statei
.ri
— reduce by productioni
.gi
— go to statei
.a
— accept.- Blank — error.
We maintain a stack of elements, and a state stack. We always start with state 0. Each time we push/pop from the element stack, we do the same with the state stack.
Reduction doesn’t advance the pointer. This only happens when we shift.
Parser states represent the set of productions the parser may currently use, and how far the parser is in each production.
Say we run into a non-terminal, we look for other productions that can still satisfy the transition, i.e., we transitively add items (see slides)1
Footnotes
-
related by necessity, see dictionary definition ↩