192 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Lua
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			192 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], "w")
 | |
| 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], "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()
 | |
| 
 |