Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
|
|
@ -0,0 +1,216 @@
|
|||
package xyz.hyperreal.rosettacodeCompiler
|
||||
|
||||
import java.io.{BufferedReader, FileReader, Reader, StringReader}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
object VirtualMachine {
|
||||
|
||||
private object Opcodes {
|
||||
val FETCH: Byte = 0
|
||||
val STORE: Byte = 1
|
||||
val PUSH: Byte = 2
|
||||
val JMP: Byte = 3
|
||||
val JZ: Byte = 4
|
||||
val ADD: Byte = 5
|
||||
val SUB: Byte = 6
|
||||
val MUL: Byte = 7
|
||||
val DIV: Byte = 8
|
||||
val MOD: Byte = 9
|
||||
val LT: Byte = 10
|
||||
val GT: Byte = 11
|
||||
val LE: Byte = 12
|
||||
val GE: Byte = 13
|
||||
val EQ: Byte = 14
|
||||
val NE: Byte = 15
|
||||
val AND: Byte = 16
|
||||
val OR: Byte = 17
|
||||
val NEG: Byte = 18
|
||||
val NOT: Byte = 19
|
||||
val PRTC: Byte = 20
|
||||
val PRTI: Byte = 21
|
||||
val PRTS: Byte = 22
|
||||
val HALT: Byte = 23
|
||||
}
|
||||
|
||||
import Opcodes._
|
||||
|
||||
private val HEADER_REGEX = "Datasize: ([0-9]+) Strings: ([0-9]+)" r
|
||||
private val STRING_REGEX = "\"([^\"]*)\"" r
|
||||
private val PUSH_REGEX = " *[0-9]+ push +([0-9]+|'(?:[^'\\n]|\\\\n|\\\\\\\\)')" r
|
||||
private val PRTS_REGEX = " *[0-9]+ prts" r
|
||||
private val PRTI_REGEX = " *[0-9]+ prti" r
|
||||
private val PRTC_REGEX = " *[0-9]+ prtc" r
|
||||
private val HALT_REGEX = " *[0-9]+ halt" r
|
||||
private val STORE_REGEX = " *[0-9]+ store +\\[([0-9]+)\\]" r
|
||||
private val FETCH_REGEX = " *[0-9]+ fetch +\\[([0-9]+)\\]" r
|
||||
private val LT_REGEX = " *[0-9]+ lt" r
|
||||
private val GT_REGEX = " *[0-9]+ gt" r
|
||||
private val LE_REGEX = " *[0-9]+ le" r
|
||||
private val GE_REGEX = " *[0-9]+ ge" r
|
||||
private val NE_REGEX = " *[0-9]+ ne" r
|
||||
private val EQ_REGEX = " *[0-9]+ eq" r
|
||||
private val JZ_REGEX = " *[0-9]+ jz +\\((-?[0-9]+)\\) [0-9]+" r
|
||||
private val ADD_REGEX = " *[0-9]+ add" r
|
||||
private val SUB_REGEX = " *[0-9]+ sub" r
|
||||
private val MUL_REGEX = " *[0-9]+ mul" r
|
||||
private val DIV_REGEX = " *[0-9]+ div" r
|
||||
private val MOD_REGEX = " *[0-9]+ mod" r
|
||||
private val AND_REGEX = " *[0-9]+ and" r
|
||||
private val OR_REGEX = " *[0-9]+ or" r
|
||||
private val NOT_REGEX = " *[0-9]+ not" r
|
||||
private val NEG_REGEX = " *[0-9]+ neg" r
|
||||
private val JMP_REGEX = " *[0-9]+ jmp +\\((-?[0-9]+)\\) [0-9]+" r
|
||||
|
||||
def fromStdin = fromReader(Console.in)
|
||||
|
||||
def fromFile(file: String) = fromReader(new FileReader(file))
|
||||
|
||||
def fromString(src: String) = fromReader(new StringReader(src))
|
||||
|
||||
def fromReader(r: Reader) = {
|
||||
val in = new BufferedReader(r)
|
||||
val vm =
|
||||
in.readLine match {
|
||||
case HEADER_REGEX(datasize, stringsize) =>
|
||||
val strings =
|
||||
for (_ <- 1 to stringsize.toInt)
|
||||
yield
|
||||
in.readLine match {
|
||||
case STRING_REGEX(s) => unescape(s)
|
||||
case null => sys.error("expected string constant but encountered end of input")
|
||||
case s => sys.error(s"expected string constant: $s")
|
||||
}
|
||||
var line: String = null
|
||||
val code = new ArrayBuffer[Byte]
|
||||
|
||||
def addShort(a: Int) = {
|
||||
code += (a >> 8).toByte
|
||||
code += a.toByte
|
||||
}
|
||||
|
||||
def addInstIntOperand(opcode: Byte, operand: Int) = {
|
||||
code += opcode
|
||||
addShort(operand >> 16)
|
||||
addShort(operand)
|
||||
}
|
||||
|
||||
def addInst(opcode: Byte, operand: String) = addInstIntOperand(opcode, operand.toInt)
|
||||
|
||||
while ({ line = in.readLine; line ne null }) line match {
|
||||
case PUSH_REGEX(n) if n startsWith "'" =>
|
||||
addInstIntOperand(PUSH, unescape(n.substring(1, n.length - 1)).head)
|
||||
case PUSH_REGEX(n) => addInst(PUSH, n)
|
||||
case PRTS_REGEX() => code += PRTS
|
||||
case PRTI_REGEX() => code += PRTI
|
||||
case PRTC_REGEX() => code += PRTC
|
||||
case HALT_REGEX() => code += HALT
|
||||
case STORE_REGEX(idx) => addInst(STORE, idx)
|
||||
case FETCH_REGEX(idx) => addInst(FETCH, idx)
|
||||
case LT_REGEX() => code += LT
|
||||
case GT_REGEX() => code += GT
|
||||
case LE_REGEX() => code += LE
|
||||
case GE_REGEX() => code += GE
|
||||
case NE_REGEX() => code += NE
|
||||
case EQ_REGEX() => code += EQ
|
||||
case JZ_REGEX(disp) => addInst(JZ, disp)
|
||||
case ADD_REGEX() => code += ADD
|
||||
case SUB_REGEX() => code += SUB
|
||||
case MUL_REGEX() => code += MUL
|
||||
case DIV_REGEX() => code += DIV
|
||||
case MOD_REGEX() => code += MOD
|
||||
case AND_REGEX() => code += AND
|
||||
case OR_REGEX() => code += OR
|
||||
case NOT_REGEX() => code += NOT
|
||||
case NEG_REGEX() => code += NEG
|
||||
case JMP_REGEX(disp) => addInst(JMP, disp)
|
||||
}
|
||||
|
||||
new VirtualMachine(code, datasize.toInt, strings)
|
||||
case _ => sys.error("expected header")
|
||||
}
|
||||
|
||||
in.close
|
||||
vm
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class VirtualMachine(code: IndexedSeq[Byte], datasize: Int, strings: IndexedSeq[String]) {
|
||||
|
||||
import VirtualMachine.Opcodes._
|
||||
|
||||
var pc = 0
|
||||
val stack = new mutable.ArrayStack[Int]
|
||||
val data = new Array[Int](datasize)
|
||||
var running = false
|
||||
|
||||
def getByte = {
|
||||
val byte = code(pc) & 0xFF
|
||||
|
||||
pc += 1
|
||||
byte
|
||||
}
|
||||
|
||||
def getShort = getByte << 8 | getByte
|
||||
|
||||
def getInt = getShort << 16 | getShort
|
||||
|
||||
def pushBoolean(b: Boolean) = stack push (if (b) 1 else 0)
|
||||
|
||||
def popBoolean = if (stack.pop != 0) true else false
|
||||
|
||||
def operator(f: (Int, Int) => Int) = {
|
||||
val y = stack.pop
|
||||
|
||||
stack.push(f(stack.pop, y))
|
||||
}
|
||||
|
||||
def relation(r: (Int, Int) => Boolean) = {
|
||||
val y = stack.pop
|
||||
|
||||
pushBoolean(r(stack.pop, y))
|
||||
}
|
||||
|
||||
def connective(c: (Boolean, Boolean) => Boolean) = pushBoolean(c(popBoolean, popBoolean))
|
||||
|
||||
def execute: Unit =
|
||||
getByte match {
|
||||
case FETCH => stack push data(getInt)
|
||||
case STORE => data(getInt) = stack.pop
|
||||
case PUSH => stack push getInt
|
||||
case JMP => pc = pc + getInt
|
||||
case JZ => if (stack.pop == 0) pc = pc + getInt else pc += 4
|
||||
case ADD => operator(_ + _)
|
||||
case SUB => operator(_ - _)
|
||||
case MUL => operator(_ * _)
|
||||
case DIV => operator(_ / _)
|
||||
case MOD => operator(_ % _)
|
||||
case LT => relation(_ < _)
|
||||
case GT => relation(_ > _)
|
||||
case LE => relation(_ <= _)
|
||||
case GE => relation(_ >= _)
|
||||
case EQ => relation(_ == _)
|
||||
case NE => relation(_ != _)
|
||||
case AND => connective(_ && _)
|
||||
case OR => connective(_ || _)
|
||||
case NEG => stack push -stack.pop
|
||||
case NOT => pushBoolean(!popBoolean)
|
||||
case PRTC => print(stack.pop.toChar)
|
||||
case PRTI => print(stack.pop)
|
||||
case PRTS => print(strings(stack.pop))
|
||||
case HALT => running = false
|
||||
}
|
||||
|
||||
def run = {
|
||||
pc = 0
|
||||
stack.clear
|
||||
running = true
|
||||
|
||||
for (i <- data.indices) data(i) = 0
|
||||
|
||||
while (running) execute
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package xyz.hyperreal
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
package object rosettacodeCompiler {
|
||||
|
||||
val escapes = "\\\\b|\\\\f|\\\\t|\\\\r|\\\\n|\\\\\\\\|\\\\\"" r
|
||||
|
||||
def unescape(s: String) =
|
||||
escapes.replaceAllIn(s, _.matched match {
|
||||
case "\\b" => "\b"
|
||||
case "\\f" => "\f"
|
||||
case "\\t" => "\t"
|
||||
case "\\r" => "\r"
|
||||
case "\\n" => "\n"
|
||||
case "\\\\" => "\\"
|
||||
case "\\\"" => "\""
|
||||
})
|
||||
|
||||
def capture(thunk: => Unit) = {
|
||||
val buf = new ByteArrayOutputStream
|
||||
|
||||
Console.withOut(buf)(thunk)
|
||||
buf.toString
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue