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], "w") for word, value in pairs(words) do definitionsfp:write("%token OP_", tostring(value), " /* ", word, " */\n") end definitionsfp:close() local tokensfp = io.open(args[2], "w") for word, value in pairs(words) do tokensfp:write("0, OP_", value, ", 0, \"", word, "\",\n") end tokensfp:close() local rulesfp = io.open(args[3], "w") 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()