ANTLR不匹配输入错误



我正在为我自己的语言写一个解析器。我正在尝试解析短语

Number a is 10;

基本等同于int a = 10;

应该匹配variable_def规则。当我运行它时,我得到错误

line 1:0 extraneous input 'Number' expecting {<EOF>, 'while', ';', 'if', 'function', TYPE, 'global', 'room', ID}
line 1:9 mismatched input 'is' expecting '('

这是我的语法:

grammar Script;
@header {
package script;
}
// PARSER
program
:
    block EOF
;
block
:
    (
        statement
        | functionDecl
    )*
;
statement
:
    (variable_def
    | functionCall
    | ifStatement
    | forStatement
    | whileStatement) ';'
;
whileStatement
:
    'while' '(' expression ')' '{' (statement)* '}'
;
forStatement
:
;
ifStatement
:
    'if' '(' expression ')' '{' statement* '}'
    (
        (
            'else' '{' statement* '}'
        )
        |
        (
            'else' ifStatement
        )
    )?
;
functionDecl
:
    'function' ID
    (
        '('
        (
            TYPE ID
        )?
        (
            ',' TYPE ID
        )* ')'
    )?
    (
        'returns' RETURN_TYPE
    )? '{' statement* '}'
;
functionCall
:
    ID '(' exprList? ')'
;
exprList
:
    expression
    (
        ',' expression
    )*
;
variable_def
:
    TYPE assignment
    | GLOBAL variable_def
    | ROOM variable_def
;
expression
:
    '-' expression # unaryMinusExpression
    | '!' expression # notExpression
    | expression '^' expression # powerExpression
    | expression '*' expression # multiplyExpression
    | expression '/' expression # divideExpression
    | expression '%' expression # modulusExpression
    | expression '+' expression # addExpression
    | expression '-' expression # subtractExpression
    | expression '>=' expression # gtEqExpression
    | expression '<=' expression # ltEqExpression
    | expression '>' expression # gtExpression
    | expression '<' expression # ltExpression
    | expression '==' expression # eqExpression
    | expression '!=' expression # notEqExpression
    | expression '&&' expression # andExpression
    | expression '||' expression # orExpression
    | expression IN expression # inExpression
    | NUMBER # numberExpression
    | BOOLEAN # boolExpression
    | functionCall # functionCallExpression
    | '(' expression ')' # expressionExpression
;
assignment
:
    ID ASSIGN expression
;
// LEXER
RETURN_TYPE
:
    TYPE
    | 'Nothing'
;
TYPE
:
    'Number'
    | 'String'
    | 'Anything'
    | 'Boolean'
    | 'Growable'? 'List' 'of' TYPE
;
GLOBAL
:
    'global'
;
ROOM
:
    'room'
;
ASSIGN
:
    'is'
    (
        'a'
        | 'an'
        | 'the'
    )?
;
EQUAL
:
    'is'?
    (
        'equal'
        (
            's'
            | 'to'
        )?
        | 'equivalent' 'to'?
        | 'the'? 'same' 'as'?
    )
;
IN
:
    'in'
;
BOOLEAN
:
    'true'
    | 'false'
;
NUMBER
:
    '-'? INT '.' INT EXP? // 1.35, 1.35E-9, 0.3, -4.5
    | '-'? '.' INT EXP? // -.35, .35e5
    | '-'? INT EXP // 1e10 -3e4
    | '-'? INT // -3, 45
;
fragment
EXP
:
    [Ee] [+-]? INT
;
fragment
INT
:
    '0'
    | [1-9] [0-9]*
;
STRING
:
    '"'
    (
        ' ' .. '~'
    )* '"'
;
ID
:
    (
        'a' .. 'z'
        | 'A' .. 'Z'
        | '_'
    )
    (
        'a' .. 'z'
        | 'A' .. 'Z'
        | '0' .. '9'
        | '_'
    )*
;
fragment
JAVADOC_COMMENT
:
    '/*' .*? '*/'
;
fragment
LINE_COMMENT
:
    (
        '//'
        | '#'
    ) ~( 'r' | 'n' )*
;
COMMENT
:
    (
        LINE_COMMENT
        | JAVADOC_COMMENT
    ) -> skip
;
WS
:
    [ tnr]+ -> skip
;

如何修复这个错误?

主要原因是因为在您当前的语法中,TYPE令牌将永远不会被创建,因为RETURN_TYPE也匹配TYPE,并且在TYPE之前定义(因此具有优先级)。

而且,您在词法分析器中做了太多的工作。一旦您开始在词法分析器中将单词粘合在一起,这就表明您应该将这些规则改为语法分析器规则。

和空格可能被词法分析器跳过,但只能从解析器规则中跳过。以ASSIGN规则为例:

ASSIGN
 : 'is' ( 'a' | 'an' | 'the' )?
 ;

此规则将不匹配字符串"is a" ("is""a"之间的空格),它只匹配"isa", "isan""isthe"。解决方案:从它创建一个解析器规则:

assign
 : 'is' ( 'a' | 'an' | 'the' )?
 ;

相当于:

assign
 : 'is' ( 'a' | 'an' | 'the' )?
 ;
IS : 'is';
A : 'a';
AN : 'an';
THE : 'the';
...
ID : [a-zA-Z_] [a-zA-Z_0-9]*;

这将导致令牌'is', 'a', 'an''the'永远不会作为ID令牌匹配。因此,以下源代码作为正确的赋值将失败:

Number a is 42;

因为'a'被标记为A令牌,而不是ID

要解决这个问题,可以添加以下解析器规则:
id
 : ( ID | A | AN | IS | THE | ... )
 ;

并在其他解析器规则中使用该规则而不是ID

一个快速的演示是这样的:

grammar Script;
// PARSER
program
 : block EOF
 ;
block
 : ( statement | functionDecl )*
 ;
statement
 : ( variable_def
   | functionCall
   | ifStatement
   | forStatement
   | whileStatement
   )
   ';'
 ;
whileStatement
 : 'while' '(' expression ')' '{' statement* '}'
 ;
forStatement
 :
 ;
ifStatement
 : 'if' '(' expression ')' '{' statement* '}'
   ( ( 'else' '{' statement* '}' ) | ( 'else' ifStatement ) )?
 ;
functionDecl
 : 'function' id ( '(' ( type id )? ( ',' type id )* ')' )?
   ( 'returns' return_type )? '{' statement* '}'
 ;
functionCall
 : id '(' exprList? ')'
 ;
exprList
 : expression ( ',' expression )*
 ;
variable_def
 : type assignment
 | GLOBAL variable_def
 | ROOM variable_def
 ;
expression
 : '-' expression             # unaryMinusExpression
 | '!' expression             # notExpression
 | expression '^' expression  # powerExpression
 | expression '*' expression  # multiplyExpression
 | expression '/' expression  # divideExpression
 | expression '%' expression  # modulusExpression
 | expression '+' expression  # addExpression
 | expression '-' expression  # subtractExpression
 | expression '>=' expression # gtEqExpression
 | expression '<=' expression # ltEqExpression
 | expression '>' expression  # gtExpression
 | expression '<' expression  # ltExpression
 | expression '==' expression # eqExpression
 | expression '!=' expression # notEqExpression
 | expression '&&' expression # andExpression
 | expression '||' expression # orExpression
 | expression IN expression   # inExpression
 | NUMBER                     # numberExpression
 | BOOLEAN                    # boolExpression
 | functionCall               # functionCallExpression
 | '(' expression ')'         # expressionExpression
 ;
assignment
 : id assign expression
 ;
return_type
 : type
 | 'Nothing'
 ;
type
 : TYPE
 | 'Growable'? 'List' OF TYPE
 ;
assign
 : 'is' ( A | AN | THE )?
 ;
equal
 : 'is'? ( EQUAL ( S
                 | TO
                 )?
         | EQUIVALENT TO?
         | THE? SAME AS?
         )
 ;
id
 : ( ID | OF | A | AN | EQUAL | S | EQUIVALENT | TO | THE | SAME | AS )
 ;
// LEXER
// Some keyword you might want to match as an identifier too:
OF : 'of';
A : 'a';
AN : 'an';
EQUAL : 'equal';
S : 's';
EQUIVALENT : 'equivalent';
TO : 'to';
THE : 'the';
SAME : 'same';
AS : 'as';
COMMENT
 : ( LINE_COMMENT | JAVADOC_COMMENT ) -> skip
 ;
WS
 : [ tnr]+ -> skip
 ;
TYPE
 : 'Number'
 | 'String'
 | 'Anything'
 | 'Boolean'
 ;
GLOBAL
 : 'global'
 ;
ROOM
 : 'room'
 ;
IN
 : 'in'
 ;
BOOLEAN
 : 'true'
 | 'false'
 ;
NUMBER
 : '-'? INT '.' INT EXP? // 1.35, 1.35E-9, 0.3, -4.5
 | '-'? '.' INT EXP? // -.35, .35e5
 | '-'? INT EXP // 1e10 -3e4
 | '-'? INT // -3, 45
 ;
STRING
 : '"' .*? '"'
 ;
ID
 : [a-zA-Z_] [a-zA-Z_0-9]*
 ;
fragment EXP
 : [Ee] [+-]? INT
 ;
fragment INT
 : '0'
 | [1-9] [0-9]*
 ;
fragment JAVADOC_COMMENT
 : '/*' .*? '*/'
 ;
fragment LINE_COMMENT
 : ( '//' | '#' ) ~( 'r' | 'n' )*
 ;

这个特殊的错误发生是因为在语法的词法分析器部分TYPE术语与RETURN_TYPE词法分析器术语冲突。还有其他错误,但问题展示可能被简化为以下内容:

grammar Script;
program
:
    block EOF
;
block
:
    (
       statement
     | functionDecl
    )*
;
statement
:
    (
      variable_def
    ) ';'
;
functionDecl
:
    'function' ID
    (
      'returns' RETURN_TYPE
    )?
    '{' statement* '}'
;
variable_def
:
    TYPE assignment
;
expression
:
    NUMBER # numberExpression
;
assignment
:
    ID ASSIGN expression
;
RETURN_TYPE
:
    TYPE
    | 'Nothing'
;
TYPE
:
    'Number'
;
ASSIGN
:
    'is'
    (
        'a'
      | 'an'
      | 'the'
    )?
;
NUMBER
:
    '-'? INT // -3, 45
;
fragment
INT
:
    '0'
  | [1-9] [0-9]*
;
ID
:
     (
        'a' .. 'z'
      | 'A' .. 'Z'
      | '_'
     )
     (
        'a' .. 'z'
      | 'A' .. 'Z'
      | '0' .. '9'
      | '_'
    )*
;
WS
:
    [ tnr]+ -> skip
;

如果RETURN_TYPE被转换成解析器规则,例如returnType,那么一切都没问题(对于这个特定的测试,正如我所说的,你的语法包含其他类似的错误)。这展示了关于Antlr(以及所有其他词法分析器和解析器分开的解析器生成器)行为的基本原则:词法分析器总是在自己的上下文中工作,它不能确定一个特定的符号序列是一个术语还是另一个术语,如果两个术语共享相同的字符序列。因此,您有两种选择:引入词法分析器上下文(称为模式),或者只在词法分析器级别保留基本和明确的实体,并将其他所有内容移到解析器中。

相关内容

  • 没有找到相关文章

最新更新