我正在为各种基本语言编写示例语法,其中包含类似以下的说明:
i8 my_variable_1_8
i16 my_second_variable_2_something_else
i32 another_variable
i4 forth
i8 last_one_1
void empty
void empty_for_the_2_time
请注意,变量名可以按任何顺序包含任何字母,数字,下划线和点。自动柜员机我对诸如``.... variable_name ....`这样的情况不感兴趣,所以让我们接受它们:)
我当前使用的PoC语法在下面的段落中:
grammar example;
prog: (expr NEWLINE)+;
expr : instr
;
instr : type WORD
;
type : 'i' NUMBER
| 'void'
;
NUMBER : ('-')* ([0-9])+
;
WORD : (LETTER|'_'|'.'|[0-9])+
;
LETTER : ([a-z]|[A-Z]) ;
NEWLINE : [\r\n]+ ;
WS: [ \t\n\r]+ -> skip ;
我要解析的示例文件是
i32 i_cannot_parse_this_1_as_i_want
void hello
输出为
➜ grammar antlr4 -no-listener example.g4 && javac *.java && grun example prog -tokens example.txt
[@0,0:2='i32',<WORD>,1:0]
[@1,4:34='i_cannot_parse_this_1_as_i_want',<WORD>,1:4]
[@2,35:35='\n',<NEWLINE>,1:35]
[@3,36:39='void',<'void'>,2:0]
[@4,41:45='hello',<WORD>,2:5]
[@5,48:47='<EOF>',<EOF>,3:0]
line 1:0 mismatched input 'i32' expecting {'i', 'void'}
➜ grammar
如您所见,i32
被认为是WORD
,而不是类型。关于优先级,我肯定有一些遗漏,但我无法理解。
最后,我想说的是,我创建了解析器规则type
,因为在运行时,一旦我重写了visitInstr
方法,我便希望能够执行类似ctx.type().NUMBER()
的操作。
是否有更好的方法来实现这一目标?请考虑我想添加其他更复杂的类型。
非常感谢您的时间
T__0 : 'i';
T__1 : 'void';
NUMBER : ('-')* ([0-9])+;
WORD : (LETTER|'_'|'.'|[0-9])+;
LETTER : ([a-z]|[A-Z]);
NEWLINE : [\r\n]+;
WS : [ \t\n\r]+ -> skip; // NOTE: remove the \n\r from this class since it is already matched by NEWLINE
如果现在向词法分析器输入i32
,它将创建一个WORD
令牌。它将不会创建两个标记T__0
(i
)和NUMBER
(32
),因为词法分析器会尝试使给定输入的最长匹配。这就是它的工作方式。
[此外,通过将:]]中定义它type
设为解析器规则,您可以将i 32
(之间有空格的i
)作为输入匹配为type
。换句话说:不要在解析器中创建type
,而是将其设置为词法分析器规则,并确保在[WORD
规则:[[之前
type : TYPE
| VOID
;
VOID : 'void';
TYPE : 'i' NUMBER;
NUMBER : '-'* [0-9]+;
WORD : [a-zA-Z_.0-9]+;
NEWLINE : [\r\n]+;
WS : [ \t]+ -> skip;
这将使i32
与TYPE
而不是WORD
匹配。如果您还希望在某些情况下将i32
匹配为WORD
(例如,输入i32 i32
也有效),请执行以下操作:
instr : type word ; word : WORD | type ; type : TYPE | VOID ;