ANTLR:表达评估器、除法和 pow

发布于 2024-12-05 21:19:01 字数 1419 浏览 1 评论 0原文

我正在尝试编写一个语法来评估表达式。
我从 ANTLR 网站上给定的示例开始(它管理 +、- 和 *)。 我添加了部门。但如果用户尝试除以 0,我想通知他。 此外,我想在我的求值器中添加 pow(优先级高于乘法和除法。(例如 2^3=8)。
希望这是可以理解的。
这是我的语法 Expr.g :

grammar Expr;

@header {  
import java.util.HashMap;  
}

@members {  
/** Map variable name to Integer object holding value */  
HashMap memory = new HashMap();  
}

prog:   stat+ ;

stat:   expr NEWLINE {System.out.println($expr.value);}  
    |   ID '=' expr NEWLINE  
        {memory.put($ID.text, new Integer($expr.value));}  
    |   NEWLINE  
    ;

expr returns [int value]
    :   e=multExpr {$value = $e.value;}
        ((   '+' e=multExpr {$value += $e.value;}
        |   '-' e=multExpr {$value -= $e.value;}
        ))*
    ;

multExpr returns [int value]
    :   e=atom {$value = $e.value;} 
        ('*' e=atom {$value *= $e.value;}
        |'/' e=atom {if (e != 0) $value /= $e.value; 
                else System.err.println("Division par 0 !");}
        )*
    ; 

atom returns [int value]
    :   INT {$value = Integer.parseInt($INT.text);}
    |   ID
        {
        Integer v = (Integer)memory.get($ID.text);
        if ( v!=null ) $value = v.intValue();
        else System.err.println("Variable indéfinie "+$ID.text);
        }
    |   '(' expr ')' {$value = $expr.value;}
    ;

ID  :   ('a'..'z'|'A'..'Z')+ ;
INT :   '0'..'9'+ ;
NEWLINE:'\r'? '\n' ;
WS  :   (' '|'\t')+ {skip();} ;

提前致谢。 埃德。

I'm trying to write a grammar to evaluate expressions.
I've started with the given example on the ANTLR website (it manage +,- and *).
I added the division. But I would like to notify user if he tries to divide by 0.
Moreover, I would like to add the pow in my evaluator (with an higher precedence than multiply and divide. (for example 2^3=8).
Hope it's understandable.
Here's my grammar Expr.g :

grammar Expr;

@header {  
import java.util.HashMap;  
}

@members {  
/** Map variable name to Integer object holding value */  
HashMap memory = new HashMap();  
}

prog:   stat+ ;

stat:   expr NEWLINE {System.out.println($expr.value);}  
    |   ID '=' expr NEWLINE  
        {memory.put($ID.text, new Integer($expr.value));}  
    |   NEWLINE  
    ;

expr returns [int value]
    :   e=multExpr {$value = $e.value;}
        ((   '+' e=multExpr {$value += $e.value;}
        |   '-' e=multExpr {$value -= $e.value;}
        ))*
    ;

multExpr returns [int value]
    :   e=atom {$value = $e.value;} 
        ('*' e=atom {$value *= $e.value;}
        |'/' e=atom {if (e != 0) $value /= $e.value; 
                else System.err.println("Division par 0 !");}
        )*
    ; 

atom returns [int value]
    :   INT {$value = Integer.parseInt($INT.text);}
    |   ID
        {
        Integer v = (Integer)memory.get($ID.text);
        if ( v!=null ) $value = v.intValue();
        else System.err.println("Variable indéfinie "+$ID.text);
        }
    |   '(' expr ')' {$value = $expr.value;}
    ;

ID  :   ('a'..'z'|'A'..'Z')+ ;
INT :   '0'..'9'+ ;
NEWLINE:'\r'? '\n' ;
WS  :   (' '|'\t')+ {skip();} ;

Thanks in advance.
Ed.

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

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

发布评论

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

评论(1

围归者 2024-12-12 21:19:01

euti 写道:

我添加了部门。但如果用户尝试除以 0,我想通知他。

在您的 multExpr 规则中,您不应该执行 if (e != 0) ...,但您应该访问 evalue 属性。另外,表达式的左侧称为 e,而右侧也称为 e。您最好给它们指定唯一的名称:

multExpr returns [int value]
    :   e1=atom {$value = $e1.value;} 
        ( '*' e2=atom {$value *= $e2.value;}
        | '/' e2=atom {if ($e2.value != 0) $value /= $e2.value; 
                       else System.err.println("Division par 0 !");}
        )*
    ; 

但是,您真的想警告用户吗?出现此警告后,计算将继续进行。 IMO,你应该让异常被抛出。

euti 写道:

我想在我的求值器中添加 pow(优先级高于乘法和除法。

然后在中添加一个 powExpr 规则)在 multExpratom 之间,并让 multExpr 使用此 powExpr 规则而不是 atom规则:

multExpr returns [int value]
    :   e1=powExpr       {...} 
        ( '*' e2=powExpr {...}
        | '/' e2=powExpr {...}
        )*
    ;  

powExpr returns [int value]
    :   atom      {...} 
        ('^' atom {...} 
        )*
    ;

atom returns [int value]
    :   INT          {...}
    |   ID           {...}
    |   '(' expr ')' {...}
    ;

powExpr 当然,实际上并不需要位于这些规则之间...)

另外,您可能想要更改 returns [int value] 到 返回 [double value],特别是因为您正在使用除法。

eouti wrote:

I added the division. But I would like to notify user if he tries to divide by 0.

Inside your multExpr rule, you shouldn't do if (e != 0) ..., but you should access e's value attribute instead. Also, the left-hand-side of your expression is called e while the right-hand-side is also called e. You'd better give them unique names:

multExpr returns [int value]
    :   e1=atom {$value = $e1.value;} 
        ( '*' e2=atom {$value *= $e2.value;}
        | '/' e2=atom {if ($e2.value != 0) $value /= $e2.value; 
                       else System.err.println("Division par 0 !");}
        )*
    ; 

But, do you really want to warn the user? After this warning, the calculation will just continue at the moment. IMO, you should just let the exception be thrown.

eouti wrote:

I would like to add the pow in my evaluator (with an higher precedence than multiply and divide.

Then add a powExpr rule in between multExpr and atom and let multExpr use this powExpr rule instead of the atom rule:

multExpr returns [int value]
    :   e1=powExpr       {...} 
        ( '*' e2=powExpr {...}
        | '/' e2=powExpr {...}
        )*
    ;  

powExpr returns [int value]
    :   atom      {...} 
        ('^' atom {...} 
        )*
    ;

atom returns [int value]
    :   INT          {...}
    |   ID           {...}
    |   '(' expr ')' {...}
    ;

(powExpr doesn't literally need to be in between these rules of course...)

Also, you might want to change returns [int value] into returns [double value], especially since you're using division.

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