193 lines
4.2 KiB
Lua
Executable file
193 lines
4.2 KiB
Lua
Executable file
local args = {...}
|
|
|
|
local words = {}
|
|
local insns = {}
|
|
|
|
local function addword(word)
|
|
local w = words[word]
|
|
if not w then
|
|
w = word:upper()
|
|
w = w:gsub("%.", "_DOT_")
|
|
if not w:match("^[A-Z0-9_]*$") then
|
|
error(word.." is not a valid token")
|
|
end
|
|
words[word] = w
|
|
end
|
|
return w
|
|
end
|
|
|
|
local function parsesyntax(line)
|
|
local syntax = {}
|
|
for word in line:gmatch("%S+") do
|
|
local _, _, s = word:find('^"(.*)"$')
|
|
if s then
|
|
syntax[#syntax+1] = {word=addword(s) }
|
|
else
|
|
_, _, s = word:find("^('.*')$")
|
|
if s then
|
|
syntax[#syntax+1] = {punct=s }
|
|
else
|
|
local token = {}
|
|
for equate in word:gmatch("([^=]+)=") do
|
|
token[#token+1] = equate
|
|
end
|
|
_, _, token.token = word:find("([^=]*)$")
|
|
syntax[#syntax+1] = token
|
|
if not token.token then
|
|
error("can't parse "..word)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return syntax
|
|
end
|
|
|
|
local function parsefields(line)
|
|
local _, _, bits = line:find("^([^ ]+) ")
|
|
if #bits ~= 32 then
|
|
error("'"..bits.."' isn't 32 bits long")
|
|
end
|
|
|
|
local fields = {}
|
|
local i = 1
|
|
while i ~= 33 do
|
|
local c = line:sub(i, i)
|
|
if c ~= "." then
|
|
local f = { pos=i }
|
|
if c:find("%w") then
|
|
f.size = 1
|
|
f.value = c
|
|
elseif c == "<" then
|
|
local _, newi, name = line:find("^<%-*(%w+)%-*>", i)
|
|
f.size = 1 + newi - i
|
|
f.value = name
|
|
i = newi
|
|
else
|
|
error("bad field char '"..c.."' in '"..line.."'")
|
|
end
|
|
if f.value:find("[0-9]+") then
|
|
f.literal = true
|
|
f.variable = false
|
|
else
|
|
f.literal = false
|
|
f.variable = true
|
|
end
|
|
-- Convert from PowerPC numbering to sane numbering
|
|
f.pos = 33-(f.pos + f.size)
|
|
fields[#fields+1] = f
|
|
if f.value then
|
|
fields[f.value] = f
|
|
end
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
local value = 0
|
|
for _, f in ipairs(fields) do
|
|
if f.literal then
|
|
local s = math.pow(2, f.pos)
|
|
value = value + f.value*s
|
|
end
|
|
end
|
|
fields.value = value
|
|
|
|
return fields
|
|
end
|
|
|
|
|
|
local function emit(fields, code)
|
|
local mask = 0
|
|
local value = 0
|
|
for _, f in ipairs(fields) do
|
|
if f.literal then
|
|
local s = math.pow(2, f.pos)
|
|
local m = math.pow(2, f.size) - 1
|
|
mask = mask + m*s
|
|
value = value + f.value*s
|
|
end
|
|
end
|
|
|
|
print(string.format("if ((value & 0x%x) == 0x%x) {", mask, value))
|
|
for _, f in ipairs(fields) do
|
|
if f.variable then
|
|
local m = math.pow(2, f.size) - 1
|
|
print(string.format("uint32_t %s = (value >> %d) & 0x%x;", f.value, f.pos, m))
|
|
end
|
|
end
|
|
|
|
print(code)
|
|
print("return;")
|
|
print("}")
|
|
end
|
|
|
|
while true do
|
|
local line = io.stdin:read("*l")
|
|
if not line then
|
|
break
|
|
end
|
|
line = line:gsub("#.*$", "")
|
|
line = line:gsub(" *$", "")
|
|
if line:find("^%%token ") then
|
|
addword(line:sub(8))
|
|
elseif line ~= "" then
|
|
local fields = parsefields(line)
|
|
local syntax = parsesyntax(line:sub(34, #line))
|
|
insns[#insns+1] = {
|
|
fields=parsefields(line),
|
|
syntax=parsesyntax(line:sub(34, #line))
|
|
}
|
|
end
|
|
end
|
|
|
|
local definitionsfp = io.open(args[1], "wb")
|
|
for word, value in pairs(words) do
|
|
definitionsfp:write("%token <y_word> OP_", tostring(value), " /* ", word, " */\n")
|
|
end
|
|
definitionsfp:close()
|
|
|
|
local tokensfp = io.open(args[2], "wb")
|
|
for word, value in pairs(words) do
|
|
tokensfp:write("0, OP_", value, ", 0, \"", word, "\",\n")
|
|
end
|
|
tokensfp:close()
|
|
|
|
local rulesfp = io.open(args[3], "wb")
|
|
rulesfp:write("operation\n")
|
|
for index, insn in ipairs(insns) do
|
|
if index == 1 then
|
|
rulesfp:write("\t:")
|
|
else
|
|
rulesfp:write("\t|")
|
|
end
|
|
for _, word in ipairs(insn.syntax) do
|
|
if word.word then
|
|
rulesfp:write(" OP_", word.word)
|
|
end
|
|
if word.punct then
|
|
rulesfp:write(" ", word.punct)
|
|
end
|
|
if word.token then
|
|
rulesfp:write(" ", word.token)
|
|
end
|
|
end
|
|
rulesfp:write("\n")
|
|
|
|
rulesfp:write("\t{ emit4(", string.format("0x%08x", insn.fields.value))
|
|
for wordindex, word in ipairs(insn.syntax) do
|
|
if word.token then
|
|
for _, alias in ipairs(word) do
|
|
local f = insn.fields[alias]
|
|
if not f then
|
|
error("reference to field "..alias.." which doesn't exist")
|
|
end
|
|
local mask = math.pow(2, f.size) - 1
|
|
rulesfp:write(" | (($", wordindex,
|
|
" & ", string.format("0x%x", mask), ") << ", f.pos, ")")
|
|
end
|
|
end
|
|
end
|
|
rulesfp:write("); }\n")
|
|
end
|
|
rulesfp:close()
|
|
|