簡體   English   中英

狡猾地解析多個語句,其中除了最后一個之外的所有語句都必須用換行符終止

[英]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.

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