Sly解析多行语句:除最后一条外需以换行符终止的问题
问题分析
原语法的核心问题是未区分需要换行的中间语句和不需要换行的最终语句:
statement_or_NL强制要求语句必须跟NEWLINE,导致最后一条无换行的语句无法匹配- 顶层
script的规则statement_set statement试图补全最后一条语句,但statement_set本身由statement_or_NL组成,无法处理开头空行场景,也不兼容结尾空行的情况
修正后的语法实现
重新设计语法规则,明确区分带换行的单元和最终语句,同时兼容空行场景:
from sly import Parser, Lexer # 补全必要的词法分析部分 class MyLexer(Lexer): tokens = {PLUS, MINUS, NEWLINE} ignore = ' \t' PLUS = r'\+' MINUS = r'-' NEWLINE = r'\n' class MyParser(Parser): tokens = MyLexer.tokens @_('line_list', 'line_list statement', 'statement') def script(self, p): # 收集有效语句,过滤空行产生的空列表 statements = [] if hasattr(p, 'line_list'): statements.extend([stmt for line in p.line_list for stmt in line]) if hasattr(p, 'statement'): statements.append(p.statement) return statements @_('') def line_list(self, p): return [] @_('line_list line') def line_list(self, p): p.line_list.append(p.line) return p.line_list @_('statement NEWLINE', 'NEWLINE') def line(self, p): # 带换行的单元:语句+换行返回[语句],空行返回[] if len(p) > 1: return [p.statement] else: return [] @_('PLUS', 'MINUS') def statement(self, p): return p[0]
关键修改点
- 顶层规则拆分:
script直接覆盖三种合法场景:全是空行/带换行的语句、带换行语句+最终无换行语句、仅一条无换行语句 line_list支持空序列:
新增空规则line_list -> '',允许脚本开头是空行,或者整个脚本只有空行- 明确
line单元:
把原statement_or_NL改名为line,表示一个带换行的单元(语句+换行或空换行),语义动作保持不变 - 语义动作优化:
在script的处理中,统一收集所有有效语句,自动过滤空行产生的空列表
验证场景
现在可正确处理所有问题场景:
- 以换行开头:比如
\n + \n -,解析结果为['+', '-'] - 以换行结尾:比如
+ \n - \n,解析结果为['+', '-'] - 无结尾换行:比如
+ \n -,解析结果为['+', '-'] - 仅空行:比如
\n\n,解析结果为[] - 单条无换行语句:比如
+,解析结果为['+']
内容的提问来源于stack exchange,提问作者Sean Duggan
相关产品推荐
相关产品推荐

