Tracing and debugging¶
When the parser doesn't work as expected there are several options. First, you can use pglr command to visualize LR PDA automata and GLR trace. The same command can also be used to print detailed information on the grammar, LR states and conflicts.
Printing detailed debug information on grammar can be also achieved by putting the grammar in the debug mode:
grammar = Grammar.from_file(file_name, debug=True)
For example, calc
grammar from the quick intro would give the following
output:
*** GRAMMAR ***
Terminals:
EMPTY - * ^ + STOP ( \d+(\.\d+)? number / EOF )
NonTerminals:
E S'
Productions:
0: S' = E STOP
1: E = E + E
2: E = E - E
3: E = E * E
4: E = E / E
5: E = E ^ E
6: E = ( E )
7: E = number
During grammar object construction, grammar file is parsed using the parglare
itself and the grammar object for the new language is constructed. If you want
to see the debug output of this process set the parse_debug
parameter to
True
:
grammar = Grammar.from_file(file_name, parse_debug=True)
If you are using custom recognizers or would like to see the result of each action in debug output then you should put the parser in the debug mode from the code.
To put the parser in the debug mode do:
parser = Parser(grammar, debug=True)
To debug layout grammar do:
parser = Parser(grammar, debug_layout=True)
GLRParser
can produce visual trace. To enable
visual tracing set debug
and debug_trace
to True
:
parser = GLRParser(grammar, debug=True, debug_trace=True)
Debug output and visual trace can be generated using pglr command.
For example, parsing expression 1 + 2 * 3
with GLRParser
in debug mode will
produce the following output (this output is generated by pglr -i trace calc.pg
"1 + 2 * 3"
):
Grammar OK.
*** STATES ***
State 0
0: S' = . E STOP {}
1: E = . E + E {STOP, ^, ), /, *, -, +}
2: E = . E - E {STOP, ^, ), /, *, -, +}
3: E = . E * E {STOP, ^, ), /, *, -, +}
4: E = . E / E {STOP, ^, ), /, *, -, +}
5: E = . E ^ E {STOP, ^, ), /, *, -, +}
6: E = . ( E ) {STOP, ^, ), /, *, -, +}
7: E = . number {STOP, ^, ), /, *, -, +}
GOTO:
E->1
ACTIONS:
(->SHIFT:2, number->SHIFT:3
....
....
*** PARSING STARTED
Skipping whitespaces: ''
New position: (1, 0)
**REDUCING HEADS
Active heads 1: [state=0:S', pos=0, endpos=0, empty=[False,True], parents=0, trees=1]
Number of trees = 1
Reducing head: state=0:S', pos=0, endpos=0, empty=[False,True], parents=0, trees=1
Skipping whitespaces: ''
New position: (1, 0)
Position: (1, 0)
Context: *1 + 2 * 3
Symbols expected: ['(', 'number']
Token(s) ahead: [<number(1)>]
New head for shifting: state=0:S', pos=0, endpos=0, token
ahead=<number(1)>, empty=[False,True], parents=0, trees=1.
No more reductions for this head and lookahead token <number(1)>.
**SHIFTING HEADS
Active heads 1: [state=0:S', pos=0, endpos=0, token ahead=<number(1)>,
empty=[False,True], parents=0, trees=1]
Number of trees = 1
Shifting head: state=0:S', pos=0, endpos=0, token ahead=<number(1)>,
empty=[False,True], parents=0, trees=1
Position: (1, 0)
Context: *1 + 2 * 3
Token(s) ahead: <number(1)>
Shift:3 "1" at position (1, 0)
Action result = type:<class 'parglare.parser.NodeTerm'>
value:<Term(start=0, end=1, sym=number, val="1")>
New shifted head state=3:number, pos=0, endpos=1, empty=[False,True],
parents=0, trees=0.
Creating link from head state=3:number, pos=0, endpos=1,
empty=[False,False], parents=1, trees=1
to head state=0:S', pos=0, endpos=0, token
ahead=<number(1)>, empty=[False,True],
parents=0, trees=1
....
....
Reducing head: state=1:E, pos=0, endpos=9, token ahead=<STOP()>,
empty=[False,False], parents=1, trees=1
Position: (1, 9)
Context: 1 + 2 * 3*
Symbols expected: ['STOP']
Token(s) ahead: <STOP()>
*** SUCCESS!!!!
*** 1 sucessful parse(s).
Generated file parglare_trace.dot.
In addition, a visualization of GLR trace is produced as a Graphviz dot file.