diff --git a/src/Builtins.lama b/src/Builtins.lama index f7eecdad..34cd57a8 100644 --- a/src/Builtins.lama +++ b/src/Builtins.lama @@ -1,9 +1,24 @@ -- Builtins import World; +import List; + +fun exprToStr(e) { + case e of + Sexp(tag, args) -> if compare(args, {}) then + tag ++ " (" ++ foldl(fun(s, arg) { + if compare(s, "") then s ++ ", " ++ exprToStr(arg) + else exprToStr(arg) + fi + }, "", args) ++ ")" + else tag + fi | + _ -> e.string + esac +} public fun evalBuiltin (name, args, w) { case [name, args] of - ["stringval", {a}] -> [a.string, w] + ["stringval", {a}] -> [exprToStr(a), w] | ["length" , {a@#array}] -> [a.length, w] | ["length" , {a@#string}] -> [a.length, w] | ["read" , {}] -> readWorld (w) diff --git a/src/Expr.lama b/src/Expr.lama index cd2f983d..152676f7 100644 --- a/src/Expr.lama +++ b/src/Expr.lama @@ -100,9 +100,104 @@ fun evalList (c, exprs) { esac } +fun matchSexp(c@[s, w], val, sexpr) { + case sexpr of + Sexp(setag, sexprs) -> case setag of + "_" -> c | + _ -> case val of + Sexp(vtag, vals) -> if compare(vtag, setag) == 0 && size(vals) == size(sexprs) then + foldl(fun (c, [val, sexpr]) { + case c of + None -> None | + _ -> matchSexp(c, val, sexpr) + esac}, c, zip(vals, sexprs)) + else None + fi | + _ -> None + esac + esac | + Var(x) -> [addName(s, x) <- [x, Val(val)], w] + esac +} + (* Assignment *) fun eval (c@[s, w], expr) { - failure ("evalExpr not implemented\n") + case expr of + Assn (x, e) -> case evalList(c, {x, e}) of + [[s, w], {Ref(x), a}] -> [[s <- [x, Val(a)], w], a] | + [c, {ElemRef(arr, i), a}] -> arr[i] := a;[c, a] + esac | + Skip -> [c, Void] | + If (cond, e1, e2) -> case eval(c, cond) of + [c, val] -> if val then eval(c, e1) else eval(c, e2) fi + esac | + While (cond, body) -> case eval(c, cond) of + [c, val] -> if val then case eval(c, body) of [c, _] -> eval(c, expr) esac + else [c, Void] + fi + esac | + Repeat (body, cond) -> case evalList(c, {body, cond}) of + [c, _:val:_] -> if val then [c, Void] else eval(c, expr) fi + esac | + Seq (e1, e2) -> case evalList(c, {e1, e2}) of [c, _:res:_] -> [c, res] esac | + Var (x) -> [c, case s.lookupVal(x) of Val(v) -> v esac] | + Ref (x) -> [c, Ref(x)] | + Const (val) -> [c, val] | + Binop (op, lhs, rhs) -> case evalList(c, {lhs, rhs}) of + [c, lval:rval:_] -> [c, evalOp(op, lval, rval)] + esac | + Ignore (e) -> [eval(c, e).fst, Void] | + Scope(defs, e) -> case evalList([s.enterScope, w], defs) of + [c, _] -> case eval(c, e) of + [[s, w], val] -> [[s.leaveScope, w], val] + esac + esac | + Local(vars) -> [[s.addNames(vars), w], Void] | + Fun (f, args, body) -> [[s.addFunction(f, args, body), w], Void] | + Call (f, exprs) -> case s.lookupFun(f) of + Fun(args, body) -> case evalList(c, exprs) of + [[s, w], vals] -> case body of + External -> case evalBuiltin(f, vals, w) of + [res, w] -> [[s, w], res] + esac | + _ -> local s2 = foldl(fun (s1, [arg, val]) { + s1.addName(arg, Val(val)) + }, s.enterFunction, zip(args, vals)); + case eval([s2, w], body) of + [[s2, w], res] -> [[s.leaveFunction(s2.getGlobal), w], res] + esac + esac + esac + esac | + String(str) -> [c, str] | + Array (exprs) -> case evalList(c, exprs) of + [c, vals] -> [c, listArray(vals)] + esac | + Elem(arrExpr, indexExpr) -> case evalList(c, {arrExpr, indexExpr}) of + [c, {arr, index}] -> [c, arr[index]] + esac | + ElemRef(arrExpr, indexExpr) -> case evalList(c, {arrExpr, indexExpr}) of + [c, {arr, index}] -> [c, ElemRef(arr, index)] + esac | + Builtin(f, args) -> case evalList(c, args) of + [[s, w], vals] -> case evalBuiltin(f, vals, w) of + [res, w] -> [[s, w], res] + esac + esac | + Sexp(tag, args) -> case evalList(c, args) of + [c, vals] -> [c, Sexp(tag, vals)] + esac | + Case (x, pats) -> case eval(c, x) of + [c, val] -> case find(fun ([pat, _]) { + compare(matchSexp([enterScope(s), w], val, pat), None) + }, pats) of + None -> failure("Matching failed %s\n", val.string) | + Some([pat, e]) -> case eval(matchSexp([enterScope(s), w], val, pat), e) of + [[s, w], val] -> [[leaveScope(s), w], val] + esac + esac + esac + esac } (* End *) diff --git a/src/Lexer.lama b/src/Lexer.lama index 0c432e28..04c49184 100644 --- a/src/Lexer.lama +++ b/src/Lexer.lama @@ -70,7 +70,8 @@ public rSkip = createRegexp ("skip\\b", "skip"), rCase = createRegexp ("case\\b", """case"""), rOf = createRegexp ("of\\b", """of"""), rEsac = createRegexp ("esac\\b", """esac"""), - rLength = createRegexp ("length\\b", """length"""); + rLength = createRegexp ("length\\b", """length"""), + rString = createRegexp ("string\\b", """string"""); local whiteSpace = token (rWhiteSpace); @@ -97,6 +98,7 @@ public kSkip = s (rSkip), kOf = s (rOf), kEsac = s (rEsac), kLength = s (rLength), + kString = s (rString), decimal = s (rDecimal), chrlit = syntax (x=s[rChar] {case substring (x, 1, x.length - 2) of "\\t" -> '\t' diff --git a/src/Parser.lama b/src/Parser.lama index d994f51c..91ddd6a4 100644 --- a/src/Parser.lama +++ b/src/Parser.lama @@ -130,7 +130,38 @@ local primary = memo $ eta syntax ( esac }} | (* Assignment *) - $(failure ("the rest of primary parsing in not implemented\n"))), + loc=pos kSkip {fun(a) {assertVoid(a, Skip, loc)}} | + loc=pos kIf cond=exp kThen s1=exp s2=elseBranch {fun (a) {If (cond(Val), s1(a), s2(a))}} | + loc=pos kWhile cond=exp kDo body=scopeExpr kOd { + fun (a) { assertVoid(a, While (cond(Val), body(Void)), loc) } + } | + loc=pos kRepeat body=scopeExpr kUntil cond=inbr[s("("), exp, s(")")] { + fun (a) { + case body(Void) of + Scope(defs, e) -> assertVoid(a, Scope(defs, Repeat (e, cond(Val))), loc) + esac + } + } | + loc=pos kFor init=scopeExpr s[","] cond=exp s[","] step=exp kDo body=scopeExpr kOd { + fun (a) { + case init(Void) of + Scope(defs, e) -> assertVoid(a, Scope(defs, Seq (e, While (cond(Val), Seq (body(Void), step(Void))))), loc) + esac + } + } | + inbr[s("("), exp, s(")")] | + inbr[s("{"), scopeExpr, s("}")] | + loc=pos x=sexpLhs {fun (a) { assertValue (a, Sexp(x, {}), loc)}} | + loc=pos x=uident y=inbr[s("("), list0(syntax (e=exp {e(Val)})), s(")")] {fun (a) {assertValue (a, Sexp(x, y), loc)}} | + loc=pos kCase x=exp kOf pats=list0By[caseBranch, s("|")] kEsac {fun (a) { Case(x(Val), map(fun ([p, e]) {[p(Val), e(a)]}, pats)) }} + ), + sexpLhs = memo $ eta syntax (uident|s["_"]), + caseBranch = memo $ eta syntax (loc=pos p=primary s["->"] e=exp {[p, e]}), + elseBranch = memo $ eta syntax ( + loc=pos kFi {fun (a) { assertVoid(a, Skip, loc)}} | + -kElse exp -kFi| + kElif cond=exp kThen s1=exp s2=elseBranch {fun (a) {If (cond (Val), s1 (a), s2 (a))}} + ), (* End *) basic = memo $ eta (expr ({[Right, singleton ([s (":="), fun (l, loc, r) { @@ -143,11 +174,14 @@ local primary = memo $ eta syntax ( [Left , map (binop, {"*", "/", "%"})] }, postfix)), - postfix = memo $ eta syntax (loc=pos e=primary ps=(i=inbr[s("["), exp, s("]")] {Index (i (Val))} | - -s["."] kLength {Length} - )* {fun (a) {foldl (fun (e, p) { + postfixOp = memo $ eta syntax (i=inbr[s("["), exp, s("]")] {Index (i (Val))} | + -s["."] kLength {Length} | + -s["."] kString {String} + ), + postfix = memo $ eta syntax (loc=pos e=primary ps= postfixOp* {fun (a) {foldl (fun (e, p) { case p of Length -> fun (a) {assertValue (a, Builtin ("length", singleton (e (Val))), loc)} + | String -> fun (a) {assertValue (a, Builtin ("stringval", singleton (e (Val))), loc)} | Index (i) -> fun (a) { case a of @@ -161,7 +195,7 @@ local primary = memo $ eta syntax ( ), scopeExpr = memo $ eta syntax (ds=definition* e=exp? {fun (a) {fun (e) { case ds of - {} -> e + {} -> Scope({}, e) | _ -> expandScope (ds, e) esac } (case e of diff --git a/src/SM.lama b/src/SM.lama index b590ea03..f54918b3 100644 --- a/src/SM.lama +++ b/src/SM.lama @@ -120,11 +120,75 @@ fun eval (env, w, insns) { inner (n, {}, list) } + + fun enumerate(l) { + fun inner(ls, n) { + case ls of + {} -> {} | + x : xs -> [x, n] : inner(xs, n + 1) + esac + } + inner(l, 0) + } -- Core interpreter: takes a configuration and a program, returns a configuration (* Assignment *) - fun eval (c@[st, cst, s, w], insns) { - failure ("SM interpreter is not implemented\n") + fun eval (c@[stack, cst, state, w], insns) { + case insns of + {} -> c + | i : is -> case i of + CONST (n) -> eval([n : stack, cst, state, w], is) + | BINOP (op) -> eval(case stack of lhs : rhs : t -> [evalOp (op, lhs, rhs) : t, cst, state, w] esac, is) + | LD (x) -> eval([lookup(state, x) : stack, cst, state, w], is) + | LDA(x) -> eval([Ref(x) : stack, cst, state, w], is) + | ST (x) -> eval(case stack of h : t -> assign(state, x, h); [t, cst, state, w] esac, is) + | STI -> eval(case stack of val : Ref(x) : t -> assign(state, x, val); [val:t, cst, state, w] esac, is) + | DROP -> eval(case stack of _:t -> [t, cst, state, w] esac, is) + | LABEL (l) -> eval(c, is) + | JMP (l) -> eval(c, env.fromLabel(l)) + | CJMP ("z", l) -> case stack of h : t -> + eval([t, cst, state, w], if h then is else env.fromLabel(l) fi) + esac + | CJMP ("nz", l) -> case stack of h : t -> + eval([t, cst, state, w], if h == 0 then is else env.fromLabel(l) fi) + esac + | GLOBAL(x) -> assign(state, Glb(x), 0); eval([stack, cst, state, w], is) + | CALL(f, _) -> case f of + "read" -> case evalBuiltin(f, {}, w) of [res, w] -> eval([res : stack, cst, state, w], is) esac | + "write" -> case stack of + x : stack -> case evalBuiltin(f, x:{}, w) of [res, w] -> eval([res : stack, cst, state, w], is) esac + esac | + _ -> eval([stack, [state, is]: cst, state, w], env.fromLabel(f)) + esac + | BEGIN(_, nArgs, nLocals) -> case take(stack, nArgs) of + [stack, vals] -> local state = foldl(fun(s, [val, narg]) { + assign(s, Arg(narg), val); + s + }, makeState(nArgs, nLocals), enumerate(vals)); + eval([stack, cst, state, w], is) + esac + | END -> case cst of + {} -> c | + [state, is]:cst -> eval([stack, cst, state, w], is) + esac + | BUILTIN (f, n) -> case take(stack, n) of + [stack, vals] -> case evalBuiltin(f, vals, w) of + [res, w] -> eval([res: stack, cst, state, w], is) + esac + esac + | STRING(str) -> eval([str : stack, cst, state, w], is) + | ARRAY (n) -> case take(stack, n) of + [stack, vals] -> eval([listArray(vals) : stack, cst, state, w], is) + esac + | ELEM -> case stack of + i : a : stack -> eval([a[i] : stack, cst, state, w], is) + esac + | STA -> case stack of + val : i : a : stack -> a[i] := val; eval([val : stack, cst, state, w], is) + esac + | _ -> failure("evaluation not yet implemented") + esac + esac } (* End *) @@ -354,6 +418,116 @@ fun addVars (env, names) { -- (use env.addArg). public fun compileSM (expr) { - failure ("compileSM not implemented\n") + fun compileSMListImpl(env, exprs) { + case foldl(fun ([smInsns, env], expr) { + case compileSMImpl (env, expr) of + [is, env] -> [is : smInsns, env] + esac + }, [{}, env], exprs) of + [insns, env] -> [reverse(insns), env] + esac + } + fun addDefs(env, defs) { + case foldl(fun([env, funs, globs], def) { + case def of + Local(vars) -> [addVars(env, vars), funs, if isGlobal(env) then (map(fun (x) {GLOBAL(x)}, vars)) : globs else globs fi] | + Fun (name, args, body) -> case genFunLabel(env, name) of + [fLabel, env] -> [addFun(env, name, fLabel, size(args)), [fLabel, args, body] : funs, globs] + esac + esac + }, [env, {}, {}], defs) of + [env, funs, globs] -> [env, reverse(funs), reverse(globs)] + esac + } + fun compileSMImpl(env, stmt) { + case stmt of + Var (x) -> [LD (lookupVar(env, x)), env] + | Ref (x) -> [LDA (lookupVar(env, x)), env] + | Ignore (e) -> case compileSMImpl(env, e) of + [is, env] -> [{is, DROP}, env] + esac + | Const (n) -> [CONST (n), env] + | Binop(op, lhs, rhs) -> case compileSMListImpl(env, {lhs, rhs}) of + [lis:ris:_, env] -> [{ris, lis, BINOP(op)}, env] + esac + | Assn (x, e) -> case compileSMListImpl(env, {x, e}) of + [xis:eis:_, env] -> [{xis, eis, case x of ElemRef(_, _) -> STA | _ -> STI esac}, env] + esac + | Seq (s1, s2) -> case compileSMListImpl(env, {s1, s2}) of + [is1:is2:_, env] -> [{is1, is2}, env] + esac + | Skip -> [{}, env] + | If (cond, s1, s2) -> case genLabels(env, 2) of + [l1, l2, env] -> case compileSMListImpl(env, {cond, s1, s2}) of + [cis:is1:is2:_, env] -> [{cis, CJMP("z", l1), is1, JMP(l2), LABEL(l1), is2, LABEL(l2)}, env] + esac + esac + | While (cond, stmt) -> case genLabels(env, 2) of + [l1, l2, env] -> case compileSMListImpl(env, {cond, stmt}) of + [cis:body:_, env] -> [{JMP (l2), LABEL (l1), body, LABEL(l2), cis, CJMP ("nz", l1)}, env] + esac + esac + | Repeat (stmt, cond) -> case genLabel(env) of + [l, env] -> case compileSMListImpl(env, {stmt, cond}) of + [body:cis:_, env] -> [{LABEL(l), body, cis, CJMP ("z", l)}, env] + esac + esac + | Scope(defs, expr) -> case addDefs(beginScope(env), defs) of + [env, funs, globs] -> case compileSMImpl(foldl(fun(env, [fLabel, args, body]) { + rememberFun(env, fLabel, args, body) + }, env, funs), expr) of + [is, env] -> [{globs, is}, env.endScope] + esac + esac + | Call (f, exprs) -> case compileSMListImpl(env, exprs) of + [is, env] -> case f of + "read" -> [{is, CALL(f, 0)}, env] | + "write" -> [{is, CALL(f, 1)}, env] | + _ -> case lookupFun(env, f) of + Fun(fLabel, n) -> [{is, CALL(fLabel, n)}, env] + esac + esac + esac + | Fun(fLabel, args, body, fEnv) -> case compileSMImpl(addArgs(beginFun(env, fEnv), args), body) of + [is, env] -> [{LABEL(fLabel), BEGIN(fLabel, size(args), env.getLocals), is, END}, env] + esac + | String (str) -> [STRING(str), env] + | Array (exprs) -> case compileSMListImpl(env, exprs) of + [is, env] -> [{is, ARRAY(size(exprs))}, env] + esac + | Elem(arrExpr, indexExpr) -> case compileSMListImpl(env, {arrExpr, indexExpr}) of + [is, env] -> [{is, ELEM}, env] + esac + | ElemRef(arrExpr, indexExpr) -> compileSMListImpl(env, {arrExpr, indexExpr}) + | Builtin (f, exprs) -> case compileSMListImpl(env, exprs) of + [is, env] -> [{is, BUILTIN(f, size(exprs))}, env] + esac + | _ -> failure ("not yet implemented") + esac + } + + fun compileFuns(env) { + case getFuns(env) of + [funs, env] -> case foldl(fun ([is1, env1], f) { + case compileScope(env1, f) of + [is2, env2] -> [is2 : is1, env2] + esac + }, [{}, env], funs) of + [fis, env] -> [reverse (fis), env] + esac + esac + } + fun compileScope(env, scopeExpr) { + case compileSMImpl(env, scopeExpr) of + [is, env] -> case compileFuns(env) of + [fis, env] -> [is : fis, env] + esac + esac + } + case compileSMImpl(beginScope(initCompEnv()), expr) of + [main, env] -> case compileFuns(env) of + [fis, _] -> deepFlatten({LABEL("main"), BEGIN("main", 0, getLocals(env)), main, END, fis}) + esac + esac } (* End *) diff --git a/src/X86.lama b/src/X86.lama index 06e1349c..cd2fa194 100644 --- a/src/X86.lama +++ b/src/X86.lama @@ -502,6 +502,20 @@ fun call (env, fLabel, nA) { } (* End *) +fun opType (op) { + case op of + "&&" -> 0 + |"!!" -> 0 + |"<" -> 1 + | "<=" -> 1 + | "==" -> 1 + | "!=" -> 1 + | ">=" -> 1 + | ">" -> 1 + | _ -> 2 + esac +} + -- Compiles stack machine code into a list of x86 instructions. Takes an environment -- and stack machine code, returns an updated environment and x86 code. fun compile (env, code) { @@ -510,14 +524,6 @@ fun compile (env, code) { fun ([env, scode], i) { local code = scode <+ Meta ("# " ++ showSMInsn (i) ++ "\n"); case i of - READ -> - case env.allocate of - [s, env] -> [env, code <+ Call ("Lread") <+ Mov (eax, s)] - esac - | WRITE -> - case env.pop of - [s, env] -> [env, code <+ Push (s) <+ Call ("Lwrite") <+ Pop (eax)] - esac (* Assignment *) -- Some guidelines for generating function calls: @@ -535,7 +541,69 @@ fun compile (env, code) { -- 1. generate proper prologue for BEGIN instruction (use "prologue" helper); use -- env.enterFunction to create a proper environment; -- 2. generate epilogue for END instruction. - + CONST(n) -> case allocate(env) of + [s, env] -> [env, code <+ Mov (L(box(n)), s)] + esac + | LD(x) -> case allocate(env) of + [s, env] -> [env, code <+> move (env.loc(x), s)] + esac + | LDA (x) -> case allocate(env) of + [s, env] -> [env, code <+ Lea(env.loc(x), eax) <+ Mov(eax, s)] + esac + | ST(x) -> case pop(env) of + [s, env] -> [env, code <+> move (s, env.loc(x))] + esac + | STI -> case pop2(env) of + [s, addr, env] -> case allocate(env) of [s2, env] -> + [env, code <+> move (s, I(0, addr)) <+> move(s, s2)] + esac + esac + | DROP -> [pop(env)[1], code] + | BINOP(op) -> case pop2(env) of + [x, y, env] -> case allocate(env) of + [s, env] -> case [op, opType (op)] of + [_, 0] -> [env, code<+ Mov (L (0), eax) + <+ Mov (L (0), edx) + <+ Binop ("cmp", L (box(0)), x) + <+ Set ("ne", "%al") + <+ Binop ("cmp", L (box(0)), y) + <+ Set ("ne", "%dl") + <+ Binop (op, eax, edx) + <+ Mov (edx, s) <+> toFixedNum(s)] + | [_, 1] -> [env, code <+ Mov (L (box(0)), eax) + <+ Mov(y, edx) + <+ Binop("cmp", edx, x) + <+ Set(suffix(op), "%al") + <+ Mov(eax, s) <+> toFixedNum(s)] + | ["/", 2] -> [env, code <+ Sar1(x) <+ Sar1(y) <+ Mov(x, eax) <+ Cltd <+ IDiv(y) <+ Mov(eax, s) <+> toFixedNum(s)] + | ["%", 2] -> [env, code <+ Sar1(x) <+ Sar1(y) <+ Mov(x, eax) <+ Cltd <+ IDiv(y) <+ Mov(edx, s) <+> toFixedNum(s)] + | [_, 2] -> [env, code <+ Sar1(x) <+ Sar1(y) <+ Mov(x, eax) <+ Binop(op, y, eax) <+ Mov(eax, s) <+> toFixedNum(s)] + esac + esac + esac + | LABEL(l) -> [if isBarrier(env) then retrieveStack(env, l) else env fi, code <+ Label(l)] + | JMP(l) -> [setBarrier(setStack(env, l)), code <+ Jmp(l)] + | CJMP(t, l) -> case pop(env) of [s, env] -> [env.setStack(l), code <+ Mov(L(box(0)), eax) <+ Binop("cmp", eax, s) <+ CJmp(t, l)] esac + | GLOBAL(x) -> [addGlobal(env, x), code] + | CALL(fLabel, nArgs) -> local fname = case fLabel of + "read" -> "Lread" | + "write" -> "Lwrite" | + _ -> fLabel + esac; + case call(env, fname, nArgs) of [env, fcode] -> [env, code <+> fcode] esac + | BEGIN (fLabel, nArgs, nLocals) -> [enterFunction(env, fLabel, nLocals), code <+> prologue(fLabel)] + | END -> case epilogue(env) of [env, ecode] -> [env, code <+> ecode] esac + | STRING(str) -> case addString(env, str) of + [env, name] -> case allocate(env) of + [s, env] -> case call(env, "Bstring", 1) of + [env, code1] -> [env, code <+> move(M("$" ++ name), s) <+> code1] + esac + esac + esac + | ARRAY (n) -> case call(env, "Barray", n) of [env, code1] -> [env, code <+> code1] esac + | ELEM -> case call(env, "Belem", 2) of [env, code1] -> [env, code <+> code1] esac + | STA -> case call(env, "Bsta", 2) of [env, code1] -> [env, code <+> code1] esac + | BUILTIN (f, a) -> case call(env, "B" ++ f, a) of [env, code1] -> [env, code <+> code1] esac | _ -> failure ("codegeneration for instruction %s is not yet implemented\n", i.string) (* End *) esac