为什么Antlr4将我的句子解析为两个陈述



我正在为表达式写一些解析器。目前,我只希望它识别二进制乘法( myid * myid )和类似C的dereed Persed Pointer( * myid ),以及一些分配语句( myid)*= myid )。

使解析器投掷错误的输入是:

x *= y;

...解析器在此消息和解析树上失败:

[line 1:1 mismatched input ' *' expecting {';', NEWLINE}]
(sourceFile (statement (expressionStatement (expression (monoOperatedExpression (atomicExpression x))))  * =  ) (statement (expressionStatement (expression (monoOperatedExpression (atomicExpression y)))) ;) <EOF>)

我已经挠头了一段时间,但是我看不到语法中有什么问题(在下面查看)。有提示吗?预先感谢。

grammar Sable;
options {}
@header {
    package org.sable.parser;
}
ASSIGNMENT_OP:
    '='
    ;
BINARY_OP:
    '*'
    ;
WS_BUT_NOT_NEWLINE:
    WhiteSpaceButNotNewLineCharacter
    ;
NEWLINE:
    ('u000D' 'u000A')
    | 'u000A'
    ;
WSA_BINARY_OP:
    (WS_BUT_NOT_NEWLINE+ BINARY_OP WS_BUT_NOT_NEWLINE+)
    | BINARY_OP
    ;
WSA_PREFIX_OP:
    (WS_BUT_NOT_NEWLINE+ '*' )
    ;
WS  :  WhiteSpaceCharacter+ -> skip
    ;
IDENTIFIER:
    (IdentifierHead IdentifierCharacter*)
    | ('`'(IdentifierHead IdentifierCharacter*)'`')
    ;
// NOTE: a file with zero statements is allowed because
// it can contain just comments.
sourceFile:
    statement* EOF;
statement:
    expressionStatement (';' | NEWLINE);
// Req. not existing any valid expression starting from
// an equals sign or any other assignment operator.
expressionStatement:
    expression (assignmentOperator expression)?;
expression:
    monoOperatedExpression (binaryOperator monoOperatedExpression)?
    ;
monoOperatedExpression:
    atomicExpression
    ;
binaryOperator:
    WSA_BINARY_OP
    ;
atomicExpression:
    IDENTIFIER ('<' type (',' type)* '>')? //TODO: can this be a lsv?
    ;
type:
    IDENTIFIER
    ;
assignmentOperator:
    ASSIGNMENT_OP
    ;
fragment DecimalDigit:
    '0'..'9'
    ;
fragment IdentifierHead:
    'a'..'z'
    | 'A'..'Z'
    ;
fragment IdentifierCharacter:
    DecimalDigit
    | IdentifierHead
    ;
fragment WhiteSpaceCharacter:
    WhiteSpaceButNotNewLineCharacter
    | NewLineCharacter;
fragment WhiteSpaceButNotNewLineCharacter:
    [u0020u000Cu0009u000Bu000C]
    ;
fragment NewLineCharacter:
    [u000Au000D]
    ;

编辑:应评论者的要求添加语法的新版本。

grammar Sable;
options {}
@header {
    package org.sable.parser;
}
//
// PARSER RULES.
sourceFile              : statement* EOF;
statement               : expressionStatement (SEMICOLON | NEWLINE);
expressionStatement     : expression (ASSIGNMENT_OPERATOR expression)?;
expression:
    expression WSA_OPERATOR expression
    | expression OPERATOR expression
    | OPERATOR expression
    | expression OPERATOR
    | atomicExpression
    ;
atomicExpression:
    IDENTIFIER ('<' type (',' type)* '>')? //TODO: can this be a lsv?
    ;
type                    : IDENTIFIER;

//
// LEXER RULES.
COMMENT                 : '/*' .*? '*/'                    -> channel(HIDDEN);
LINE_COMMENT            : '//' ~[00A00D]*              -> channel(HIDDEN);
ASSIGNMENT_OPERATOR     : Operator? '=';
// WSA = White Space Aware token.
// These are tokens that occurr in a given whitespace context.
WSA_OPERATOR:
    (WhiteSpaceNotNewline+ Operator WhiteSpaceNotNewline+)
    ;
OPERATOR         : Operator;
// Newline chars are defined apart because they carry meaning as a statement
// delimiter.
NEWLINE:
    ('u000D' 'u000A')
    | 'u000A'
    ;
WS                      : WhiteSpaceNotNewline -> skip;
SEMICOLON               : ';';

IDENTIFIER:
    (IdentifierHead IdentifierCharacter*)
    | ('`'(IdentifierHead IdentifierCharacter*)'`')
    ;
fragment DecimalDigit   :'0'..'9';
fragment IdentifierHead:
    'a'..'z'
    | 'A'..'Z'
    | '_'
    | 'u00A8'
    | 'u00AA'
    | 'u00AD'
    | 'u00AF' |
    'u00B2'..'u00B5' |
    'u00B7'..'u00BA'  |
    'u00BC'..'u00BE' |
    'u00C0'..'u00D6' |
    'u00D8'..'u00F6' |
    'u00F8'..'u00FF' |
    'u0100'..'u02FF' |
    'u0370'..'u167F' |
    'u1681'..'u180D' |
    'u180F'..'u1DBF' |
    'u1E00'..'u1FFF' |
    'u200B'..'u200D' |
    'u202A'..'u202E' |
    'u203F'..'u2040' |
    'u2054' |
    'u2060'..'u206F' |
    'u2070'..'u20CF' |
    'u2100'..'u218F' |
    'u2460'..'u24FF' |
    'u2776'..'u2793' |
    'u2C00'..'u2DFF' |
    'u2E80'..'u2FFF' |
    'u3004'..'u3007' |
    'u3021'..'u302F' |
    'u3031'..'u303F' |
    'u3040'..'uD7FF' |
    'uF900'..'uFD3D' |
    'uFD40'..'uFDCF' |
    'uFDF0'..'uFE1F' |
    'uFE30'..'uFE44' |
    'uFE47'..'uFFFD'
    ;
fragment IdentifierCharacter:
    DecimalDigit
    | 'u0300'..'u036F'
    | 'u1DC0'..'u1DFF'
    | 'u20D0'..'u20FF'
    | 'uFE20'..'uFE2F'
    | IdentifierHead
    ;
// Non-newline whitespaces are defined apart because they carry meaning in
// certain contexts, e.g. within space-aware operators.
fragment WhiteSpaceNotNewline    : [u0020u000Cu0009u000Bu000C];
fragment Operator:
    '*'
    | '/'
    | '%'
    | '+'
    | '-'
    | '<<'
    | '>>'
    | '&'
    | '^'
    | '|'
    ;

规则

expression
    : monoOperatedExpression (binaryOperator monoOperatedExpression)?
    ;

binaryOperator之后不允许=。因此,运行时报告说,它不知道在消耗BINARY_OP后使用什么规则。

语法可以通过一些显着的重组固定,最好是简化。

1-可以通过忽略Whitespace/Newline处理。

WS : [ trn] -> skip;

c家族和类似python的语言是上下文的自由语言,具有一些众所周知的上下文敏感角案例。ANTLR是一种免费的解析器,具有许多方便能力来处理上下文敏感性。因此,忽略(或隐藏)的空格应该是默认的。

2-根据定义,请歧义*的使用:

STAR_EQUAL : '*=' ;
STAR       : '*'  ;
EQUAL      : '='  ;

这可以确保任何单个STAR仅可被视为指针标记或乘法运算符(序列星WS等于您的语言无效,或者可能具有某些自定义含义)。

>

3-使用解析器规则递归:考虑C语法中的表达处理规则,特别是从expression规则开始。简化的模式是:

expression     // list of all valid syntaxes for an `expression`
    : LPAREN expression RPAREN
    | expression ( COMMA expression )*
    | expression op expression 
    | unitary_op expression 
    | expression unitary_op 
    | << any other valid syntax >>
    | atom
    ;
 unitary_op : 2PLUS | 2DASH | .... ;
 op         : STAR_EQUAL | STAR | EQUAL | .... ;
 atom
    : STAR? IDENTIFIER   // pointer usage
    | NUMBER
    ;

以这种方式提出,语法将更加可读和可维护。

随着这些更改,完成语法的修订是一个简单的操作练习(意思是,尝试并发布遇到的任何问题)。

奖励 - ANTLR是自上而下的解析器。因此,将解析器规则放在顶部,组织到狭窄。其次是Lexer规则,也以相同的方式(任何Lexer模式)排序,然后在最底部进行片段规则。

这种秩序减轻了您和其他人的语法的认知能力。例如,使树转储更容易/更快地理解。还将简化最终分为分裂语法的任务(如果语法具有任何显着的复杂性,则建议使用模式)。

)。

完整的语法

grammar Sable;
@header {
    package org.sable.parser.gen;
}
sable
    : statement* EOF
    ;
statement
    : expression? SEMI
    ;
expression
    : LPAREN expression RPAREN
    | COMMA expression
    | expression op expression
    | unitary_op expression
    | expression unitary_op
    | STAR? IDENTIFIER
    | NUMBER
    ;
 unitary_op
    : DPLUS | DMINUS
    ;
 op : STAR_EQUAL | DIV_EQUAL | PLUS_EQUAL | MINUS_EQUAL | EQUAL
    | STAR | DIV | PLUS | MINUS
    ;

COMMENT     : Comment -> skip ;
STAR_EQUAL  : '*=' ;
DIV_EQUAL   : '/=' ;
PLUS_EQUAL  : '+=' ;
MINUS_EQUAL : '-=' ;
EQUAL       : '='  ;
STAR        : '*'  ; // mult or pointer
DIV         : '/'  ;
PLUS        : '+'  ;
MINUS       : '-'  ;
DPLUS       : '++' ;
DMINUS      : '--' ;
COMMA       : ','  ;
DOT         : '.'  ;
SEMI        : ';'  ;
LPAREN      : '('  ;
RPAREN      : ')'  ;
LBRACE      : '{'  ;
RBRACE      : '}'  ;
LBRACK      : '['  ;
RBRACK      : ']'  ;
LANGLE      : '<'  ;
RANGLE      : '>'  ;
NUMBER      : [0-9]+ ('.' [0-9]+)? ([eE] [+-]? [0-9]+)? ;
IDENTIFIER  : [a-zA-Z_][a-zA-Z0-9_-]*  ;
WS          : [ trn]+    -> skip;
ERRCHAR
    :   .   -> channel(HIDDEN)
    ;
fragment Comment
    :   '/*' .*? '*/'
    |   '//' ~[rn]*
    ;

生成但未测试。报告未处理的任何角案件。

相关内容

  • 没有找到相关文章

最新更新