-- Source/VM code formatter for Lua -- Nick Trout 3/7/01 -- Merges Lua VM code with Lua source so we can see whats going on -- (see usage below) -- $Header: /Tools/build/vmmerge.lua 7 28/08/01 12:06 Nick $ usage = [[ Usage: lua -f vmmerge.lua ...options... Options are: --file --fmt , valid formats are: merge - merge source and VM instructions (default) html - generate HTML merged output --nl, no line numbers (default is on) * Make sure you have luac in your path * eg. lua -f vmmerge.lua --file my.lua --fmt merge ]] function process_args(args) -- get args set by user in command line local ta,i = {},1 while i "..luacout assert( os.execute(cmd)==0, "luac failed to execute properly" ) local llines = read_lines(luacout) return { src=slines,luac=llines } end function parse(args,lines) -- parse luac output into table mapping lines to code -- lmap = { [line nb] = { "context", vmline, "code" } ... } local cmap = { ["function"]={}, ["main"]={} } local context = {""} for i=1,table.getn(lines.luac) do local line=lines.luac[i] -- get line -- get context from: -- main <0:@b.lua> (4 instructions/16 bytes at 002F3200) -- function <2:@b.lua> (7 instructions/28 bytes at 002F3318) string.gsub(line,"(%w+)%s<.-:(%d+)>.+", function (c,lnb) context[1]=c end ) local lmap = cmap[context[1]] or {"none"} -- swap to appropriate context -- format is: [] ; string.gsub(line,"%s+(%d+)%s+%[(%d+)%]%s+(%w.*)", function (vmlnb,slnb,code) local n = tonumber(slnb) -- create a map for list line if one doesnt exist if not lmap[n] then lmap[n]={} end -- we store { linenb, "code" } table.insert(lmap[n], {vmlnb+0,code} ) end ) end lines.cmap = cmap -- remember our info end -- FS/E - file start/end -- SLS/E - source line start/end -- ALS/E - assembler line start/end -- contextS/E - context start/end fmttxt = { merge = { ALS=" ",END="\n\n", context={ main={S="-------- { main\n",E="-------- } main"} } }, html = { replace={ ["<"]="<",[">"]=">" }, context={ main={S="",E=""} }, FS="
",FE="
", SLS="",SLE="", ALS=" ", END="
" } } function replace(txt,reps) if not reps then return txt end for s,r in reps do txt = string.gsub(txt,s,r) end return txt end function out(...) local s="" for i=1,arg.n do if arg[i] then s=s..arg[i] end end if s~="" then print(s) end end -- merge all of the vm for a source line (yuck) function mergevm(args,lines) local fmt=fmttxt[args.format] local ctxtorder = {"function","main"} local ins = function(t,o) if o then table.insert(t,o) end end -- merged will contain a list of lines with a single list of formatted vm code local merged = {} for ci=1,table.getn(ctxtorder) do local ctxt = lines.cmap[ctxtorder[ci]] -- get context code local cfmt = fmt.context[ctxtorder[ci]] -- get formatting info for lnb=1,table.getn(lines.src) do -- go over every line local li = ctxt[lnb] if li then -- this context has vm code for this line if not merged[lnb] then merged[lnb]={} end local m=merged[lnb] if cfmt and cfmt.S then ins(m,cfmt.S) end for iv=1,table.getn(li) do local vmlnb,ass = li[iv][1],li[iv][2] if not args.nolines then ins(m,string.format("%8d",vmlnb)) end ins(m,fmt.ALS) ins(m,replace(ass,fmt.replace)) ins(m,fmt.ALE) ins(m,"\n") -- look for "END" op if string.sub(ass,1,4)=="END " then ins(m,fmt.END) end end if cfmt and cfmt.E then ins(m,cfmt.E) end end end end lines.vmcode = merged end function mergecode(args,lines) mergevm(args,lines) local fmt=fmttxt[args.format] local ctxtorder = {"function","main"} out(fmt.FS) for i=1,table.getn(lines.src) do local li = lines.src[i] if li and li~="" then -- we have src for this line out(fmt.SLS,replace(li,fmt.replace),fmt.SLE) -- write source local vm = lines.vmcode[i] -- find vm code for this line if vm then -- we have vm code for this source line for iv=1,table.getn(vm) do -- write code for each context io.write(vm[iv]) end io.write("\n") end end end out(fmt.FE) end function main() local args = process_args(arg) local lines = get_files(args) parse(args,lines) mergecode(args,lines) end main()