PEG解析器匹配合法字符失败:Java风格浮点数解析规则异常
你遇到的问题核心来自两点:
- 语法规则的分支设计有歧义,和PEG类解析器的贪婪匹配/有序选择特性冲突
- 原有规则没有显式覆盖无小数点的浮点数字面量必须跟指数/后缀的合法场景,导致解析器分支匹配异常
问题原因分析
首先看你现有float_lit的规则逻辑:
float_lit = [[DIGITS] '.'] DIGITS [FLOAT_EXP] [FLOAT_SUFFIX] ;
这个规则里[[DIGITS] '.']是可选结构,含义是「要么出现 可选DIGITS加小数点 的组合,要么不出现这个组合」。当解析输入1e10时,解析器会优先匹配最左侧的分支:先尝试匹配[[DIGITS] '.'],第一步匹配到开头的1作为DIGITS,接下来尝试匹配小数点失败,因此整个可选结构匹配失败,需要回滚到输入开头位置。
如果你的解析器是PEG(绝大多数现代手写/生成的解析器都是PEG),回滚后会尝试跳过可选结构,匹配后面的必选DIGITS,再次匹配到开头的1,此时解析位置移动到e所在的位置。
接下来按照规则应该匹配FLOAT_EXP,但原有规则的模糊结构会导致部分解析器误判当前分支已经结束,或者在回滚时状态异常,最终出现e匹配失败的情况。
修复方案
你需要把规则调整为显式覆盖Java浮点字面量的三种合法场景,避免分支歧义:
float_lit = // 场景1:带小数点的情况,小数点前后至少有一边有数字 ( DIGITS '.' DIGITS? | '.' DIGITS ) [FLOAT_EXP] [FLOAT_SUFFIX] // 场景2:不带小数点的情况,必须带指数才能是浮点数 | DIGITS FLOAT_EXP [FLOAT_SUFFIX] ; DIGITS = /\d[\d_]*\d/ | /\d/ ; FLOAT_EXP = ( 'e' | 'E' ) [ '+' | '-' ] DIGITS ; FLOAT_SUFFIX = 'f' | 'F' | 'd' | 'D' ;
调整后每个分支场景明确,不会出现分支匹配歧义,即可正常匹配1e10这类无小数点的浮点字面量。
另外如果你是把float_lit作为语法规则实现,而非词法规则,需要注意:词法分析器会默认把1e10切分为数字token1和标识符tokene10,语法层无法拿到连续的e字符,必须把浮点数规则放到词法分析阶段实现。
内容的提问来源于stack exchange,提问作者Bruno Kim
相关产品推荐
相关产品推荐

