diff -r 2f9a0dcf61ae -r 059f970287d1 progs/fun/fun.sc --- a/progs/fun/fun.sc Fri Nov 27 13:53:06 2020 +0000 +++ b/progs/fun/fun.sc Tue Dec 01 05:41:12 2020 +0000 @@ -1,17 +1,25 @@ // A Small Compiler for a Simple Functional Language -// (it does not include a parser and lexer) +// (includes a parser and lexer) // // call with // +// amm fun.sc test +// +// or +// // amm fun.sc main defs.fun -// // amm fun.sc main fact.fun // -// or -// amm fun.sc test +// or +// +// amm fun.sc run defs.fun +// amm fun.sc run fact.fun // -// the latter will print out the JVM instructions for two +// the first prints out the JVM instructions for two // factorial functions +// +// the next compile/run fun files +// import $file.fun_tokens, fun_tokens._ import $file.fun_parser, fun_parser._ @@ -76,15 +84,21 @@ // variable / index environments type Env = Map[String, Int] +def compile_op(op: String) = op match { + case "+" => i"iadd" + case "-" => i"isub" + case "*" => i"imul" + case "/" => i"idiv" + case "%" => i"irem" +} + + // compile expressions -def compile_exp(a: Exp, env : Env) : String = a match { +def compile_exp(a: Exp, env: Env) : String = a match { case Num(i) => i"ldc $i" case Var(s) => i"iload ${env(s)}" - case Aop("+", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"iadd" - case Aop("-", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"isub" - case Aop("*", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"imul" - case Aop("/", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"idiv" - case Aop("%", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"irem" + case Aop(op, a1, a2) => + compile_exp(a1, env) ++ compile_exp(a2, env) ++ compile_op(op) case If(b, a1, a2) => { val if_else = Fresh("If_else") val if_end = Fresh("If_end") @@ -137,8 +151,8 @@ } case Main(a) => { m".method public static main([Ljava/lang/String;)V" ++ - m".limit locals 200" ++ - m".limit stack 200" ++ + m".limit locals 1" ++ + m".limit stack ${1 + max_stack_exp(a)}" ++ compile_exp(a, Map()) ++ i"invokestatic XXX/XXX/write(I)V" ++ i"return" ++ @@ -153,6 +167,21 @@ } +import ammonite.ops._ + +def compile_to_file(prog: List[Decl], class_name: String) : Unit = + write.over(pwd / s"$class_name.j", compile(prog, class_name)) + +def compile_and_run(prog: List[Decl], class_name: String) : Unit = { + println(s"Start of compilation") + compile_to_file(prog, class_name) + println(s"generated $class_name.j file") + os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call() + println(s"generated $class_name.class file") + println(s"Run program") + os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit) + println(s"done.") +} // An example program (two versions of factorial) @@ -181,9 +210,9 @@ Aop("*",Var("n"),Var("acc")))))), Main(Sequence(Write(Call("fact",List(Num(10)))), - Write(Call("facT",List(Num(10), Num(1))))))) + Write(Call("facT",List(Num(10), Num(1))))))) -// prints out the JVM instructions +// prints out the JVM instructions for the factorial example @main def test() = println(compile(test_prog, "fact")) @@ -197,3 +226,12 @@ val ast = parse_tks(tks) println(compile(ast, class_name)) } + +@main +def run(fname: String) = { + val path = os.pwd / fname + val class_name = fname.stripSuffix("." ++ path.ext) + val tks = tokenise(os.read(path)) + val ast = parse_tks(tks) + compile_and_run(ast, class_name) +}