ANTLR4:算术表达式的语法 - 除零检查,关键字检查

时间:2017-08-18 17:44:04

标签: compiler-construction grammar 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 ;

1 个答案:

答案 0 :(得分:1)

我发现了许多我在下面的语法中纠正的小问题。

  • 没有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 ;
    

现在,纠正了许多lexing和"良好的形式"的问题。接下来的问题是如何处理,例如,除以零。

语法不是强制执行此类规则的地方。例如,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以获得语法和实现的绝佳示例。