以下语法有效,但也会发出警告:
测试.g
grammar test;
options {
language = Java;
output = AST;
ASTLabelType = CommonTree;
}
program
: expr ';'!
;
term: ID | INT
;
assign
: term ('='^ expr)?
;
add : assign (('+' | '-')^ assign)*
;
expr: add
;
// T O K E N S
ID : (LETTER | '_') (LETTER | DIGIT | '_')* ;
INT : DIGIT+ ;
WS :
( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
DOT : '.' ;
fragment
LETTER : ('a'..'z'|'A'..'Z') ;
fragment
DIGIT : '0'..'9' ;
警告
[15:08:20] warning(200): C:\Users\Charles\Desktop\test.g:21:34:
Decision can match input such as "'+'..'-'" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
同样,它确实按照我想要的方式生成了一棵树:
Input: 0 + a = 1 + b = 2 + 3;
ANTLR produces | ... but I think it
this tree: | gives the warning
| because it _could_
+ | also be parsed this
/ \ | way:
0 = |
/ \ | +
a + | / \
/ \ | + 3
1 = | / \
/ \ | + =
b + | / \ / \
/ \ | 0 = b 2
2 3 | / \
| a 1
我如何明确告诉 ANTLR 我希望它在左侧创建 AST,从而使我的意图清晰并消除警告?
最佳答案
您不应为 assign
和 add
创建两个单独的规则。正如您现在的规则一样, assign
优先于 add
,这是您不想要的:通过查看您想要的 AST,它们应该具有相同的优先级。因此,您需要将所有运算符 +
、 -
和 =
包装在一个规则中:
program
: expr ';'!
;
expr
: term (('+' | '-' | '=')^ expr)*
;
但现在语法仍然有歧义。您需要“帮助”解析器超越这种歧义,以确保在解析
operator expr
时前面确实有 (('+' | '-' | '=') expr)*
。这可以使用 syntactic predicate 来完成,如下所示:(look_ahead_rule(s)_in_here)=> rule(s)_to_actually_parse
(
( ... )=>
是谓词语法)一个小演示:
grammar test;
options {
output=AST;
ASTLabelType=CommonTree;
}
program
: expr ';'!
;
expr
: term ((op expr)=> op^ expr)*
;
op
: '+'
| '-'
| '='
;
term
: ID
| INT
;
ID : (LETTER | '_') (LETTER | DIGIT | '_')* ;
INT : DIGIT+ ;
WS : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
fragment LETTER : ('a'..'z'|'A'..'Z');
fragment DIGIT : '0'..'9';
可以使用类进行测试:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "0 + a = 1 + b = 2 + 3;";
testLexer lexer = new testLexer(new ANTLRStringStream(source));
testParser parser = new testParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.program().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
而 Main 类的输出对应于以下 AST:
它是在没有 来自 ANTLR 的任何警告的情况下创建的 。
关于parsing - ANTLR 赋值表达式消歧,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7354124/