为什么我的 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
;
*/

编辑:更改了解析器语法,更改了错误

globala 都列在您的语法中 kwr 规则下。

kwrinl 规则中提到,但未在任何地方使用。所以你的解析器不知道如何处理 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 中的方法并不是一个好方法。)