ANTLR: оценка выражения, деление и пау - PullRequest
3 голосов
/ 21 сентября 2011

Я пытаюсь написать грамматику для оценки выражений.
Я начал с данного примера на веб-сайте ANTLR (он управляет +, - и *).Я добавил разделение.Но я хотел бы уведомить пользователя, если он попытается разделить на 0. Более того, я хотел бы добавить пау в моем анализаторе (с более высоким приоритетом, чем умножение и деление. (Например, 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();} ;

Заранее спасибо. Ред.

1 Ответ

3 голосов
/ 21 сентября 2011

Eouti писал:

Я добавил разделение. Но я хотел бы уведомить пользователя, если он попытается разделить на 0.

Внутри вашего правила multExpr вы не должны делать if (e != 0) ..., но вместо этого вы должны получить доступ к атрибуту e value. Кроме того, левая сторона вашего выражения называется 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 !");}
        )*
    ; 

Но вы действительно хотите предупредить пользователя? После этого предупреждения расчет просто продолжится в данный момент. ИМО, тебе нужно просто выбросить исключение.

Eouti писал:

Я хотел бы добавить пау в моем анализаторе (с более высоким приоритетом, чем умножение и деление.

Затем добавьте правило powExpr между multExpr и atom и позвольте 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] на returns [double value], особенно если вы используете деление.

...