Parsing 为什么antlr4将我的句子解析为两个语句?
我正在为表达式编写一个小解析器。目前,我只想让它识别二进制乘法(myId*myId)和类C的去引用指针(*myId),再加上一些赋值语句(myId*=myId) 使解析器抛出错误的输入是:Parsing 为什么antlr4将我的句子解析为两个语句?,parsing,antlr,whitespace,grammar,antlr4,Parsing,Antlr,Whitespace,Grammar,Antlr4,我正在为表达式编写一个小解析器。目前,我只想让它识别二进制乘法(myId*myId)和类C的去引用指针(*myId),再加上一些赋值语句(myId*=myId) 使解析器抛出错误的输入是: x *= y; 。。。解析器在其上失败,并显示此消息和解析树: [line 1:1 mismatched input ' *' expecting {';', NEWLINE}] (sourceFile (statement (expressionStatement (expression (monoOpe
x *= y;
。。。解析器在其上失败,并显示此消息和解析树:
[line 1:1 mismatched input ' *' expecting {';', NEWLINE}]
(sourceFile (statement (expressionStatement (expression (monoOperatedExpression (atomicExpression x)))) * = ) (statement (expressionStatement (expression (monoOperatedExpression (atomicExpression y)))) ;) <EOF>)
[行1:1不匹配的输入'*'应为{';',换行符}]
(源文件(语句(表达式语句(表达式(单操作表达式(原子表达式x)))*=)(语句(表达式语句(表达式(单操作表达式(原子表达式y)));)
我挠头已经有一段时间了,但我看不出我的语法有什么错误(见下文)。有什么提示吗?提前谢谢
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:
[\u0020\u000C\u0009u000B\u000C]
;
fragment NewLineCharacter:
[\u000A\u000D]
;
语法;
选项{}
@标题{
包org.sable.parser;
}
作业(OP):
'='
;
二进制运算:
'*'
;
WS_但_非_新行:
空白但不换行字符
;
新行:
(“\u000D”\u000A”)
|“\u000A”
;
WSA_二进制运算:
(WS_但非NEWLINE+二进制操作WS_但非NEWLINE+)
|二进制运算
;
WSA_前缀_OP:
(WS_但不是新行+'*')
;
WS:WhiteSpaceCharacter+->skip
;
标识符:
(IdentifierHead IdentifierCharacter*)
|('`'(IdentifierHead IdentifierCharacter*)'`')
;
//注意:允许使用零语句的文件,因为
//它可以只包含注释。
源文件:
报表*EOF;
声明:
表达式语句(“;”|换行符);
//请求。不存在任何从开始的有效表达式
//等号或任何其他赋值运算符。
表达声明:
表达式(赋值运算符表达式)?;
表达方式:
monoOperatedExpression(二进制运算符monoOperatedExpression)?
;
单操作表达式:
原子表达式
;
二进制运算符:
WSA_二进制运算
;
原子表达式:
标识符(“”)//托多:这是lsv吗?
;
类型:
标识符
;
转让经营人:
作业
;
片段小数位数:
'0'..'9'
;
碎片识别头:
“a”…“z”
|“A”…“Z”
;
片段标识符字符:
小数位数
|识别头
;
片段空白字符:
空白但不换行字符
|换行符;
片段WhiteSpaceButNotNewLineCharacter:
[\u0020\u000C\u0009u000B\u000C]
;
片段换行符:
[\u000A\u000D]
;
编辑:应评论员的请求添加新版本的语法
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 : '//' ~[\000A\000D]* -> 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 : [\u0020\u000C\u0009u000B\u000C];
fragment Operator:
'*'
| '/'
| '%'
| '+'
| '-'
| '<<'
| '>>'
| '&'
| '^'
| '|'
;
语法;
选项{}
@标题{
包org.sable.parser;
}
//
//解析器规则。
sourceFile:statement*EOF;
语句:expressionStatement(分号|换行符);
表达式语句:表达式(赋值运算符表达式)?;
表达方式:
表达式WSA_运算符表达式
|表达式运算符表达式
|运算符表达式
|表达式运算符
|原子表达式
;
原子表达式:
标识符(“”)//托多:这是lsv吗?
;
类型:标识符;
//
//LEXER规则。
注释:'/*'.'*/'->通道(隐藏);
行注释:'/'~[\000A\000D]*->通道(隐藏);
赋值_运算符:运算符?'=';
//WSA=空白感知令牌。
//这些标记出现在给定的空白上下文中。
WSA_操作员:
(WhiteSpaceNotNewline+运算符WhiteSpaceNotNewline+)
;
操作员:操作员;
//换行符是分开定义的,因为它们作为一个语句具有意义
//定界符。
新行:
(“\u000D”\u000A”)
|“\u000A”
;
WS:WhiteSpaceNotNewline->skip;
分号:';';
标识符:
(IdentifierHead IdentifierCharacter*)
|('`'(IdentifierHead IdentifierCharacter*)'`')
;
片段小数位数:'0'..'9';
碎片识别头:
“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'..'\u1ff'|
'\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'
;
片段标识符字符:
小数位数
|'\u0300'..'\u036F'
|'\u1DC0'..'\u1DFF'
|'\u20D0'..'\u20FF'
|'\uFE20'..'\uFE2F'
|识别头
;
//非换行空格是分开定义的,因为它们在
//某些上下文,例如空间感知操作员内部。
片段WhiteSpaceNotNewline:[\u0020\u000C\u0009u000B\u000C];
片段运算符:
'*'
| '/'
| '%'
| '+'
| '-'
| ''
| '&'
| '^'
| '|'
;
规则
expression
: monoOperatedExpression (binaryOperator monoOperatedExpression)?
;
不允许在二进制运算符之后使用=
。因此,运行时报告说,在使用二进制\u OP
之后,它不知道下一个要使用的规则
语法可以通过一些重要的重组,最好是简化来固定
1-忽略空格/换行符可以大大简化处理
WS : [ \t\r\n] -> skip;
C族语言和类似Python的语言都是上下文无关的语言,有一些众所周知的上下文敏感的情况。ANTLR是一个上下文无关的解析器,具有许多方便的功能来处理上下文敏感性。因此,默认情况下忽略(或隐藏)空白
二,
STAR_EQUAL : '*=' ;
STAR : '*' ;
EQUAL : '=' ;
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
;
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 : [ \t\r\n]+ -> skip;
ERRCHAR
: . -> channel(HIDDEN)
;
fragment Comment
: '/*' .*? '*/'
| '//' ~[\r\n]*
;