某些语法场景的语法验证问题

Issue with syntax validations for certain scenarios with grammar

我已经编写了用于创建简单表达式的基本语法(add、mul、div、mod、min 以及使用带有一些参数的函数)。

语法:

grammar ExpressionGrammar;

parse: expr EOF;

expr:
    MIN expr
    | expr ( MUL | DIV) expr
    | expr ( ADD | MIN) expr
    | expr  ( MOD )  expr
    | NUM
    | ID
    | STRING
    | function
    | '(' expr ')';

function: ID '(' arguments? ')';

arguments: expr ( ',' expr)*;

/* Tokens */

MUL: '*';
DIV: '/';
MIN: '-';
ADD: '+';
MOD: '%';
OPEN_PAR: '(';
CLOSE_PAR: ')';

NUM: ([0-9]*[.])?[0-9]+;
STRING: '"' ~ ["]* '"';
fragment ID_NODE: [a-zA-Z_$][a-zA-Z0-9_$]*;
ID: ID_NODE ('.' ID_NODE)*;
COMMENT: '/*' .*? '*/' -> skip;
LINE_COMMENT
    : '//' ~[\r\n]* -> skip
    ;
WS: [ \r\t\n]+ -> skip;

有效表达式示例:

1. 1+2    - simple add, multiply, divide and mod operations. 
2. "adadfasdf"   -- simply return a string
3. 233.4234234    -- return a number
4. field.value1    -- field is a fieldType on which value exists ( field with multiple values) 
3. SUBSTR("asdfasdf","adsfasdff","asd");   -- a built in function ( such as SUBSTR, ADD, MIN, etc ) which takes arguments. 
4. ABS(field.value1)  
5. ADD( field.value1,field.value2) 
6. MAX( field.value1,field.value3, 2)
7. field.value1 % field.value2

8. It can even span multiple lines 

 ADD(
    field.value1,
    2,
    ABS(field.valu2)   -- can have another function inside this function. 
    )

ANTLR 在某些情况下当用户输入错误的语法时抛出语法错误 但以下情况未显示为错误。

  1. 允许多个右括号:trim(fields.value1))))))))

  2. 允许多个表达式之间没有任何运算符(当使用两个字段之间没有任何运算符时不会抛出任何错误):

    field.v1 field.v2

  3. 当我在多行中有两个不同的表达式时也不会抛出错误(可能是上述情况的扩展)。

     field.v1 + 2
     field.v2 + 3
    
  4. 当有多个收盘价时不显示任何错误 - "adfadsfad""""""

以上所有情况都可能与我的语法问题有关?不确定。

谁能帮我纠正我的语法以发现这些错误?

这些是您调用的规则中没有 EOF 的典型症状。

如果不包含 EOF,那么 ANTLR4 将解析所有匹配的输入并退出(在输入流结束之前,如果没有其他匹配)。

在你的每个例子中,如果你把它看成“有一些有效的东西,然后是无效的输入”,你会发现它们都是合适的。

这就是为什么 @sepp2k 询问您调用了哪个规则。

很明显您可能调用了 expr 规则而不是 parse 规则(因为 parse 规则确实包含 EOF 标记,它将继续解析直到它看到一个 EOF,并会在此过程中报告错误)。

当您生成 ANTLR 代码时,它会生成 methods/functions 以从您想要的任何规则开始。您必须编写一些代码来创建输入流,然后从该流创建一个 Lexer,然后从您从 Lexer 获得的 TokenStream 创建一个 Parser。最后,一旦您拥有解析器对象,您将选择要调用的解析器规则。

将该规则从 expr() 更改为 parse(),您应该会开始收到预期的错误。

基本上,解析器规则中的 EOF 表示整个输入必须匹配此规则(即它还必须使用“文件结束”标记)。如果没有该标记,规则可以(并且将会)匹配任何与规则匹配的内容,并在无法再找到有效输入时停止。

只看到一个以 EOF 结尾的“顶级”或“入口”规则是很常见的。这通常是一个线索,表明它是您调用的解析器规则。

几个例外:

  • 也许您想要只解析您可以匹配的任何内容而忽略其余部分。然后使用没有终端 EOF 的规则。 (这可能相当罕见)。
  • 也许在某些情况下,您知道自己的输入只能是 expr,但您的顶级规则类似于 stmtscompilationUnit。在这种情况下,您可以创建一个 exprOnly: expr EOF; 规则,然后调用该规则来解析表达式,除非整个输入与 expr 的语法匹配,否则该表达式将失败。您不会有任何其他规则引用 exprOnly 规则,有效地使其成为顶级或入口规则。没有什么可以阻止您有多个顶级规则可供选择。

任何规则中的 EOF 被另一个规则引用,但期望匹配 EOF,很可能(几乎可以肯定)是一个错误。

注意:毫无疑问,您会发现顶级规则不以 EOF 标记结尾的语法。这被认为是一种不好的做法(正是由于您遇到的原因;它可以在不消耗所有输入的情况下成功解析。