ANTLR4:算术表达式语法 - 除零检查,关键字检查
我需要此语法的算术表达式帮助。ANTLR4:算术表达式语法 - 除零检查,关键字检查
我想通知用户一些错误消息,如果他试图除以零,或者他使用一些VHDL keywords(目标语言)作为变量名称。
但我是新来的ANTLR,我不能弄清楚如何延长这个语法:
grammar arithmetic;
@header {
package generated;
}
stat
: Left = VARIABLE Op = ASSIGMENT Right = expr # Assigment
;
expr
: '(' Exp = expr ')' # Parens
| MINUS Exp = expr # UnaryMinus
| Left = expr Op = (TIMES | DIV) Right = expr # MulDiv
| Left = expr Op = (PLUS | MINUS) Right = expr # AddSub
| (VARIABLE | CONSTANT) # Element
;
ASSIGMENT : '=' ;
PLUS : '+' ;
MINUS : '-' ;
TIMES : '*' ;
DIV : '/' ;
LPAREN : '(' ;
RPAREN : ')' ;
VARIABLE : (LETTER+|DIGIT+|'_')+ ;
CONSTANT : INTEGER ;
INTEGER : DIGIT+ ;
LETTER : ('a' .. 'z') | ('A' .. 'Z') ;
DIGIT : ('0' .. '9') ;
WS : [ \r\n\t] + -> skip ;
我发现,我在下面的语法已经纠正了许多小问题。
- 没有EOF标记
- 只能运行一个语句,因此它扩展到
program
- 的@header事情引起的java grungui不运行
-
_
是一个合法的变量名,可能不是你想要什么。 -
'5'是作业的有效左侧。所以
5=6
是一个有效的赋值语句,可能不是你想要的。grammar Arithmetic; program : stat+ EOF; stat : Left = VARIABLE Op = ASSIGMENT Right = expr # Assigment ; expr : '(' Exp = expr ')' # Parens | MINUS Exp = expr # UnaryMinus | Left = expr Op = (TIMES | DIV) Right = expr # MulDiv | Left = expr Op = (PLUS | MINUS) Right = expr # AddSub | (VARIABLE | CONSTANT) # Element ; ASSIGMENT : '=' ; PLUS : '+' ; MINUS : '-' ; TIMES : '*' ; DIV : '/' ; LPAREN : '(' ; RPAREN : ')' ; VARIABLE : LETTER+(LETTER|DIGIT|'_')* ; CONSTANT : INTEGER ; INTEGER : DIGIT+ ; LETTER : ('a' .. 'z') | ('A' .. 'Z') ; DIGIT : ('0' .. '9') ; WS : [ \r\n\t] + -> skip ;
现在修正了很多文法和“好形式”问题。接下来的问题是如何处理,例如,除以零。
语法是不是地方执行这样的规则。例如,3/0是一个完全合法的数学表达式。它恰好会评估为无穷大,因此在程序中被防范。同样,你应该在代码中处理像这样的特殊情况。当您在#MulDiv上下文的右侧等于零时实现您的访问者或侦听器模式时,您应该在该点进行干预。语法不适用于试图实现这样复杂的语义和上下文敏感的规则。
至于如何编程的if
声明,我给你在偷看他们的方式我实现了他们:
public override MuValue VisitIfstmt(LISBASICParser.IfstmtContext context)
{
LISBASICParser.Condition_blockContext[] conditions = context.condition_block();
bool evaluatedBlock = false;
foreach (LISBASICParser.Condition_blockContext condition in conditions)
{
MuValue evaluated = Visit(condition.expr());
if (evaluated.AsBoolean())
{
evaluatedBlock = true;
Visit(condition.stmt_block());
break;
}
}
if (!evaluatedBlock && context.stmt_block() != null)
{
Visit(context.stmt_block());
}
return MuValue.Void;
}
当然,这可能并没有多大意义,断章取义,但休息保证它的工作。要全面了解这一点,请访问Bart Kiers,以获得语法和实现的绝佳示例。
谢谢你的回答。我正在从GUI的文本字段读取算术表达式,这就是为什么我没有使用EOF。我需要将单个表达式转换为VHDL代码。我想从ANTLR生成的类中分离语法,所以我使用头将其生成为不同的包。我不知道grungui是什么,我的javafx应用程序似乎没有它的工作。你是对的,并且5 = 6。我不希望发生这种情况,谢谢。 – Samuel
在每种情况下,我都可以控制生成的代码中的零分割,而不管它是否是像3/0这样的表达式。但是你是对的,这是合法的表达,所以我不应该在语法上处理它。关于关键字。我的问题是错的,我编辑它。我需要摆脱每个VHDL关键字(有问题的链接)。我正在考虑使用否定符号,不知何故,所有列出的关键字我都不想要。 如果有兴趣,我的丑编译器- https://github.com/SamuelSutaj/diplomovka/tree/testing/Compiler/src – Samuel
@Samuel要处理关键字作为特定的标记,你可以简单地按照专家的建议[in这个SO回答](https://*.com/questions/16419707/antlr4-tokenizing-a-huge-set-of-keywords)来自Sam Harwell。 – TomServo
用零除在运行时发生,而不是在编译时。 ANTLR系统已经区分了关键字和标识符。你的问题没有意义。 – EJP
那么我正在编译表达式到VHDL代码。所以我需要摆脱VHDL关键字 - “abs”,“access”,“after”,“alias”,“all”,“and”,“architecture”,“array”,“assert”,“attribute” ,“开始”,“块”,“身体”等。上面的关键字只是一个例子,我将编辑问题thnx。 – Samuel