位置跟踪通常是个设计编译器时的技巧性玩意儿。默认情况下,PLY跟踪所有标记的行号和位置,这些信息可以这样得到:
* p.lineno(num)返回第num个符号的行号
* p.lexpos(num)返回第num个符号的词法位置偏移
例如:
~~~
def p_expression(p):
'expression : expression PLUS expression'
p.lineno(1) # Line number of the left expression
p.lineno(2) # line number of the PLUS operator
p.lineno(3) # line number of the right expression
...
start,end = p.linespan(3) # Start,end lines of the right expression
starti,endi = p.lexspan(3) # Start,end positions of right expression
~~~
注意:lexspan()方法只会返回的结束位置是最后一个符号的起始位置。
虽然,PLY对所有符号的行号和位置的跟踪很管用,但经常是不必要的。例如,你仅仅是在错误信息中使用行号,你通常可以仅仅使用关键标记的信息,比如:
~~~
def p_bad_func(p):
'funccall : fname LPAREN error RPAREN'
# Line number reported from LPAREN token
print "Bad function call at line", p.lineno(2)
~~~
类似的,为了改善性能,你可以有选择性的将行号信息在必要的时候进行传递,这是通过p.set_lineno()实现的,例如:
~~~
def p_fname(p):
'fname : ID'
p[0] = p[1]
p.set_lineno(0,p.lineno(1))
~~~
对于已经完成分析的规则,PLY不会保留行号信息,如果你是在构建抽象语法树而且需要行号,你应该确保行号保留在树上。
- 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 如何继续