1 ----------------------------------------------------
2 local _setfenv
, _ipairs
, _pairs
, _select
, _tostr
= setfenv
, ipairs
, pairs
, select
, tostring
3 local _loadstr
, _pcall
, _type
= loadstring
, pcall
, type
4 local _open
, _write
, _err
, _rerouteoutput
= io
.open
, io
.write, io
.stderr
, io
.output
5 local _flush
, _filelines
= io
.flush, io
.lines
6 local _match
, _gmatch
, _fmt
, _upper
= string.match
, string.gmatch
, string.format, string.upper
7 local _gsub
, _sub
, _byte
= string.gsub, string.sub
, string.byte
8 local _exec
, _getenv
= os
.execute, os
.getenv
9 local _cat
= table.concat
11 local _filesep
= _match(_getenv("OS"),"Windows") and "\\" or "/"
13 local function _existfile(n
)
15 if not f
then return false end
20 local function _readfile(n
)
22 local ctnt
= f
:read("*a")
26 local function _writefile(n
, c
)
27 local f
= _open(n
, "w")
32 local function _strlines(self
)
33 local me
, ix
= self
[1], self
[2]
35 if ix
> n
then return nil end
37 local c
= _byte(me
, ix2
)
38 while c
~= 13 and c
~= 10 and ix2
<= n
do
43 while ix3
<= n
and _byte(me
, ix3
) == 13 do ix3
= ix3
+ 1 end
44 if ix3
<= n
and _byte(me
, ix3
) == 10 then ix3
= ix3
+ 1 end
46 return _sub(me
, ix
, ix2
- 1)
48 local function strlines(str
) return _strlines
,{str
,1} end
50 local function stream_valid_input(s
)
51 if type(s
) == "string" then return _existfile(s
) end
52 if type(s
) == "table" and s
.type == "file" then return _existfile(s
.value
) end
53 if type(s
) == "table" and s
.type == "string" then return true end
56 local function _stream_filename(s
)
57 if type(s
) == "string" then return s
or "" end
58 if type(s
) == "table" and s
.type == "file" then return s
.value
or "" end
59 if type(s
) == "table" and s
.type == "string" then return s
.file
or "" end
63 local function stream_lines(s
)
64 if type(s
) == "string" then return _filelines(s
) end
65 if type(s
) == "table" and s
.type == "file" then return _filelines(s
.value
) end
66 if type(s
) == "table" and s
.type == "string" then return strlines(s
.value
) end
69 local function _nil_output_stream()
71 close
= function(self
) end,
72 write = function(self
, c
) end,
75 local function _file_output_stream(s
)
78 close
= function(self
) self
._f
:close() end,
79 write = function(self
, c
) self
._f
:write(c
) end,
82 local function _string_output_stream(t
)
87 _flush
= function(self
)
88 if #self
._tt
== 0 then return end
90 t
[#t
+ 1] = _cat(self
._tt
, "")
93 close
= function(self
) self
:_flush(); self
._ref
.value
= _cat(self
._t
, "") end,
94 write = function(self
, c
)
97 if #self
._tt
>= 32 then self
:_flush() end
101 local function stream_output(s
)
102 if type(s
) == "string" then return _file_output_stream(s
) end
103 if type(s
) == "table" and s
.type == "file" then return _file_output_stream(s
.value
) end
104 if type(s
) == "table" and s
.type == "string" then return _string_output_stream(s
) end
107 local myprint
,myprintf
= print,printf
108 local print_outstream
= nil
109 function _printwrite(s
)
110 if print_outstream
then
111 print_outstream
:write(s
)
116 function print( ... )
117 local n
= _select( "#",... )
119 _printwrite( _tostr(_select(i
,...)) )
120 if i
<n
then _printwrite( "\t" ) end
124 function printf( ... )
126 _printwrite( _fmt( ... ) )
130 function readfile( s
)
131 return _readfile(FILEDIR
.._gsub(s
, "[\\/]", _filesep
))
133 function runfile( s
,... )
134 local d
= readfile( s
)
135 local code
= _loadstr( d
,s
)
139 local function run(script
, srcfile
, params
)
140 local fun
,msg
= _loadstr(script
)
143 _err
:write( msg
,"\n" )
145 doneok
,msg
= _pcall( fun
, srcfile
, params
)
147 _err
:write( msg
,"\n" )
155 local function varprefix(vardelim
)
156 return _gsub(vardelim
,".","%%%0")
158 local function varpattern(vardelim
)
159 return varprefix(vardelim
).."(%b())"
161 local function preidpattern()
164 local function idpattern()
165 return "([%a_][%w_]*)"
167 local function varpattern2(vardelim
)
168 return varprefix(vardelim
)..idpattern()
171 local function getidents(s
,vardelim
)
173 local nonempty
= false
174 local ignore
= {["not"]=true,["or"]=true,["and"]=true,["false"]=true,["true"]=true,["nil"]=true}
175 for id
in _gmatch(s
, varpattern2(vardelim
)) do
176 if not ignore
[id
] then
181 for b
in _gmatch(s
, varpattern(vardelim
)) do
182 local bb
= _sub(b
, 2,-2)
183 for id
in _gmatch(bb
, preidpattern()) do
184 if _match(id
, "^"..idpattern().."$") and not ignore
[id
] then
190 return nonempty
and result
192 local function identsparam(idents
)
194 for k
,v
in _pairs(idents
) do
195 result
= result
..k
.."="..k
..","
197 return "{"..result
.."}"
199 local function generateXYZPrint(vardelim
)
201 local _gsub, _sub, _loadstr, _setfenv, _tostr, _err = string.gsub, string.sub
202 local _loadstr, _setfenv, _tostr, _err = loadstring, setfenv, tostring, io.stderr
203 function _xyz_print( line,vars )
204 line= _gsub(line,"%s",vars)
205 line= _gsub(line,"(%s)",
207 local fx,gx= _loadstr("return ".._sub(x,2,-2))
209 _err:write( "error in pattern "..pattern.." : "..gx.."\n" )
217 ]],varpattern2(vardelim
),varpattern(vardelim
))
220 local function main(SELF
, IN
, OUT
, SEP
, PARAMS
)
221 if _type(IN
) == "string" then IN
= {type = "file", value
= IN
} end
222 if _type(OUT
) == "string" then OUT
= {type = "file", value
= OUT
} end
223 if not stream_valid_input(IN
) then
225 usage: %s IN [OUT=IN.out] [SEP=|] [PARAMS=]
226 convert lua interface file IN into C source code file OUT
227 lua script lines start with separator SEP, defaults to |
228 PARAMS may denote a file containing further data
232 FILEPOS
= _stream_filename(IN
)
233 if not (_type(OUT
) == "table" and OUT
.type == "string") then
234 local OUTN
= _stream_filename(OUT
)
235 if OUTN
== "" or _sub(OUTN
, 1, 1) == "." then
236 if FILEPOS
== "" then
237 OUT
= {type = "string"}
239 if OUTN
== "" then OUTN
= ".out" end
240 OUT
= {type = "file", value
= _match(FILEPOS
, "^(.-)%.[^.\\/]*$") .. OUTN
}
244 assert(FILEPOS
== "" or FILEPOS
~= _stream_filename(OUT
))
245 local prefix
= SEP
or "|"
247 if _match(FILEPOS
, "[/\\]" ) then
248 FILEDIR
= _match(FILEPOS
, [[^(.-[/\])[^/\]*$]] )
251 local prefixlist
= {}
252 for line
in stream_lines(IN
) do
254 local x
= _match(line
, "^#/.-/emblua(.-)$")
256 --title line with settings
257 for var
,val
in _gmatch(x
, idpattern().."=(%S+)") do
258 if _upper(var
) == "LUAPREFIX" then
259 prefixlist
[#prefixlist
+ 1] = val
261 _err
:write( "unknown setup variable "..var
.." in line 1" )
268 if #prefixlist
== 0 then prefixlist
= {prefix
} end
272 for k
,prefix
in _ipairs(prefixlist
) do
273 printf("running pass %d of %d, prefix %s",k
,#prefixlist
,prefix
)
274 local paramsfile
= PARAMS
275 outputfile
= #prefixlist
== k
and OUT
or {type="string"}
279 local currentscript
= ""
280 local needvarreplfun
= false
281 local printing
= false
283 for line
in stream_lines(inputfile
) do
286 local x
= _match(line
, "^#/.-/emblua(.-)$")
292 if not handled
and not printing
then
293 local pfx
, var
, val
= _match(line
, "^%s*(%S+)%s*%-%-%s*"..idpattern().."%s*=%s*(%S+)%s*$" )
294 if pfx
and pfx
== prefix
then
295 if _upper(var
) == "VARDELIM" then
297 elseif _upper(var
)=="CMTDELIM" then
299 elseif _upper(var
)=="DUMPSCRIPT" then
306 local firstword
, remainder
= _match(line
, "^%s*(%S+)(.*)$")
307 if not handled
and firstword
==prefix
then
309 currentscript
= currentscript
..remainder
.."\n"
314 local idents
= getidents(line
,vardelim
)
315 local quoteline
= _fmt("%q",line
)
319 local parms
= identsparam(idents
)
320 newline
= "_xyz_print("..quoteline
..","..parms
..")"
322 newline
= "print("..quoteline
..")"
324 currentscript
= currentscript
..newline
.."\n"
328 if needvarreplfun
then
329 currentscript
= generateXYZPrint(vardelim
).."local SRCFILE,PARAMS=...;\n"..currentscript
334 if paramsfile
and paramsfile
~= "" then
335 local paramsfile
= readfile(paramsfile
)
337 local paramsdatafnc
= _loadstr("return "..paramsfile
)
338 if paramsdatafnc
then
339 local paramsdata
= paramsdatafnc()
340 if _type(paramsdata
) == "table" then
347 if dumpscript
and _stream_filename(outputfile
) ~= "" then
348 _writefile(_stream_filename(outputfile
)..".script",currentscript
)
351 print_outstream
= stream_output(outputfile
)
352 if k
== #prefixlist
then
353 if _stream_filename(IN
) ~= "" then
354 printf(comment
.." DO NOT EDIT. this file was autogenerated from %s",_stream_filename(IN
))
356 print(comment
.." DO NOT EDIT. this file was autogenerated")
359 --print( currentscript )
360 run(currentscript
, paramsfile
, params
)
362 print_outstream
:close()
363 print_outstream
= nil
364 inputfile
= outputfile
369 return main(arg
[0], ...)