blob: e83dc7acf3d8b5bb8b14bccabe9d82ca87ac3c5f [file] [log] [blame]
// Reverse Polish Notation, rpn.k
// © 2001, Michael Piefel <piefel@informatik.hu-berlin.de>
// Define which views (ie., different paths) we intent to take
// during unparse and rewrite
%uview infix postfix;
%rview canon calculate;
// Simple expressions
Plus( exp1, exp2 )
-> [ infix: exp1 "+" exp2 ]
[ postfix: exp1 " " exp2 " +" ];
Minus( exp1, exp2 )
-> [ infix: exp1 "-" exp2 ]
[ postfix: exp1 " " exp2 " -" ];
// Beware of parentheses in infix representation
Mul( exp1, exp2=Plus(*,*) ),
Mul( exp1, exp2=Minus(*,*) )
-> [ infix: exp1 "*(" exp2 ")" ];
Mul( exp1=Plus(*,*), exp2 ),
Mul( exp1=Minus(*,*), exp2 )
-> [ infix: "(" exp1 ")*" exp2 ];
Mul( exp1=Plus(*,*), exp2=Plus(*,*) ),
Mul( exp1=Plus(*,*), exp2=Minus(*,*) ),
Mul( exp1=Minus(*,*), exp2=Plus(*,*) ),
Mul( exp1=Minus(*,*), exp2=Minus(*,*) )
-> [ infix: "(" exp1 ")*(" exp2 ")" ];
Mul( exp1, exp2 )
-> [ infix: exp1 "*" exp2 ]
[ postfix: exp1 " " exp2 " *"];
Div( exp1=Plus(*,*), exp2 ),
Div( exp1=Minus(*,*), exp2 )
-> [ infix: "(" exp1 ")/" exp2 ];
Div( exp1, exp2=Plus(*,*) ),
Div( exp1, exp2=Minus(*,*) ),
Div( exp1, exp2=Mul(*,*) ),
Div( exp1, exp2=Div(*,*) )
-> [ infix: exp1 "/(" exp2 ")"];
Div( exp1=Plus(*,*), exp2=Plus(*,*) ),
Div( exp1=Plus(*,*), exp2=Minus(*,*) ),
Div( exp1=Minus(*,*), exp2=Plus(*,*) ),
Div( exp1=Minus(*,*), exp2=Minus(*,*) )
-> [ infix: "(" exp1 ")/(" exp2 ")" ];
Div( exp1, exp2 )
-> [ infix: exp1 "/" exp2 ]
[ postfix: exp1 " " exp2 " /" ];
// Calculate all that can be calculated (ie. all where
// we have concrete numbers)
Plus( Term(Number(a)), Term(Number(b)) )
-> < calculate: Term(Number(plus(a,b)))>;
Plus( Term(Number(a)), Plus(Term(Number(b)), rest) )
-> < calculate: Plus(Term(Number(plus(a,b))), rest)>;
Plus( Term(Number(a)), Minus(Term(Number(b)), rest) )
-> < calculate: Minus(Term(Number(plus(a,b))), rest)>;
Minus( Term(Number(a)), Term(Number(b)) )
-> < calculate: Term(Number(minus(a,b)))>;
Minus( Term(Number(a)), Minus(Term(Number(b)), rest) )
-> < calculate: Plus(Term(Number(minus(a,b))), rest)>;
Minus( Term(Number(a)), Plus(Term(Number(b)), rest) )
-> < calculate: Minus(Term(Number(minus(a,b))), rest)>;
Mul( Term(Number(a)), Term(Number(b)) )
-> < calculate: Term(Number(mul(a,b)))>;
Mul( Term(Number(a)), Mul(Term(Number(b)), rest) )
-> < calculate: Mul(Term(Number(mul(a,b))), rest)>;
Mul( Term(Number(a)), Div(Term(Number(b)), rest) )
-> < calculate: Div(Term(Number(mul(a,b))), rest)>;
Div( Term(Number(a)), Term(Number(b)) )
-> < calculate: Term(Number(divi(a,b)))>;
Div( Term(Number(a)), Div(Term(Number(b)), rest) )
-> < calculate: Mul(Term(Number(divi(a,b))), rest)>;
Div( Term(Number(a)), Mul(Term(Number(b)), rest) )
-> < calculate: Div(Term(Number(divi(a,b))), rest)>;
// Helper functions to actually compute
%{ KC_REWRITE
inline integer plus(integer a, integer b) { return mkinteger(a->value+b->value); }
inline integer minus(integer a, integer b) { return mkinteger(a->value-b->value); }
inline integer mul(integer a, integer b) { return mkinteger(a->value*b->value); }
inline integer divi(integer a, integer b) { return mkinteger(b->value==0 ? 0 : a->value / b->value); }
%}
// Rewrite to a canonical form of the expression where operators
// are to be put as far to the end as possible
Plus( Plus(a, b), c)
-> < canon: Plus(a, Plus(b, c))>;
Plus( Minus(a, b), c)
-> < canon: Plus(c, Minus(a, b))>;
Minus( Plus(a, b), c)
-> < canon: Plus(a, Minus(b, c))>;
Mul( Mul(a, b), c)
-> < canon: Mul(a, Mul(b, c))>;
Plus( a=Term(Ident(*)), b=Term(Number(*)) )
-> < canon: Plus(b, a)>;
Mul( a=Term(Ident(*)), b=Term(Number(*)) )
-> < canon: Mul(b, a)>;
Plus( a=Term(Ident(*)), Plus(b=Term(Number(*)), rest) )
-> < canon: Plus(b, Plus(a,rest))>;
Mul( a=Term(Ident(*)), Mul(b=Term(Number(*)), rest) )
-> < canon: Mul(b, Mul(a,rest))>;