#!/usr/local/bin/lua51 ----------------------------------------------------------------------------- -- INITIALIZING DEFAULTS ----------------------------------------------------------------------------- progname = "6c" -- Important for log local oargs = require("oargs") local log = require("log") local stdio = require("stdio") local tcmod = require("tcmod") local args = oargs.compile(arg, { "-entry", "-org" } ) if args.none[1] == nil then printeger("usage: 6c input") os.exit(1) end if args.none[2] == nil then args.none[2] = string.gsub(args.none[1], "%.%w+$", ".6") end local src = io.open(args.none[1], "r") local offset = (args["-org"] == nil) and "0h00" or args["-org"] if src == nil then log.error("failed to open " .. args.none[1]) end local dst = io.open(args.none[2], "wb") if dst == nil then log.error("failed to open " .. args.none[2]) end ----------------------------------------------------------------------------- -- GLOBAL VARIABLES ----------------------------------------------------------------------------- local ncol = 0 local nline = 0 ----------------------------------------------------------------------------- -- UTILITY ----------------------------------------------------------------------------- local function emittoken(line, col, type, len, raw) stdio.writeu32(dst, line) stdio.writeu32(dst, col) stdio.writeu16(dst, type) stdio.writeu16(dst, len) if len == 0 then return end for i = 1, len do stdio.writeu8(dst, string.byte(raw:sub(i, i))) end end local function readinteger(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 tcmod.issymbol(char) then break end if tcmod.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 log.error("illegal token `" .. prefix .. "` next to number : " .. line) end hex = true else log.error("illegal character `" .. char .. "` line : " .. line) end else if not char:match("[0-9a-fA-F]") then log.error("illegal sufix `" .. char .. "` for hexadecimal " .. line) end end end table.insert(buf, char) end return table.concat(buf) end local function readstring(line, s) local sub = { } while true do s = s + 1 if s > #line then break end local char = line:sub(s, s) if char == "\"" or char == nil then break end table.insert(sub, char) end return table.concat(sub) 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 tcmod.isarithmetic(char) == true then break end if tcmod.issymbol(char) == true then break end if i == s and tcmod.isnumber(char) == true then break end table.insert(buf, char) end return table.concat(buf) end ----------------------------------------------------------------------------- -- TOKENIZING ----------------------------------------------------------------------------- emittoken(0, 0, tcmod.tokens.org, #offset, offset) emittoken(0, 0, tcmod.tokens.nwl, 0, 0) -- Injects a rel jump at the start of the binary when read by 6l if args["-entry"] then local entry = args["-entry"] emittoken(0, 0, tcmod.tokens["asm"], 0, nil) emittoken(0, 1, tcmod.tokens["{"], 0, nil) emittoken(0, 2, tcmod.tokens.nwl, 0, nil) nline = nline + 1 emittoken(0, 0, tcmod.tokens["jmp"], 0, nil) emittoken(0, 0, tcmod.tokens["&"], 0, nil) emittoken(0, 2, tcmod.tokens.id, #entry, entry) emittoken(0, 3, tcmod.tokens.nwl, 0, nil) nline = nline + 1 emittoken(0, 0, tcmod.tokens["}"], 0, nil) nline = nline + 1 end nline = 1 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 tcmod.issymbol(char) == true then if tcmod.tokens[char] == nil then log.error("unknown symbol `" .. char .. "`") end emittoken(nline, ncol, tcmod.tokens[char], 0, nil) i = i + 1 elseif tcmod.isnumber(char) == true then local data = readinteger(line, i) local ishex = (data:sub(2, 2) == "h") and true or false if ishex == true then local hex = tostring(tcmod.hexval(data)) emittoken(nline, ncol, tcmod.tokens.integer, #hex, hex) else emittoken(nline, ncol, tcmod.tokens.integer, #data, data) end i = i + #data elseif tcmod.isarithmetic(char) == true then emittoken(nline, ncol, tcmod.tokens[char], 0, nil) i = i + 1 elseif char == "\"" then local data = readstring(line, i) i = i + #data + 2 emittoken(nline, ncol, tcmod.tokens.string, #data, data) elseif char == " " or char == "\t" then i = i + 1 else local id = readid(line, i) if #id == 0 then break end if tcmod.tokens[id] == nil then emittoken(nline, ncol, tcmod.tokens.id, #id, id) else emittoken(nline, ncol, tcmod.tokens[id], 0, nil) end i = i + #id end ncol = i end emittoken(nline, ncol, tcmod.tokens.nwl, 0, nil) nline = nline + 1 end ----------------------------------------------------------------------------- -- WE'RE DONE ----------------------------------------------------------------------------- src:close() dst:close()