antlr 词法分析器规则与另一个规则的前缀匹配

标签 antlr antlr3

我不确定问题实际上是前缀,但这里是。

我的语法中有这两条规则(以及许多其他规则)

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_TEQ_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 现在将永远不会生成 DECIMALKIND 标记。如果您希望发生这种情况,您需要更改类型:

NUMBER_T
 : DIGIT+ ((DECIMAL)=> DECIMAL {/*change type*/} ((KIND)=> KIND {/*change type*/})?)?
 ;

关于antlr 词法分析器规则与另一个规则的前缀匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9994510/

相关文章:

java - Antlr - 控制流图

antlr3 - antlr 3.5.1 使用未声明的标识符 : _empty. 为 C 运行时生成代码有任何可用的修复吗?

ANTLR:在语法中定义新 channel

java - ANTLR(或替代): decoupling parsing from evaluation

nuget - 程序集的 list 定义与程序集引用不匹配

java - 如何访问语法中当前的树节点?

recursion - 如何消除左递归

c++ - ANTLR 3.2 中的 C++ 代码生成准备好了吗?

antlr - 语句或退出语句的 ANTLR 文法

java - 从java语法antlr创建解析器时出错