.
This commit is contained in:
@@ -82,10 +82,10 @@ External code:
|
|||||||
49 asmbl Assemble code to bytecode format
|
49 asmbl Assemble code to bytecode format
|
||||||
4a load Load bytecode as function (will place function on stack)
|
4a load Load bytecode as function (will place function on stack)
|
||||||
|
|
||||||
Control flow:
|
Control flow (the destination is always a 16-bit field):
|
||||||
a8 c8 e8 bz [pc] Branch if zero
|
c8 bz [pc] Branch if zero
|
||||||
a9 c9 e9 bnz [pc] Branch if not zero
|
c9 bnz [pc] Branch if not zero
|
||||||
aa ca ea jmp [pc] Unconditional jump
|
ca jmp [pc] Unconditional jump
|
||||||
* Jumps can only happen within the same function.
|
* Jumps can only happen within the same function.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,30 +71,30 @@ do TEST "Parser"
|
|||||||
assert_eq(found, expected)
|
assert_eq(found, expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
--do TEST "Parser: labels"
|
do TEST "Parser: labels"
|
||||||
--
|
|
||||||
-- local source = [[
|
local source = [[
|
||||||
-- .func 0
|
.func 0
|
||||||
-- jmp %my_label
|
jmp @my_label
|
||||||
-- pushi 3
|
pushi 3
|
||||||
-- %my_label:
|
@my_label:
|
||||||
-- ret ]]
|
ret ]]
|
||||||
--
|
|
||||||
-- local expected = {
|
local expected = {
|
||||||
-- constants = {},
|
constants = {},
|
||||||
-- functions = {
|
functions = {
|
||||||
-- [0] = {
|
[0] = {
|
||||||
-- { "jmp", "%my_label" },
|
{ "jmp", "@my_label" },
|
||||||
-- { "pushi", 3 },
|
{ "pushi", 3 },
|
||||||
-- { "ret", labels = { "%my_label" } },
|
{ "ret", labels = { "@my_label" } },
|
||||||
-- }
|
}
|
||||||
-- }
|
}
|
||||||
-- }
|
}
|
||||||
--
|
|
||||||
-- local found = assemble(source)
|
local found = assemble(source)
|
||||||
-- pprint(found)
|
pprint(found)
|
||||||
-- assert_eq(found, expected)
|
assert_eq(found, expected)
|
||||||
--end
|
end
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
-- --
|
-- --
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ local function assemble(source)
|
|||||||
local section = ''
|
local section = ''
|
||||||
local current_f_id = 0
|
local current_f_id = 0
|
||||||
|
|
||||||
|
local next_label = nil
|
||||||
for line in source:gmatch("([^\n]+)") do
|
for line in source:gmatch("([^\n]+)") do
|
||||||
local line = line:gsub("%s*;.*$", "") -- remove comments
|
local line = line:gsub("%s*;.*$", "") -- remove comments
|
||||||
line = line:match("^%s*(.-)%s*$") -- trim
|
line = line:match("^%s*(.-)%s*$") -- trim
|
||||||
@@ -28,21 +29,43 @@ local function assemble(source)
|
|||||||
current_f_id = f_id
|
current_f_id = f_id
|
||||||
elseif section == 'const' then
|
elseif section == 'const' then
|
||||||
local k, v = line:match("^%s*(%d+)%s*:%s*(.+)$")
|
local k, v = line:match("^%s*(%d+)%s*:%s*(.+)$")
|
||||||
if not k then error("Invalid row for constant") end
|
if not k then error("Invalid row for constant: " .. line) end
|
||||||
if v:sub(1, 1) == '"' then
|
if v:sub(1, 1) == '"' then
|
||||||
proto.constants[tonumber(k)] = line:match('"(.*)"')
|
proto.constants[tonumber(k)] = line:match('"(.*)"')
|
||||||
else
|
else
|
||||||
proto.constants[tonumber(k)] = tonumber(v)
|
proto.constants[tonumber(k)] = tonumber(v)
|
||||||
end
|
end
|
||||||
elseif section == 'function' then
|
elseif section == 'function' then
|
||||||
local inst, par = line:match("^%s*(%a+)%s+(%d+)%s*$")
|
local regexes = {
|
||||||
if inst then
|
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
|
||||||
table.insert(proto.functions[current_f_id], { inst, tonumber(par) })
|
"^%s*(%a+)%s+(@[%a_]+)%s*$", -- instruction + label
|
||||||
else
|
"^%s*(%a+)%s*$", -- instruction only
|
||||||
local inst = line:match("^%s*(%a+)%s*$")
|
"^(@[%a_]+):%s*$", -- label
|
||||||
if not inst then error("Invalid row for function") end
|
}
|
||||||
table.insert(proto.functions[current_f_id], { inst })
|
local match = false
|
||||||
|
for i,regex in ipairs(regexes) do
|
||||||
|
local inst, par = line:match(regex)
|
||||||
|
if inst then
|
||||||
|
match = true
|
||||||
|
if i == 1 then -- instruction + parameter
|
||||||
|
table.insert(proto.functions[current_f_id], { inst, tonumber(par), labels = next_label })
|
||||||
|
elseif i == 2 then -- instruction + label
|
||||||
|
table.insert(proto.functions[current_f_id], { inst, par, labels = next_label })
|
||||||
|
elseif i == 3 then -- instruction only
|
||||||
|
table.insert(proto.functions[current_f_id], { inst, labels = next_label })
|
||||||
|
elseif i == 4 then -- label
|
||||||
|
if not next_label then
|
||||||
|
next_label = { inst }
|
||||||
|
else
|
||||||
|
table.insert(next_label, inst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if i ~= 4 then
|
||||||
|
next_label = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
if not match then error("Invalid instruction: " .. line) end
|
||||||
end
|
end
|
||||||
|
|
||||||
::continue::
|
::continue::
|
||||||
|
|||||||
Reference in New Issue
Block a user