You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    ;

问题根源

  1. 符号复用冲突://同时被定义为行注释开头和算术运算符(opMulDivMod规则中的'//'),词法分析器无法区分两者。
  2. 隐式词法规则优先级:解析器规则中的字面量(如'//')会生成隐式词法规则,这些规则的优先级高于自定义的COMMENT规则。因此,注释中的//会被优先识别为算术运算符,而解析器在当前上下文(stat规则)中不期望该符号,从而抛出错误。

解决方法

根据需求选择以下任一修改方向:

方向一:修改注释符号,避免与运算符冲突

参考Lua注释风格,将行注释改为--,彻底避免符号冲突:

  1. 修改COMMENT词法规则:
COMMENT
    :   '--' ~[\r\n]* -> skip
    ;
  1. 将测试文件中的注释统一改为--开头。

方向二:保留//作为注释,调整运算符规则

若坚持使用//作为行注释,需移除运算符规则中的//,或替换为其他符号:

  1. 修改opMulDivMod规则:
opMulDivMod
    : '*' | '/' | '%'
    ;
  1. 将COMMENT规则移至所有词法规则最前面,确保优先级最高。

额外优化:显式定义运算符词法规则(可选)

为彻底避免隐式规则优先级问题,建议将所有运算符定义为显式词法规则,完全控制匹配顺序:

  1. 调整词法规则顺序与定义:
// 优先定义COMMENT,确保注释被优先匹配
COMMENT
    :   '//' ~[\r\n]* -> skip
    ;

WS
    : [ \t\r\n]+ -> skip
    ;

// 显式定义运算符词法规则
STAR : '*';
SLASH : '/';
PERCENT : '%';

// 其他词法规则...
  1. 修改解析器中的运算符规则:
opMulDivMod
    : STAR | SLASH | PERCENT
    ;

验证修改

重新生成解析器与词法分析器后,运行测试文件,注释将被正确跳过,不再出现解析错误。

内容的提问来源于stack exchange,提问作者ron_the_doe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 03:45:48