ANTLR4词法分析器无法识别注释Token问题求助
ANTLR自定义语法中COMMENT词法规则不生效的问题解决
问题描述
基于ANTLR官方仓库中的Lua和C语法从零编写了示例语法,运行时遇到核心问题:定义的COMMENT词法规则完全不被识别。当测试文件以注释开头时,直接抛出解析错误:
Parser error (2, 1): mismatched input '//' expecting {<EOF>, 'break', 'while', 'if', 'fields', 'keys', 'vals', 'func', 'funcdoc', 'return', NAME},<unknown>,2,0,true Tokens:[@0,81:82='//',<52>,2:0], [@1,159:160='//',<52>,4:0], [@2,381:382='//',<52>,8:0]
测试文件开头内容:
/////////////////////////////////////////////////////////////////////////////// // // group tests // // All of these should be very high level // /////////////////////////////////////////////////////////////////////////////// // Common Master funcs master_funcs
已尝试的操作:
- 将COMMENT规则移至所有词法规则最前面
- 把注释逻辑加入stat解析规则
- 调整COMMENT规则细节(规则逻辑本身无明显错误)
怀疑问题与解析器规则编写有关,附上完整语法代码:
grammar example; /////////////////////////// // PARSER RULES // /////////////////////////// //starting rule chunk : block EOF ; block : stat* retstat? ; //statements stat : 'break' | funcdef | decblock | varlist '=' explist | 'while' '(' exp ')' block 'endwhile' | 'if' ('(' exp ')'|exp) block ('elseif' ('(' exp ')'|exp) block)* ('else' block)? 'endif' ; precompstat : '@define' NAME number | '@if' ('(' exp ')'|exp) block ('@elseif' ('(' exp ')'|exp) block)* ('@else' block)? '@endif' ; //declaration blocks decblock : 'fields' fieldlist? 'endfields' | 'keys' keylist? 'endkeys' | 'vals' NAME vallist? 'endvals' ; exp : 'NULL' | 'TRUE' | 'FALSE' | tabledec | number | STRING | funccall | <assoc=right> exp opPower exp | opUnary exp | exp opMulDivMod exp | exp opAddSub exp | exp opComparison exp | exp opAnd exp | exp opOr exp | exp opBitwise exp ; funcdef : 'func' '(' args? ')' funcbody | funcdoc 'func' '(' args? ')' funcbody ; args : (explist | namelist | fieldlist | funccall | tableconstruct)+ ; funcbody : ('locals' namelist)? 'does' block 'endfunc' ; funccall : NAME '(' args? ')' NAME ; funcdoc : 'funcdoc' NAME STRING ; explist : exp (',' exp)* ; fieldlist : NAME ':' ('[]')? NAME (number)? (',' fieldlist)? ; funclist : funccall ('(' args? ')')? (',' funclist)? ; keylist : NAME '(' (explist|namelist|varlist)(',' (explist|namelist|varlist))* ')' 'comment' STRING (',' keylist)? ; namelist : NAME (',' NAME)* ; vallist : NAME (number|NAME|exp) (',' vallist)? ; varlist : NAME ('[' (NAME|number) ']')? ('[' number (',' number)* ']') (',' varlist)? ; //return statement retstat : 'return' explist? ; number : INT | HEX | FLOAT ; tabledec : NAME ':' '[]' NAME 'new' '[]' NAME tableconstruct ; tableconstruct : '{' (explist|namelist|funclist)* '}' | '(' (explist|namelist|funclist)* ')' ; opOr : 'or' ; opAnd : 'and' ; opComparison : '<' | '>' | '<=' | '>=' | '==' ; opAddSub : '+' | '-' ; opMulDivMod : '*' | '/' | '%' | '//' ; opBitwise : '&' | '|' | '~' | '<<' | '>>' ; opUnary : 'not' | '#' | '-' | '~' ; opPower : '^' ; /////////////////////////// // LEXER RULES // /////////////////////////// INT : Digit+ ; HEX : '0' [xX] HexDigit+ ; FLOAT : Digit+ '.' Digit* | '.' Digit+ ; NAME : [a-zA-Z_][a-zA-Z_0-9]* ; STRING : '"' (EscapeSequence|~('\\'|'"'))* '"' ; fragment Digit : [0-9] ; fragment EscapeSequence : '\\' [abfnrtvz"'\\] | '\\' '\r'? '\n' ; fragment HexDigit : [0-9a-fA-F] ; WS : [ \t\r\n]+ -> skip ; COMMENT : '//' ~[\r\n]* -> skip ;
问题根源
- 符号复用冲突:
//同时被定义为行注释开头和算术运算符(opMulDivMod规则中的'//'),词法分析器无法区分两者。 - 隐式词法规则优先级:解析器规则中的字面量(如
'//')会生成隐式词法规则,这些规则的优先级高于自定义的COMMENT规则。因此,注释中的//会被优先识别为算术运算符,而解析器在当前上下文(stat规则)中不期望该符号,从而抛出错误。
解决方法
根据需求选择以下任一修改方向:
方向一:修改注释符号,避免与运算符冲突
参考Lua注释风格,将行注释改为--,彻底避免符号冲突:
- 修改COMMENT词法规则:
COMMENT : '--' ~[\r\n]* -> skip ;
- 将测试文件中的注释统一改为
--开头。
方向二:保留//作为注释,调整运算符规则
若坚持使用//作为行注释,需移除运算符规则中的//,或替换为其他符号:
- 修改
opMulDivMod规则:
opMulDivMod : '*' | '/' | '%' ;
- 将COMMENT规则移至所有词法规则最前面,确保优先级最高。
额外优化:显式定义运算符词法规则(可选)
为彻底避免隐式规则优先级问题,建议将所有运算符定义为显式词法规则,完全控制匹配顺序:
- 调整词法规则顺序与定义:
// 优先定义COMMENT,确保注释被优先匹配 COMMENT : '//' ~[\r\n]* -> skip ; WS : [ \t\r\n]+ -> skip ; // 显式定义运算符词法规则 STAR : '*'; SLASH : '/'; PERCENT : '%'; // 其他词法规则...
- 修改解析器中的运算符规则:
opMulDivMod : STAR | SLASH | PERCENT ;
验证修改
重新生成解析器与词法分析器后,运行测试文件,注释将被正确跳过,不再出现解析错误。
内容的提问来源于stack exchange,提问作者ron_the_doe
相关产品推荐
相关产品推荐

