lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I've written a simple preprocessor in Lua, to preprocess Lua scripts.
Basically, it implements #include and #define, so I don't have to define
a large number of global variables for commonly used constants. (By the
way, will I really save anything doing it this way? I assume numerical
constants are more efficient than global variables.)

Anyway, I decided to build it into a function I can include with my
program to preprocess and then byte-compile source files, so I don't
have to package a seperate luac binary. My problem is that string.dump()
doesn't seem to be generating valid byte-code. If I execute the function
returned from loadstring(), I get the expected results. If I dump the
code my preprocessor generates, and run it through either luac or
luac.lua, I get the expected results.

The byte-code string.dump() generates seems to contain a copy of the
text of the source passed to loadstring. I notice that neither luac or
luac.lua seem to do this.

The source is attached. To test it, call it like this:

lua preprocess.lua infile.lua outfile

My platform is win32, in case that matters.

Thanks, Philip Bock
--[[
	This preprocessor was written for Lua scripts. It's not a C preprocessor,
	because it only understands the #include, #define, and #undef directives.
	No other features are supported, not even comments. No error checking
	is performed, so incorrect directives will result in mangled output.
]]

-- Main parser
function preprocess(infile, outfile, macros)
	for line in infile:lines() do
		-- Perfrom macro substitution
		for mname, mval in pairs(macros) do
			line = string.gsub(line, "([^%w_])"..mname.."([^%w_])", function (x, y) return x..mval..y end)
			line = string.gsub(line, "^"..mname.."$", mval)
			line = string.gsub(line, "^"..mname.."[^%w_]", function (x) return mval..x end)
			line = string.gsub(line, "[^%w_]"..mname.."$", function (x) return x..mval end)
		end

		-- Check for directives
		local _, _, directive, arguments = string.find(line, "^%#(%w+)%s+(.+)$")

		if (directive == nil) then -- No directives
			outfile:write(line.."\n")
		elseif (directive == "define") then
			local _, _, macro_name, macro_val = string.find(arguments, "^(%S+)%s+(%S+)")
			if (macro_val) then
				macros[macro_name] = macro_val
			else
				macros[macro_name] = 0
			end
		elseif (directive == "undef") then
			macros[arguments] = nil
		elseif (directive == "include") then
			local _, _, includefile = string.find(arguments, "^%p(.+)%p$")
			preprocess(assert(io.open(includefile, "r"), "Error opening #include file "..includefile), outfile, macros)
		else
			error("Unknown directive "..directive)
		end
	end
end

function luac(infilename, outfilename)
	local macros = {}
	local infile = assert(io.open(infilename, "r"))
	local outfile = assert(io.open(outfilename, "wb"))
	local tempfile = io.tmpfile()

	preprocess(infile, tempfile, macros)
	tempfile:seek("set")

	func = loadstring(tempfile:read("*a"))

	func()

	outfile:write(string.dump(func))

	tempfile:close()
	infile:close()
	outfile:close()
end

luac(arg[1], arg[2])