Antlr 语法中的赋值表达式

发布于 2024-12-19 18:16:11 字数 755 浏览 2 评论 0原文

我正在尝试扩展 Tiny Language 的语法< /a> 将赋值视为表达式。 是有效的

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(*) 决策的语法,如何找到导致问题的两条路径
  • 如何修复它

I'm trying to extend the grammar of the Tiny Language to treat assignment as expression. Thus it would be valid to write

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

Assignment differs from other operators in two aspects. It's right associative (not a big deal), and its left-hand side is has to be a variable. So I changed the grammar like this

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

It doesn't work, because it contains a non-LL(*) decision. I also tried this variant:

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

but I got the same error. I am interested in

  • This specific question
  • Given a grammar with a non-LL(*) decision, how to find the two paths that cause the problem
  • How to fix it

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我认为你可以像这样改变你的语法来实现相同的目的,而不使用句法谓词:

statement: Expr ';' | functionCall ';'...;

Expr: Identifier indexes? '=' Expr  |  condExpr ;

condExpr: .... and so on;

我改变了巴特的例子,考虑到这个想法:

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

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

I think you can change your grammar like this to achieve the same, without using syntactic predicates:

statement: Expr ';' | functionCall ';'...;

Expr: Identifier indexes? '=' Expr  |  condExpr ;

condExpr: .... and so on;

I altered Bart's example with this idea in mind:

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

And for the input:

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

you get following parse tree:
enter image description here

°如果伤别离去 2024-12-26 18:16:11

这里的关键是,您需要向解析器“保证”表达式内部存在满足该表达式的内容。这可以使用语法谓词(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:

在此处输入图像描述

The key here is that you need to "assure" the parser that inside an expression, there is something ahead that satisfies the expression. This can be done using a syntactic predicate (the ( ... )=> parts in the add and mult rules).

A quick demo:

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

which will parse the input:

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

into the following AST:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文