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