This commit is contained in:
Andre Wagner
2026-05-07 20:26:03 -05:00
parent 4a23c52781
commit 9ff38cd4c0
3 changed files with 59 additions and 36 deletions

View File

@@ -82,10 +82,10 @@ External code:
49 asmbl Assemble code to bytecode format
4a load Load bytecode as function (will place function on stack)
Control flow:
a8 c8 e8 bz [pc] Branch if zero
a9 c9 e9 bnz [pc] Branch if not zero
aa ca ea jmp [pc] Unconditional jump
Control flow (the destination is always a 16-bit field):
c8 bz [pc] Branch if zero
c9 bnz [pc] Branch if not zero
ca jmp [pc] Unconditional jump
* Jumps can only happen within the same function.

View File

@@ -71,30 +71,30 @@ do TEST "Parser"
assert_eq(found, expected)
end
--do TEST "Parser: labels"
--
-- local source = [[
-- .func 0
-- jmp %my_label
-- pushi 3
-- %my_label:
-- ret ]]
--
-- local expected = {
-- constants = {},
-- functions = {
-- [0] = {
-- { "jmp", "%my_label" },
-- { "pushi", 3 },
-- { "ret", labels = { "%my_label" } },
-- }
-- }
-- }
--
-- local found = assemble(source)
-- pprint(found)
-- assert_eq(found, expected)
--end
do TEST "Parser: labels"
local source = [[
.func 0
jmp @my_label
pushi 3
@my_label:
ret ]]
local expected = {
constants = {},
functions = {
[0] = {
{ "jmp", "@my_label" },
{ "pushi", 3 },
{ "ret", labels = { "@my_label" } },
}
}
}
local found = assemble(source)
pprint(found)
assert_eq(found, expected)
end
----------------------
-- --

View File

@@ -13,6 +13,7 @@ local function assemble(source)
local section = ''
local current_f_id = 0
local next_label = nil
for line in source:gmatch("([^\n]+)") do
local line = line:gsub("%s*;.*$", "") -- remove comments
line = line:match("^%s*(.-)%s*$") -- trim
@@ -28,21 +29,43 @@ local function assemble(source)
current_f_id = f_id
elseif section == 'const' then
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
proto.constants[tonumber(k)] = line:match('"(.*)"')
else
proto.constants[tonumber(k)] = tonumber(v)
end
elseif section == 'function' then
local inst, par = line:match("^%s*(%a+)%s+(%d+)%s*$")
if inst then
table.insert(proto.functions[current_f_id], { inst, tonumber(par) })
else
local inst = line:match("^%s*(%a+)%s*$")
if not inst then error("Invalid row for function") end
table.insert(proto.functions[current_f_id], { inst })
local regexes = {
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
"^%s*(%a+)%s+(@[%a_]+)%s*$", -- instruction + label
"^%s*(%a+)%s*$", -- instruction only
"^(@[%a_]+):%s*$", -- label
}
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
if not match then error("Invalid instruction: " .. line) end
end
::continue::