Lexer 规则顺序对 .g4 语法文件中解析的影响

问题描述 投票:0回答:1

我在 ANTLR 中处理自定义语言的语法文件 (.g4) 时遇到了一个令人困惑的问题。该语法定义了词法分析器和解析器规则,我注意到词法分析器规则的顺序似乎会影响解析器的行为。

具体问题在于cellLiteral规则,它应该匹配TABLENAME、TABLENUMBER、COLUMNDESIGNATORINSIDE和KEYCOLUMNQUALIFIER的不同组合。但是,我发现如果我将 LITERALNUMERIC 和 IDENTIFIER 规则移至词法分析器中 KEYCOLUMNQUALIFIER 规则下方,则解析器会成功识别 cellLiteral 规则。但这样做会导致其他规则,尤其是与算术运算和标识符相关的规则,停止正常工作。

作为参考,这里是语法文件:

grammar MYScript;

/*
 * Parser Rules
 */

formula : expression EOF ;

expression 
    :   expression op=(MUL|DIV) expression              #multiplicativeOpExpression         // MultiplicativeOperation
    |   expression op=(ADD|SUB) expression              #additiveExpression                 // AdditiveOperation
    |   expression POW expression                       #powerOpExpression                  // MultiplicativeOperation
    |   expression op=(GT|GE|LT|LE) expression          #compareExpression                  // Comparison Operations
    |   expression op=(EQ|NE) expression                #equalityExpression                 // Equality Operations
    |   expression AND expression                       #andExpression                      // Logical AND
    |   expression OR expression                        #orExpression                       // Logical OR
    |   invocation                                      #invocationExpression               // Call to a built-in or user-defined function
    |   LITERALSTRING                                   #stringLiteralExpression
    |   numericConstant                                 #numericLiteralExpression
    |   DATE                                            #dateExpression                     // Date Expression
    |   '-'expression                                   #unaryNegationExpression            // unary negation
    |   PARAMETER                                       #primaryParameterExpression
    |   TRUE                                            #booleanLiteralTrue
    |   FALSE                                           #booleanLiteralFalse
    |   OPENBRACKET expression CLOSEBRACKET             #bracketExpression                  // Parenthesized Expression
    |   OPENPAREN expression CLOSEPAREN                 #parenExpression                    // Parenthesized Expression
    |   cellLiteral                                     #cellLiteralExpression
    ;

 numericConstant
    : LITERALNUMERIC
    | SUB LITERALNUMERIC
    ;

invocation
    : (IDENTIFIER) OPENPAREN (expression (COMMA expression)*)? CLOSEPAREN
    ;  

cellLiteral
    : OPENBRACKET TABLENAME COMMA TABLENUMBER COMMA TABLENUMBER CLOSEBRACKET
    | OPENBRACKET TABLENAME COMMA TABLENUMBER COMMA COLUMNDESIGNATORINSIDE CLOSEBRACKET
    | OPENBRACKET TABLENAME COMMA TABLENUMBER OPENPAREN KEYCOLUMNQUALIFIER CLOSEPAREN COMMA TABLENUMBER CLOSEBRACKET
    | OPENBRACKET TABLENAME COMMA TABLENUMBER OPENPAREN KEYCOLUMNQUALIFIER CLOSEPAREN COMMA COLUMNDESIGNATORINSIDE CLOSEBRACKET
    ;     
 


/*
 * Lexer Rules
 */

MUL :   '*';
DIV :   '/';
POW :   '^';
ADD :   '+';
SUB :   '-';
EQ  :   '=';
NE  :   '!=';
GT  :   '>';
LT  :   '<';
GE  :   '>=';
LE  :   '<=';
AND :   'And';
OR  :   'Or';
TRUE:   'True';
FALSE:  'False';

LITERALNUMERIC
    : FLOAT
    | INT
    ;
    
IDENTIFIER  
    :   (LETTER) (LETTER | DIGIT | [_])* 
    ;

TABLENAME
    : ('F'|'L'|'P'|'T'|'X'|'LS'|'PS'|'MS'|'MSQ'|'YS'|'YSQ'|'MLR'|'HS'|'HSQ') DIGIT DIGIT DIGIT DIGIT [0-9A-Z]*
    ;

TABLENUMBER
    : [A-Za-z0-9]+('.'[A-Za-z0-9]+)?('.'[A-Za-z0-9]+)?
    ;
    
COLUMNDESIGNATORINSIDE
    : '~' TABLENUMBER
    ;

KEYCOLUMNQUALIFIER
    : KEYCODE EQ LITERALSTRING
    | KEYCODE NE LITERALSTRING
    | QUARTER EQ TABLENUMBER
    | QUARTER NE TABLENUMBER
    | SEQNO EQ LITERALSTRING
    | SEQNO NE LITERALSTRING
    | STAABBR EQ LITERALSTRING
    | STAABBR NE LITERALSTRING
    ;

LITERALSTRING
    : SINGLEQUOTE ~ ('\'')* SINGLEQUOTE
    | DOUBLEQUOTE ~ ('"')* DOUBLEQUOTE
    ;

SINGLEQUOTE : '\'';
DOUBLEQUOTE : '"';

PARAMETER : '$'[1-9A];

DATE
    : '#'[01][0-9]'/'[0-3][0-9]'/'[23][01][0-9][0-9]'#'
    ;

FLOAT
    :   DIGIT+ '.' DIGIT*
    |   '.' DIGIT+ 
    ;

INT :    DIGIT+ ;



KEYCODE
    : 'key_code';

QUARTER
    : 'quarter';

SEQNO
    : 'seq_no';

STAABBR
    : 'stabbr';

OPENBRACKET : '[';
CLOSEBRACKET: ']';

OPENPAREN  : '(';
CLOSEPAREN : ')';

COMMA : ',';
AMPERSAND : '@';

fragment
LETTER : [a-zA-Z] ;

fragment
DIGIT : [0-9] ; // match single Digit

COMMENT:     ';'  .*?    -> channel(HIDDEN);

WS :     [ \t\r\n]+ -> channel(HIDDEN) ;

/* Anything else is accepted by the lexer and passed to the parser for error handling */
ERRORCHAR : . ;

我尝试调整其他词法分析器规则的顺序,但这似乎并不能解决问题。我怀疑这个问题可能与词法分析器规则优先级或令牌重叠有关,但我不完全确定。

如果有人遇到过类似的问题或了解 ANTLR 词法分析器和解析器行为的复杂性,我将非常感谢您对如何解决此问题的见解和指导。我需要解析器正确识别 cellLiteral 和算术运算以及 IDENTIFIER 相关规则。

提前感谢您的帮助!

antlr antlr4
1个回答
0
投票

分词器使用以下两个标准来匹配 Lexer 规则。

1 - 匹配最长的输入字符序列的规则将被视为匹配规则。

2 - 如果两个(或多个)规则匹配完全相同数量的输入字符,则将选择首先出现的 Lexer 规则。这意味着您希望更具体的规则出现在更一般的规则之前(如果更一般的规则先出现,您将永远不会匹配更具体的规则)

使用插件或

grun
别名(调用
TestRig
)和
-tokens
选项来了解标记生成器生成了哪些标记总是一个好主意。

注意:用户认为解析器规则将控制尝试哪些词法分析器规则的情况并不罕见。不是这种情况。 ANTLR 将处理输入字符流并生成一个(令牌的)TokenStream,然后将其与解析器规则进行匹配。解析器规则对 Lexer 输入匹配过程没有影响。

© www.soinside.com 2019 - 2024. All rights reserved.