RosettaCodeData/Task/Compiler-virtual-machine-in.../AWK/compiler-virtual-machine-in...

155 lines
4.3 KiB
Awk

function error(msg) {
printf("%s\n", msg)
exit(1)
}
function bytes_to_int(bstr, i, sum) {
sum = 0
for (i=word_size-1; i>=0; i--) {
sum *= 256
sum += code[bstr+i]
}
return sum
}
function emit_byte(x) {
code[next_free_code_index++] = x
}
function emit_word(x, i) {
for (i=0; i<word_size; i++) {
emit_byte(int(x)%256);
x = int(x/256)
}
}
function run_vm(data_size) {
sp = data_size + 1
pc = 0
while (1) {
op = code[pc++]
if (op == FETCH) {
stack[sp++] = stack[bytes_to_int(pc)]
pc += word_size
} else if (op == STORE) {
stack[bytes_to_int(pc)] = stack[--sp]
pc += word_size
} else if (op == PUSH) {
stack[sp++] = bytes_to_int(pc)
pc += word_size
} else if (op == ADD ) { stack[sp-2] += stack[sp-1]; sp--
} else if (op == SUB ) { stack[sp-2] -= stack[sp-1]; sp--
} else if (op == MUL ) { stack[sp-2] *= stack[sp-1]; sp--
} else if (op == DIV ) { stack[sp-2] = int(stack[sp-2] / stack[sp-1]); sp--
} else if (op == MOD ) { stack[sp-2] %= stack[sp-1]; sp--
} else if (op == LT ) { stack[sp-2] = stack[sp-2] < stack[sp-1]; sp--
} else if (op == GT ) { stack[sp-2] = stack[sp-2] > stack[sp-1]; sp--
} else if (op == LE ) { stack[sp-2] = stack[sp-2] <= stack[sp-1]; sp--
} else if (op == GE ) { stack[sp-2] = stack[sp-2] >= stack[sp-1]; sp--
} else if (op == EQ ) { stack[sp-2] = stack[sp-2] == stack[sp-1]; sp--
} else if (op == NE ) { stack[sp-2] = stack[sp-2] != stack[sp-1]; sp--
} else if (op == AND ) { stack[sp-2] = stack[sp-2] && stack[sp-1]; sp--
} else if (op == OR ) { stack[sp-2] = stack[sp-2] || stack[sp-1]; sp--
} else if (op == NEG ) { stack[sp-1] = - stack[sp-1]
} else if (op == NOT ) { stack[sp-1] = ! stack[sp-1]
} else if (op == JMP ) { pc += bytes_to_int(pc)
} else if (op == JZ ) { if (stack[--sp]) { pc += word_size } else { pc += bytes_to_int(pc) }
} else if (op == PRTC) { printf("%c", stack[--sp])
} else if (op == PRTS) { printf("%s", string_pool[stack[--sp]])
} else if (op == PRTI) { printf("%d", stack[--sp])
} else if (op == HALT) { break
}
} # while
}
function str_trans(srce, dest, i) {
dest = ""
for (i=1; i <= length(srce); ) {
if (substr(srce, i, 1) == "\\" && i < length(srce)) {
if (substr(srce, i+1, 1) == "n") {
dest = dest "\n"
i += 2
} else if (substr(srce, i+1, 1) == "\\") {
dest = dest "\\"
i += 2
}
} else {
dest = dest substr(srce, i, 1)
i += 1
}
}
return dest
}
function load_code( n, i) {
getline line
if (line == "")
error("empty line")
n=split(line, line_list)
data_size = line_list[2]
n_strings = line_list[4]
for (i=0; i<n_strings; i++) {
getline line
gsub(/\n/, "", line)
gsub(/"/ , "", line)
string_pool[i] = str_trans(line)
}
while (getline) {
offset = int($1)
instr = $2
opcode = code_map[instr]
if (opcode == "")
error("Unknown instruction " instr " at " offset)
emit_byte(opcode)
if (opcode == JMP || opcode == JZ) {
p = int($4)
emit_word(p - (offset + 1))
} else if (opcode == PUSH) {
value = int($3)
emit_word(value)
} else if (opcode == FETCH || opcode == STORE) {
gsub(/\[/, "", $3)
gsub(/\]/, "", $3)
value = int($3)
emit_word(value)
}
}
return data_size
}
BEGIN {
code_map["fetch"] = FETCH = 1
code_map["store"] = STORE = 2
code_map["push" ] = PUSH = 3
code_map["add" ] = ADD = 4
code_map["sub" ] = SUB = 5
code_map["mul" ] = MUL = 6
code_map["div" ] = DIV = 7
code_map["mod" ] = MOD = 8
code_map["lt" ] = LT = 9
code_map["gt" ] = GT = 10
code_map["le" ] = LE = 11
code_map["ge" ] = GE = 12
code_map["eq" ] = EQ = 13
code_map["ne" ] = NE = 14
code_map["and" ] = AND = 15
code_map["or" ] = OR = 16
code_map["neg" ] = NEG = 17
code_map["not" ] = NOT = 18
code_map["jmp" ] = JMP = 19
code_map["jz" ] = JZ = 20
code_map["prtc" ] = PRTC = 21
code_map["prts" ] = PRTS = 22
code_map["prti" ] = PRTI = 23
code_map["halt" ] = HALT = 24
next_free_node_index = 1
next_free_code_index = 0
word_size = 4
input_file = "-"
if (ARGC > 1)
input_file = ARGV[1]
data_size = load_code()
run_vm(data_size)
}