使用LR分析算法跟踪移进/归约冲突和归约/归约冲突是件乐在其中的事。为了辅助调试,yacc.py在生成分析表时会创建出一个调试文件叫parser.out:
~~~
Unused terminals:
Grammar
Rule 1     expression -> expression PLUS expression
Rule 2     expression -> expression MINUS expression
Rule 3     expression -> expression TIMES expression
Rule 4     expression -> expression DIVIDE expression
Rule 5     expression -> NUMBER
Rule 6     expression -> LPAREN expression RPAREN
Terminals, with rules where they appear
TIMES                : 3
error                : 
MINUS                : 2
RPAREN               : 6
LPAREN               : 6
DIVIDE               : 4
PLUS                 : 1
NUMBER               : 5
Nonterminals, with rules where they appear
expression           : 1 1 2 2 3 3 4 4 6 0
Parsing method: LALR
state 0
    S' -> . expression
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 1
    S' -> expression .
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    PLUS            shift and go to state 6
    MINUS           shift and go to state 5
    TIMES           shift and go to state 4
    DIVIDE          shift and go to state 7
state 2
    expression -> LPAREN . expression RPAREN
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 3
    expression -> NUMBER .
    $               reduce using rule 5
    PLUS            reduce using rule 5
    MINUS           reduce using rule 5
    TIMES           reduce using rule 5
    DIVIDE          reduce using rule 5
    RPAREN          reduce using rule 5
state 4
    expression -> expression TIMES . expression
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 5
    expression -> expression MINUS . expression
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 6
    expression -> expression PLUS . expression
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 7
    expression -> expression DIVIDE . expression
    expression -> . expression PLUS expression
    expression -> . expression MINUS expression
    expression -> . expression TIMES expression
    expression -> . expression DIVIDE expression
    expression -> . NUMBER
    expression -> . LPAREN expression RPAREN
    NUMBER          shift and go to state 3
    LPAREN          shift and go to state 2
state 8
    expression -> LPAREN expression . RPAREN
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    RPAREN          shift and go to state 13
    PLUS            shift and go to state 6
    MINUS           shift and go to state 5
    TIMES           shift and go to state 4
    DIVIDE          shift and go to state 7
state 9
    expression -> expression TIMES expression .
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    $               reduce using rule 3
    PLUS            reduce using rule 3
    MINUS           reduce using rule 3
    TIMES           reduce using rule 3
    DIVIDE          reduce using rule 3
    RPAREN          reduce using rule 3
  ! PLUS            [ shift and go to state 6 ]
  ! MINUS           [ shift and go to state 5 ]
  ! TIMES           [ shift and go to state 4 ]
  ! DIVIDE          [ shift and go to state 7 ]
state 10
    expression -> expression MINUS expression .
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    $               reduce using rule 2
    PLUS            reduce using rule 2
    MINUS           reduce using rule 2
    RPAREN          reduce using rule 2
    TIMES           shift and go to state 4
    DIVIDE          shift and go to state 7
  ! TIMES           [ reduce using rule 2 ]
  ! DIVIDE          [ reduce using rule 2 ]
  ! PLUS            [ shift and go to state 6 ]
  ! MINUS           [ shift and go to state 5 ]
state 11
    expression -> expression PLUS expression .
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    $               reduce using rule 1
    PLUS            reduce using rule 1
    MINUS           reduce using rule 1
    RPAREN          reduce using rule 1
    TIMES           shift and go to state 4
    DIVIDE          shift and go to state 7
  ! TIMES           [ reduce using rule 1 ]
  ! DIVIDE          [ reduce using rule 1 ]
  ! PLUS            [ shift and go to state 6 ]
  ! MINUS           [ shift and go to state 5 ]
state 12
    expression -> expression DIVIDE expression .
    expression -> expression . PLUS expression
    expression -> expression . MINUS expression
    expression -> expression . TIMES expression
    expression -> expression . DIVIDE expression
    $               reduce using rule 4
    PLUS            reduce using rule 4
    MINUS           reduce using rule 4
    TIMES           reduce using rule 4
    DIVIDE          reduce using rule 4
    RPAREN          reduce using rule 4
  ! PLUS            [ shift and go to state 6 ]
  ! MINUS           [ shift and go to state 5 ]
  ! TIMES           [ shift and go to state 4 ]
  ! DIVIDE          [ shift and go to state 7 ]
state 13
    expression -> LPAREN expression RPAREN .
    $               reduce using rule 6
    PLUS            reduce using rule 6
    MINUS           reduce using rule 6
    TIMES           reduce using rule 6
    DIVIDE          reduce using rule 6
    RPAREN          reduce using rule 6
~~~
文件中出现的不同状态,代表了有效输入标记的所有可能的组合,这是依据文法规则得到的。当得到输入标记时,分析器将构造一个栈,并找到匹配的规则。每个状态跟踪了当前输入进行到语法规则中的哪个位置,在每个规则中,’.’表示当前分析到规则的哪个位置,而且,对于在当前状态下,输入的每个有效标记导致的动作也被罗列出来。当出现移进/归约或归约/归约冲突时,被忽略的规则前面会添加!,就像这样:
~~~
! TIMES           [ reduce using rule 2 ]
  ! DIVIDE          [ reduce using rule 2 ]
  ! PLUS            [ shift and go to state 6 ]
  ! MINUS           [ shift and go to state 5 ]
~~~
通过查看这些规则并结合一些实例,通常能够找到大部分冲突的根源。应该强调的是,不是所有的移进归约冲突都是不好的,想要确定解决方法是否正确,唯一的办法就是查看parser.out。
                    
        - 0 一些翻译约定
- 1 前言和预备
- 2 介绍
- 3 PLY概要
- 4 Lex
- 4.1 Lex的例子
- 4.2 标记列表
- 4.3 标记的规则
- 4.4 标记的值
- 4.5 丢弃标记
- 4.6 行号和位置信息
- 4.7 忽略字符
- 4.8 字面字符
- 4.9 错误处理
- 4.10 构建和使用lexer
- 4.11 @TOKEN装饰器
- 4.12 优化模式
- 4.13 调试
- 4.14 其他方式定义词法规则
- 4.15 额外状态维护
- 4.16 Lexer克隆
- 4.17 Lexer的内部状态
- 4.18 基于条件的扫描和启动条件
- 4.19 其他问题
- 5 语法分析基础
- 6 Yacc
- 6.1 一个例子
- 6.2 将语法规则合并
- 6.3 字面字符
- 6.4 空产生式
- 6.5 改变起始符号
- 6.6 处理二义文法
- 6.7 parser.out调试文件
- 6.8 处理语法错误
- 6.9 行号和位置的跟踪
- 6.10 构造抽象语法树
- 6.11 嵌入式动作
- 6.12 Yacc的其他
- 7 多个语法和词法分析器
- 8 使用Python的优化模式
- 9 高级调试
- 9.1 调试lex()和yacc()命令
- 9.2 运行时调试
- 10 如何继续
