【问题标题】:Assignment as expression in Antlr grammar赋值为 Antlr 语法中的表达式
【发布时间】:2011-12-06 10:52:20
【问题描述】:

我正在尝试扩展 the grammar of the Tiny Language 以将赋值视为表达式。因此写是有效的

a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
a = 1 = 2; // invalid

赋值在两个方面不同于其他运算符。它是右关联的(没什么大不了的),它的左边必须是一个变量。所以我就这样改了语法

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

它不起作用,因为它包含一个非 LL(*) 决定。我也试过这个变种:

assignmentExpr: Identifier indexes? '=' (expression | condExpr);

但我遇到了同样的错误。我有兴趣

  • 这个具体问题
  • 给定一个具有非 LL(*) 判定的文法,如何找到导致问题的两条路径
  • 如何解决

【问题讨论】:

    标签: parsing antlr ll


    【解决方案1】:

    我认为你可以像这样改变你的语法来达到同样的效果,而不使用句法谓词:

    statement: Expr ';' | functionCall ';'...;
    
    Expr: Identifier indexes? '=' Expr  |  condExpr ;
    
    condExpr: .... and so on;
    

    考虑到这个想法,我修改了 Bart 的示例:

    grammar TL;
    
    options {
      output=AST;
    }
    
    tokens {
      ROOT;
    }
    
    parse
      :  stat+ EOF -> ^(ROOT stat+)
      ;
    
    stat
      :  expr ';' 
      ;
    
    expr
      : Id Assign expr -> ^(Assign Id expr)
    
      | add
      ;
    
    add
      :  mult (('+' | '-')^ mult)*
      ;
    
    mult
      :  atom (('*' | '/')^ atom)*
      ;
    
    atom
      :  Id
      |  Num
      |  '('! expr ')' !
      ;
    
    Assign  :   '=' ;
    Comment : '//' ~('\r' | '\n')* {skip();};
    Id      : 'a'..'z'+;
    Num     : '0'..'9'+;
    Space   : (' ' | '\t' | '\r' | '\n')+ {skip();};
    

    对于输入:

    a=b=4;
    a = 2 * (b = 1);
    

    你得到以下解析树:

    【讨论】:

    • 谢谢!非常感谢您的意见!
    【解决方案2】:

    这里的关键是你需要向解析器“保证”在表达式中,前面有满足表达式的东西。这可以使用语法谓词(addmult 规则中的 ( ... )=> 部分)来完成。

    快速演示:

    grammar TL;
    
    options {
      output=AST;
    }
    
    tokens {
      ROOT;
      ASSIGN;
    }
    
    parse
      :  stat* EOF -> ^(ROOT stat+)
      ;
    
    stat
      :  expr ';' -> expr
      ;
    
    expr
      :  add
      ;
    
    add
      :  mult ((('+' | '-') mult)=> ('+' | '-')^ mult)*
      ;
    
    mult
      :  atom ((('*' | '/') atom)=> ('*' | '/')^ atom)*
      ;
    
    atom
      :  (Id -> Id) ('=' expr -> ^(ASSIGN Id expr))?
      |  Num
      |  '(' expr ')' -> expr
      ;
    
    Comment : '//' ~('\r' | '\n')* {skip();};
    Id      : 'a'..'z'+;
    Num     : '0'..'9'+;
    Space   : (' ' | '\t' | '\r' | '\n')+ {skip();};
    

    它将解析输入:

    a = b = 1;       // -> a = (b = 1)
    a = 2 * (b = 1); // contrived but valid
    

    进入以下 AST:

    【讨论】:

    • 它帮助我减少了我正在编写的更大语法中的所有警告。我发现这方面的一些背景很有用:dslmeinte.wordpress.com/2011/12/05/…
    • 很高兴听到@Adam。是的,我读到一些最新版本的 XText 支持谓词:感谢链接。我没有仔细研究过 XText,但我已经看到的它看起来令人印象深刻!
    • @AdamSchmideg,另请参阅 Vladimir Radojicic 的答案,它更简洁(并且应该是公认的答案,IMO)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 2018-10-22
    相关资源
    最近更新 更多