为什么我的 ANTLR4 解析器语法错误 'no viable alternative at input'?
Why is my ANTLR4 parser grammar erroring 'no viable alternative at input'?
当我在 powershell 中 运行 我的语法(词法分析器和解析器)时,它会产生这些错误:
line 1:6 no viable alternative at input 'global '
我已经尝试搜索 google 等有关错误和无限循环的信息,但我真的什么都不懂(可能是因为我几天前才开始使用 antlr)。
测试文件:
global a = 2
词法分析器语法:
lexer grammar Test;
// tokens { SMT, SST, SCH, USM, USS, USC, NMT, NST, NCH, UNM, UNS, NAS, UNC, NAC, MLC, SLC, PXI, DXI, PXF, DXF, PXB, DXB, PXD, DXD, PXP, DXP, PRX, DEX, IMG, FLT, DBL, DCM, PRC, INT, CKW, KWR, RMH, IMH, NAN, IND, UND, NIL, NON, TRU, FLS, IDN, WSP, BKS, SMC, CMA, IVC }
MST: '\'\'' -> pushMode(multiline);
SMT: SPS SDSQ ODQ*? SDSQ;
SST: SPS '"' NTD* '"';
SCH: [rf] SLSQ OQC SLSQ;
USM: SPS SDSQ ODQ*? EOF;
USS: SPS '"' NTD* (EOL* ODC*)? EOF;
USC: [rf] SLSQ OQC? EOF;
NMT: SDSQ ODQ*? SDSQ;
NST: '"' NTD* '"';
NCH: SLSQ OQC SLSQ;
UNM: SDSQ ODQ*? EOF;
UNS: '"' NTD* (EOL* ODC*)? EOF;
NAS: SPS? '"' NTD* EOL* ODC* '"';
UNC: SLSQ OQC? EOF;
NAC: (('p'[f]?|[f]?'p')? SLSQ OQC+ SLSQ? | [rpf]? SLSQ OQC OQC+ SLSQ?);
MLC: '##' NDH* '##'? -> skip;
SLC: '--' NEN* -> skip;
EOL: '\r'? '\n' | [\n\u000b\f\r\u0085\u2028\u2029];
EML: '[]';
EMS: '{}';
PXI: NUM 'E' NUM 'i';
DXI: NUM 'e' NUM 'i';
PXF: NUM 'E' NUM 'f';
DXF: NUM 'e' NUM 'f';
PXB: NUM 'E' NUM 'd';
DXB: NUM 'e' NUM 'd';
PXD: NUM 'E' NUM 'D';
DXD: NUM 'e' NUM 'D';
PXP: NUM 'E' NUM 'p'
| '+'? NUM 'E' NUM
;
DXP: NUM 'e' NUM 'p'
| '+'? NUM 'e' NUM
;
PRX: '-'? NUM 'E' NUM;
DEX: '-'? NUM 'e' NUM;
IMG: NUM? 'i';
FLT: NUM 'f'
| DIGIT+ '.' DIGIT DIGITFQ DIGITTQ
;
DBL: NUM 'd'
| DIGIT+ '.' DIGITE DIGITFQ DIGITGQ
;
DCM: NUM 'D'
| DIGIT+ '.' DIGITE DIGITE DIGITEQ DIGITFQ DIGITGQ
;
PRC: NUM 'p'
| DIGIT+ '.' DIGITE DIGITE DIGITE DIGITE DIGIT*
;
INT: INTEGER | DIGIT;
OPN: 'opn';
OUT: 'out';
OUTF: 'outf';
PRINT: 'print';
PRINTF: 'printf';
LAMBDA: 'lambda';
FUNC: 'func';
ERR: 'err';
ERRF: 'errf';
ASSERT: 'assert';
ASSERTF: 'assertf';
FORMAT: 'format';
SWITCH: 'switch';
ABS: 'abs';
ASCII: 'ascii';
CALLABLE: 'callable';
CHR: 'chr';
DIR: 'dir';
EVAL: 'eval';
EXEC: 'exec';
FILTER: 'filter';
GET: 'get';
HASH: 'hash';
ID: 'id';
INST: 'inst';
SUB: 'sub';
SUPER: 'super';
MAX: 'max';
MIN: 'min';
OBJ: 'obj';
ORD: 'ord';
POWF: 'pow';
REV: 'rev';
REPR: 'repr';
ROUND: 'round';
FLOOR: 'floor';
CEIL: 'ceil';
MUL: 'mul';
SORT: 'sort';
ADD: 'add';
ZIP: 'zip';
WAIT: 'wait';
SECS: 'secs';
MILS: 'mils';
BENCHMARK: 'benchmark';
HAS: 'has';
SIBLING: 'sibling';
A: 'a';
CHILD: 'child';
OF: 'of';
WHILE: 'while';
FOR: 'for';
DO: 'do';
DEL: 'del';
NEW: 'new';
IMPORT: 'import';
EXPORT: 'export';
DEF: 'def';
END: 'end';
GLOBAL: 'global';
BREAK: 'break';
CONTINUE: 'continue';
NOT: 'not';
AND: 'and';
OR: 'or';
IN: 'in';
CASE: 'case';
DEFAULT: 'default';
RETURN: 'return';
TRY: 'try';
EXCEPT: 'except';
FINALLY: 'finally';
ELIF: 'elif';
IF: 'if';
ELSE: 'else';
AS: 'as';
STRT: 'str';
INTT: 'int';
NUMT: 'num';
DECIMALT: 'decimal';
FLOATT: 'float';
DOUBLET: 'double';
PRECISET: 'precise';
EXPNT: 'expn';
CONST: 'const';
REPEAT: 'repeat';
UNTIL: 'until';
THEN: 'then';
CHART: 'char';
GOTO: 'goto';
LABEL: 'label';
TYPET: 'type';
USING: 'using';
BOOLT: 'bool';
PUBLIC: 'public';
PROTECTED: 'protected';
PRIVATE: 'private';
CLASSD: 'class';
SELF: 'self';
STRUCTD: 'struct';
FROM: 'from';
XOR: 'xor';
LISTD: 'list';
TUPLED: 'tuple';
DICTD: 'dict';
SETD: 'set';
IMAGT: 'imag';
REALT: 'real';
WHERE: 'where';
PASS: 'pass';
G_G: '_G';
L_L: '_L';
HEXT: 'hex';
BINT: 'bin';
OCTT: 'oct';
MAP: 'map';
ANYT: 'any';
VOIDT: 'void';
IS: 'is';
A_FDV: '//=';
A_CDV: '*/=';
A_NOR: '||=';
A_FAC: '=!=';
A_LTE: '=<=';
A_GTE: '=>=';
A_EQL: '===';
A_NEQ: '!==';
A_CON: '..=';
A_NXR: '$$=';
A_BRS: '>>=';
A_NND: '&&=';
A_BLS: '<<=';
A_DCL: '::=';
A_CLD: ':.=';
A_KUN: '=**';
A_VUN: '=*';
A_DOT: '.=';
A_POW: '^=';
A_NOT: '=!';
A_BNT: '=~';
A_LEN: '=#';
A_PER: '=%';
A_MUL: '*=';
A_DIV: '/=';
A_MOD: '%=';
A_ADD: '+=';
A_SUB: '-=';
A_LET: '=<';
A_GRT: '=>';
A_BND: '&=';
A_BXR: '$=';
A_BOR: '|=';
A_TND: '?=';
A_TOR: ':=';
A_NML: '=';
NND: '&&';
NXR: '$$';
NOR: '||';
CLP: '()';
SUP: '::';
SIB: ':.';
KUN: '**';
INC: '++';
DEC: '+-';
FDV: '//';
CDV: '*/';
CON: '..';
BLS: '<<';
BRS: '>>';
LTE: '<=';
GTE: '>=';
EQL: '==';
NEQ: '!=';
LPR: '(';
RPR: ')';
LBR: '[';
RBR: ']';
LBC: '{';
RBC: '}';
STR: '*';
POW: '^';
PLS: '+';
MNS: '-';
BNT: '~';
EXC: '!';
LEN: '#';
PER: '%';
DIV: '/';
LET: '<';
GRT: '>';
BND: '&';
BXR: '$';
BOR: '|';
TND: '?';
TOR: ':';
DOT: '.';
RMH: 'inf';
IMH: 'inf*i';
NAN: 'nan';
IND: 'ind';
UND: 'und';
NIL: 'nil'
| 'null';
NON: 'none';
TRU: 'true';
FLS: 'false';
IDN: AUL WORD*;
WSP: (('\r'? '\n') | [\u0009\u0020\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\n\u000b\f\r\u0085\u2028\u2029])+;
BKS: [\u007f\u0008]+;
SMC: ';';
CMA: ',';
SPC: ' ';
IVC: .;
mode multiline;
SCE: ESCAPE -> type(SCN);
SND: (SDSQ | EOF) -> popMode;
SCN: '\'' ~'\'' | ~'\'';
mode multicom;
CCE: '\##' -> type(CCN);
CND: ('##' | EOF) -> popMode;
CCN: '#' ~'#' | ~'#';
fragment DIGITE: DIGITF DIGITF;
fragment DIGITEQ: DIGITFQ DIGITFQ;
fragment DIGITF: DIGITG DIGIT;
fragment DIGITFQ: DIGITGQ DIGITQ;
fragment SPS: 'pf' | 'fp' | [rpf];
fragment OCH: ESCAPE | ALL;
fragment OQC: ESCAPE | ~['];
fragment ODQ: ESCAPE | SCN;
fragment ODC: ESCAPE | ~["];
fragment NDN: ESCAPE | NED;
fragment AUL: [a-zA-Z_];
fragment DIGIT: [0-9];
fragment DECM: INTEGER '.' INTEGER;
fragment WORD: AUL | DIGIT;
fragment DIGITQ: DIGIT?;
fragment DIGITG: DIGIT DIGIT DIGIT;
fragment DIGITGQ: DIGIT? DIGIT? DIGIT?;
fragment DIGITT: DIGIT DIGIT;
fragment DIGITTQ: DIGIT? DIGIT?;
fragment INTEGER: DIGITG ('_'? DIGITG)* | DIGIT+;
fragment ALL: .;
fragment TNQ: '\' SLSQ | ~['];
fragment TNDQQ: '\"' | ~["];
fragment NDH: CCN;
fragment NEN: ~[\n\u000b\f\r\u0085\u2028\u2029];
fragment NED: ~[\n\u000b\f\r\u0085\u2028\u2029"];
fragment ENN: ESCAPE | NEN;
fragment NTD: ESCAPE | NED;
fragment HEX: DIGIT | [a-fA-F];
fragment HEXQ: HEX?;
fragment SPCF: ' ';
fragment ESCAPE: '\' ( 'x' HEX HEXQ | 'u' HEX HEXQ HEXQ HEXQ | 'U' HEX HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ | 'X' HEX HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ| 'o' OCT OCTQ OCTQ | 'O' OCT OCTQ OCTQ OCTQ OCTQ OCTQ | ESCS );
fragment ESCS: ['"nrtbfv\];
fragment OCT: [0-7];
fragment OCTQ: OCT?;
fragment NUM: DECM | INTEGER;
fragment SLDQ: ["];
fragment SLSQ: ['];
fragment SDSQ: SLSQ SLSQ;
解析器语法:
parser grammar TestP;
options { tokenVocab=Test; }
program: line (EOL line*) EOL? EOF;
line: expression+ SMC* | expression* SMC+;
expression: wsp* assign_expression wsp*;
assign_expression: <assoc=right> GLOBAL var_list wsp* aop wsp* (var_list wsp* aop wsp*)* or_expression (wsp* CMA wsp* or_expression)*;
or_expression: xor_expression (wsp* (NOR | OR) wsp* xor_expression)*;
xor_expression: and_expression (wsp* (NXR | XOR) wsp* and_expression)*;
and_expression: ternary (wsp* (NND | AND) wsp* ternary)*;
ternary: <assoc=right> bit_or (wsp* (AND | TND) wsp* bit_or wsp* (OR | TOR) wsp* bit_or)?;
bit_or: bit_xor (wsp* BOR wsp* bit_xor)*;
bit_xor: bit_and (wsp* BXR wsp* bit_and)*;
bit_and: eql_expr (wsp* BND wsp* eql_expr)*;
eql_expr: com_expr (wsp* (EQL | IS | NEQ | IS wsp* NOT) wsp* com_expr)*;
com_expr: shift_expr (wsp* (LET | LTE | GRT | GTE) wsp* shift_expr)*;
shift_expr: con_expr (wsp* (BLS | BRS) wsp* con_expr)*;
con_expr: one_expr (wsp* CON wsp* one_expr)*;
one_expr: perc_expr (wsp* (PLS | MNS) wsp* perc_expr)*;
perc_expr: fac_expr ((wsp* (STR | DIV | PER | FDV | CDV) wsp* fac_expr)+ | PER)*;
fac_expr: unary_expr EXC?;
unary_expr: (PLS | MNS | BNT | EXC | LEN | NOT)* crement_expr;
crement_expr: pow_expr (wsp* (INC|DEC) wsp* pow_expr | INC | DEC)*;
pow_expr: <assoc=right> unpack_expr (wsp* POW wsp* unpack_expr)*;
unpack_expr: (STR | KUN)* brackets_expr;
brackets_expr
: tupled
| LPR access_expr RPR
| dictd
| setd
| LBC access_expr RBC
| listd
| LBR access_expr RBR
| access_expr
;
var_list: assign ( wsp* CMA wsp* assign)*;
assign
: idn
| index
;
access_expr
: atom ((DOT | SUP | SIB) atom)*
;
atom
: litidn
|datat
| val
| num
| index
;
literal
: strt
| num
;
datat
: listd
| dictd
| setd
| tupled
;
listd
: LBR wsp* comma_separated wsp* RBR
| EML
;
dictd
: LBC wsp* kvpair wsp*
(
CMA
wsp*
kvpair
wsp*
)+
RBC
| LBC wsp* kvpair wsp* RBC
;
setd
: LBC wsp* comma_separated wsp* RBC
| EMS
;
tupled: LPR wsp* comma_separated wsp* RPR;
comma_separated
: expression
(
wsp*
CMA
wsp*
expression
)*
;
kvpair: expression wsp* TOR SPC wsp* expression;
litidn
: literal
| idn
;
typecast: typet LPR expression RPR;
call:
(
dictd
| idn
| index
)
(
CLP
|
tupled
)
;
strt
: multi_line
| single_line
| char_string
;
idn
: IDN
| A
;
index: (datat | strt) LBR expression RBR;
multi_line
: SMT
| USM
| NMT
| UNM
;
single_line
: SST
| USS
| NST
| UNS
| NAS
;
char_string
: SCH
| USC
| NCH
| UNC
| NAC
;
num
: exponential
| non_exponential
;
exponential
: PXI
| DXI
| PXF
| DXF
| PXB
| DXB
| PXD
| DXD
| PXP
| DXP
| PRX
| DEX
;
non_exponential
: IMG
| FLT
| DBL
| DCM
| PRC
| INT
;
typet
: STRT
| INTT
| NUMT
| DECIMALT
| FLOATT
| DOUBLET
| PRECISET
| EXPNT
| CHART
| IMAGT
| REALT
| HEXT
| BINT
| OCTT
| LISTD
| SETD
| DICTD
| TUPLED
| TYPET
| BOOLT
;
wsp
: WSP
| EOL
;
bks_or_wsp
: wsp
| BKS
| SPC
;
emd
: EML
| EMS
;
sep
: SMC
| CMA
| TOR
;
/*
kwr
: WHILE
| FOR
| DO
| DEL
| NEW
| IMPORT
| EXPORT
| DEF
| END
| GLOBAL
| BREAK
| CONTINUE
| NOT
| AND
| OR
| IN
| CASE
| DEFAULT
| RETURN
| TRY
| EXCEPT
| FINALLY
| ELIF
| IF
| ELSE
| AS
| CONST
| REPEAT
| UNTIL
| THEN
| GOTO
| LABEL
| USING
| PUBLIC
| PROTECTED
| PRIVATE
| SELF
| FROM
| XOR
| IMAGT
| REALT
| WHERE
| PASS
| G_G
| L_L
| MAP
| IS
;
ckw
: OPN
| OUT
| OUTF
| PRINT
| PRINTF
| LAMBDA
| FUNC
| ERR
| ERRF
| ASSERT
| ASSERTF
| FORMAT
| SWITCH
| ABS
| ASCII
| CALLABLE
| CHR
| DIR
| EVAL
| EXEC
| FILTER
| GET
| HASH
| ID
| INST
| SUB
| SUPER
| MAX
| MIN
| OBJ
| ORD
| POWF
| REV
| REPR
| ROUND
| FLOOR
| CEIL
| MUL
| SORT
| ADD
| ZIP
| WAIT
| SECS
| MILS
| BENCHMARK
;
*/
val
: RMH // 'inf'
| IMH // 'inf*i'
| NAN // 'nan'
| IND // 'ind'
| UND // 'und'
| NIL // 'nil'
| NON // 'none'
| TRU // 'true'
| FLS // 'false'
;
aop
: A_FDV // '//='
| A_CDV // '*/='
| A_NOR // '||='
| A_FAC // '=!='
| A_LTE // '=<='
| A_GTE // '=>='
| A_EQL // '==='
| A_NEQ // '!=='
| A_CON // '..='
| A_NXR // '$$='
| A_BRS // '>>='
| A_NND // '&&='
| A_BLS // '<<='
| A_DCL // '::='
| A_CLD // ':.='
| A_KUN // '=**'
| A_VUN // '=*'
| A_DOT // '.='
| A_POW // '^='
| A_NOT // '=!'
| A_BNT // '=~'
| A_LEN // '=#'
| A_PER // '=%'
| A_MUL // '*='
| A_DIV // '/='
| A_MOD // '%='
| A_ADD // '+='
| A_SUB // '-='
| A_LET // '=<'
| A_GRT // '=>'
| A_BND // '&='
| A_BXR // '$='
| A_BOR // '|='
| A_TND // '?='
| A_TOR // ':='
| A_NML // '='
;
opr
: NND // '&&'
| NXR // '$$'
| NOR // '||'
| CLP // '()'
| SUP // '::'
| SIB // ':.'
| KUN // '**'
| INC // '++'
| DEC // '+-'
| FDV // '//'
| CDV // '*/'
| CON // '..'
| BLS // '<<'
| BRS // '>>'
| LTE // '<='
| GTE // '>='
| EQL // '=='
| NEQ // '!='
| LPR // '('
| RPR // ')'
| LBR // '['
| RBR // ']'
| LBC // '{'
| RBC // '}'
| STR // '*'
| POW // '^'
| PLS // '+'
| MNS // '-'
| BNT // '~'
| EXC // '!'
| LEN // '#'
| PER // '%'
| DIV // '/'
| LET // '<'
| GRT // '>'
| BND // '&'
| BXR // '$'
| BOR // '|'
| TND // '?'
| TOR // ':'
| DOT // '.'
;
/*
inl
: strt
| num
| ckw
| kwr
| val
| idn
| bks_or_wsp
| sep
| emd
| aop
| opr
| typet
| IVC
;
*/
编辑:更改了解析器语法,更改了错误
global
和 a
都列在您的语法中 kwr
规则下。
kwr
在 inl
规则中提到,但未在任何地方使用。所以你的解析器不知道如何处理 inl
并且不知道如何处理两个链接在一起的 inl
(global a
)
这个 Lexer/Parser 中有很多“东西”。对于完整的语法来说这不是一件坏事,但我建议你“从小事做起”。 (有很多“危险信号”表明您没有真正“了解”ANTLR 及其工作原理。)
一个示例:您的 kwr
parserRule 出现 以列出语法中的关键字。不太可能有任何地方需要匹配“任何关键字”
@momolechart 是正确的,您没有从 program
规则到任何使用 GLOBAL
标记的规则的路径。
让我们从小事做起,因为您需要这个表达式:
你有:
- 一个
GLOBAL
关键字(令牌),
- 一个
A
标记(?? 这看起来很可疑,它应该是一个标识符,但是,我会从表面上看, 'a' 在您的上下文中具有特殊含义
因为您为其定义了令牌规则。
- 一个
A_NML
令牌(值'=')(这变得越来越陌生,但我会接受它)
- 一个
INT
标记 ('2')
- 哦,还有几个
WSP
标记(我将说明通常如何处理空格)
让我们剥离 Lexer 来处理这个问题:
lexer grammar Test;
GLOBAL: 'global';
A: 'a';
INT: INTEGER;
A_NML: '=';
SMC: ';';
EOL: '\r'? '\n' | [\n\u000b\f\r\u0085\u2028\u2029];
WSP: (('\r'? '\n') | [\u0009\u0020\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\n\u000b\f\r\u0085\u2028\u2029])+ -> skip;
fragment DIGIT: [0-9];
fragment DIGITG: DIGIT DIGIT DIGIT;
fragment INTEGER: DIGITG ('_'? DIGITG)* | DIGIT+;
(我已尝试尽可能多地保留您的原始 Lexer 语法。我确实以“正常方式”处理空白,即使用 -> skip
。在您的解析器规则中,我看到很多 wsp*
s(这消除了那个需要)
现在我们需要认识赋值语句。因此,处理该问题的最小解析器语法为:
parser grammar TestP;
options { tokenVocab=Test; }
program: line (EOL line*) EOL? EOF;
line: expression+ SMC* | expression* SMC+;
expression: assign_expression ;
assign_expression: GLOBAL A A_NML INT;
那是对您的 assign_expression
的 实质性 简化,但现在您“在做生意”;你正在识别你的样本输入。您可以从那里开始构建语法。
您的直接问题(如另一个答案中所述)是 expression
引用的任何规则(直接或间接)都无法识别 GLOBAL
关键字。
现在寻求长期建议。这些语法(对我来说)看起来像是对某些技术规范(我无法想象语言是什么)进行直译的尝试,将其转化为您对如何在 ANTLR 中表示它的最佳猜测。
这通常是非常不明智的。我建议备份一点并通过一些更简单的努力来学习 ANTLR,并且,一旦您掌握了 ANTLR,然后就着手解决这个问题。我还建议,如果您要解决任何如此复杂的问题,请从务实的程序员那里获取和阅读 The Definitive ANTLR4 Reference。这将是非常值得你花时间的。 (它实际上指出这种将技术规范实施到 ANTLR 中的方法并不是一个好方法。)
当我在 powershell 中 运行 我的语法(词法分析器和解析器)时,它会产生这些错误:
line 1:6 no viable alternative at input 'global '
我已经尝试搜索 google 等有关错误和无限循环的信息,但我真的什么都不懂(可能是因为我几天前才开始使用 antlr)。
测试文件:
global a = 2
词法分析器语法:
lexer grammar Test;
// tokens { SMT, SST, SCH, USM, USS, USC, NMT, NST, NCH, UNM, UNS, NAS, UNC, NAC, MLC, SLC, PXI, DXI, PXF, DXF, PXB, DXB, PXD, DXD, PXP, DXP, PRX, DEX, IMG, FLT, DBL, DCM, PRC, INT, CKW, KWR, RMH, IMH, NAN, IND, UND, NIL, NON, TRU, FLS, IDN, WSP, BKS, SMC, CMA, IVC }
MST: '\'\'' -> pushMode(multiline);
SMT: SPS SDSQ ODQ*? SDSQ;
SST: SPS '"' NTD* '"';
SCH: [rf] SLSQ OQC SLSQ;
USM: SPS SDSQ ODQ*? EOF;
USS: SPS '"' NTD* (EOL* ODC*)? EOF;
USC: [rf] SLSQ OQC? EOF;
NMT: SDSQ ODQ*? SDSQ;
NST: '"' NTD* '"';
NCH: SLSQ OQC SLSQ;
UNM: SDSQ ODQ*? EOF;
UNS: '"' NTD* (EOL* ODC*)? EOF;
NAS: SPS? '"' NTD* EOL* ODC* '"';
UNC: SLSQ OQC? EOF;
NAC: (('p'[f]?|[f]?'p')? SLSQ OQC+ SLSQ? | [rpf]? SLSQ OQC OQC+ SLSQ?);
MLC: '##' NDH* '##'? -> skip;
SLC: '--' NEN* -> skip;
EOL: '\r'? '\n' | [\n\u000b\f\r\u0085\u2028\u2029];
EML: '[]';
EMS: '{}';
PXI: NUM 'E' NUM 'i';
DXI: NUM 'e' NUM 'i';
PXF: NUM 'E' NUM 'f';
DXF: NUM 'e' NUM 'f';
PXB: NUM 'E' NUM 'd';
DXB: NUM 'e' NUM 'd';
PXD: NUM 'E' NUM 'D';
DXD: NUM 'e' NUM 'D';
PXP: NUM 'E' NUM 'p'
| '+'? NUM 'E' NUM
;
DXP: NUM 'e' NUM 'p'
| '+'? NUM 'e' NUM
;
PRX: '-'? NUM 'E' NUM;
DEX: '-'? NUM 'e' NUM;
IMG: NUM? 'i';
FLT: NUM 'f'
| DIGIT+ '.' DIGIT DIGITFQ DIGITTQ
;
DBL: NUM 'd'
| DIGIT+ '.' DIGITE DIGITFQ DIGITGQ
;
DCM: NUM 'D'
| DIGIT+ '.' DIGITE DIGITE DIGITEQ DIGITFQ DIGITGQ
;
PRC: NUM 'p'
| DIGIT+ '.' DIGITE DIGITE DIGITE DIGITE DIGIT*
;
INT: INTEGER | DIGIT;
OPN: 'opn';
OUT: 'out';
OUTF: 'outf';
PRINT: 'print';
PRINTF: 'printf';
LAMBDA: 'lambda';
FUNC: 'func';
ERR: 'err';
ERRF: 'errf';
ASSERT: 'assert';
ASSERTF: 'assertf';
FORMAT: 'format';
SWITCH: 'switch';
ABS: 'abs';
ASCII: 'ascii';
CALLABLE: 'callable';
CHR: 'chr';
DIR: 'dir';
EVAL: 'eval';
EXEC: 'exec';
FILTER: 'filter';
GET: 'get';
HASH: 'hash';
ID: 'id';
INST: 'inst';
SUB: 'sub';
SUPER: 'super';
MAX: 'max';
MIN: 'min';
OBJ: 'obj';
ORD: 'ord';
POWF: 'pow';
REV: 'rev';
REPR: 'repr';
ROUND: 'round';
FLOOR: 'floor';
CEIL: 'ceil';
MUL: 'mul';
SORT: 'sort';
ADD: 'add';
ZIP: 'zip';
WAIT: 'wait';
SECS: 'secs';
MILS: 'mils';
BENCHMARK: 'benchmark';
HAS: 'has';
SIBLING: 'sibling';
A: 'a';
CHILD: 'child';
OF: 'of';
WHILE: 'while';
FOR: 'for';
DO: 'do';
DEL: 'del';
NEW: 'new';
IMPORT: 'import';
EXPORT: 'export';
DEF: 'def';
END: 'end';
GLOBAL: 'global';
BREAK: 'break';
CONTINUE: 'continue';
NOT: 'not';
AND: 'and';
OR: 'or';
IN: 'in';
CASE: 'case';
DEFAULT: 'default';
RETURN: 'return';
TRY: 'try';
EXCEPT: 'except';
FINALLY: 'finally';
ELIF: 'elif';
IF: 'if';
ELSE: 'else';
AS: 'as';
STRT: 'str';
INTT: 'int';
NUMT: 'num';
DECIMALT: 'decimal';
FLOATT: 'float';
DOUBLET: 'double';
PRECISET: 'precise';
EXPNT: 'expn';
CONST: 'const';
REPEAT: 'repeat';
UNTIL: 'until';
THEN: 'then';
CHART: 'char';
GOTO: 'goto';
LABEL: 'label';
TYPET: 'type';
USING: 'using';
BOOLT: 'bool';
PUBLIC: 'public';
PROTECTED: 'protected';
PRIVATE: 'private';
CLASSD: 'class';
SELF: 'self';
STRUCTD: 'struct';
FROM: 'from';
XOR: 'xor';
LISTD: 'list';
TUPLED: 'tuple';
DICTD: 'dict';
SETD: 'set';
IMAGT: 'imag';
REALT: 'real';
WHERE: 'where';
PASS: 'pass';
G_G: '_G';
L_L: '_L';
HEXT: 'hex';
BINT: 'bin';
OCTT: 'oct';
MAP: 'map';
ANYT: 'any';
VOIDT: 'void';
IS: 'is';
A_FDV: '//=';
A_CDV: '*/=';
A_NOR: '||=';
A_FAC: '=!=';
A_LTE: '=<=';
A_GTE: '=>=';
A_EQL: '===';
A_NEQ: '!==';
A_CON: '..=';
A_NXR: '$$=';
A_BRS: '>>=';
A_NND: '&&=';
A_BLS: '<<=';
A_DCL: '::=';
A_CLD: ':.=';
A_KUN: '=**';
A_VUN: '=*';
A_DOT: '.=';
A_POW: '^=';
A_NOT: '=!';
A_BNT: '=~';
A_LEN: '=#';
A_PER: '=%';
A_MUL: '*=';
A_DIV: '/=';
A_MOD: '%=';
A_ADD: '+=';
A_SUB: '-=';
A_LET: '=<';
A_GRT: '=>';
A_BND: '&=';
A_BXR: '$=';
A_BOR: '|=';
A_TND: '?=';
A_TOR: ':=';
A_NML: '=';
NND: '&&';
NXR: '$$';
NOR: '||';
CLP: '()';
SUP: '::';
SIB: ':.';
KUN: '**';
INC: '++';
DEC: '+-';
FDV: '//';
CDV: '*/';
CON: '..';
BLS: '<<';
BRS: '>>';
LTE: '<=';
GTE: '>=';
EQL: '==';
NEQ: '!=';
LPR: '(';
RPR: ')';
LBR: '[';
RBR: ']';
LBC: '{';
RBC: '}';
STR: '*';
POW: '^';
PLS: '+';
MNS: '-';
BNT: '~';
EXC: '!';
LEN: '#';
PER: '%';
DIV: '/';
LET: '<';
GRT: '>';
BND: '&';
BXR: '$';
BOR: '|';
TND: '?';
TOR: ':';
DOT: '.';
RMH: 'inf';
IMH: 'inf*i';
NAN: 'nan';
IND: 'ind';
UND: 'und';
NIL: 'nil'
| 'null';
NON: 'none';
TRU: 'true';
FLS: 'false';
IDN: AUL WORD*;
WSP: (('\r'? '\n') | [\u0009\u0020\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\n\u000b\f\r\u0085\u2028\u2029])+;
BKS: [\u007f\u0008]+;
SMC: ';';
CMA: ',';
SPC: ' ';
IVC: .;
mode multiline;
SCE: ESCAPE -> type(SCN);
SND: (SDSQ | EOF) -> popMode;
SCN: '\'' ~'\'' | ~'\'';
mode multicom;
CCE: '\##' -> type(CCN);
CND: ('##' | EOF) -> popMode;
CCN: '#' ~'#' | ~'#';
fragment DIGITE: DIGITF DIGITF;
fragment DIGITEQ: DIGITFQ DIGITFQ;
fragment DIGITF: DIGITG DIGIT;
fragment DIGITFQ: DIGITGQ DIGITQ;
fragment SPS: 'pf' | 'fp' | [rpf];
fragment OCH: ESCAPE | ALL;
fragment OQC: ESCAPE | ~['];
fragment ODQ: ESCAPE | SCN;
fragment ODC: ESCAPE | ~["];
fragment NDN: ESCAPE | NED;
fragment AUL: [a-zA-Z_];
fragment DIGIT: [0-9];
fragment DECM: INTEGER '.' INTEGER;
fragment WORD: AUL | DIGIT;
fragment DIGITQ: DIGIT?;
fragment DIGITG: DIGIT DIGIT DIGIT;
fragment DIGITGQ: DIGIT? DIGIT? DIGIT?;
fragment DIGITT: DIGIT DIGIT;
fragment DIGITTQ: DIGIT? DIGIT?;
fragment INTEGER: DIGITG ('_'? DIGITG)* | DIGIT+;
fragment ALL: .;
fragment TNQ: '\' SLSQ | ~['];
fragment TNDQQ: '\"' | ~["];
fragment NDH: CCN;
fragment NEN: ~[\n\u000b\f\r\u0085\u2028\u2029];
fragment NED: ~[\n\u000b\f\r\u0085\u2028\u2029"];
fragment ENN: ESCAPE | NEN;
fragment NTD: ESCAPE | NED;
fragment HEX: DIGIT | [a-fA-F];
fragment HEXQ: HEX?;
fragment SPCF: ' ';
fragment ESCAPE: '\' ( 'x' HEX HEXQ | 'u' HEX HEXQ HEXQ HEXQ | 'U' HEX HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ | 'X' HEX HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ HEXQ| 'o' OCT OCTQ OCTQ | 'O' OCT OCTQ OCTQ OCTQ OCTQ OCTQ | ESCS );
fragment ESCS: ['"nrtbfv\];
fragment OCT: [0-7];
fragment OCTQ: OCT?;
fragment NUM: DECM | INTEGER;
fragment SLDQ: ["];
fragment SLSQ: ['];
fragment SDSQ: SLSQ SLSQ;
解析器语法:
parser grammar TestP;
options { tokenVocab=Test; }
program: line (EOL line*) EOL? EOF;
line: expression+ SMC* | expression* SMC+;
expression: wsp* assign_expression wsp*;
assign_expression: <assoc=right> GLOBAL var_list wsp* aop wsp* (var_list wsp* aop wsp*)* or_expression (wsp* CMA wsp* or_expression)*;
or_expression: xor_expression (wsp* (NOR | OR) wsp* xor_expression)*;
xor_expression: and_expression (wsp* (NXR | XOR) wsp* and_expression)*;
and_expression: ternary (wsp* (NND | AND) wsp* ternary)*;
ternary: <assoc=right> bit_or (wsp* (AND | TND) wsp* bit_or wsp* (OR | TOR) wsp* bit_or)?;
bit_or: bit_xor (wsp* BOR wsp* bit_xor)*;
bit_xor: bit_and (wsp* BXR wsp* bit_and)*;
bit_and: eql_expr (wsp* BND wsp* eql_expr)*;
eql_expr: com_expr (wsp* (EQL | IS | NEQ | IS wsp* NOT) wsp* com_expr)*;
com_expr: shift_expr (wsp* (LET | LTE | GRT | GTE) wsp* shift_expr)*;
shift_expr: con_expr (wsp* (BLS | BRS) wsp* con_expr)*;
con_expr: one_expr (wsp* CON wsp* one_expr)*;
one_expr: perc_expr (wsp* (PLS | MNS) wsp* perc_expr)*;
perc_expr: fac_expr ((wsp* (STR | DIV | PER | FDV | CDV) wsp* fac_expr)+ | PER)*;
fac_expr: unary_expr EXC?;
unary_expr: (PLS | MNS | BNT | EXC | LEN | NOT)* crement_expr;
crement_expr: pow_expr (wsp* (INC|DEC) wsp* pow_expr | INC | DEC)*;
pow_expr: <assoc=right> unpack_expr (wsp* POW wsp* unpack_expr)*;
unpack_expr: (STR | KUN)* brackets_expr;
brackets_expr
: tupled
| LPR access_expr RPR
| dictd
| setd
| LBC access_expr RBC
| listd
| LBR access_expr RBR
| access_expr
;
var_list: assign ( wsp* CMA wsp* assign)*;
assign
: idn
| index
;
access_expr
: atom ((DOT | SUP | SIB) atom)*
;
atom
: litidn
|datat
| val
| num
| index
;
literal
: strt
| num
;
datat
: listd
| dictd
| setd
| tupled
;
listd
: LBR wsp* comma_separated wsp* RBR
| EML
;
dictd
: LBC wsp* kvpair wsp*
(
CMA
wsp*
kvpair
wsp*
)+
RBC
| LBC wsp* kvpair wsp* RBC
;
setd
: LBC wsp* comma_separated wsp* RBC
| EMS
;
tupled: LPR wsp* comma_separated wsp* RPR;
comma_separated
: expression
(
wsp*
CMA
wsp*
expression
)*
;
kvpair: expression wsp* TOR SPC wsp* expression;
litidn
: literal
| idn
;
typecast: typet LPR expression RPR;
call:
(
dictd
| idn
| index
)
(
CLP
|
tupled
)
;
strt
: multi_line
| single_line
| char_string
;
idn
: IDN
| A
;
index: (datat | strt) LBR expression RBR;
multi_line
: SMT
| USM
| NMT
| UNM
;
single_line
: SST
| USS
| NST
| UNS
| NAS
;
char_string
: SCH
| USC
| NCH
| UNC
| NAC
;
num
: exponential
| non_exponential
;
exponential
: PXI
| DXI
| PXF
| DXF
| PXB
| DXB
| PXD
| DXD
| PXP
| DXP
| PRX
| DEX
;
non_exponential
: IMG
| FLT
| DBL
| DCM
| PRC
| INT
;
typet
: STRT
| INTT
| NUMT
| DECIMALT
| FLOATT
| DOUBLET
| PRECISET
| EXPNT
| CHART
| IMAGT
| REALT
| HEXT
| BINT
| OCTT
| LISTD
| SETD
| DICTD
| TUPLED
| TYPET
| BOOLT
;
wsp
: WSP
| EOL
;
bks_or_wsp
: wsp
| BKS
| SPC
;
emd
: EML
| EMS
;
sep
: SMC
| CMA
| TOR
;
/*
kwr
: WHILE
| FOR
| DO
| DEL
| NEW
| IMPORT
| EXPORT
| DEF
| END
| GLOBAL
| BREAK
| CONTINUE
| NOT
| AND
| OR
| IN
| CASE
| DEFAULT
| RETURN
| TRY
| EXCEPT
| FINALLY
| ELIF
| IF
| ELSE
| AS
| CONST
| REPEAT
| UNTIL
| THEN
| GOTO
| LABEL
| USING
| PUBLIC
| PROTECTED
| PRIVATE
| SELF
| FROM
| XOR
| IMAGT
| REALT
| WHERE
| PASS
| G_G
| L_L
| MAP
| IS
;
ckw
: OPN
| OUT
| OUTF
| PRINT
| PRINTF
| LAMBDA
| FUNC
| ERR
| ERRF
| ASSERT
| ASSERTF
| FORMAT
| SWITCH
| ABS
| ASCII
| CALLABLE
| CHR
| DIR
| EVAL
| EXEC
| FILTER
| GET
| HASH
| ID
| INST
| SUB
| SUPER
| MAX
| MIN
| OBJ
| ORD
| POWF
| REV
| REPR
| ROUND
| FLOOR
| CEIL
| MUL
| SORT
| ADD
| ZIP
| WAIT
| SECS
| MILS
| BENCHMARK
;
*/
val
: RMH // 'inf'
| IMH // 'inf*i'
| NAN // 'nan'
| IND // 'ind'
| UND // 'und'
| NIL // 'nil'
| NON // 'none'
| TRU // 'true'
| FLS // 'false'
;
aop
: A_FDV // '//='
| A_CDV // '*/='
| A_NOR // '||='
| A_FAC // '=!='
| A_LTE // '=<='
| A_GTE // '=>='
| A_EQL // '==='
| A_NEQ // '!=='
| A_CON // '..='
| A_NXR // '$$='
| A_BRS // '>>='
| A_NND // '&&='
| A_BLS // '<<='
| A_DCL // '::='
| A_CLD // ':.='
| A_KUN // '=**'
| A_VUN // '=*'
| A_DOT // '.='
| A_POW // '^='
| A_NOT // '=!'
| A_BNT // '=~'
| A_LEN // '=#'
| A_PER // '=%'
| A_MUL // '*='
| A_DIV // '/='
| A_MOD // '%='
| A_ADD // '+='
| A_SUB // '-='
| A_LET // '=<'
| A_GRT // '=>'
| A_BND // '&='
| A_BXR // '$='
| A_BOR // '|='
| A_TND // '?='
| A_TOR // ':='
| A_NML // '='
;
opr
: NND // '&&'
| NXR // '$$'
| NOR // '||'
| CLP // '()'
| SUP // '::'
| SIB // ':.'
| KUN // '**'
| INC // '++'
| DEC // '+-'
| FDV // '//'
| CDV // '*/'
| CON // '..'
| BLS // '<<'
| BRS // '>>'
| LTE // '<='
| GTE // '>='
| EQL // '=='
| NEQ // '!='
| LPR // '('
| RPR // ')'
| LBR // '['
| RBR // ']'
| LBC // '{'
| RBC // '}'
| STR // '*'
| POW // '^'
| PLS // '+'
| MNS // '-'
| BNT // '~'
| EXC // '!'
| LEN // '#'
| PER // '%'
| DIV // '/'
| LET // '<'
| GRT // '>'
| BND // '&'
| BXR // '$'
| BOR // '|'
| TND // '?'
| TOR // ':'
| DOT // '.'
;
/*
inl
: strt
| num
| ckw
| kwr
| val
| idn
| bks_or_wsp
| sep
| emd
| aop
| opr
| typet
| IVC
;
*/
编辑:更改了解析器语法,更改了错误
global
和 a
都列在您的语法中 kwr
规则下。
kwr
在 inl
规则中提到,但未在任何地方使用。所以你的解析器不知道如何处理 inl
并且不知道如何处理两个链接在一起的 inl
(global a
)
这个 Lexer/Parser 中有很多“东西”。对于完整的语法来说这不是一件坏事,但我建议你“从小事做起”。 (有很多“危险信号”表明您没有真正“了解”ANTLR 及其工作原理。)
一个示例:您的 kwr
parserRule 出现 以列出语法中的关键字。不太可能有任何地方需要匹配“任何关键字”
@momolechart 是正确的,您没有从 program
规则到任何使用 GLOBAL
标记的规则的路径。
让我们从小事做起,因为您需要这个表达式:
你有:
- 一个
GLOBAL
关键字(令牌), - 一个
A
标记(?? 这看起来很可疑,它应该是一个标识符,但是,我会从表面上看, 'a' 在您的上下文中具有特殊含义 因为您为其定义了令牌规则。 - 一个
A_NML
令牌(值'=')(这变得越来越陌生,但我会接受它) - 一个
INT
标记 ('2') - 哦,还有几个
WSP
标记(我将说明通常如何处理空格)
让我们剥离 Lexer 来处理这个问题:
lexer grammar Test;
GLOBAL: 'global';
A: 'a';
INT: INTEGER;
A_NML: '=';
SMC: ';';
EOL: '\r'? '\n' | [\n\u000b\f\r\u0085\u2028\u2029];
WSP: (('\r'? '\n') | [\u0009\u0020\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\n\u000b\f\r\u0085\u2028\u2029])+ -> skip;
fragment DIGIT: [0-9];
fragment DIGITG: DIGIT DIGIT DIGIT;
fragment INTEGER: DIGITG ('_'? DIGITG)* | DIGIT+;
(我已尝试尽可能多地保留您的原始 Lexer 语法。我确实以“正常方式”处理空白,即使用 -> skip
。在您的解析器规则中,我看到很多 wsp*
s(这消除了那个需要)
现在我们需要认识赋值语句。因此,处理该问题的最小解析器语法为:
parser grammar TestP;
options { tokenVocab=Test; }
program: line (EOL line*) EOL? EOF;
line: expression+ SMC* | expression* SMC+;
expression: assign_expression ;
assign_expression: GLOBAL A A_NML INT;
那是对您的 assign_expression
的 实质性 简化,但现在您“在做生意”;你正在识别你的样本输入。您可以从那里开始构建语法。
您的直接问题(如另一个答案中所述)是 expression
引用的任何规则(直接或间接)都无法识别 GLOBAL
关键字。
现在寻求长期建议。这些语法(对我来说)看起来像是对某些技术规范(我无法想象语言是什么)进行直译的尝试,将其转化为您对如何在 ANTLR 中表示它的最佳猜测。
这通常是非常不明智的。我建议备份一点并通过一些更简单的努力来学习 ANTLR,并且,一旦您掌握了 ANTLR,然后就着手解决这个问题。我还建议,如果您要解决任何如此复杂的问题,请从务实的程序员那里获取和阅读 The Definitive ANTLR4 Reference。这将是非常值得你花时间的。 (它实际上指出这种将技术规范实施到 ANTLR 中的方法并不是一个好方法。)