繁体   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