-- LunaCON CON to Lunatic translator -- requires LPeg, http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html local lpeg = require("lpeg") if (not _EDUKE32_LUNATIC) then require("strict") end -- I think that the "too many pending calls/choices" is unavoidable in general. -- This limit is of course still arbitrary, but writing long if/else cascades -- in CON isn't pretty either (though sometimes necessary because nested switches -- don't work?) -- See also: http://lua-users.org/lists/lua-l/2010-03/msg00086.html lpeg.setmaxstack(1024); local Pat, Set, Range, Var = lpeg.P, lpeg.S, lpeg.R, lpeg.V local POS = lpeg.Cp ---- All keywords pattern -- needed for CON syntax local con = require("con_lang") local function match_until(matchsp, untilsp) -- (!untilsp matchsp)* in PEG -- sp: string or pattern return (matchsp - Pat(untilsp))^0 end local function printf(fmt, ...) print(string.format(fmt, ...)) end ---=== semantic action functions ===--- local inf = 1/0 local NaN = 0/0 -- Last keyword position, for error diagnosis. local g_lastkwpos = nil local g_lastkw = nil local g_badids = {} -- maps bad id strings to 'true' local g_recurslevel = -1 -- 0: base CON file, >0 included local g_filename = "???" local g_directory = "" -- with trailing slash if not empty local g_numerrors = 0 -- How many 'if' statements are following immediately each other, -- needed to cope with CONs dangling-else resolution local g_ifseqlevel = 0 ---=== Code generation ===--- local g_file_code = {} -- a [filename]=gencode_table mapping local g_curcode = nil -- a table of string pieces or other "gencode" tables local g_actor_code = {} -- [actornum]=gencode_table local g_event_code = {} -- [eventnum]=gencode_table local g_loadactor_code = {} -- [actornum]=gencode_table local function getlinecol(pos) end -- fwd-decl local function reset_codegen() g_file_code, g_curcode = {}, nil g_actor_code, g_event_code, g_loadactor_code = {}, {}, {} end local function addcode(x) g_curcode[#g_curcode+1] = x end local function addcodef(fmt, ...) addcode(string.format(fmt, ...)) end local function on_actor_end(usertype, tsamm, codetab) -- TODO: strength, action, move, moveflags local tilenum = tsamm[1] -- usertype is non-nil only for 'useractor' addcodef("gameactor(%d,\nfunction(actori, playeri, dist)", tilenum) g_actor_code[tilenum] = codetab addcode(codetab) addcode("end)") end ---------- local function linecolstr(pos) local line, col = getlinecol(pos) return string.format("%d:%d", line, col) end local function perrprintf(pos, fmt, ...) printf("%s %s: error: "..fmt, g_filename, linecolstr(pos), ...) end local function errprintf(fmt, ...) if (g_lastkwpos) then perrprintf(g_lastkwpos, fmt, ...) else printf("%s ???: error: "..fmt, g_filename, ...) end g_numerrors = g_numerrors+1 end local function pwarnprintf(pos, fmt, ...) printf("%s %s: warning: "..fmt, g_filename, linecolstr(pos), ...) end local function warnprintf(fmt, ...) if (g_lastkwpos) then pwarnprintf(g_lastkwpos, fmt, ...) else printf("%s ???: warning: "..fmt, g_filename, ...) end end local function parse_number(pos, numstr) local num = tonumber(numstr) if (num < -0x80000000 or num > 0xffffffff) then perrprintf(pos, "number %s out of the range of a 32-bit integer", numstr) num = NaN elseif (num >= 0x80000000 and numstr:sub(1,2):lower()~="0x") then pwarnprintf(pos, "number %s converted to a negative one", numstr) num = num-0x100000000 end return num end local LABEL = { MOVE=2, AI=3, ACTION=5, [2]="move", [3]="ai", [5]="action" } local MOVE_NO = {0,0} local ACTION_NO = {0,0,0,0,0} local LABEL_NO = { [2]=MOVE_NO, [3]={ACTION_NO, MOVE_NO, 0}, [5]=ACTION_NO } -- will contain: -- * scalar numbers: `define'd values -- * tables of length 2, 3, 5: move, ai, action definitions (respectively) -- - move: { hvel , vvel } -- - ai: { action