以下语法有效,但也会发出警告:

测试.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,从而使我的意图清晰并消除警告?

最佳答案



您不应为 assignadd 创建两个单独的规则。正如您现在的规则一样, 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/

10-15 09:18