我不确定问题实际上是前缀,但这里是。
我的语法中有这两条规则(以及许多其他规则)
DOT_T : '.' ;
AND_T : '.AND.' | '.and.' ;
我需要像这样解析字符串:
a.eq.b.and.c.ne.d
c.append(b)
这应该被词法为:
ID[a] EQ_T ID[b] AND_T ID[c] NE_T ID[d]
ID[c] DOT_T ID[append] LPAREN_T ID[b] RPAREN_T
我在第二行得到的错误是:
line 1:3 mismatched character "p"; expecting "n"
它不会将 .
词法为 DOT_T
,而是尝试匹配 .and.
,因为它看到 a
在 .
.
知道我需要做什么才能完成这项工作吗?
更新
我添加了以下规则并认为我会使用相同的技巧
NUMBER_T
: DIGIT+
( (DECIMAL)=> DECIMAL
| (KIND)=> KIND
)?
;
fragment DECIMAL
: '.' DIGIT+ ;
fragment KIND
: '.' DIGIT+ '_' (ALPHA+ | DIGIT+) ;
但是当我尝试解析这个时:
lda.eq.3.and.dim.eq.3
它给了我以下错误:
line 1:9 no viable alternative at character "a"
在词法分析 3
时。所以我猜发生了与上面相同的事情,但解决方案在这种情况下不起作用:S 现在我很困惑......
最佳答案
是的,这是因为前缀'.'
-s。
每当词法分析器偶然发现 ".a"
时,它就会尝试创建一个 AND_T
标记。如果找不到字符 "nd"
,则词法分析器会尝试构造另一个以 ".a"
开头的标记,而该标记不存在(并且 ANTLR产生错误)。因此,词法分析器将不会返回字符“a”
并回退以创建DOT_T
标记(然后是 ID
token )!这就是 ANTLR 的工作原理。
您可以选择在 DOT_T
规则内匹配这些 AND_T
、EQ_T
、...。但是,您仍然需要通过添加一些语法谓词来“帮助”词法分析器,这些谓词强制词法分析器在字符流中向前查看,以确保它可以匹配这些标记。
演示:
grammar T;
parse
: (t=. {System.out.printf("\%-10s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
;
DOT_T
: '.' ( (AND_T)=> AND_T {$type=AND_T;}
| (EQ_T)=> EQ_T {$type=EQ_T; }
| (NE_T)=> NE_T {$type=NE_T; }
)?
;
ID
: ('a'..'z' | 'A'..'Z')+
;
LPAREN_T
: '('
;
RPAREN_T
: ')'
;
SPACE
: (' ' | '\t' | '\r' | '\n')+ {skip();}
;
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL)?
;
fragment DECIMAL : '.' DIGIT+ ;
fragment AND_T : ('AND' | 'and') '.' ;
fragment EQ_T : ('EQ' | 'eq' ) '.' ;
fragment NE_T : ('NE' | 'ne' ) '.' ;
fragment DIGIT : '0'..'9';
如果您向生成的解析器提供输入:
a.eq.b.and.c.ne.d c.append(b)
the following output will be printed:
ID 'a' EQ_T '.eq.' ID 'b' AND_T '.and.' ID 'c' NE_T '.ne.' ID 'd' ID 'c' DOT_T '.' ID 'append' LPAREN_T '(' ID 'b' RPAREN_T ')'
And for the input:
lda.eq.3.and.dim.eq.3
the following is printed:
ID 'lda' EQ_T '.eq.' NUMBER_T '3' AND_T '.and.' ID 'dim' EQ_T '.eq.' NUMBER_T '3'
EDIT
The fact that DECIMAL
and KIND
both start with '.' DIGIT+
is not good. Try something like this:
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL ((KIND)=> KIND)?)?
;
fragment DECIMAL : '.' DIGIT+;
fragment KIND : '_' (ALPHA+ | DIGIT+); // removed ('.' DIGIT+) from this fragment
请注意,规则 NUMBER_T
现在将永远不会生成 DECIMAL
或 KIND
标记。如果您希望发生这种情况,您需要更改类型:
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL {/*change type*/} ((KIND)=> KIND {/*change type*/})?)?
;
关于antlr 词法分析器规则与另一个规则的前缀匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9994510/