我需要有关算术表达式语法的帮助。
如果用户尝试除以零或使用某些 VHDL 关键字(目标语言(作为变量名称,我想通知用户一些错误消息。
但是我是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 : [ rnt] + -> 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 : [ rnt] + -> 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;
}
当然,这在上下文之外可能没有多大意义,但请放心,它有效。 要在其完整的上下文中看到这一点,请访问 巴特·基尔斯 获取语法和实现的一个很好的例子。