Lunatic translator: struct read access.

git-svn-id: https://svn.eduke32.com/eduke32@3433 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-01-24 20:03:10 +00:00
parent faae812293
commit 91047d6d90
4 changed files with 440 additions and 113 deletions

View file

@ -302,74 +302,382 @@ wdata_members =
"int32_t flashcolor",
}
ActorLabels =
{
x = "sprite[%s].x",
y = "sprite[%s].y",
z = "sprite[%s].z",
cstat = "sprite[%s].cstat",
picnum = "sprite[%s].picnum",
shade = "sprite[%s].shade",
pal = "sprite[%s].pal",
clipdist = "sprite[%s].clipdist",
-- filler = "sprite[%s].filler",
detail = "sprite[%s].filler",
xrepeat = "sprite[%s].xrepeat",
yrepeat = "sprite[%s].yrepeat",
xoffset = "sprite[%s].xoffset",
yoffset = "sprite[%s].yoffset",
sectnum = "sprite[%s].sectnum",
statnum = "sprite[%s].statnum",
ang = "sprite[%s].ang",
owner = "sprite[%s].owner",
xvel = "sprite[%s].xvel",
yvel = "sprite[%s].yvel",
zvel = "sprite[%s].zvel",
lotag = "sprite[%s].lotag",
hitag = "sprite[%s].hitag",
extra = "sprite[%s].extra",
local SP = function(memb) return "sprite[%s]"..memb end
local AC = function(memb) return "actor[%s]"..memb end
local SX = function(memb) return "spriteext[%s]"..memb end
-- Generate code to access a signed member as unsigned.
local function s2u(label)
return "(_bit.band("..label.."+65536),65535)"
end
local function S2U(label)
return { s2u(label), label }
end
local ActorLabels = {
x = SP".x",
y = SP".y",
z = SP".z",
cstat = SP".cstat",
picnum = SP".picnum",
shade = SP".shade",
pal = SP".pal",
clipdist = SP".clipdist",
-- filler = SP".filler",
detail = SP".filler", -- NAME
xrepeat = SP".xrepeat",
yrepeat = SP".yrepeat",
xoffset = SP".xoffset",
yoffset = SP".yoffset",
sectnum = SP".sectnum",
statnum = SP".statnum",
ang = SP".ang",
owner = SP".owner",
xvel = SP".xvel",
yvel = SP".yvel",
zvel = SP".zvel",
lotag = SP".lotag",
hitag = SP".hitag",
extra = SP".extra",
-- { get, set }
-- Read access differs from write:
ulotag = { "(sprite[%s].lotag+65536)%65535", "sprite[%s].lotag" },
uhitag = { "(sprite[%s].hitag+65536)%65535", "sprite[%s].hitag" },
ulotag = S2U(SP".lotag"),
uhitag = S2U(SP".hitag"),
-- ActorExtra labels...
htcgg = "actor[%s].cgg",
htpicnum = "actor[%s].picnum",
htang = "actor[%s].ang",
htextra = "actor[%s].extra",
htowner = "actor[%s].owner",
htmovflag = "actor[%s].movflag",
httempang = "actor[%s].tempang",
htactorstayput = "actor[%s].actorstayput",
htdispicnum = "actor[%s].dispicnum",
httimetosleep = "actor[%s].timetosleep",
htfloorz = "actor[%s].floorz",
htceilingz = "actor[%s].ceilingz",
htlastvx = "actor[%s].lastvx",
htlastvy = "actor[%s].lastvy",
htbposx = "actor[%s].bpos.x",
htbposy = "actor[%s].bpos.y",
htbposz = "actor[%s].bpos.z",
htcgg = AC".cgg",
htpicnum = AC".picnum",
htang = AC".ang",
htextra = AC".extra",
htowner = AC".owner",
htmovflag = AC".movflag",
httempang = AC".tempang",
htactorstayput = AC".actorstayput",
htdispicnum = AC".dispicnum",
httimetosleep = AC".timetosleep",
htfloorz = AC".floorz",
htceilingz = AC".ceilingz",
htlastvx = AC".lastvx",
htlastvy = AC".lastvy",
htbposx = AC".bpos.x",
htbposy = AC".bpos.y",
htbposz = AC".bpos.z",
-- Read access differs from write, write not available:
htg_t = { "actor[%s].get_t_data(%s)" },
htflags = "actor[%s].flags",
htg_t = { AC":get_t_data(%s)" },
htflags = AC".flags",
-- model flags
angoff = "spriteext[%s].angoff",
pitch = "spriteext[%s].pitch",
roll = "spriteext[%s].roll",
mdxoff = "spriteext[%s].xoff",
mdyoff = "spriteext[%s].yoff",
mdzoff = "spriteext[%s].zoff",
mdflags = "spriteext[%s].mdflags",
xpanning = "spriteext[%s].xpanning",
ypanning = "spriteext[%s].ypanning",
angoff = SX".angoff",
pitch = SX".pitch",
roll = SX".roll",
mdxoff = SX".xoff",
mdyoff = SX".yoff",
mdzoff = SX".zoff",
mdflags = SX".mdflags",
xpanning = SX".xpanning",
ypanning = SX".ypanning",
alpha = { "_math.floor(spriteext[%s].alpha*255)" },
}
local PL = function(memb) return "player[%s]"..memb end
local PlayerLabels = {
posx = PL".pos.x",
posy = PL".pos.y",
posz = PL".pos.z",
oposx = PL".opos.x",
oposy = PL".opos.y",
oposz = PL".opos.z",
posxv = PL".vel.x", -- NAME
posyv = PL".vel.y",
poszv = PL".vel.z",
-- NOTE: no access for .npos
bobposx = PL".bobposx",
bobposy = PL".bobposy",
truefz = PL".truefz",
truecz = PL".truecz",
player_par = PL".player_par",
randomflamex = PL".randomflamex",
exitx = PL".exitx",
exity = PL".exity",
runspeed = PL".runspeed",
max_player_health = PL".max_player_health",
max_shield_amount = PL".max_shield_amount",
autostep = PL".autostep",
autostep_sbw = PL".autostep_sbw",
interface_toggle_flag = PL".interface_toggle_flag",
-- NOTE: *bombControl etc. are accessed by gamevars in CON
max_actors_killed = PL".max_actors_killed",
actors_killed = PL".actors_killed",
-- NOTE the special case:
gotweapon = { "("..PL":have_weapon(%s) and 1 or 0)" },
zoom = PL".zoom",
loogiex = {},
loogiey = {},
sbs = PL".sbs",
sound_pitch = PL".sound_pitch",
ang = PL".ang",
oang = PL".oang",
angvel = PL".angvel",
cursectnum = PL".cursectnum",
look_ang = PL".look_ang",
last_extra = PL".last_extra",
subweapon = PL".subweapon",
max_ammo_amount = { PL":get_max_ammo_amount(%s)" },
ammo_amount = { PL":get_ammo_amount(%s)" },
-- NOTE: no direct access for .inv_amount (but see end)
wackedbyactor = PL".wackedbyactor",
pyoff = PL".pyoff",
opyoff = PL".opyoff",
horiz = PL".horiz",
horizoff = PL".horizoff",
ohoriz = PL".ohoriz",
ohorizoff = PL".ohorizoff",
newowner = { PL".newowner" },
jumping_counter = PL".jumping_counter",
airleft = PL".airleft",
fta = PL".fta",
ftq = PL".ftq",
access_wallnum = PL".access_wallnum",
access_spritenum = PL".access_spritenum",
got_access = PL".got_access",
weapon_ang = PL".weapon_ang",
visibility = PL".visibility",
somethingonplayer = PL".somethingonplayer",
on_crane = PL".on_crane",
i = { PL".i" },
one_parallax_sectnum = { PL".one_parallax_sectnum" },
random_club_frame = PL".random_club_frame",
one_eighty_count = PL".one_eighty_count",
dummyplayersprite = { PL".dummyplayersprite" },
extra_extra8 = PL".extra_extra8",
actorsqu = PL".actorsqu",
timebeforeexit = PL".timebeforeexit",
customexitsound = { PL".customexitsound" },
last_pissed_time = PL".last_pissed_time",
weaprecs = { PL".weaprecs" },
weapon_sway = PL".weapon_sway",
crack_time = PL".crack_time",
bobcounter = PL".bobcounter",
-- NOTE: no access for .orotscrnang
rotscrnang = PL".rotscrnang",
dead_flag = PL".dead_flag",
holoduke_on = PL".holoduke_on",
pycount = PL".pycount",
transporter_hold = PL".transporter_hold",
max_secret_rooms = PL".max_secret_rooms",
secret_rooms = PL".secret_rooms",
frag = PL".frag",
fraggedself = PL".fraggedself",
quick_kick = PL".quick_kick",
last_quick_kick = PL".last_quick_kick",
return_to_center = PL".return_to_center",
reloading = PL".reloading",
weapreccnt = PL".weapreccnt",
aim_mode = PL".aim_mode",
auto_aim = PL".auto_aim",
weaponswitch = PL".weaponswitch",
movement_lock = PL".movement_lock",
team = PL".team",
tipincs = PL".tipincs",
hbomb_hold_delay = PL".hbomb_hold_delay",
frag_ps = PL".frag_ps",
kickback_pic = PL".kickback_pic",
gm = PL".gm",
on_warping_sector = PL".on_warping_sector",
footprintcount = PL".footprintcount",
hurt_delay = PL".hurt_delay",
hbomb_on = PL".hbomb_on",
jumping_toggle = PL".jumping_toggle",
rapid_fire_hold = PL".rapid_fire_hold",
on_ground = PL".on_ground",
inven_icon = PL".inven_icon",
buttonpalette = PL".buttonpalette",
over_shoulder_on = PL".over_shoulder_on",
show_empty_weapon = PL".show_empty_weapon",
jetpack_on = PL".jetpack_on",
spritebridge = PL".spritebridge",
lastrandomspot = PL".lastrandomspot",
scuba_on = PL".scuba_on",
footprintpal = PL".footprintpal",
heat_on = PL".heat_on",
invdisptime = PL".invdisptime",
holster_weapon = PL".holster_weapon",
falling_counter = PL".falling_counter",
footprintshade = PL".footprintshade",
refresh_inventory = PL".refresh_inventory",
last_full_weapon = PL".last_full_weapon",
walking_snd_toggle = PL".walking_snd_toggle",
palookup = PL".palookup",
hard_landing = PL".hard_landing",
fist_incs = PL".fist_incs",
toggle_key_flag = PL".toggle_key_flag",
knuckle_incs = PL".knuckle_incs",
knee_incs = PL".knee_incs",
access_incs = PL".access_incs",
numloogs = PL".numloogs",
loogcnt = PL".loogcnt",
scream_voice = PL".scream_voice",
last_weapon = PL".last_weapon",
cheat_phase = PL".cheat_phase",
weapon_pos = PL".weapon_pos",
wantweaponfire = PL".wantweaponfire",
curr_weapon = { PL".curr_weapon" },
palette = PL".palette",
-- NOTE the special case:
pals = {},
pals_time = PL".pals.f",
name = {},
-- Access to .inv_amount
steroids_amount = { PL":get_inv_amount(0)", },
shield_amount = { PL":get_inv_amount(1)", },
scuba_amount = { PL":get_inv_amount(2)", },
holoduke_amount = { PL":get_inv_amount(3)", },
jetpack_amount = { PL":get_inv_amount(4)", },
-- 5: dummy
-- 6: no "access_amount"
heat_amount = { PL":get_inv_amount(7)" },
-- 8: dummy
firstaid_amount = { PL":get_inv_amount(9)" },
boot_amount = { PL":get_inv_amount(10)" },
}
local SEC = function(memb) return "sector[%s]"..memb end
local SECRO = function(memb) return { "sector[%s]"..memb } end
local SectorLabels = {
wallptr = SECRO".wallptr",
wallnum = SECRO".wallnum",
ceilingz = SEC".ceilingz",
floorz = SEC".floorz",
ceilingstat = SEC".ceilingstat",
floorstat = SEC".floorstat",
-- CEILING
ceilingpicnum = SECRO".ceilingpicnum",
ceilingslope = SEC".ceilingheinum", -- NAME
ceilingshade = SEC".ceilingshade",
ceilingpal = SEC".ceilingpal",
ceilingxpanning = SEC".ceilingxpanning",
ceilingypanning = SEC".ceilingypanning",
-- FLOOR
floorpicnum = SECRO".floorpicnum",
floorslope = SEC".floorheinum", -- NAME
floorshade = SEC".floorshade",
floorpal = SEC".floorpal",
floorxpanning = SEC".floorxpanning",
floorypanning = SEC".floorypanning",
visibility = SEC".visibility",
filler = SEC".filler",
alignto = SEC".filler", -- NAME
lotag = SEC".lotag",
hitag = SEC".hitag",
extra = SEC".extra",
ceilingbunch = {},
floorbunch = {},
ulotag = S2U(SEC".lotag"),
uhitag = S2U(SEC".hitag"),
}
local WAL = function(memb) return "wall[%s]"..memb end
local WALRO = function(memb) return { "wall[%s]"..memb } end
local WallLabels = {
x = WAL".x",
y = WAL".y",
point2 = WALRO".point2",
nextwall = WALRO".nextwall",
nextsector = WALRO".nextsector",
cstat = WAL".cstat",
picnum = WALRO".picnum",
overpicnum = WALRO".overpicnum",
shade = WAL".shade",
pal = WAL".pal",
xrepeat = WAL".xrepeat",
yrepeat = WAL".yrepeat",
xpanning = WAL".xpanning",
ypanning = WAL".ypanning",
lotag = WAL".lotag",
hitag = WAL".hitag",
extra = WAL".extra",
ulotag = S2U(WAL".lotag"),
uhitag = S2U(WAL".hitag"),
}
StructAccessCode =
{
sector = SectorLabels,
wall = WallLabels,
sprite = ActorLabels,
player = PlayerLabels,
}
-- NOTE: These MUST be in reverse lexicographical order!
-- Per CON syntax, valid identifiers names are disjunct from keywords,

View file

@ -281,10 +281,6 @@ end
--- Helper functions (might be exported later) ---
local function have_weapon(ps, weap)
return (bit.band(ps.gotweapon, bit.lshift(1, weap)) ~= 0)
end
local function have_ammo_at_max(ps, weap)
return (ps:get_ammo_amount(weap) >= ps:get_max_ammo_amount(weap))
end
@ -301,7 +297,7 @@ end
local function P_AddWeaponAmmoCommon(ps, weap, amount)
P_AddAmmo(ps, weap, amount)
if (ps.curr_weapon==ffiC.KNEE_WEAPON and have_weapon(ps, weap)) then
if (ps.curr_weapon==ffiC.KNEE_WEAPON and ps:have_weapon(weap)) then
ffiC.P_AddWeaponMaybeSwitch(ps, weap);
end
end
@ -597,7 +593,7 @@ function _addweapon(ps, weap, amount)
error("Invalid weapon ID "..weap, 2)
end
if (not have_weapon(ps, weap)) then
if (not ps:have_weapon(weap)) then
ffiC.P_AddWeaponMaybeSwitch(ps, weap);
elseif (have_ammo_at_max(ps, weap)) then
return true

View file

@ -227,7 +227,7 @@ local DUKEPLAYER_STRUCT = [[
int8_t numloogs, loogcnt, scream_voice;
int8_t last_weapon, cheat_phase, weapon_pos, wantweaponfire;
int8_t const curr_weapon;
const int8_t curr_weapon;
uint8_t palette;
palette_t pals;
@ -866,6 +866,10 @@ local player_mt = {
stomp = con._pstomp,
have_weapon = function(p, weap)
return (bit.band(p.gotweapon, bit.lshift(1, weap)) ~= 0)
end,
-- XXX: is the correct spelling "whack"?
wack = function(p, no_return_to_center)
p.horiz = p.horiz + 64

View file

@ -390,7 +390,7 @@ local function reset_labels()
g_badids = {}
-- NO is also a valid `move', `ai' or `action', but they are handled
-- separately in lookup_composite().
-- separately in lookup.composite().
g_labeldef = {
NO = 0,
-- NOTE: these are read-only gamevars in C-CON
@ -416,7 +416,10 @@ local function reset_labels()
end
end
local function lookup_defined_label(pos, maybe_minus_str, identifier)
-- Table of functions doing various lookups (label, gamevar, ...)
local lookup = {}
function lookup.defined_label(pos, maybe_minus_str, identifier)
local num = g_labeldef[identifier]
if (num == nil) then
@ -471,7 +474,7 @@ local function check_composite_literal(labeltype, pos, num)
end
end
local function lookup_composite(labeltype, pos, identifier)
function lookup.composite(labeltype, pos, identifier)
if (identifier=="NO") then
-- NO is a special case and is valid for move, action and ai,
-- being the same as passing a literal 0.
@ -858,7 +861,7 @@ function Cmd.gamevar(identifier, initval, flags)
end
end
local function lookup_gamevar(identifier, writable)
function lookup.gamevar(identifier, writable)
local gv = g_gamevar[identifier]
if (gv == nil) then
@ -880,7 +883,7 @@ end
local function maybe_gamevar_Cmt(subj, pos, identifier)
if (g_gamevar[identifier]) then
return true, lookup_gamevar(identifier)
return true, lookup.gamevar(identifier)
end
end
@ -1099,41 +1102,57 @@ local getperxvarcmd = -- get<actor/player>var[<idx>].<member> <<var>>
local setperxvarcmd = -- set<actor/player>var[<idx>].<<member>> <var>
arraypat * singlememberpat * sp1 * tok.rvar
-- Function generating code for a struct read/write access.
local function StructAccess(Structname, writep, index, membertab)
assert(type(membertab)=="table")
local member, parm2 = membertab[1], membertab[2]
assert(member ~= nil)
-- Look up array+member name first, e.g. "spriteext[%s].angoff".
local armembcode = conl.StructAccessCode[Structname][member]
if (armembcode == nil) then
errprintf("invalid %s member `.%s'", Structname, member)
return "_MEMBINVALID"
end
if (type(armembcode)=="table") then
-- Read and write accesses differ.
armembcode = armembcode[writep and 2 or 1]
if (armembcode==nil) then
errprintf("%s access to %s[].%s is not available",
writep and "write" or "read", Structname, member)
return "_MEMBNOACCESS"
end
end
local _, numparms = armembcode:gsub("%%s", "%%s", 2)
if (#membertab ~= numparms) then
local nums = { "one", "two" }
errprintf("%s[].%s has %s parameter%s, but %s given", Structname,
member, nums[numparms], numparms==1 and "" or "s",
nums[#membertab])
return "_MEMBINVPARM"
end
return format(armembcode, index, parm2)
end
function lookup.array_expr(writep, structname, index, membertab)
if (conl.StructAccessCode[structname] == nil) then
-- warnprintf("gamearray access: NYI")
return "_NYI"
end
return StructAccess(structname, writep, index, membertab)
end
local Access =
{
-- <writtenp>: whether the actor is written to.
actor = function(writtenp, index, membertab)
assert(type(membertab)=="table")
local member, parm2 = membertab[1], membertab[2]
assert(member ~= nil)
-- Look up array+member name first, e.g. "spriteext[%s].angoff".
local armembcode = conl.ActorLabels[member]
if (armembcode == nil) then
errprintf("invalid CON actor member `%s'", member)
return "_MEMBINVALID"
end
if (type(armembcode)=="table") then
-- Read and write accesses differ.
armembcode = armembcode[writtenp and 2 or 1]
if (armembcode==nil) then
assert(writtenp)
errprintf("write access to CON actor[].%s is not available", member)
return "_MEMBRO"
end
end
local _, numparms = armembcode:gsub("%%s", "%%s", 2)
if (#membertab ~= numparms) then
local one = numparms==1
errprintf("CON actor[].%s has %s parameter%s, but %d given", member,
one and "one" or "two", one and "" or "s", #membertab)
return "_MEMBINVPARM"
end
return format(armembcode, index, parm2)
end,
sector = function(...) return StructAccess("sector", ...) end,
wall = function(...) return StructAccess("wall", ...) end,
xsprite = function(...) return StructAccess("sprite", ...) end,
player = function(...) return StructAccess("player", ...) end,
}
local function GetStructCmd(accessfunc)
@ -1206,11 +1225,11 @@ local Cinner = {
/ handle.state,
--- 1. get*, set*
getactor = GetStructCmd(Access.actor),
getactor = GetStructCmd(Access.xsprite),
getinput = getstructcmd,
getplayer = getstructcmd,
getplayer = GetStructCmd(Access.player),
getprojectile = getstructcmd,
getsector = getstructcmd,
getsector = GetStructCmd(Access.sector),
getthisprojectile = getstructcmd,
gettspr = getstructcmd,
-- NOTE: {get,set}userdef is the only struct that can be accessed without
@ -1222,7 +1241,7 @@ local Cinner = {
-- We disallow them unless CONs in the wild crop up that actually used
-- these.
getuserdef = (arraypat + sp1)/{} * singlememberpat * sp1 * tok.wvar,
getwall = getstructcmd,
getwall = GetStructCmd(Access.wall),
getactorvar = getperxvarcmd,
getplayervar = getperxvarcmd,
@ -2040,31 +2059,31 @@ local Grammar = Pat{
-- However, this conflicts with bad-identifiers, so it should be checked last.
-- This would also handle LNGA2's "00000000h", though would give problems with
-- e.g. "800h" (hex 0x800 or decimal 800?).
t_define = (POS() * lpeg.C(tok.maybe_minus) * tok.identifier / lookup_defined_label) + tok.number,
t_define = (POS() * lpeg.C(tok.maybe_minus) * tok.identifier / lookup.defined_label) + tok.number,
-- Defines and constants can take the place of vars that are only read.
-- XXX: now, when tok.rvar fails, the tok.define failure message is printed.
t_rvar = Var("t_botharrayexp") / function() --[[warnprintf("t_rvar: array exprs NYI")--]] return "_NYIVAR" end
+ lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define,
t_rvar = Var("t_botharrayexp") + lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define,
-- For written-to vars, only (non-parm2) array exprs and writable gamevars
-- are permitted. NOTE: C-CON doesn't support inline array exprs here.
t_wvar = Var("t_singlearrayexp") / function() errprintf("t_wvar: array exprs NYI") return "_NYIVAR" end
+ (tok.identifier / function(id) return lookup_gamevar(id, true) end),
+ (tok.identifier / function(id) return lookup.gamevar(id, true) end),
t_move =
POS()*tok.identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end +
POS()*tok.identifier / function(...) return lookup.composite(LABEL.MOVE, ...) end +
POS()*tok.number / function(...) return check_composite_literal(LABEL.MOVE, ...) end,
t_ai =
POS()*tok.identifier / function(...) return lookup_composite(LABEL.AI, ...) end +
POS()*tok.identifier / function(...) return lookup.composite(LABEL.AI, ...) end +
POS()*tok.number / function(...) return check_composite_literal(LABEL.AI, ...) end,
t_action =
POS()*tok.identifier / function(...) return lookup_composite(LABEL.ACTION, ...) end +
POS()*tok.identifier / function(...) return lookup.composite(LABEL.ACTION, ...) end +
POS()*tok.number / function(...) return check_composite_literal(LABEL.ACTION, ...) end,
-- New-style inline arrays and structures.
t_botharrayexp = tok.identifier * arraypat * bothmemberpat^-1,
t_botharrayexp = tok.identifier * arraypat * bothmemberpat^-1
/ function(...) return lookup.array_expr(false, ...) end,
t_singlearrayexp = tok.identifier * arraypat * singlememberpat^-1,
-- SWITCH