【问题标题】:ANTLR Grammar incompleteANTLR 语法不完整
【发布时间】:2011-12-09 05:21:29
【问题描述】:

使用这个语法我可以找到指数,但我得到的答案是相反的(例如:这就是我得到的:2 ^ 2 ^ 3 = 64 这是我应该得到的:2 ^ 2 ^ 3 = 2 ^ 8 = 256))

grammar SDD1
;

options {
  language = Java;
}
// header for parser related java
@header {
  package com.compiler.tutorial;
}

// header for lexer related java
@lexer::header {
  package com.compiler.tutorial;

}

evaluator returns[int result]
  : expression EOF  {$result = $expression.result;}
  ;   

expression returns[int result]
    : op1=mult {$result = $op1.result;}  
    ( '+' op2=mult {$result = $result + $op2.result;}
    | '-' op2=mult {$result = $result - $op2.result;}
    )*
    ;

mult returns [int result]
  :  op1 = exponent {$result = $op1.result;}
  (  '*' op2=exponent  {$result = $result * $op2.result;}
  |  '/' op2=exponent  {$result = $result / $op2.result;}

  )*
   ;

 exponent returns [int result]
  :  op1=factor {$result = $op1.result;}
     ( '^' op2=factor {$result = (int) Math.pow( $result,$op2.result);}
     )*
  ;



factor returns [int result]
   :  NUMBER  {$result = Integer.parseInt($NUMBER.text); 
                System.out.println ("Number= " + $result);}|
      IDENT  {$result = 0;}|
      '(' expression ')' {$result = $expression.result;}
   ;


fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
IDENT: LETTER( LETTER | DIGIT )*;
NUMBER: DIGIT+;
WS: (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};

【问题讨论】:

  • 2^2^3 = 64 如果你像 (2^2)^3 = 64 一样评估它本身就是正确的......也许这是因为你的语法不完全正确应该是递归的(应该首先评估最右边的表达式???)
  • 请不要用“紧急”标记您的问题。

标签: antlr


【解决方案1】:

您的问题是 ^ 运算符是右结合的。并且使用您当前的语法,它被定义为左结合。像 + 、 - 或 * 这样的运算符是左结合的,这在 ANTLR 语法中很自然地表达。要表达右关联性,您需要递归规则。我改变了你的语法,但没有触及你在花括号内的动作,所以它给出了正确的解析树:

grammar SDD1
;

options {
  language = Java;
}
// header for parser related java
@header {
  package com.compiler.tutorial;
}

// header for lexer related java
@lexer::header {
  package com.compiler.tutorial;

}

evaluator returns[int result]
  : expression EOF  {$result = $expression.result;}
  ;   

expression returns[int result]
    : op1=mult {$result = $op1.result;}  
    ( '+' op2=mult {$result = $result + $op2.result;}
    | '-' op2=mult {$result = $result - $op2.result;}
    )*
    ;

mult returns [int result]
  :  op1 = exponent {$result = $op1.result;}
  (  '*' op2=exponent  {$result = $result * $op2.result;}
  |  '/' op2=exponent  {$result = $result / $op2.result;}

  )*
   ;

 exponent returns [int result]
  : atom ('^' exponent)?
  ;



atom returns [int result]
   :  NUMBER  {$result = Integer.parseInt($NUMBER.text); 
                System.out.println ("Number= " + $result);}|
      IDENT  {$result = 0;}|
      '(' expression ')' {$result = $expression.result;}
   ;



fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
IDENT: LETTER( LETTER | DIGIT )*;
NUMBER: DIGIT+;
WS: (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};

(注意我添加的关键规则:

 exponent returns [int result]
  : atom ('^' exponent)?
  ;

右大括号后面没有*,但是?)

所以对于输入:

2^3^4^5

你会得到以下解析树:

【讨论】:

    【解决方案2】:

    对于初学者,2<sup>(2<sup>3</sup>)</sup> 是 256,而不是 512 - 没有(非奇异的)关联性会从该表达式中为您提供 512 :-)

    但是,如果您希望指数运算符具有从右到左的关联性,则需要修改 exponent 规则以使其变得贪婪。换句话说,允许它采用 exponent 作为辅助操作数(优先),而不是像现在这样仅采用 factor

    这样,2^2^3 确实会评估为 2<sup>(2<sup>3</sup>)</sup> 而不是 (2<sup>2</sup>)<sup>3</sup>

    抱歉,我不知道确切如何使用 ANTLR 实现这一目标,我在这里展示了我的年龄,但我非常喜欢 lex/yacc :-)

    this PDF 似乎是您所追求的(见幻灯片 35)。基本上,你定义你的项目服从指数I(在你的情况下是factor),指数E变成:

    E = I  ^ E
      | I
    

    【讨论】:

    • 我的要求是,如果假设 2^4^2 首先应该完成指数 4^2,结果是 16,然后应该完成 2^16。这是我的要求,请帮忙
    • @pranith,我明白你在追求什么,我只需要花一些时间从 yacc 翻译 - 查看更新。
    • @paxdiablo 是对的...您的规则指数返回 [int result] : op1=factor {$result = $op1.result;} ( '^' op2=factor {$result = (int ) Math.pow( $result,$op2.result);} )* ;应该分成两个规则(类似于 exp : op1 '^' extEXP; 和 extEXP : op2 | exp)我没有 antlr 来精确测试,但问题是,你写了一个更扁平的语法来避免贪婪的方法。跨度>
    • @paxdiablo 感谢您的回复能否请您更改代码,我一直在尝试但无法弄清楚,请帮助我。
    • @pranith,如上所述,我只是为您提供修复它所需的信息,因为我(通常)非常了解解析器而 ANTLR(具体而言)不太了解。虽然很容易理解您拥有的规则,但我不会有信心从头开始编写规则。如果您希望我学习 ANTLR 为您完成所有您的工作(而不仅仅是免费协助您),我的费率目前为100 美元/小时 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多