156 lines
3.9 KiB
Scala
156 lines
3.9 KiB
Scala
package xyz.hyperreal.rosettacodeCompiler
|
|
|
|
import scala.collection.mutable.{ArrayBuffer, HashMap}
|
|
import scala.io.Source
|
|
|
|
object CodeGenerator {
|
|
|
|
def fromStdin = fromSource(Source.stdin)
|
|
|
|
def fromString(src: String) = fromSource(Source.fromString(src))
|
|
|
|
def fromSource(ast: Source) = {
|
|
val vars = new HashMap[String, Int]
|
|
val strings = new ArrayBuffer[String]
|
|
val code = new ArrayBuffer[String]
|
|
var s: Stream[String] = ast.getLines.toStream
|
|
|
|
def line =
|
|
if (s.nonEmpty) {
|
|
val n = s.head
|
|
|
|
s = s.tail
|
|
|
|
n.split(" +", 2) match {
|
|
case Array(n) => n
|
|
case a => a
|
|
}
|
|
} else
|
|
sys.error("unexpected end of AST")
|
|
|
|
def variableIndex(name: String) =
|
|
vars get name match {
|
|
case None =>
|
|
val idx = vars.size
|
|
|
|
vars(name) = idx
|
|
idx
|
|
case Some(idx) => idx
|
|
}
|
|
|
|
def stringIndex(s: String) =
|
|
strings indexOf s match {
|
|
case -1 =>
|
|
val idx = strings.length
|
|
|
|
strings += s
|
|
idx
|
|
case idx => idx
|
|
}
|
|
|
|
var loc = 0
|
|
|
|
def addSimple(inst: String) = {
|
|
code += f"$loc%4d $inst"
|
|
loc += 1
|
|
}
|
|
|
|
def addOperand(inst: String, operand: String) = {
|
|
code += f"$loc%4d $inst%-5s $operand"
|
|
loc += 5
|
|
}
|
|
|
|
def fixup(inst: String, idx: Int, at: Int) = code(idx) = f"$at%4d $inst%-5s (${loc - at - 1}) $loc"
|
|
|
|
generate
|
|
addSimple("halt")
|
|
println(s"Datasize: ${vars.size} Strings: ${strings.length}")
|
|
|
|
for (s <- strings)
|
|
println(s)
|
|
|
|
println(code mkString "\n")
|
|
|
|
def generate: Unit =
|
|
line match {
|
|
case "Sequence" =>
|
|
generate
|
|
generate
|
|
case ";" =>
|
|
case "Assign" =>
|
|
val idx =
|
|
line match {
|
|
case Array("Identifier", name: String) =>
|
|
variableIndex(name)
|
|
case l => sys.error(s"expected identifier: $l")
|
|
}
|
|
|
|
generate
|
|
addOperand("store", s"[$idx]")
|
|
case Array("Identifier", name: String) => addOperand("fetch", s"[${variableIndex(name)}]")
|
|
case Array("Integer", n: String) => addOperand("push", s"$n")
|
|
case Array("String", s: String) => addOperand("push", s"${stringIndex(s)}")
|
|
case "If" =>
|
|
generate
|
|
|
|
val cond = loc
|
|
val condidx = code.length
|
|
|
|
addOperand("", "")
|
|
s = s.tail
|
|
generate
|
|
|
|
if (s.head == ";") {
|
|
s = s.tail
|
|
fixup("jz", condidx, cond)
|
|
} else {
|
|
val jump = loc
|
|
val jumpidx = code.length
|
|
|
|
addOperand("", "")
|
|
fixup("jz", condidx, cond)
|
|
generate
|
|
fixup("jmp", jumpidx, jump)
|
|
}
|
|
case "While" =>
|
|
val start = loc
|
|
|
|
generate
|
|
|
|
val cond = loc
|
|
val condidx = code.length
|
|
|
|
addOperand("", "")
|
|
generate
|
|
addOperand("jmp", s"(${start - loc - 1}) $start")
|
|
fixup("jz", condidx, cond)
|
|
case op =>
|
|
generate
|
|
generate
|
|
addSimple(
|
|
op match {
|
|
case "Prti" => "prti"
|
|
case "Prts" => "prts"
|
|
case "Prtc" => "prtc"
|
|
case "Add" => "add"
|
|
case "Subtract" => "sub"
|
|
case "Multiply" => "mul"
|
|
case "Divide" => "div"
|
|
case "Mod" => "mod"
|
|
case "Less" => "lt"
|
|
case "LessEqual" => "le"
|
|
case "Greater" => "gt"
|
|
case "GreaterEqual" => "ge"
|
|
case "Equal" => "eq"
|
|
case "NotEqual" => "ne"
|
|
case "And" => "and"
|
|
case "Or" => "or"
|
|
case "Negate" => "neg"
|
|
case "Not" => "not"
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
}
|