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])