[英]Parse Python Code using PyParsing?
我正在嘗試編寫能夠解析任何 Python 代碼的 PyParsing 代碼(我知道 AST 模塊存在,但這只是一個起點 - 我最終想要解析的不僅僅是 Python 代碼。)
無論如何,我想我會先寫一些能夠解析經典的東西
print("Hello World!")
所以這是我寫的:
from pyparsing import (alphanums, alphas, delimitedList, Forward,
quotedString, removeQuotes, Suppress, Word)
expr = Forward()
string = quotedString.setParseAction(removeQuotes)
call = expr + Suppress('(') + Optional(delimitedList(expr)) + Suppress(')')
name = World(alphas + '_', alphanums + '_')
expr <<= string | name | call
test = 'print("Hello World!")'
print(expr.parseString(test))
但是,當我這樣做時,它只是吐出來:
['print']
這在技術上是一個有效的expr
- 你可以將它輸入到 REPL 中,解析它沒有問題,即使它沒用。
所以我想也許我想要的是翻轉name
並call
我的expr
定義,所以它更喜歡將call
s 返回到name
s,如下所示:
expr <<= string | call | name
現在我得到一個最大遞歸深度超出錯誤。 這也有道理:
expr
。
string
,它不是。call
。
expr
開頭,返回到外部列表的開頭。 所以我的問題是......我如何定義call
和expr
以便我不會以無限遞歸結束,而且它不會在看到名稱時停止並忽略參數?
Python 代碼是否太復雜以至於 PyParsing 無法處理? 如果沒有,PyParsing 可以處理的內容是否有任何限制?
(注意 - 我已經包含了通用標簽parsing 、 abstract-syntax-tree和bnf ,因為我懷疑這是一個通用的遞歸語法定義問題,不一定特定於pyparsing 。)
你的語法是左遞歸的: expr
期望一個期望一個期望一個call
的expr
的call
......如果 PyParsing 不能處理左遞歸,你需要將語法更改為 PyParsing 可以使用的東西。
刪除直接左遞歸的一種方法是更改語法規則,例如:
A = A b | c
進入
A = c b*
在您的情況下,左遞歸是間接的:它不會發生在expr
,而是發生在子規則( call
)中:
E = C | s | n
C = E x y z
要刪除間接左遞歸,您通常將子規則的定義“提升”到主規則。 不幸的是,這從語法中刪除了有問題的子規則——換句話說,當你這樣做時,你會失去一些結構表達能力。
前面的例子,去掉了間接遞歸,看起來像這樣:
E = E x y z | s | n
此時,您有了直接左遞歸,更容易轉換。 當你處理它時,結果將是這樣的——在偽 EBNF 中:
E = (s | n) (x y z)*
在您的情況下, Expr
的定義將變為:
Expr = (string | name) Args*
Args = "(" ExprList? ")"
ExprList = Expr ("," Expr)*
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.