[英]Sly parsing of multiple statements where all but the last one must be terminated with a Newline
我有一種正在實現的腳本語言,其中每個語句都由換行符終止,可能是最后一個語句除外。 也可能有只是換行符的行。 這是一個實現(省略了語句代碼,因為它並沒有真正添加任何東西):
@_('statement_set statement', 'statement_set')
def script(self, p):
if len(p) > 1:
p.statement_set.append(p.statement)
return p.statement_set
@_('statement_or_NL')
def statement_set(self, p):
return p.statement_or_NL
@_('statement_set statement_or_NL')
def statement_set(self, p):
p.statement_set.append(p.statement_or_NL)
return p.statement_set
@_('statement NEWLINE', 'NEWLINE')
def statement_or_NL(self, p):
if len(p) > 1:
return [p.statement]
else:
return []
@_('PLUS', 'MINUS')
def statement(self, p):
return p[0]
這會生成以下規則:
Rule 0 S' -> script
Rule 1 script -> statement_set
Rule 2 script -> statement_set statement
Rule 3 statement_set -> statement_set statement_or_NL
Rule 4 statement_set -> statement_or_NL
Rule 5 statement_or_NL -> NEWLINE
Rule 6 statement_or_NL -> statement NEWLINE
如果您願意,我也可以發布生成的狀態。 我遇到的問題是,即使我消除了所有移位減少沖突,我仍然幾乎總是在以換行符開頭的代碼、以換行符結尾的代碼和具有最后沒有換行符。 解析中出現了問題,以至於它將最終語句(以 EOF 結尾)讀取為“語句 NEWLINE”,然后因為沒有換行而出錯。 更糟糕的是,我有一個版本,只要沒有沒有換行符的最終語句就可以工作,所以我可能可以操縱解析器將其添加到帶有代碼的初始字符串中,或者插入令牌,但感覺笨重。
我之前在 Ply 中得到了這個工作,我認為它本質上是相同的代碼,但它似乎對我不起作用。
對於此類問題,這是一個相當通用的解決方案。 它基本上將語句列表視為一個兩態自動機,在“以換行符結尾”和“以語句結尾”之間交替。 最終結果是所有語句的列表(盡管您也可以使用換行符做一些更有趣的事情)。
由於所有換行符都被忽略,除了它們在分隔語句中的作用,您可以有任意數量的連續換行符,輸入末尾的換行符是可選的。 簡單的過渡圖:
CURRENT STATE INPUT RESULT STATE
------------------- --------- -------------------
ends-with-newline NL ends-with-newline
ends-with-newline statement ends-with-statement
ends-with-statement NL ends-with-newline
ends-with-statement statement *ERROR*
使用模板很容易將有限自動機轉換為 CFG:
RESULT: CURRENT INPUT
這導致以下情況(其中省略了statement
的實際定義,因為唯一重要的是它不能派生任何以語句終止符開頭的東西,這至少可以說是不尋常的,而且它必須不導出為空,偶爾需要一些調整):
@_('script_ends_nl', 'script_ends_stmt')
def script(self, p):
return p[0]
@_('')
def script_ends_nl(self, p):
return []
@_(' script_ends_nl NL ',
' script_ends_stmt NL ')
def script_ends_nl(self, p):
return p[0]
@_('script_ends_nl statement')
def script_ends_stmt(self, p):
return p.script_ends_nl + [p.statement]
或者,使用 Sly 的調試文件,語法:
Rule 0 S' -> script
Rule 1 script -> script_ends_stmt
Rule 2 script -> script_ends_nl
Rule 3 script_ends_nl -> script_ends_stmt NL
Rule 4 script_ends_nl -> script_ends_nl NL
Rule 5 script_ends_nl -> <empty>
Rule 6 script_ends_stmt -> script_ends_nl statement
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.