Sophie

Sophie

distrib > Fedora > 14 > x86_64 > media > updates > by-pkgid > cd38b09e3cb8d6c675b02d30393e68af > files > 39

kaya-doc-0.5.2-8.fc14.noarch.rpm

module calclang; // -*-C-*-ish

import IO;
import Parse;
import Dict;

abstract data Expr 
     = Var(String name)
     | Assign(String varname, Expr val)
     | Num(Int num)
     | Infix(Op op,Expr l, Expr r);
       
data Op = Plus | Minus | Times | Divide;

Expr parseExpr(var ParseState st) =
    (parseAssign `or`
     parsePlusMinus `or`
     parseMultDiv `or`
     parseBrackets `or`
     parseVar `or`
     parseNum)(st);

Expr parseVar(var ParseState st) = Var(identifier(st));

Expr parseNum(var ParseState st) {
    num = Num(integer(st));
    return num;
}

Expr parseBrackets(var ParseState st) {
    c = char('(',st);
    exp = parseExpr(st);
    c = char(')',st);
    return exp;
}

Expr parsePlusMinus(var ParseState st) {
    left = (parseMultDiv `or` parseBrackets `or` parseNum `or` parseVar)(st);

//    putStrLn(st.input);

    whitespace(st);
    opch = ((char@('+')) `or` (char@('-')))(st);
    whitespace(st);
    if (opch=='+') { op = Plus; }
    else if (opch=='-') { op = Minus; }
    right = parseExpr(st);
    return Infix(op,left,right);
}

Expr parseAssign(var ParseState st) {
    name = identifier(st);
    whitespace(st);
    opch = char('=',st);
    whitespace(st);
    exp = parseExpr(st);
    return Assign(name, exp);
}

Expr parseMultDiv(var ParseState st) {
    left = (parseBrackets `or` parseNum `or` parseVar)(st);
    whitespace(st);
    opch = ((char@('*')) `or` (char@('/')))(st);
    whitespace(st);
    if (opch=='*') { op = Times; }
    else if (opch=='/') { op = Divide; }
    right = (parseBrackets `or` parseMultDiv `or` parseNum `or` parseVar)(st);
    return Infix(op,left,right);
}

type Context = Dict<String,Int>;

Exception NoSuchVariable(String v);

Int eval(Context ctxt, Expr e) {
    case e of {
	Num(x) -> return x;
	| Var(v) -> case lookup(ctxt,v) of {
	                nothing -> throw(NoSuchVariable(v));
			| just(val) -> return val;
	            }
	| Assign(v,expr) -> ev = eval(ctxt,expr); add(ctxt, v, ev); return ev;
	| Infix(op,l,r) -> case op of {
	    Plus -> return eval(ctxt,l)+eval(ctxt,r);
	    | Minus -> return eval(ctxt,l)-eval(ctxt,r);
	    | Times -> return eval(ctxt,l)*eval(ctxt,r);
	    | Divide -> return eval(ctxt,l)/eval(ctxt,r);
	}
    }
}

Exception CalcParseError(String err, Int p);

public Int calcExpr(Context ctxt, String strexp) {
    case parse(parseExpr, strexp) of {
	Success(expr) -> return eval(ctxt, expr);
	| ParseError(err,l,p) ->
	    throw(CalcParseError(err,p));
    }
}