yacc使用的分析技術只允許在規則規約后執行動作。假設有如下規則:
~~~
def p_foo(p):
"foo : A B C D"
print "Parsed a foo", p[1],p[2],p[3],p[4]
~~~
方法只會在符號A,B,C和D都完成后才能執行。可是有的時候,在中間階段執行一小段代碼是有用的。假如,你想在A完成后立即執行一些動作,像下面這樣用空規則:
~~~
def p_foo(p):
"foo : A seen_A B C D"
print "Parsed a foo", p[1],p[3],p[4],p[5]
print "seen_A returned", p[2]
def p_seen_A(p):
"seen_A :"
print "Saw an A = ", p[-1] # Access grammar symbol to left
p[0] = some_value # Assign value to seen_A
~~~
在這個例子中,空規則seen_A將在A移進分析棧后立即執行。p[-1]指代的是在分析棧上緊跟在seen_A左側的符號。在這個例子中,是A符號。像其他普通的規則一樣,在嵌入式行為中也可以通過為p[0]賦值來返回某些值。
使用嵌入式動作可能會導致移進歸約沖突,比如,下面的語法是沒有沖突的:
~~~
def p_foo(p):
"""foo : abcd
| abcx"""
def p_abcd(p):
"abcd : A B C D"
def p_abcx(p):
"abcx : A B C X"
~~~
可是,如果像這樣插入一個嵌入式動作:
~~~
def p_foo(p):
"""foo : abcd
| abcx"""
def p_abcd(p):
"abcd : A B C D"
def p_abcx(p):
"abcx : A B seen_AB C X"
def p_seen_AB(p):
"seen_AB :"
~~~
會產生移進歸約沖,只是由于對于兩個規則abcd和abcx中的C,分析器既可以根據abcd規則移進,也可以根據abcx規則先將空的seen_AB歸約。
嵌入動作的一般用于分析以外的控制,比如為本地變量定義作用于。對于C語言:
~~~
def p_statements_block(p):
"statements: LBRACE new_scope statements RBRACE"""
# Action code
...
pop_scope() # Return to previous scope
def p_new_scope(p):
"new_scope :"
# Create a new scope for local variables
s = new_scope()
push_scope(s)
...
~~~
在這個例子中,new_scope作為嵌入式行為,在左大括號{之后立即執行。可以是調正內部符號表或者其他方面。statements_block一完成,代碼可能會撤銷在嵌入動作時的操作(比如,pop_scope())
- 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 如何繼續