ANTLR以递归方式替换令牌

时间:2012-05-01 09:48:46

标签: java antlr antlr3 antlrworks

我有以下语法:

rule: q=QualifiedName {System.out.println($q.text);};

QualifiedName
   :   
        i=Identifier { $i.setText($i.text + "_");}
        ('[' (QualifiedName+ | Integer)? ']')*
   ;


Integer
    : Digit Digit*
    ;

fragment
Digit 
    : '0'..'9'
    ;

fragment
Identifier
    :   (   '_'
        |   '$'
        |   ('a'..'z' | 'A'..'Z')
        )
        ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '$')*
    ;

和来自Java的代码:

ANTLRStringStream stream = new ANTLRStringStream("array1[array2[array3[index]]]");
TestLexer lexer = new TestLexer(stream);
CommonTokenStream tokens = new TokenRewriteStream(lexer);
TestParser parser = new TestParser(tokens);
try {
    parser.rule();
} catch (RecognitionException e) {
    e.printStackTrace();
}

对于输入:array1[array2[array3[index]]],我想修改每个标识符。我期待看到输出:array1_[array_2[array3_[index_]]],但输出与输入相同。

所以问题是:为什么setText()方法在这里不起作用?

修改

我用以下方式修改了Bart的答案:

rule: q=qualifiedName {System.out.println($q.modified);};

qualifiedName returns [String modified]
   :   
        Identifier
        ('[' (qualifiedName+ | Integer)? ']')*
        {
            $modified = $text + "_";
        }
   ;

Identifier
    :   (   '_'
        |   '$'
        |   ('a'..'z' | 'A'..'Z')
        )
        ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '$')*
    ;

Integer
    : Digit Digit*
    ;

fragment
Digit 
    : '0'..'9'
    ;

我想修改规则qualifiedName匹配的每个令牌。我尝试了上面的代码,对于输入array1[array2[array3[index]]],我希望看到输出array1[array2[array3[index_]_]_]_,但只修改了最后一个标记:array1[array2[array3[index]]]_

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

创建令牌后,您只能使用setText(...)。您递归调用此标记 设置其他一些文本,这些文本无效。您需要使用QualifiedName而不是词法分析器规则创建解析器规则,并在fragment之前移除Identifier

rule: q=qualifiedName {System.out.println($q.text);};

qualifiedName
   :   
        i=Identifier { $i.setText($i.text + "_");}
        ('[' (qualifiedName+ | Integer)? ']')*
   ;

Identifier
    :   (   '_'
        |   '$'
        |   ('a'..'z' | 'A'..'Z')
        )
        ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '$')*
    ;

Integer
    : Digit Digit*
    ;

fragment
Digit 
    : '0'..'9'
    ;

现在,将在控制台上打印:array1_[array2_[array3_[index_]]]

修改

我不知道您为什么要这样做,但似乎您只是想将]重写为]_,这可以按照我上面显示的相同方式完成:

qualifiedName
   :   
        Identifier
        ('[' (qualifiedName+ | Integer)? t=']' {$t.setText("]_");} )*
   ;