Antlr - 为什么它期望 FunctionCall 但 PrintCommand 给了

Antlr - Why it expect FunctionCall but PrintCommand gave

我的 Antlr 语法需要一个 FunctionCall,但在我为 antlr 构建的编译器编写的示例代码中,我写了一个打印命令。有人知道为什么以及如何解决这个问题吗?打印命令被命名为:RetroBox.show();打印命令应该被识别为从blockstatementsblockstatementstatement localFunctionCallprintCommand

这是我的 Antrl 语法:

grammar Mars;
// ******************************LEXER 
BEGIN*****************************************

// Keywords
FUNC:                           'func';
ENTRY:                          'entry';
VARI:                           'vari';
VARF:                           'varf';
VARC:                           'varc';
VARS:                           'vars';
LET:                            'let';
INCREMENTS:                     'increments';
RETROBOX:                       'retrobox';
SHOW:                           'show';

// Literals

DECIMAL_LITERAL:    ('0' | [1-9] (Digits? | '_'+ Digits)) [lL]?;

FLOAT_LITERAL:      (Digits '.' Digits? | '.' Digits) ExponentPart? [fFdD]?
         |       Digits (ExponentPart [fFdD]? | [fFdD])
         ;

CHAR_LITERAL:       '\'' (~['\\r\n] | EscapeSequence) '\'';

STRING_LITERAL:     '"' (~["\\r\n] | EscapeSequence)* '"';

// Seperators

ORBRACKET:                          '(';
CRBRACKET:                          ')';
OEBRACKET:                          '{';
CEBRACKET:                          '}';
SEMI:                               ';';
POINT:                              '.';

// Operators

ASSIGN:             '=';

// Whitespace and comments

WS:                 [ \t\r\n\u000C]+ -> channel(HIDDEN);
COMMENT:            '/*' .*? '*/'    -> channel(HIDDEN);
LINE_COMMENT:       '//' ~[\r\n]*    -> channel(HIDDEN);

// Identifiers

IDENTIFIER:         Letter LetterOrDigit*;

// Fragment rules

fragment ExponentPart
    : [eE] [+-]? Digits
    ;  

fragment EscapeSequence
    : '\' [btnfr"'\]
    | '\' ([0-3]? [0-7])? [0-7]
    | '\' 'u'+ HexDigit HexDigit HexDigit HexDigit
    ;

fragment HexDigits
    : HexDigit ((HexDigit | '_')* HexDigit)?
    ;

fragment HexDigit
    : [0-9a-fA-F]
    ;

fragment Digits
    : [0-9] ([0-9_]* [0-9])?
    ;

fragment LetterOrDigit
    : Letter
    | [0-9]
    ;

fragment Letter
    : [a-zA-Z$_] // these are the "java letters" below 0x7F
    | ~[\u0000-\u007F\uD800-\uDBFF] // covers all characters above 0x7F                 which are not a surrogate
    | [\uD800-\uDBFF] [\uDC00-\uDFFF] // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
    ;

// *******************************LEXER     END****************************************

// *****************************PARSER BEGIN*****************************************

program
    : mainfunction  #Programm
    | /*EMPTY*/              #Garnichts
    ;

mainfunction
    : FUNC VARI ENTRY ORBRACKET CRBRACKET block  #NormaleHauptmethode
    ;

block
    : '{' blockStatement '}'   #CodeBlock
    | /*EMPTY*/                #EmptyCodeBlock
    ;

blockStatement
    : statement* #Befehl
    ;

statement
    : localVariableDeclaration
    | localVariableInitialization
    | localFunctionImplementation
    | localFunctionCall
    ;

expression
    : left=expression op='%'
    | left=expression op=('*' | '/') right=expression
    | left=expression op=('+' | '-') right=expression
    | neg='-' right=expression
    | number
    | IDENTIFIER
    | '(' expression ')'
    ;

number
    : DECIMAL_LITERAL
    | FLOAT_LITERAL
    ;

localFunctionImplementation
    : FUNC primitiveType IDENTIFIER ORBRACKET CRBRACKET block #Methodenimplementierung
    ;

localFunctionCall
    : IDENTIFIER ORBRACKET CRBRACKET SEMI #Methodenaufruf
    | printCommand #RetroBoxShowCommand
    ;

printCommand
    : RETROBOX POINT SHOW ORBRACKET params=primitiveLiteral CRBRACKET SEMI     #PrintCommandWP
    ;

localVariableDeclaration
    : varTypeDek=primitiveType IDENTIFIER SEMI #Variablendeklaration
    ;

localVariableInitialization
    : varTypeIni=primitiveType IDENTIFIER ASSIGN varValue=primitiveLiteral     SEMI #VariableninitKonst
    | varTypeIni=primitiveType IDENTIFIER ASSIGN varValue=expression SEMI #VariableninitExpr
    ;

primitiveLiteral
    : DECIMAL_LITERAL
    | FLOAT_LITERAL
    | STRING_LITERAL
    | CHAR_LITERAL
    ;

primitiveType
    : VARI
    | VARC
    | VARF
    | VARS
    ;

// ******************************PARSER END****************************************

这是我的示例代码:

func vari entry()
{
    RetroBox.show("Hallo"); //Should be recognised as print-command
}

这是从 Antlr 打印的 AST:

AST from Compiler

问题是您的 RETROBOX 关键字是 'retrobox' 但您的示例代码将其键入 'RetroBox'。 Antlr 将 'RetroBox' 解析为标识符,因此以下 '.'出乎意料。

Antlr 应该发出一个错误:"line 3:12 mismatched input '.' expecting '('".

然后它会尝试恢复并继续解析。它尝试删除单个标记(只是忽略“.”)并发现它有效...除了它现在匹配的规则是#Methodenaufruf 而不是#RetroBoxShowCommand。