【问题标题】:Antlr - Why it expect FunctionCall but PrintCommand gaveAntlr - 为什么它期望 FunctionCall 但 PrintCommand 给了
【发布时间】:2018-01-27 21:55:53
【问题描述】:

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

这是我的 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

【问题讨论】:

  • 你用的是什么antlr版本和命令行? 4.7.1 版给了我错误:“rule localFunctionCall: must label all alternatives or none”。
  • 哦,抱歉,现在修复了上面的代码,这种错误不应该被抛出

标签: java compiler-construction antlr antlr4


【解决方案1】:

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

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

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

【讨论】:

  • 那么关键字'retrobox'的验证是antlr区分大小写的吧?
  • 是的,词法分析是区分大小写的。没有内置的方法来指定不区分大小写的标记,但this page 提供了几种方法,如果您需要的话。
猜你喜欢
  • 2020-12-02
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2016-09-15
相关资源
最近更新 更多