Compare commits
2 Commits
2634ddd1ca
...
04b9821662
| Author | SHA1 | Date | |
|---|---|---|---|
| 04b9821662 | |||
| b2a829d6e5 |
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -3,5 +3,7 @@
|
||||
<component name="CMakePythonSetting">
|
||||
<option name="pythonIntegrationState" value="YES" />
|
||||
</component>
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CMakeWorkspace">
|
||||
<contentRoot DIR="$PROJECT_DIR$" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/tyche.iml
generated
2
.idea/tyche.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CIDR" type="CPP_MODULE" version="4" />
|
||||
@@ -151,7 +151,7 @@ end
|
||||
----------------------
|
||||
|
||||
local function arith(a, b, op)
|
||||
return VM:new():load(assemble(string.format([[
|
||||
return VM.new():load(assemble(string.format([[
|
||||
.func 0
|
||||
pushi %d
|
||||
pushi %d
|
||||
@@ -162,7 +162,7 @@ end
|
||||
|
||||
|
||||
do TEST "VM: basic"
|
||||
local vm = VM:new()
|
||||
local vm = VM.new()
|
||||
-- vm.debug = true
|
||||
local bytecode = assemble [[
|
||||
.func 0
|
||||
@@ -206,7 +206,7 @@ do TEST "VM: logic/arithmetic"
|
||||
end
|
||||
|
||||
do TEST "VM: local variables"
|
||||
local vm = VM:new():load(assemble([[
|
||||
local vm = VM.new():load(assemble([[
|
||||
.func 0
|
||||
pushv 2 ; local a, b
|
||||
pushi 3 ; a = 3
|
||||
@@ -222,7 +222,7 @@ do TEST "VM: local variables"
|
||||
end
|
||||
|
||||
do TEST "VM: functions"
|
||||
local vm = VM:new():load(assemble([[
|
||||
local vm = VM.new():load(assemble([[
|
||||
.func 0
|
||||
pushf 1
|
||||
pushi 2
|
||||
@@ -240,4 +240,63 @@ do TEST "VM: functions"
|
||||
assert_eq(vm:to_integer(-1), -1)
|
||||
end
|
||||
|
||||
do
|
||||
TEST "VM: jumps (jmp + bnz)"
|
||||
local vm = VM.new():load(assemble [[
|
||||
.func 0
|
||||
jmp @x1
|
||||
pushi 5
|
||||
@x1:
|
||||
pushi 1
|
||||
bnz @x2
|
||||
bz @x3
|
||||
@x2:
|
||||
pushi 6
|
||||
ret
|
||||
@x3:
|
||||
pushi 7
|
||||
ret
|
||||
]]):call(0)
|
||||
|
||||
assert_eq(vm:to_integer(-1), 6)
|
||||
end
|
||||
|
||||
do
|
||||
TEST "VM: jumps (bz)"
|
||||
pprint(assemble [[
|
||||
.func 0
|
||||
jmp @x1
|
||||
pushi 5
|
||||
@x1:
|
||||
pushi 0
|
||||
bnz @x2
|
||||
pushi 0
|
||||
bz @x3
|
||||
@x2:
|
||||
pushi 6
|
||||
ret
|
||||
@x3:
|
||||
pushi 7
|
||||
ret
|
||||
]])
|
||||
local vm = VM.new():set_debug(true):load(assemble [[
|
||||
.func 0
|
||||
jmp @x1
|
||||
pushi 5
|
||||
@x1:
|
||||
pushi 0
|
||||
bnz @x2
|
||||
bz @x3
|
||||
@x2:
|
||||
pushi 6
|
||||
ret
|
||||
@x3:
|
||||
pushi 7
|
||||
ret
|
||||
]]):call(0)
|
||||
|
||||
assert_eq(vm:to_integer(-1), 7)
|
||||
end
|
||||
|
||||
|
||||
print('End.')
|
||||
@@ -38,9 +38,9 @@ local function assemble(source)
|
||||
elseif section == 'function' then
|
||||
local regexes = {
|
||||
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
|
||||
"^%s*(%a+)%s+(@[%a_]+)%s*$", -- instruction + label
|
||||
"^%s*(%a+)%s+(@[%a_][%a%d_]*)%s*$", -- instruction + label
|
||||
"^%s*(%a+)%s*$", -- instruction only
|
||||
"^(@[%a_]+):%s*$", -- label
|
||||
"^(@[%a_][%a%d_]*):%s*$", -- label
|
||||
}
|
||||
local match = false
|
||||
for i,regex in ipairs(regexes) do
|
||||
|
||||
@@ -14,7 +14,7 @@ local ARITH_LOGIC_OPS = {
|
||||
-- --
|
||||
----------------------
|
||||
|
||||
function format_value(v)
|
||||
local function format_value(v)
|
||||
if v.type == 'integer' or v.type == 'real' then
|
||||
return tostring(v.value)
|
||||
elseif v.type == 'string' then
|
||||
@@ -28,9 +28,10 @@ function format_value(v)
|
||||
end
|
||||
end
|
||||
|
||||
function validate_value(v)
|
||||
local function validate_value(v)
|
||||
assert(v, "value cannot be nil")
|
||||
assert(type(v) == 'table', "invalid value format (expected { type='...', value=... }), received: " .. pprint.pformat(value))
|
||||
assert(type(v) == 'table',
|
||||
"invalid value format (expected { type='...', value=... }), received: " .. pprint.pformat(v))
|
||||
assert(TYPE_MAP[v.type], "missing field 'type' in value")
|
||||
if v.type == 'nil' then
|
||||
assert(v.value == nil)
|
||||
@@ -41,6 +42,12 @@ function validate_value(v)
|
||||
end
|
||||
end
|
||||
|
||||
function is_zero(v)
|
||||
if v.type == 'nil' then return true end
|
||||
if v.type == 'integer' and v.value == 0 then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------
|
||||
-- --
|
||||
-- STACK --
|
||||
@@ -168,6 +175,18 @@ function Code:next_instruction(function_id, pc)
|
||||
}
|
||||
end
|
||||
|
||||
function Code:find_label(function_id, label)
|
||||
for pc, op in ipairs(self.bytecode.functions[function_id]) do
|
||||
if op.labels then
|
||||
for _,lbl in ipairs(op.labels) do
|
||||
if lbl == label then
|
||||
return pc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------
|
||||
-- --
|
||||
-- EXPR --
|
||||
@@ -182,7 +201,7 @@ for op,_ in pairs(ARITH_LOGIC_OPS) do
|
||||
for _,type1 in ipairs(TYPES) do
|
||||
EXPR[op][type1] = {}
|
||||
for _,type2 in ipairs(TYPES) do
|
||||
EXPR[op][type1][type2] = function(vm, a, b) error(string.format("Type mismatch for operation '%s': types '%s' and '%s'", op, type1, type2)) end
|
||||
EXPR[op][type1][type2] = function(_, _, _) error(string.format("Type mismatch for operation '%s': types '%s' and '%s'", op, type1, type2)) end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -310,6 +329,12 @@ function VM:_run_until_return()
|
||||
end
|
||||
end
|
||||
|
||||
function VM:_debug_stack()
|
||||
if self.debug then
|
||||
print(self.stack:debug())
|
||||
end
|
||||
end
|
||||
|
||||
function VM:_step()
|
||||
local loc = self.loc[#self.loc]
|
||||
local op = self.code:next_instruction(loc.f_id, loc.pc)
|
||||
@@ -327,13 +352,16 @@ function VM:_step()
|
||||
assert(op.operand >= 0)
|
||||
self.stack:push({ type = 'function', value = op.operand })
|
||||
|
||||
elseif op.operator == 'dup' then
|
||||
self.stack:push(self.stack:peek())
|
||||
|
||||
--
|
||||
-- local variables
|
||||
--
|
||||
|
||||
elseif op.operator == 'pushv' then
|
||||
assert(op.operand >= 0)
|
||||
for i=1,op.operand do
|
||||
for _=1,op.operand do
|
||||
self:push_nil()
|
||||
end
|
||||
|
||||
@@ -369,14 +397,43 @@ function VM:_step()
|
||||
self.stack:pop_fp()
|
||||
self.stack:push(v)
|
||||
table.remove(self.loc)
|
||||
if self.debug then print(self.stack:debug()) end
|
||||
self:_debug_stack()
|
||||
return
|
||||
else
|
||||
|
||||
--
|
||||
-- jumps/branching
|
||||
--
|
||||
|
||||
elseif op.operator == 'jmp' then
|
||||
loc.pc = self.code:find_label(loc.f_id, op.operand)
|
||||
self:_debug_stack()
|
||||
return
|
||||
|
||||
elseif op.operator == 'bz' then
|
||||
local v = self.stack:pop()
|
||||
if is_zero(v) then
|
||||
loc.pc = self.code:find_label(loc.f_id, op.operand)
|
||||
self:_debug_stack()
|
||||
return
|
||||
end
|
||||
|
||||
elseif op.operator == 'bnz' then
|
||||
local v = self.stack:pop()
|
||||
if not is_zero(v) then
|
||||
loc.pc = self.code:find_label(loc.f_id, op.operand)
|
||||
self:_debug_stack()
|
||||
return
|
||||
end
|
||||
|
||||
--
|
||||
-- instruction not found
|
||||
--
|
||||
|
||||
else
|
||||
error("Unknown operator '" .. tostring(op.operator) .. "'")
|
||||
end
|
||||
|
||||
if self.debug then print(self.stack:debug()) end
|
||||
self:_debug_stack()
|
||||
|
||||
loc.pc = loc.pc + op.instruction_size
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user