簡體   English   中英

使用 PyParsing 解析 Python 代碼?

[英]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 中,解析它沒有問題,即使它沒用。

所以我想也許我想要的是翻轉namecall我的expr定義,所以它更喜歡將call s 返回到name s,如下所示:

expr <<= string | call | name

現在我得到一個最大遞歸深度超出錯誤。 這也有道理:

  1. 檢查它是否是expr
    1. 檢查它是否是一個string ,它不是。
    2. 檢查它是否是一個call
      1. 它必須以expr開頭,返回到外部列表的開頭。

所以我的問題是......我如何定義callexpr以便我不會以無限遞歸結束,而且它不會在看到名稱時停止並忽略參數?

Python 代碼是否太復雜以至於 PyParsing 無法處理? 如果沒有,PyParsing 可以處理的內容是否有任何限制?

(注意 - 我已經包含了通用標簽 ,因為我懷疑這是一個通用的遞歸語法定義問題,不一定特定於 。)

你的語法是左遞歸的: expr期望一個期望一個期望一個callexprcall ......如果 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM