Antlr解析器和/或逻辑 - 如何在逻辑运算符之间获取表达式?

时间:2012-03-01 00:41:34

标签: parsing antlr antlr3

我正在使用ANTLR来创建和/或解析器+评估器。表达式的格式如下:

  • x eq 1 && y eq 10
  • (x lt 10 && x gt 1) OR x eq -1

我正在阅读ANTLR Looking for advice on project. Parsing logical expression中关于逻辑表达式的这篇文章,我发现那里的语法有一个良好的开端:

grammar Logic;

parse
  :  expression EOF
  ;

expression
  :  implication
  ;

implication
  :  or ('->' or)*
  ;

or
  :  and ('&&' and)*
  ;

and
  :  not ('||' not)*
  ;

not
  :  '~' atom
  |  atom
  ;

atom
  :  ID
  |  '(' expression ')'
  ;

ID    : ('a'..'z' | 'A'..'Z')+;
Space : (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};

但是,从解析器获取树时,对于变量只是一个字符的表达式(即"(A || B) AND C"),我很难适应我的情况(在示例{{1}中)我希望有一个"x eq 1 && y eq 10"个父母和两个孩子"AND""x eq 1",请参阅下面的测试用例。)

"y eq 10"

我认为这与@Test public void simpleAndEvaluation() throws RecognitionException{ String src = "1 eq 1 && B"; LogicLexer lexer = new LogicLexer(new ANTLRStringStream(src)); LogicParser parser = new LogicParser(new CommonTokenStream(lexer)); CommonTree tree = (CommonTree)parser.parse().getTree(); assertEquals("&&",tree.getText()); assertEquals("1 eq 1",tree.getChild(0).getText()); assertEquals("a neq a",tree.getChild(1).getText()); } 有关。正确的语法是什么?

2 个答案:

答案 0 :(得分:2)

对于那些感兴趣的人,我在语法文件中做了一些改进(见下文)

目前的限制:

  • 仅适用于&& / ||,而非AND / OR(不是很有问题)

  • 括号和&& / ||之间不能有空格(我通过在提供词法分析器之前在源字符串中将“(”with“)”和“)”替换为“)”来解决这个问题。

    语法逻辑;

    options {
      output = AST;
    }
    
    tokens {
      AND = '&&';
      OR  = '||';
      NOT = '~';
    }
    
    // parser/production rules start with a lower case letter
    parse
      :  expression EOF!    // omit the EOF token
      ;
    
    expression
      :  or
      ;
    
    or
      :  and (OR^ and)*    // make `||` the root
      ;
    
    and
      :  not (AND^ not)*      // make `&&` the root
      ;
    
    not
      :  NOT^ atom    // make `~` the root
      |  atom
      ;
    
    atom
      :  ID
      |  '('! expression ')'!    // omit both `(` and `)`
      ;
    
    // lexer/terminal rules start with an upper case letter
    ID
      :
        (
        'a'..'z'
        | 'A'..'Z'
        | '0'..'9' | ' '
        | SYMBOL
      )+ 
      ;
    
    SYMBOL
      :
        ('+'|'-'|'*'|'/'|'_')
     ;
    

答案 1 :(得分:0)

ID    : ('a'..'z' | 'A'..'Z')+;

声明标识符是一个或多个字母的序列,但不允许任何数字。尝试

ID    : ('a'..'z' | 'A'..'Z' | '0'..'9')+;

允许例如abc12312abab12。如果你不想要后者的类型,你将不得不重新调整规则(留下挑战......)

为了接受任意多个标识符,您可以将atom定义为ID+而不是ID

此外,您可能需要指定ANDOR->~作为代币,以便像@Bart Kiers所说的那样,前两个赢了' t被归类为ID,因此后两者将被识别。