commit - e0074095e24797bb794ffd465b0b2a6442caa8d9
commit + 9b4c94f07693bf4d51126899cbecf7ca5b3d904e
blob - 7de524159eeb3940ea7270e030f030511e494f59
blob + 1133285b38617bb7472f5063ad4ee08c6cd06f2c
--- tools/6c
+++ tools/6c
#!/usr/local/bin/lua51
---[[
-This is the structure a token must follow. The token can be
-followed by a series of raw bytes if Length > 0.
+-----------------------------------------------------------------------
+-- TOKEN MATCHING
+-----------------------------------------------------------------------
+local mnemonics = { "mov", "cli", "hlt", "ret", "sti" }
-Token {
- u32 Column;
- u32 Line;
- u16 Type;
- u16 Length;
-}
+local symbols = { ",", "[", "]", "(", ")", "{", "}", "*", "/", "-",
+ "+", "!", "~", "#", "?", ";", ":" }
-Types are eight Opcodes, or C keywords
+local regs8 = { "al", "ah", "bl", "bh", "cl", "ch", "dl", "dh" }
-]]--
+local asmkwd = { "asm" }
-progname="6c"
+local tk_type = { }
+local count = 0
--- Program error
+for i = 1, #mnemonics do
+ count = count + 1
+ tk_type[mnemonics[i]] = count
+end
+
+for i = 1, #symbols do
+ count = count + 1
+ tk_type[symbols[i]] = count
+end
+
+for i = 1, #regs8 do
+ count = count + 1
+ tk_type[regs8[i]] = count
+end
+
+for i = 1, #asmkwd do
+ count = count + 1
+ tk_type[asmkwd[i]] = count
+end
+
+local function cincadd()
+ count = count + 1
+ return count
+end
+tk_type.hexadecimal = cincadd()
+tk_type.integer = cincadd()
+tk_type.id = cincadd()
+tk_type["\n"] = cincadd()
+
+-----------------------------------------------------------------------
+-- DEBUGING
+-----------------------------------------------------------------------
local function perror(msg)
print(progname .. ": error: " .. msg)
os.exit(1)
end
-if arg[1] == nil then
- print("usage: " .. progname .. " input [output]")
- os.exit(1)
+-----------------------------------------------------------------------
+-- BOOLEAN check
+-----------------------------------------------------------------------
+local function isnumber(n)
+ if n:match("[0-9]") then
+ return true
+ end
+ return false
end
-if arg[2] == nil then
- arg[2] = string.gsub(arg[1], "%.%w+$", ".6")
+local function issymbol(char)
+ for i,v in ipairs(symbols) do
+ if v == char then
+ return true
+ end
+ end
+ return false
end
-src = io.open(arg[1], "r")
-dst = io.open(arg[2], "wb")
+local function gettokenkey(m)
+ for i, v in pairs(tk_type) do
+ if tk_type[i] == m.type then
+ return i
+ end
+ end
+ return nil
+end
-if src == nil then
- perror("failed to open src");
+local function ismnemonic(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(mnemonics) do
+ if v == key then
+ return true
+ end
+ end
+ return false
end
-if dst == nil then
- perror("failed to open dst");
- src:close()
+local function isregs8(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(regs8) do
+ if v == key then
+ return true
+ end
+ end
+ return false
end
+-----------------------------------------------------------------------
+-- BITWISE OPERATIONS
+-----------------------------------------------------------------------
local function brshift(value, bit)
return math.floor(value / (2 ^ bit))
end
return result
end
-local function write_u32(value)
+local function bor(a, b)
+ local result = 0
+ local shift = 1
+
+ while a > 0 or b > 0 do
+ local r1 = a % 2
+ local r2 = b % 2
+
+ if r1 == 1 or r2 == 1 then
+ result = result + shift
+ end
+
+ a = math.floor(a / 2)
+ b = math.floor(b / 2)
+ shift = shift * 2
+ end
+
+ return result
+end
+
+-----------------------------------------------------------------------
+-- WRITE OPERATIONS
+-----------------------------------------------------------------------
+local function writeu8(dst, value)
+ local b = band(value, 0xff)
+ dst:write(string.char(b))
+end
+
+local function writeu16(dst, value)
+ local b2 = band(brshift(value, 8), 0xff)
+ local b1 = band(value, 0xff)
+
+ dst:write(string.char(b2, b1)) -- Little Endian x86
+end
+
+local function writeu32(dst, value)
local b4 = band(brshift(value, 24), 0xff)
local b3 = band(brshift(value, 16), 0xff)
local b2 = band(brshift(value, 8), 0xff)
dst:write(string.char(b4, b3, b2, b1)) -- Little Endian x86
end
-local function write_u16(value)
- local b2 = band(brshift(value, 8), 0xff)
- local b1 = band(value, 0xff)
- dst:write(string.char(b2, b1)) -- Little Endian x86
-end
+local function intval(intstr)
+ local len = #intstr
+ local res = 0
-local function write_u8(value)
- local b = band(value, 0xff)
- dst:write(string.char(b))
+ for i = 1, len do
+ local s = intstr:sub(len - i + 1, len - i + 1)
+ s = s * (10 ^ (i - 1))
+ res = res + s
+ end
+ return res
end
-local TOKEN_ASM = 0
-local TOKEN_LEFT_CURLY_BRACKET = 1
-local TOKEN_RIGHT_CURLY_BRACKET = 2
-local TOKEN_MULTIPLY = 3
-local TOKEN_DIVIDE = 4
-local TOKEN_SUBTRACT = 5
-local TOKEN_ADD = 6
-local TOKEN_LEFT_SQUARE_BRACKET = 7
-local TOKEN_RIGHT_SQUARE_BRACKET = 8
-local TOKEN_LEFT_PARANTHESIS = 9
-local TOKEN_RIGHT_PARANTHESIS = 10
-local TOKEN_QUESTION = 11
-local TOKEN_EXCLAMATION = 12
-local TOKEN_TILDA = 13
-local TOKEN_PERIOD = 14
-local TOKEN_COLUMN = 15
-local TOKEN_INTEGER = 16
-local TOKEN_ID = 17
-local TOKEN_STRING = 18
-local TOKEN_SEMICOLON = 19
-local TOKEN_HASH = 20
-local TOKEN_COMMA = 21
-local TOKEN_HLT = 22
-local TOKEN_RET = 23
-local TOKEN_CLI = 24
-local TOKEN_STI = 25
-local TOKEN_AH = 26
-local TOKEN_AL = 27
-local TOKEN_BH = 28
-local TOKEN_BL = 29
-local TOKEN_CL = 30
-local TOKEN_CH = 31
-local TOKEN_DL = 32
-local TOKEN_DH = 33
-local TOKEN_MOV = 34
-local TOKEN_HEXADECIMAL = 35
+function hexval(hex)
+ local dig = hex:sub(3)
+ local len = #dig
+ local result = 0
-local function issymbol(char)
- if char == "{" or
- char == "}" or
- char == "*" or
- char == "/" or
- char == "-" or
- char == "+" or
- char == "[" or
- char == "]" or
- char == "(" or
- char == ")" or
- char == "?" or
- char == "!" or
- char == "~" or
- char == "." or
- char == ":" or
- char == ";" or
- char == "," or
- char == "#" then
- return true
+ for i = 1,len do
+ local d = dig:sub(i, i)
+
+ if d:lower() == "a" then
+ d = 10
+ elseif d:lower() == "b" then
+ d = 11
+ elseif d:lower() == "c" then
+ d = 12
+ elseif d:lower() == "d" then
+ d = 13
+ elseif d:lower() == "e" then
+ d = 14
+ elseif d:lower() == "f" then
+ d = 15
+ end
+
+ result = result + d * (16 ^ (len - i))
end
- return false
+
+ return result
end
+-----------------------------------------------------------------------
+-- Checking arguments and setting read and write file
+-----------------------------------------------------------------------
-local function isnumber(char)
- if char == "0" or
- char == "1" or
- char == "2" or
- char == "3" or
- char == "4" or
- char == "5" or
- char == "6" or
- char == "7" or
- char == "8" or
- char == "9" then
- return true
- end
- return false
+progname = "6c"
+local input = arg[1]
+local output = arg[2]
+
+if input == nil then
+ print("usage: 6c input output")
+ os.exit(1)
end
-local function readid(line, s)
- local len = #line
- local buf = { }
+if output == nil then
+ output = string.gsub(input, "%.%w+$", ".6")
+end
- for i = s, len do
- local char = line:sub(i, i)
- if char == " " then
- break
- end
+local src = io.open(input, "r")
+local dst = io.open(output, "wb")
- if issymbol(char) == true then
- break
- end
+-----------------------------------------------------------------------
+-- Compiler functions
+-----------------------------------------------------------------------
+local function emittoken(line, col, type, len, raw)
+ writeu32(dst, line)
+ writeu32(dst, col)
+ writeu16(dst, type)
+ writeu16(dst, len)
- if i == s and isnumber(char) == true then
- break
+ if len > 0 then
+ for i = 1, len do
+ writeu8(dst, string.byte(raw:sub(i, i)))
end
-
- table.insert(buf, char)
end
-
- return table.concat(buf)
end
local function readint(line, s)
for i = s, len do
local char = line:sub(i, i)
+ if char == "" or char == " " or issymbol(char) then
+ break
+ end
+
if isnumber(char) == false then
- if hex == false then
- if char == "h" and (i - s) == 1 then
+ if hex == false and (i - s) == 1 then
+ if char == "h" then
local prefix = line:sub(i - 1, i - 1)
if prefix ~= "0" then
hex = true
else
- if char ~= "" and char ~= " " then
- print("illegal sufix for number line : " .. line)
- end
+ perror("illegal character `" .. char .. "` line : " .. line)
end
else
- if char == "" or char == " " then
- break
- end
-
- if char ~= "a" and char ~= "A" and char ~= "b" and char ~= "B" and
- char ~= "c" and char ~= "C" and char ~= "d" and char ~= "D" and
- char ~= "e" and char ~= "E" and char ~= "f" and char ~= "F" then
+ if not char:match("[0-9a-fA-F]") then
perror("illegal sufix `" .. char .. "` for hexadecimal " .. line)
end
end
return table.concat(buf)
end
-local nline = 0;
+local function readid(line, s)
+ local len = #line
+ local buf = { }
+ for i = s, len do
+ local char = line:sub(i, i)
+ if char == " " then
+ break
+ end
+
+ if issymbol(char) == true then
+ break
+ end
+
+ if i == s and isnumber(char) == true then
+ break
+ end
+
+ table.insert(buf, char)
+ end
+
+ return table.concat(buf)
+end
+
+-----------------------------------------------------------------------
+-- Tokenizing
+-----------------------------------------------------------------------
+
+local nline = 0
while true do
- line = src:read("*l");
- if (line == nil) then
- break;
+ local line = src:read("*l")
+ if line == nil then
+ break
end
local i = 1
- local len = #line
- local column = 0
+ local ncol = 0
- while i <= len do
+ while i <= #line do
local char = line:sub(i, i)
- local buf = { }
if issymbol(char) == true then
- write_u32(nline)
- write_u32(column)
- if char == "{" then
- write_u16(TOKEN_LEFT_CURLY_BRACKET)
- elseif char == "}" then
- write_u16(TOKEN_RIGHT_CURLY_BRACKET)
- elseif char == "*" then
- write_u16(TOKEN_MULTIPLY)
- elseif char == "/" then
- write_u16(TOKEN_DIVIDE)
- elseif char == "." then
- write_u16(TOKEN_PERIOD)
- elseif char == ":" then
- write_u16(TOKEN_COLUMN)
- elseif char == "[" then
- write_u16(TOKEN_LEFT_SQUARE_BRACKET)
- elseif char == "]" then
- write_u16(TOKEN_RIGHT_SQUARE_BRACKET)
- elseif char == "(" then
- write_u16(TOKEN_LEFT_PARANTHESIS)
- elseif char == ")" then
- write_u16(TOKEN_RIGHT_PARANTHESIS)
- elseif char == ";" then
- write_u16(TOKEN_SEMICOLON)
- elseif char == "#" then
- write_u16(TOKEN_HASH)
- elseif char == "," then
- write_u16(TOKEN_COMMA)
- else
- print("Unknown symbol : " .. char)
+ if tk_type[char] == nil then
+ perror("Unknown symbol `" .. char .. "`")
end
-
- write_u16(0)
+ emittoken(nline, ncol, tk_type[char], 0, nil)
i = i + 1
-
- elseif char == " " or char == "\t" then
- i = i + 1
-
- elseif char == "\n" then
- i = i + 1
-
- elseif isnumber(char) then
- local sint = readint(line, i)
+ elseif isnumber(char) == true then
+ local data = readint(line, i)
local ishex = false
- if sint:sub(2, 2) == "h" then
+ if data:sub(2, 2) == "h" then
ishex = true
end
- local j = 1
- write_u32(nline)
- write_u32(column)
if ishex == true then
- write_u16(TOKEN_HEXADECIMAL)
+ emittoken(nline, ncol, tk_type.hexadecimal, #data, data)
else
- write_u16(TOKEN_INTEGER)
+ emittoken(nline, ncol, tk_type.integer, #data, data)
end
- write_u16(#sint)
- i = i + #sint
-
- while j <= #sint do
- local c = sint:sub(j, j)
- write_u8(string.byte(c))
- j = j + 1
- end
-
- elseif (char:match(".")) then
+ i = i + #data
+ elseif char == " " or char == "\t" then
+ i = i + 1
+ else
local id = readid(line, i)
+ if #id == 0 then
+ break
+ end
- write_u32(nline)
- write_u32(column)
- if id == "asm" then
- write_u16(TOKEN_ASM)
- write_u16(0)
- elseif id == "hlt" then
- write_u16(TOKEN_HLT)
- write_u16(0)
- elseif id == "ret" then
- write_u16(TOKEN_RET)
- write_u16(0)
- elseif id == "cli" then
- write_u16(TOKEN_CLI)
- write_u16(0)
- elseif id == "sti" then
- write_u16(TOKEN_STI)
- write_u16(0)
- elseif id == "ah" then
- write_u16(TOKEN_AH)
- write_u16(0)
- elseif id == "al" then
- write_u16(TOKEN_AL)
- write_u16(0)
- elseif id == "bh" then
- write_u16(TOKEN_BH)
- write_u16(0)
- elseif id == "bl" then
- write_u16(TOKEN_BL)
- write_u16(0)
- elseif id == "ch" then
- write_u16(TOKEN_CH)
- write_u16(0)
- elseif id == "cl" then
- write_u16(TOKEN_CL)
- write_u16(0)
- elseif id == "dh" then
- write_u16(TOKEN_DH)
- write_u16(0)
- elseif id == "dl" then
- write_u16(TOKEN_DL)
- write_u16(0)
- elseif id == "mov" then
- write_u16(TOKEN_MOV)
- write_u16(0)
+ if tk_type[id] == nil then
+ emittoken(nline, ncol, tk_type.id, #id, id)
else
- local j = 1
- write_u16(TOKEN_ID)
- write_u16(#id)
-
- -- Raw bytes
- while j <= #id do
- local c = id:sub(j, j)
- write_u8(string.byte(c))
- j = j + 1
- end
+ emittoken(nline, ncol, tk_type[id], 0, nil)
end
+
i = i + #id
- else
- i = i + 1
end
- column = i
+ ncol = i
end
+ emittoken(nline, ncol, tk_type["\n"], 0, nil)
nline = nline + 1
end
+-----------------------------------------------------------------------
+-- Close files
+-----------------------------------------------------------------------
src:close()
dst:close()
-
-print(progname .. ": " .. arg[1] .. " -> " .. arg[2])
blob - ce8ce69a13ac2aa9f4ce553f4fe23518d06d60e8
blob + 116e3a97da138a8770841c72c42d761751f72500
--- tools/6l
+++ tools/6l
#!/usr/local/bin/lua51
-progname = "6l"
+-----------------------------------------------------------------------
+-- TOKEN MATCHING
+-----------------------------------------------------------------------
+local mnemonics = { "mov", "cli", "hlt", "ret", "sti" }
-if (arg[1] == nil) then
- print("usage: " .. progname .. " [file ...]")
- os.exit(1)
+local symbols = { ",", "[", "]", "(", ")", "{", "}", "*", "/", "-",
+ "+", "!", "~", "#", "?", ";", ":" }
+
+local regs8 = { "al", "ah", "bl", "bh", "cl", "ch", "dl", "dh" }
+
+local asmkwd = { "asm" }
+
+local tk_type = { }
+local count = 0
+
+for i = 1, #mnemonics do
+ count = count + 1
+ tk_type[mnemonics[i]] = count
end
-if arg[2] == nil then
- arg[2] = "6." ..string.gsub(arg[1], "%.%w+$", "")
+for i = 1, #symbols do
+ count = count + 1
+ tk_type[symbols[i]] = count
end
+for i = 1, #regs8 do
+ count = count + 1
+ tk_type[regs8[i]] = count
+end
+
+for i = 1, #asmkwd do
+ count = count + 1
+ tk_type[asmkwd[i]] = count
+end
+
+local function cincadd()
+ count = count + 1
+ return count
+end
+tk_type.hexadecimal = cincadd()
+tk_type.integer = cincadd()
+tk_type.id = cincadd()
+tk_type["\n"] = cincadd()
+
+-----------------------------------------------------------------------
+-- DEBUGING
+-----------------------------------------------------------------------
local function perror(msg)
print(progname .. ": error: " .. msg)
os.exit(1)
end
-src = io.open(arg[1], "rb")
+-----------------------------------------------------------------------
+-- BOOLEAN check
+-----------------------------------------------------------------------
+local function isnumber(n)
+ if n:match("[0-9]") then
+ return true
+ end
+ return false
+end
-if src == nil then
- perror("failed to open " .. arg[1])
+local function issymbol(char)
+ for i,v in ipairs(symbols) do
+ if v == char then
+ return true
+ end
+ end
+ return false
end
-dst = io.open(arg[2], "wb")
+local function gettokenkey(m)
+ for i, v in pairs(tk_type) do
+ if tk_type[i] == m.type then
+ return i
+ end
+ end
+ return nil
+end
-if dst == nil then
- perror("failed to open " .. arg[2])
+local function ismnemonic(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(mnemonics) do
+ if v == key then
+ return true
+ end
+ end
+ return false
end
+local function isregs8(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(regs8) do
+ if v == key then
+ return true
+ end
+ end
+ return false
+end
+
+-----------------------------------------------------------------------
+-- BITWISE OPERATIONS
+-----------------------------------------------------------------------
local function brshift(value, bit)
return math.floor(value / (2 ^ bit))
end
return value * (2 ^ bit)
end
+local function band(a, b)
+ local result = 0
+ local bitval = 1
+
+ while a > 0 and b > 0 do
+ if (a % 2 == 1) and (b % 2 == 1) then
+ result = result + bitval
+ end
+ a = math.floor(a / 2)
+ b = math.floor(b / 2)
+ bitval = bitval * 2
+ end
+
+ return result
+end
+
local function bor(a, b)
local result = 0
local shift = 1
return result
end
---[[
+-----------------------------------------------------------------------
+-- WRITE OPERATIONS
+-----------------------------------------------------------------------
+local function writeu8(dst, value)
+ local b = band(value, 0xff)
+ dst:write(string.char(b))
+end
-Token {
- u32 Line;
- u32 Column;
- u16 Type;
- u16 Length;
-}
+local function writeu16(dst, value)
+ local b2 = band(brshift(value, 8), 0xff)
+ local b1 = band(value, 0xff)
-]]--
+ dst:write(string.char(b2, b1)) -- Little Endian x86
+end
-local TOKEN_ASM = 0
-local TOKEN_LEFT_CURLY_BRACKET = 1
-local TOKEN_RIGHT_CURLY_BRACKET = 2
-local TOKEN_MULTIPLY = 3
-local TOKEN_DIVIDE = 4
-local TOKEN_SUBTRACT = 5
-local TOKEN_ADD = 6
-local TOKEN_LEFT_SQUARE_BRACKET = 7
-local TOKEN_RIGHT_SQUARE_BRACKET = 8
-local TOKEN_LEFT_PARANTHESIS = 9
-local TOKEN_RIGHT_PARANTHESIS = 10
-local TOKEN_QUESTION = 11
-local TOKEN_EXCLAMATION = 12
-local TOKEN_TILDA = 13
-local TOKEN_PERIOD = 14
-local TOKEN_COLUMN = 15
-local TOKEN_INTEGER = 16
-local TOKEN_ID = 17
-local TOKEN_STRING = 18
-local TOKEN_SEMICOLON = 19
-local TOKEN_HASH = 20
-local TOKEN_COMMA = 21
-local TOKEN_HLT = 22
-local TOKEN_RET = 23
-local TOKEN_CLI = 24
-local TOKEN_STI = 25
-local TOKEN_AH = 26
-local TOKEN_AL = 27
-local TOKEN_BH = 28
-local TOKEN_BL = 29
-local TOKEN_CL = 30
-local TOKEN_CH = 31
-local TOKEN_DL = 32
-local TOKEN_DH = 33
-local TOKEN_MOV = 34
-local TOKEN_HEXADECIMAL = 35
+local function writeu32(dst, value)
+ local b4 = band(brshift(value, 24), 0xff)
+ local b3 = band(brshift(value, 16), 0xff)
+ local b2 = band(brshift(value, 8), 0xff)
+ local b1 = band(value, 0xff)
-local asm = {
- hlt = 0xF4,
- ret = 0xC3, -- Near return
- cli = 0xFA,
- sti = 0xFB,
-}
+ dst:write(string.char(b4, b3, b2, b1)) -- Little Endian x86
+end
-local MODE_NONE = 0
-local MODE_ASM = 1
-function readtoken()
- local header = src:read(12)
+local function intval(intstr)
+ local len = #intstr
+ local res = 0
- if header == nil then
- return nil
+ for i = 1, len do
+ local s = intstr:sub(len - i + 1, len - i + 1)
+ s = s * (10 ^ (i - 1))
+ res = res + s
end
-
- local b = { string.byte(header, 1, 12) }
-
- local line = b[4] + blshift(b[3], 8) + blshift(b[2], 16) + blshift(b[1], 24)
- local col = b[8] + blshift(b[7], 8) + blshift(b[6], 16) + blshift(b[5], 24)
- local type = b[10] + blshift(b[9], 8)
- local length = b[12] + blshift(b[11], 8)
- local raw = src:read(length)
-
- return { column = col, line = line, type = type, length = length, raw = raw }
+ return res
end
function hexval(hex)
return result
end
+-----------------------------------------------------------------------
+-- Checking arguments
+-----------------------------------------------------------------------
+progname = "6l"
+local input = arg[1]
+local output = arg[2]
-local mode = MODE_NONE
-local brace_depth = 0
-local begin = src:seek("cur")
+local symbol_table = { }
+local offset = 0
+local parser = {
+ inasm = false, -- In Assembly
+ insec = false, -- In Section
+}
-while true do
- local token = readtoken()
- if token == nil then
- break
+if input == nil then
+ print("usage: 6l input output")
+ os.exit(1)
+end
+
+if output == nil then
+ output = string.gsub(input, "%.%w+$", "")
+end
+
+local src = io.open(input, "rb")
+if src == nil then
+ perror("failed to open `" .. input .. "`")
+end
+
+local dst = io.open("6." .. output, "wb")
+if dst == nil then
+ perror("failed to open `" .. output .. "`")
+end
+
+-----------------------------------------------------------------------
+-- Utility
+-----------------------------------------------------------------------
+local function readhdr()
+ local hdr = src:read(12)
+ if hdr == nil then
+ return nil
end
- -- Syntax check
- if token.type == TOKEN_ASM then
- if mode == MODE_ASM then
- perror("error: nested asm attempt at line " .. token.line .. " column " .. token.column)
- break
- end
+ local b = { string.byte((hdr), 1, 12) }
- local next = readtoken()
- if next == nil or next.type ~= TOKEN_LEFT_CURLY_BRACKET then
- perror("error: missing '{' after asm at line " .. token.line .. " column " .. token.column)
- break
- end
+ local line = b[4] + blshift(b[3], 8) + blshift(b[2], 16) + blshift(b[1], 24)
+ local col = b[8] + blshift(b[7], 8) + blshift(b[6], 16) + blshift(b[5], 24)
+ local type = b[10] + blshift(b[9], 8)
+ local len = b[12] + blshift(b[11], 8)
+ local raw = nil
- mode = MODE_ASM
- elseif token.type == TOKEN_HLT then
- if mode ~= MODE_ASM then
- perror("error: hlt instruction outside asm block at line " .. token.line .. " column " ..
- token.column)
- end
+ if len > 0 then raw = src:read(len) end
+ return { line = line, col = col, type = type, len = len, raw = raw }
+end
- local next = readtoken()
+-- This functions reads an asm line and tells if its a label or instructions
+-- If the return type is instructions, it will tell if its imm8, r8, etc
+--
+-- To keep the assembler simple we will only allow 0-3 operands. More is simply
+-- silly and unecessary for the goal.
+local ASM_UNKNOWN = 0
+local ASM_LABEL = 1
+local ASM_INSTRUCTION = 2
+local ASM_R8 = 3
+local ASM_IMM8 = 4
- if next ~= nil and next.line == token.line then
- perror("error: illegal token next to hlt on line " .. token.line .. " column " ..
- token.column)
+local function operlyze(op, ret)
+ if isregs8(op) == true then
+ ret.opcount = 1
+ table.insert(ret.details, ASM_R8)
+ elseif op.type == tk_type.integer then
+ ret.opcount = 1
+ local val = intval(op.raw)
+
+ if val < 256 then
+ table.insert(ret.details, ASM_IMM8)
+ else
+ perror("operand 1 of instruction on line " .. op.line .. " is too big!")
end
- elseif token.type == TOKEN_RET then
- if mode ~= MODE_ASM then
- perror("error: ret instruction out of asm block at line " .. token.line .. " column " ..
- token.column)
- end
+ elseif op.type == tk_type.hexadecimal then
+ ret.opcount = 1
+ local val = hexval(op.raw)
- local next = readtoken()
- if next ~= nil and next.line == token.line then
- perror("error: illegal token after ret on line " .. token.line " .. column " ..
- token.column)
+ if val < 256 then
+ table.insert(ret.details, ASM_IMM8)
+ else
+ perror("operand 1 of instruction on line " .. op.line .. " is too big!")
end
- elseif token.type == TOKEN_CLI then
- if mode ~= MODE_ASM then
- perror("error: cli instruction out of asm block at line " .. token.line .. " column " ..
- token.column)
- end
+ elseif op.type == tk_type["\n"] then
+ ret.opcount = 0
+ else
+ perror("unknown operand `" .. gettokenkey(op) .. "` at line " .. op.line)
+ end
+end
- local next = readtoken()
- if next ~= nil and next.line == token.line then
- perror("error: illegal token after cli on line " .. token.line " .. column " ..
- token.column)
+local function asmlyze(first)
+ if ismnemonic(first) == true then
+ local ret = {
+ type = ASM_INSTRUCTION,
+ opcount = 0,
+ details = { }
+ }
+
+ local op1 = readhdr()
+ operlyze(op1, ret)
+
+ if ret.opcount == 0 then
+ return ret
end
- elseif token.type == TOKEN_STI then
- if mode ~= MODE_ASM then
- perror("error: sti instruction out of asm block at line " .. token.line .. " column " ..
- token.column)
- end
- local next = readtoken()
- if next ~= nil and next.line == token.line then
- perror("error: illegal token after sti on line " .. token.line " .. column " ..
- token.column)
+ local com = readhdr()
+
+ if com.type == tk_type["\n"] then
+ return ret
end
- elseif token.type == TOKEN_MOV then
- if mode ~= MODE_ASM then
- perror("error: sti instruction out of asm block at line " .. token.line .. " column " ..
- token.column)
+ if com.type ~= tk_type[","] then
+ perror("missing comma next to first operand on line " .. op1.line)
end
- local op1 = readtoken()
+ local op2 = readhdr()
+ operlyze(op2, ret)
- if op1.type ~= TOKEN_AL and op1.type ~= TOKEN_AH and op1.type ~= TOKEN_BL and
- op1.type ~= TOKEN_BH and op1.type ~= TOKEN_CH and
- op1.type ~= TOKEN_CL and op1.type ~= TOKEN_DH and
- op1.type ~= TOKEN_DL then
- perror("illegal first operand for mov at line " .. token.line .. " column " ..
- token.column)
+ if ret.opcount == 0 then
+ return ret
end
- local comma = readtoken()
+ com = readhdr()
+ if com.type == tk_type["\n"] then
+ return ret
+ end
- if comma.type ~= TOKEN_COMMA then
- perror("missing comma next to first operand line " .. token.line .. " column " ..
- token.column)
+ if com.type ~= tk_type[","] then
+ perror("missing comma next to second operand on line " .. op1.line)
end
- local op2 = readtoken()
+ local op3 = readhdr()
+ operlyze(op3, ret)
- if op2.type ~= TOKEN_AL and op2.type ~= TOKEN_AH and op2.type ~= TOKEN_BL and
- op2.type ~= TOKEN_BH and op2.type ~= TOKEN_CH and
- op2.type ~= TOKEN_CL and op2.type ~= TOKEN_DH and
- op2.type ~= TOKEN_DL and op2.type ~= TOKEN_HEXADECIMAL then
- perror("illegal second operand for mov at line " .. token.line .. " column " ..
- token.column)
+ if ret.opcount == 0 then
+ return ret
end
- -- Checking if hex value is to high: mov r8, imm8
- if op2.type == TOKEN_HEXADECIMAL and
- (op1.type == TOKEN_AH or op1.type == TOKEN_AL or
- op1.type == TOKEN_BH or op1.type == TOKEN_BL or
- op1.type == TOKEN_CH or op1.type == TOKEN_CL or
- op1.type == TOKEN_DH or op1.type == TOKEN_DL) then
- if hexval(op2.raw) > 255 then
- perror("hexvalue too high at line " .. token.line .. " column " .. token.column)
+ local nl = readhdr()
+ if nl.type == tk_type["\n"] then
+ return ret
+ end
+
+ perror("can only take up to 3 operands instructions. Line " .. first.line)
+
+ else
+ if first.type == tk_type.id then
+ local col = readhdr()
+ if col.type ~= tk_type[":"] then
+ perror("missing colon next to " .. gettokenkey(first) .. " line " .. first.line)
+ else
+ return { type = ASM_LABEL }
end
+ perror("Unknown instruction at line " .. first.line)
+ else
+ perror("illegal first element in instruction from line " .. first.line)
end
end
end
-src:seek("set", begin)
-
+-----------------------------------------------------------------------
+-- 1st pass (syntax check and symbol table)
+-----------------------------------------------------------------------
while true do
- local token = readtoken()
- if token == nil then
+ local hdr = readhdr()
+ if hdr == nil then
break
end
- if token.type == TOKEN_HLT then
- dst:write(string.char(asm.hlt))
- elseif token.type == TOKEN_RET then
- dst:write(string.char(asm.ret))
- elseif token.type == TOKEN_CLI then
- dst:write(string.char(asm.cli))
- elseif token.type == TOKEN_STI then
- dst:write(string.char(asm.sti))
- elseif token.type == TOKEN_MOV then
- local op1 = readtoken()
- readtoken() -- Comma
- local op2 = readtoken()
+ if parser.inasm == true then
+ if hdr.type == tk_type["asm"] then
+ perror("illegal nested asm keyword at line " .. hdr.line .. " column " .. hdr.col)
+ elseif hdr.type == tk_type["}"] then
+ parser.inasm = false
+ else
+ if hdr.type ~= tk_type["\n"] then
+ local inst = asmlyze(hdr)
- if op1.type == TOKEN_AL then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("000", 2), hexval(op2.raw) }
+ if inst.type == ASM_INSTRUCTION then
+ if hdr.type == tk_type["mov"] then
+ -- mov r8, r8
+ if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then
+ offset = offset + 2
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
- elseif op1.type == TOKEN_AH then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("100", 2), hexval(op2.raw) }
+ -- mov r8, imm8
+ elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then
+ offset = offset + 2
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
+ -- huh?
+ else
+ perror("invalid instruction at line " .. hdr.line)
+ end
+ end
+ -- Add symbol table
+ elseif inst.type == ASM_LABEL then
+ symbol_table[hdr.raw] = offset
+ else
+ perror("Unknown instruction line " .. hdr.line)
+ end
end
- elseif op1.type == TOKEN_BL then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("011", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
+ end
+ else
+ if hdr.type == tk_type["asm"] then
+ local next = readhdr()
+ if next.type ~= tk_type["{"] then
+ perror("missing { after asm, line " .. hdr.line .. " column " .. hdr.col)
end
- elseif op1.type == TOKEN_BH then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("111", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
- elseif op1.type == TOKEN_CL then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("001", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
- elseif op1.type == TOKEN_CH then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("101", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
- elseif op1.type == TOKEN_DL then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("010", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
- elseif op1.type == TOKEN_DH then
- if op2.type == TOKEN_HEXADECIMAL then
- local opcode = { hexval("0hB0") + tonumber("110", 2), hexval(op2.raw) }
-
- dst:write(string.char(opcode[1]))
- dst:write(string.char(opcode[2]))
- end
+ parser.inasm = true
end
end
end
+-----------------------------------------------------------------------
+-- 2nd pass binary generation
+-----------------------------------------------------------------------
+
+-----------------------------------------------------------------------
+-- Closing files
+-----------------------------------------------------------------------
src:close()
dst:close()
-print(arg[1] .. " -> " .. arg[2])
blob - 17dc1369b1522cc6139fcb7b47f9086f35c4d8bb (mode 644)
blob + /dev/null
--- tools/boot.c
+++ /dev/null
-asm {
-_start:
- ret
-}
blob - /dev/null
blob + 846d2fda3cde69a0ef32cbed3930c60c8c5bb3da (mode 644)
--- /dev/null
+++ tools/boot.sc
+asm {
+_start:
+ mov al, 0h10
+ mov ah, 22
+ ret
+main:
+ hlt
+ cli
+}
blob - /dev/null
blob + 1a239eae8c59bda6d3eae8bd932b95f37299a372 (mode 755)
--- /dev/null
+++ tools/build.sh
+#!/bin/ksh
+
+# The goal of this script is to combine lua files into
+# a single executable script
+
+COMPILER=6c
+LINKER=6l
+
+# compiler
+echo "#!/usr/local/bin/lua51\n" > $COMPILER
+cat util.lua compiler.lua >> $COMPILER
+
+# linker
+echo "#!/usr/local/bin/lua51\n" > $LINKER
+cat util.lua linker.lua >> $LINKER
+
+chmod +x $COMPILER
+chmod +x $LINKER
blob - /dev/null
blob + 71f6edaaccf35a7ecad23def99747b4524d30cd9 (mode 644)
--- /dev/null
+++ tools/compiler.lua
+-----------------------------------------------------------------------
+-- Checking arguments and setting read and write file
+-----------------------------------------------------------------------
+
+progname = "6c"
+local input = arg[1]
+local output = arg[2]
+
+if input == nil then
+ print("usage: 6c input output")
+ os.exit(1)
+end
+
+if output == nil then
+ output = string.gsub(input, "%.%w+$", ".6")
+end
+
+local src = io.open(input, "r")
+local dst = io.open(output, "wb")
+
+-----------------------------------------------------------------------
+-- Compiler functions
+-----------------------------------------------------------------------
+local function emittoken(line, col, type, len, raw)
+ writeu32(dst, line)
+ writeu32(dst, col)
+ writeu16(dst, type)
+ writeu16(dst, len)
+
+ if len > 0 then
+ for i = 1, len do
+ writeu8(dst, string.byte(raw:sub(i, i)))
+ end
+ end
+end
+
+local function readint(line, s)
+ local len = #line
+ local buf = { }
+ local hex = false
+
+ for i = s, len do
+ local char = line:sub(i, i)
+
+ if char == "" or char == " " or issymbol(char) then
+ break
+ end
+
+ if isnumber(char) == false then
+ if hex == false and (i - s) == 1 then
+ if char == "h" then
+ local prefix = line:sub(i - 1, i - 1)
+
+ if prefix ~= "0" then
+ perror("illegal token `" .. prefix .. "` next to number : " .. line)
+ end
+
+ hex = true
+ else
+ perror("illegal character `" .. char .. "` line : " .. line)
+ end
+ else
+ if not char:match("[0-9a-fA-F]") then
+ perror("illegal sufix `" .. char .. "` for hexadecimal " .. line)
+ end
+ end
+ end
+
+ table.insert(buf, char)
+ end
+
+ return table.concat(buf)
+end
+
+local function readid(line, s)
+ local len = #line
+ local buf = { }
+
+ for i = s, len do
+ local char = line:sub(i, i)
+ if char == " " then
+ break
+ end
+
+ if issymbol(char) == true then
+ break
+ end
+
+ if i == s and isnumber(char) == true then
+ break
+ end
+
+ table.insert(buf, char)
+ end
+
+ return table.concat(buf)
+end
+
+-----------------------------------------------------------------------
+-- Tokenizing
+-----------------------------------------------------------------------
+
+local nline = 0
+while true do
+ local line = src:read("*l")
+ if line == nil then
+ break
+ end
+
+ local i = 1
+ local ncol = 0
+
+ while i <= #line do
+ local char = line:sub(i, i)
+
+ if issymbol(char) == true then
+ if tk_type[char] == nil then
+ perror("Unknown symbol `" .. char .. "`")
+ end
+ emittoken(nline, ncol, tk_type[char], 0, nil)
+ i = i + 1
+ elseif isnumber(char) == true then
+ local data = readint(line, i)
+ local ishex = false
+
+ if data:sub(2, 2) == "h" then
+ ishex = true
+ end
+
+ if ishex == true then
+ emittoken(nline, ncol, tk_type.hexadecimal, #data, data)
+ else
+ emittoken(nline, ncol, tk_type.integer, #data, data)
+ end
+ i = i + #data
+ elseif char == " " or char == "\t" then
+ i = i + 1
+ else
+ local id = readid(line, i)
+ if #id == 0 then
+ break
+ end
+
+ if tk_type[id] == nil then
+ emittoken(nline, ncol, tk_type.id, #id, id)
+ else
+ emittoken(nline, ncol, tk_type[id], 0, nil)
+ end
+
+ i = i + #id
+ end
+
+ ncol = i
+ end
+
+ emittoken(nline, ncol, tk_type["\n"], 0, nil)
+ nline = nline + 1
+end
+
+-----------------------------------------------------------------------
+-- Close files
+-----------------------------------------------------------------------
+src:close()
+dst:close()
blob - /dev/null
blob + 4fd03b00959bb3a8a3763042c0eddde8adaa01e0 (mode 644)
--- /dev/null
+++ tools/linker.lua
+-----------------------------------------------------------------------
+-- Checking arguments
+-----------------------------------------------------------------------
+progname = "6l"
+local input = arg[1]
+local output = arg[2]
+
+local symbol_table = { }
+local offset = 0
+local parser = {
+ inasm = false, -- In Assembly
+ insec = false, -- In Section
+}
+
+if input == nil then
+ print("usage: 6l input output")
+ os.exit(1)
+end
+
+if output == nil then
+ output = string.gsub(input, "%.%w+$", "")
+end
+
+local src = io.open(input, "rb")
+if src == nil then
+ perror("failed to open `" .. input .. "`")
+end
+
+local dst = io.open("6." .. output, "wb")
+if dst == nil then
+ perror("failed to open `" .. output .. "`")
+end
+
+-----------------------------------------------------------------------
+-- Utility
+-----------------------------------------------------------------------
+local function readhdr()
+ local hdr = src:read(12)
+ if hdr == nil then
+ return nil
+ end
+
+ local b = { string.byte((hdr), 1, 12) }
+
+ local line = b[4] + blshift(b[3], 8) + blshift(b[2], 16) + blshift(b[1], 24)
+ local col = b[8] + blshift(b[7], 8) + blshift(b[6], 16) + blshift(b[5], 24)
+ local type = b[10] + blshift(b[9], 8)
+ local len = b[12] + blshift(b[11], 8)
+ local raw = nil
+
+ if len > 0 then raw = src:read(len) end
+ return { line = line, col = col, type = type, len = len, raw = raw }
+end
+
+-- This functions reads an asm line and tells if its a label or instructions
+-- If the return type is instructions, it will tell if its imm8, r8, etc
+--
+-- To keep the assembler simple we will only allow 0-3 operands. More is simply
+-- silly and unecessary for the goal.
+local ASM_UNKNOWN = 0
+local ASM_LABEL = 1
+local ASM_INSTRUCTION = 2
+local ASM_R8 = 3
+local ASM_IMM8 = 4
+
+local function operlyze(op, ret)
+ if isregs8(op) == true then
+ ret.opcount = 1
+ table.insert(ret.details, ASM_R8)
+ elseif op.type == tk_type.integer then
+ ret.opcount = 1
+ local val = intval(op.raw)
+
+ if val < 256 then
+ table.insert(ret.details, ASM_IMM8)
+ else
+ perror("operand 1 of instruction on line " .. op.line .. " is too big!")
+ end
+ elseif op.type == tk_type.hexadecimal then
+ ret.opcount = 1
+ local val = hexval(op.raw)
+
+ if val < 256 then
+ table.insert(ret.details, ASM_IMM8)
+ else
+ perror("operand 1 of instruction on line " .. op.line .. " is too big!")
+ end
+ elseif op.type == tk_type["\n"] then
+ ret.opcount = 0
+ else
+ perror("unknown operand `" .. gettokenkey(op) .. "` at line " .. op.line)
+ end
+end
+
+local function asmlyze(first)
+ if ismnemonic(first) == true then
+ local ret = {
+ type = ASM_INSTRUCTION,
+ opcount = 0,
+ details = { }
+ }
+
+ local op1 = readhdr()
+ operlyze(op1, ret)
+
+ if ret.opcount == 0 then
+ return ret
+ end
+
+ local com = readhdr()
+
+ if com.type == tk_type["\n"] then
+ return ret
+ end
+
+ if com.type ~= tk_type[","] then
+ perror("missing comma next to first operand on line " .. op1.line)
+ end
+
+ local op2 = readhdr()
+ operlyze(op2, ret)
+
+ if ret.opcount == 0 then
+ return ret
+ end
+
+ com = readhdr()
+ if com.type == tk_type["\n"] then
+ return ret
+ end
+
+ if com.type ~= tk_type[","] then
+ perror("missing comma next to second operand on line " .. op1.line)
+ end
+
+ local op3 = readhdr()
+ operlyze(op3, ret)
+
+ if ret.opcount == 0 then
+ return ret
+ end
+
+ local nl = readhdr()
+ if nl.type == tk_type["\n"] then
+ return ret
+ end
+
+ perror("can only take up to 3 operands instructions. Line " .. first.line)
+
+ else
+ if first.type == tk_type.id then
+ local col = readhdr()
+ if col.type ~= tk_type[":"] then
+ perror("missing colon next to " .. gettokenkey(first) .. " line " .. first.line)
+ else
+ return { type = ASM_LABEL }
+ end
+ perror("Unknown instruction at line " .. first.line)
+ else
+ perror("illegal first element in instruction from line " .. first.line)
+ end
+ end
+end
+
+-----------------------------------------------------------------------
+-- 1st pass (syntax check and symbol table)
+-----------------------------------------------------------------------
+while true do
+ local hdr = readhdr()
+ if hdr == nil then
+ break
+ end
+
+ if parser.inasm == true then
+ if hdr.type == tk_type["asm"] then
+ perror("illegal nested asm keyword at line " .. hdr.line .. " column " .. hdr.col)
+ elseif hdr.type == tk_type["}"] then
+ parser.inasm = false
+ else
+ if hdr.type ~= tk_type["\n"] then
+ local inst = asmlyze(hdr)
+
+ if inst.type == ASM_INSTRUCTION then
+ if hdr.type == tk_type["mov"] then
+ -- mov r8, r8
+ if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then
+ offset = offset + 2
+
+ -- mov r8, imm8
+ elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then
+ offset = offset + 2
+
+ -- huh?
+ else
+ perror("invalid instruction at line " .. hdr.line)
+ end
+ end
+ -- Add symbol table
+ elseif inst.type == ASM_LABEL then
+ symbol_table[hdr.raw] = offset
+ else
+ perror("Unknown instruction line " .. hdr.line)
+ end
+ end
+ end
+ else
+ if hdr.type == tk_type["asm"] then
+ local next = readhdr()
+ if next.type ~= tk_type["{"] then
+ perror("missing { after asm, line " .. hdr.line .. " column " .. hdr.col)
+ end
+ parser.inasm = true
+ end
+ end
+end
+
+-----------------------------------------------------------------------
+-- 2nd pass binary generation
+-----------------------------------------------------------------------
+
+-----------------------------------------------------------------------
+-- Closing files
+-----------------------------------------------------------------------
+src:close()
+dst:close()
blob - /dev/null
blob + cc7115c9a8b1920867e53e25cd21892a6d296e45 (mode 644)
--- /dev/null
+++ tools/util.lua
+-----------------------------------------------------------------------
+-- TOKEN MATCHING
+-----------------------------------------------------------------------
+local mnemonics = { "mov", "cli", "hlt", "ret", "sti" }
+
+local symbols = { ",", "[", "]", "(", ")", "{", "}", "*", "/", "-",
+ "+", "!", "~", "#", "?", ";", ":" }
+
+local regs8 = { "al", "ah", "bl", "bh", "cl", "ch", "dl", "dh" }
+
+local asmkwd = { "asm" }
+
+local tk_type = { }
+local count = 0
+
+for i = 1, #mnemonics do
+ count = count + 1
+ tk_type[mnemonics[i]] = count
+end
+
+for i = 1, #symbols do
+ count = count + 1
+ tk_type[symbols[i]] = count
+end
+
+for i = 1, #regs8 do
+ count = count + 1
+ tk_type[regs8[i]] = count
+end
+
+for i = 1, #asmkwd do
+ count = count + 1
+ tk_type[asmkwd[i]] = count
+end
+
+local function cincadd()
+ count = count + 1
+ return count
+end
+tk_type.hexadecimal = cincadd()
+tk_type.integer = cincadd()
+tk_type.id = cincadd()
+tk_type["\n"] = cincadd()
+
+-----------------------------------------------------------------------
+-- DEBUGING
+-----------------------------------------------------------------------
+local function perror(msg)
+ print(progname .. ": error: " .. msg)
+ os.exit(1)
+end
+
+-----------------------------------------------------------------------
+-- BOOLEAN check
+-----------------------------------------------------------------------
+local function isnumber(n)
+ if n:match("[0-9]") then
+ return true
+ end
+ return false
+end
+
+local function issymbol(char)
+ for i,v in ipairs(symbols) do
+ if v == char then
+ return true
+ end
+ end
+ return false
+end
+
+local function gettokenkey(m)
+ for i, v in pairs(tk_type) do
+ if tk_type[i] == m.type then
+ return i
+ end
+ end
+ return nil
+end
+
+local function ismnemonic(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(mnemonics) do
+ if v == key then
+ return true
+ end
+ end
+ return false
+end
+
+local function isregs8(m)
+ local key = gettokenkey(m)
+
+ if key == nil then
+ return false
+ end
+
+ for i,v in ipairs(regs8) do
+ if v == key then
+ return true
+ end
+ end
+ return false
+end
+
+-----------------------------------------------------------------------
+-- BITWISE OPERATIONS
+-----------------------------------------------------------------------
+local function brshift(value, bit)
+ return math.floor(value / (2 ^ bit))
+end
+
+local function blshift(value, bit)
+ return value * (2 ^ bit)
+end
+
+local function band(a, b)
+ local result = 0
+ local bitval = 1
+
+ while a > 0 and b > 0 do
+ if (a % 2 == 1) and (b % 2 == 1) then
+ result = result + bitval
+ end
+ a = math.floor(a / 2)
+ b = math.floor(b / 2)
+ bitval = bitval * 2
+ end
+
+ return result
+end
+
+local function bor(a, b)
+ local result = 0
+ local shift = 1
+
+ while a > 0 or b > 0 do
+ local r1 = a % 2
+ local r2 = b % 2
+
+ if r1 == 1 or r2 == 1 then
+ result = result + shift
+ end
+
+ a = math.floor(a / 2)
+ b = math.floor(b / 2)
+ shift = shift * 2
+ end
+
+ return result
+end
+
+-----------------------------------------------------------------------
+-- WRITE OPERATIONS
+-----------------------------------------------------------------------
+local function writeu8(dst, value)
+ local b = band(value, 0xff)
+ dst:write(string.char(b))
+end
+
+local function writeu16(dst, value)
+ local b2 = band(brshift(value, 8), 0xff)
+ local b1 = band(value, 0xff)
+
+ dst:write(string.char(b2, b1)) -- Little Endian x86
+end
+
+local function writeu32(dst, value)
+ local b4 = band(brshift(value, 24), 0xff)
+ local b3 = band(brshift(value, 16), 0xff)
+ local b2 = band(brshift(value, 8), 0xff)
+ local b1 = band(value, 0xff)
+
+ dst:write(string.char(b4, b3, b2, b1)) -- Little Endian x86
+end
+
+
+local function intval(intstr)
+ local len = #intstr
+ local res = 0
+
+ for i = 1, len do
+ local s = intstr:sub(len - i + 1, len - i + 1)
+ s = s * (10 ^ (i - 1))
+ res = res + s
+ end
+ return res
+end
+
+function hexval(hex)
+ local dig = hex:sub(3)
+ local len = #dig
+ local result = 0
+
+ for i = 1,len do
+ local d = dig:sub(i, i)
+
+ if d:lower() == "a" then
+ d = 10
+ elseif d:lower() == "b" then
+ d = 11
+ elseif d:lower() == "c" then
+ d = 12
+ elseif d:lower() == "d" then
+ d = 13
+ elseif d:lower() == "e" then
+ d = 14
+ elseif d:lower() == "f" then
+ d = 15
+ end
+
+ result = result + d * (16 ^ (len - i))
+ end
+
+ return result
+end