4

我正在尝试扩展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(*) 决策的文法,如何找到导致问题的两条路径
  • 如何修复它
4

2 回答 2

2

我认为您可以像这样更改语法以实现相同的目的,而无需使用句法谓词:

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);

你得到以下解析树: 在此处输入图像描述

于 2011-12-06T20:04:52.377 回答
1

这里的关键是您需要向解析器“保证”在表达式内部,前面有满足表达式的东西。这可以使用句法谓词(and规则( ... )=>中的部分)来完成。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:

在此处输入图像描述

于 2011-12-06T12:43:59.447 回答