添加plus()后petitparser的有序选择规则为何被忽略?
Dart petitparser 有序选择优先级在plus()后失效的问题解决
问题根源
你遇到的问题是因为错误地将plus()包裹在了有序选择解析器外层,结合递归引用打乱了匹配逻辑:
singleCharacter能匹配单个括号/数字,这个短匹配的优先级被plus()的贪婪特性放大,解析器会优先完成短匹配,完全跳过尝试nestedTerm的长匹配机会。nestedTerm内部引用了被plus()修改后的term,递归逻辑从“单次优先级选择”变成了“重复片段匹配”,进一步破坏了原本的有序选择规则。
解决方案
保持term的单次优先级选择逻辑不变,将plus()移到解析入口(start()方法)中,让整个解析流程变成“重复执行单次优先级匹配,直到输入结束”,这样既满足了任意次数重复的需求,又保留了优先匹配nestedTerm的规则。
修改后的代码
import 'package:petitparser/petitparser.dart'; void main() { final definition = ExpressionDefinition(); final parser = definition.build(); print(parser.parse('(0)').toString()); // 输出:[ ['(' (nestedTerm), '0' (singleCharacter), ')' (nestedTerm)] ] print(parser.parse('(()0)').toString()); // 输出:[ ['(' (nestedTerm), ['(' (nestedTerm), ')' (nestedTerm)], '0' (singleCharacter), ')' (nestedTerm)] ] } class ExpressionDefinition extends GrammarDefinition { @override Parser start() => ref0(term).plus().end(); // 将重复匹配移至入口 Parser term() => ref0(nestedTerm) | ref0(singleCharacter); // 保留单次有序选择优先级 Parser nestedTerm() => (char('(')).map((value) => "'$value' (nestedTerm)") & ref0(term) & char(')').map((value) => "'$value' (nestedTerm)"); Parser singleCharacter() => char('(').map((value) => "'$value' (singleCharacter)") | char(')').map((value) => "'$value' (singleCharacter)") | char('0').map((value) => "'$value' (singleCharacter)"); }
关键说明
绝对不要将plus()这类重复匹配操作与递归的有序选择解析器嵌套在一起,否则会让解析器优先选择最短的有效匹配,完全违背有序选择的优先级设计。正确的做法是让重复操作作用于“完整的单次优先级选择单元”,而非包裹优先级选择逻辑本身。
内容的提问来源于stack exchange,提问作者CodingFun
相关产品推荐
相关产品推荐

