Lunatic translator: fix dangling else and add a test file, tweak warnings

git-svn-id: https://svn.eduke32.com/eduke32@2756 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-06-13 23:13:26 +00:00
parent ec56b8e2d9
commit f2789ab90f
2 changed files with 52 additions and 16 deletions

View file

@ -42,9 +42,13 @@ local g_lastkw = nil
local g_badids = {} -- maps bad id strings to 'true' local g_badids = {} -- maps bad id strings to 'true'
local g_recurslevel = -1 -- 0: base CON file, >0 included local g_recurslevel = -1 -- 0: base CON file, >0 included
local g_filename = "???"
local g_directory = "" -- with trailing slash if not empty local g_directory = "" -- with trailing slash if not empty
local g_numerrors = 0 local g_numerrors = 0
local g_ifnestlevel = 0 -- needed to cope with CONs dangling-else resolution
local function getlinecol(pos) end -- fwd-decl local function getlinecol(pos) end -- fwd-decl
local function linecolstr(pos) local function linecolstr(pos)
@ -54,24 +58,30 @@ end
local function errprintf(fmt, ...) local function errprintf(fmt, ...)
if (g_lastkwpos) then if (g_lastkwpos) then
printf("%s: error: "..fmt, linecolstr(g_lastkwpos), ...) printf("%s %s: error: "..fmt, g_filename, linecolstr(g_lastkwpos), ...)
else else
printf("???: error: "..fmt, ...) printf("%s ???: error: "..fmt, g_filename, ...)
end end
g_numerrors = g_numerrors+1 g_numerrors = g_numerrors+1
end end
local function parse_number(numstr, pos) local function warnprintf(fmt, ...)
if (g_lastkwpos) then
printf("%s %s: warning: "..fmt, g_filename, linecolstr(g_lastkwpos), ...)
else
printf("%s ???: warning: "..fmt, g_filename, ...)
end
end
local function parse_number(numstr)
local num = tonumber(numstr) local num = tonumber(numstr)
-- TODO: print line number -- TODO: print line number
if (num < -0x80000000 or num > 0xffffffff) then if (num < -0x80000000 or num > 0xffffffff) then
printf("%s: warning: number %s out of the range of a 32-bit integer", errprintf("number %s out of the range of a 32-bit integer", numstr)
linecolstr(g_lastkwpos), numstr)
num = 0/0 num = 0/0
elseif (num >= 0x80000000) then elseif (num >= 0x80000000 and numstr:sub(1,2):lower()~="0x") then
printf("%s: warning: number %s converted to a negative one", warnprintf("number %s converted to a negative one", numstr)
linecolstr(g_lastkwpos), numstr)
num = num-0x100000000 num = num-0x100000000
end end
@ -126,8 +136,8 @@ local function do_define_label(identifier, idornum)
local oldnum = g_labeldef[identifier] local oldnum = g_labeldef[identifier]
if (oldnum) then if (oldnum) then
if (oldnum ~= num) then if (oldnum ~= num) then
errprintf("label \"%s\" defined with different value (old: %d, new: %d)", warnprintf("label \"%s\" not redefined with new value %d (old: %d)",
identifier, oldnum, num) identifier, num, oldnum)
end end
return return
end end
@ -173,7 +183,10 @@ else
return return
end end
local oldfilename = g_filename
g_filename = filename
parse(contents) parse(contents)
g_filename = oldfilename
end end
function cmd_include(filename) function cmd_include(filename)
@ -833,7 +846,7 @@ end
local function BadIdent(pat) local function BadIdent(pat)
local function tfunc(subj, pos, a) local function tfunc(subj, pos, a)
if (not g_badids[a]) then if (not g_badids[a]) then
printf("%s: warning: bad identifier: %s", linecolstr(pos), a) warnprintf("bad identifier: %s", a)
g_badids[a] = true g_badids[a] = true
end end
return true return true
@ -895,7 +908,7 @@ end
-- actor ORGANTIC is greeting! -- actor ORGANTIC is greeting!
local function warn_on_lonely_else(subj, pos) local function warn_on_lonely_else(subj, pos)
printf("%s: warning: found `else' with no `if'", linecolstr(pos)) warnprintf("found `else' with no `if'")
return true return true
end end
@ -953,6 +966,18 @@ local t_good_identifier = Range("AZ", "az", "__") * Range("AZ", "az", "__", "09"
local t_broken_identifier = BadIdent(-((t_number + t_good_identifier) * (sp1 + Set("[]:"))) * local t_broken_identifier = BadIdent(-((t_number + t_good_identifier) * (sp1 + Set("[]:"))) *
(alphanum + Set("_/\\*")) * (alphanum + Set("_/\\*-"))^0) (alphanum + Set("_/\\*")) * (alphanum + Set("_/\\*-"))^0)
local function begin_if_fn()
g_ifnestlevel = g_ifnestlevel+1
end
local function end_if_fn()
g_ifnestlevel = g_ifnestlevel-1
end
local function check_else_Cmt()
return (g_ifnestlevel==0) -- match an 'else' only at the outermost level
end
--- The final grammar! --- The final grammar!
local Grammar = Pat{ local Grammar = Pat{
-- The starting symbol. -- The starting symbol.
@ -992,11 +1017,10 @@ local Grammar = Pat{
default_block = sp1 * Keyw("default") * (sp0*":"*sp0 + sp1) * stmt_list_nosp_or_eps, -- * "break", default_block = sp1 * Keyw("default") * (sp0*":"*sp0 + sp1) * stmt_list_nosp_or_eps, -- * "break",
-- The "lone" if statement is tested first, so that a potential dangling "else" is if_stmt = con_if_begs/begin_if_fn * sp1 * Var("single_stmt") * Pat("")/end_if_fn
-- attached to the outermost possible "if", as done by CON * (sp1 * lpeg.Cmt(Pat("else"), check_else_Cmt) * sp1 * Var("single_stmt"))^-1,
if_stmt = con_if_begs * sp1 * Var("single_stmt") * -(sp1 * Pat("else"))
+ con_if_begs * sp1 * Var("single_stmt") * sp1 * "else" * sp1 * Var("single_stmt"),
-- TODO?: SST TC has "state ... else ends"
while_stmt = Keyw("whilevarvarn") * sp1 * t_rvar * sp1 * t_rvar * sp1 * Var("single_stmt") while_stmt = Keyw("whilevarvarn") * sp1 * t_rvar * sp1 * t_rvar * sp1 * Var("single_stmt")
+ Keyw("whilevarn") * sp1 * t_rvar * sp1 * t_define * sp1 * Var("single_stmt"), + Keyw("whilevarn") * sp1 * t_rvar * sp1 * t_define * sp1 * Var("single_stmt"),
@ -1043,6 +1067,8 @@ function parse(contents) -- local
local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors
local newlineidxs = g_newlineidxs local newlineidxs = g_newlineidxs
g_ifnestlevel = 0
-- set up new state -- set up new state
-- TODO: pack into one "parser state" table? -- TODO: pack into one "parser state" table?
g_lastkw, g_lastkwpos, g_numerrors = nil, nil, 0 g_lastkw, g_lastkwpos, g_numerrors = nil, nil, 0

View file

@ -0,0 +1,10 @@
// a dangling 'else' in CON attaches to the outermost matching 'if'
onevent EVENT_INIT
redefinequote 114 DANGLING ELSE CHECK FAILED 1
ifvare 0 1
ifvare 0 0 redefinequote 114 DANGLING ELSE CHECK FAILED 2
else
redefinequote 114 DANGLING ELSE CHECK PASSED
echo 114
endevent