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

时间:2018-01-27 21:55:53

标签: java compiler-construction antlr antlr4

我的Antlr-grammar期待一个FunctionCall,但在我的示例代码中,由antlr构建的编译器,我写了一个print-command。有人知道为什么以及如何解决这个问题? print-command命名为:RetroBox.show(); print-command应该从 blockstatements 识别到 blockstatement 语句 localFunctionCall printCommand

这是我的Antrl-grammar:

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

1 个答案:

答案 0 :(得分:1)

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

Antlr应该发出错误:"第3:12行不匹配的输入'。'期待'('"。

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