mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-11 07:11:39 +00:00
LunaCON: add -ftrapv, -fwrapv opts, providing trapping/wrapping arith semantics.
Currently only for multiplication. git-svn-id: https://svn.eduke32.com/eduke32@3949 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
75204d782a
commit
adbd6394fc
2 changed files with 179 additions and 144 deletions
|
@ -19,6 +19,10 @@ local con_lang = require("con_lang")
|
|||
local byte = require("string").byte
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local band, bor = bit.band, bit.bor
|
||||
local rshift = bit.rshift
|
||||
local tobit = bit.tobit
|
||||
|
||||
local assert = assert
|
||||
local error = error
|
||||
local ipairs = ipairs
|
||||
|
@ -182,7 +186,7 @@ local D = { true }
|
|||
|
||||
|
||||
local function krandand(mask)
|
||||
return bit.band(ffiC.krand(), mask)
|
||||
return band(ffiC.krand(), mask)
|
||||
end
|
||||
|
||||
local function check_allnumbers(...)
|
||||
|
@ -325,7 +329,7 @@ local int16_st = ffi.typeof "struct { int16_t s; }"
|
|||
|
||||
-- Get INT32_MIN for the following constant; passing 0x80000000 would be
|
||||
-- out of the range for an int32_t and thus undefined behavior!
|
||||
local SHOOT_HARDCODED_ZVEL = bit.tobit(0x80000000)
|
||||
local SHOOT_HARDCODED_ZVEL = tobit(0x80000000)
|
||||
|
||||
function _shoot(i, tilenum, zvel)
|
||||
check_sprite_idx(i)
|
||||
|
@ -337,19 +341,19 @@ function _shoot(i, tilenum, zvel)
|
|||
return CF.A_ShootWithZvel(i, tilenum, zvel)
|
||||
end
|
||||
|
||||
local BADGUY_MASK = bit.bor(con_lang.SFLAG.SFLAG_HARDCODED_BADGUY, con_lang.SFLAG.SFLAG_BADGUY)
|
||||
local BADGUY_MASK = bor(con_lang.SFLAG.SFLAG_HARDCODED_BADGUY, con_lang.SFLAG.SFLAG_BADGUY)
|
||||
|
||||
function isenemytile(tilenum)
|
||||
return (bit.band(ffiC.g_tile[tilenum]._flags, BADGUY_MASK)~=0)
|
||||
return (band(ffiC.g_tile[tilenum]._flags, BADGUY_MASK)~=0)
|
||||
end
|
||||
|
||||
-- The 'rotatesprite' wrapper used by the CON commands.
|
||||
function _rotspr(x, y, zoom, ang, tilenum, shade, pal, orientation,
|
||||
alpha, cx1, cy1, cx2, cy2)
|
||||
check_tile_idx(tilenum)
|
||||
orientation = bit.band(orientation, 4095) -- ROTATESPRITE_MAX-1
|
||||
orientation = band(orientation, 4095) -- ROTATESPRITE_MAX-1
|
||||
|
||||
if (bit.band(orientation, 2048) == 0) then -- ROTATESPRITE_FULL16
|
||||
if (band(orientation, 2048) == 0) then -- ROTATESPRITE_FULL16
|
||||
x = 65536*x
|
||||
y = 65536*y
|
||||
end
|
||||
|
@ -363,7 +367,7 @@ function _rotspr(x, y, zoom, ang, tilenum, shade, pal, orientation,
|
|||
error(format("invalid coordinates (%.03f, %.03f)", x, y), 2)
|
||||
end
|
||||
|
||||
ffiC.rotatesprite_(x, y, zoom, ang, tilenum, shade, pal, bit.bor(2,orientation),
|
||||
ffiC.rotatesprite_(x, y, zoom, ang, tilenum, shade, pal, bor(2,orientation),
|
||||
alpha, cx1, cy1, cx2, cy2)
|
||||
end
|
||||
|
||||
|
@ -372,7 +376,7 @@ function rotatesprite(x, y, zoom, ang, tilenum, shade, pal, orientation,
|
|||
alpha, cx1, cy1, cx2, cy2)
|
||||
-- Disallow <<16 coordinates from Lunatic. They only unnecessarily increase
|
||||
-- complexity; you already have more precision in the FP number fraction.
|
||||
if (bit.band(orientation, 2048) ~= 0) then
|
||||
if (band(orientation, 2048) ~= 0) then
|
||||
error('left-shift-by-16 coordinates forbidden', 2)
|
||||
end
|
||||
|
||||
|
@ -402,13 +406,11 @@ function _gettimedate()
|
|||
return v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]
|
||||
end
|
||||
|
||||
local rshift = bit.rshift
|
||||
|
||||
function rnd(x)
|
||||
return (rshift(ffiC.krand(), 8) >= (255-x))
|
||||
end
|
||||
|
||||
-- Legacy operators
|
||||
--- Legacy operators ---
|
||||
|
||||
function _rand(x)
|
||||
return rshift(ffiC.krand()*(x+1), 16)
|
||||
|
@ -418,19 +420,40 @@ function _displayrand(x)
|
|||
return rshift(math.random(0, 32767)*(x+1), 15)
|
||||
end
|
||||
|
||||
function _div(a,b)
|
||||
if (b==0) then
|
||||
error("divide by zero", 2)
|
||||
end
|
||||
-- NOTE: don't confuse with math.modf!
|
||||
return (a - math.fmod(a,b))/b
|
||||
end
|
||||
do
|
||||
-- Arithmetic operations --
|
||||
local INT32_MIN = tobit(0x80000000)
|
||||
local INT32_MAX = tobit(0x7fffffff)
|
||||
|
||||
function _mod(a,b)
|
||||
if (b==0) then
|
||||
error("mod by zero", 2)
|
||||
-- Trapping multiplication.
|
||||
function _mulTR(a,b)
|
||||
local c = a*b
|
||||
if (not (c >= INT32_MIN and c <= INT32_MAX)) then
|
||||
error("overflow in multiplication", 2)
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
-- Wrapping multiplication.
|
||||
function _mulWR(a,b)
|
||||
-- XXX: problematic if a*b in an infinity or NaN.
|
||||
return tobit(a*b)
|
||||
end
|
||||
|
||||
function _div(a,b)
|
||||
if (b==0) then
|
||||
error("divide by zero", 2)
|
||||
end
|
||||
-- NOTE: don't confuse with math.modf!
|
||||
return (a - math.fmod(a,b))/b
|
||||
end
|
||||
|
||||
function _mod(a,b)
|
||||
if (b==0) then
|
||||
error("mod by zero", 2)
|
||||
end
|
||||
return (math.fmod(a,b))
|
||||
end
|
||||
return (math.fmod(a,b))
|
||||
end
|
||||
|
||||
-- Sect_ToggleInterpolation() clone
|
||||
|
@ -860,7 +883,7 @@ local function text_check_common(tilenum, orientation)
|
|||
error("invalid base tile number "..tilenum, 3)
|
||||
end
|
||||
|
||||
return bit.band(orientation, 4095) -- ROTATESPRITE_MAX-1
|
||||
return band(orientation, 4095) -- ROTATESPRITE_MAX-1
|
||||
end
|
||||
|
||||
function _gametext(tilenum, x, y, qnum, shade, pal, orientation,
|
||||
|
@ -1076,7 +1099,7 @@ function _addinventory(ps, inv, amount, i)
|
|||
if (inv == ffiC.GET_ACCESS) then
|
||||
local pal = sprite[i].pal
|
||||
if (PALBITS[pal]) then
|
||||
ps.got_access = bit.bor(ps.got_access, PALBITS[pal])
|
||||
ps.got_access = bor(ps.got_access, PALBITS[pal])
|
||||
end
|
||||
else
|
||||
if (ICONS[inv]) then
|
||||
|
@ -1097,7 +1120,7 @@ function _checkpinventory(ps, inv, amount, i)
|
|||
return ps.inv_amount[inv] ~= ps.max_shield_amount
|
||||
elseif (inv==ffiC.GET_ACCESS) then
|
||||
local palbit = PALBITS[sprite[i].pal]
|
||||
return palbit and (bit.band(ps.got_access, palbit)~=0)
|
||||
return palbit and (band(ps.got_access, palbit)~=0)
|
||||
else
|
||||
return ps.inv_amount[inv] ~= amount
|
||||
end
|
||||
|
@ -1161,7 +1184,7 @@ function _addphealth(ps, aci, hlthadd)
|
|||
j = math.max(j, 0)
|
||||
|
||||
if (hlthadd > 0) then
|
||||
local qmaxhlth = bit.rshift(ps.max_player_health, 2)
|
||||
local qmaxhlth = rshift(ps.max_player_health, 2)
|
||||
if (j-hlthadd < qmaxhlth and j >= qmaxhlth) then
|
||||
-- XXX: DUKE_GOTHEALTHATLOW
|
||||
_sound(aci, 229)
|
||||
|
@ -1221,9 +1244,9 @@ function _operate(spritenum)
|
|||
if (tag.sector >= 0) then
|
||||
local sect = sector[tag.sector]
|
||||
local lotag = sect.lotag
|
||||
if (NEAROP[bit.band(lotag, 0xff)]) then
|
||||
if (NEAROP[band(lotag, 0xff)]) then
|
||||
if (lotag==23 or sect.floorz==sect.ceilingz) then
|
||||
if (bit.band(lotag, 32768+16384) == 0) then
|
||||
if (band(lotag, 32768+16384) == 0) then
|
||||
for j in spritesofsect(tag.sector) do
|
||||
if (ispic(sprite[j].picnum, "ACTIVATOR")) then
|
||||
return
|
||||
|
@ -1300,7 +1323,7 @@ end
|
|||
|
||||
-- "otherspr" is either player or holoduke sprite
|
||||
local function A_FurthestVisiblePoint(aci, otherspr)
|
||||
if (bit.band(actor[aci]:get_count(), 63) ~= 0) then
|
||||
if (band(actor[aci]:get_count(), 63) ~= 0) then
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -1496,8 +1519,8 @@ end
|
|||
|
||||
-- G_GetAngleDelta(a1, a2)
|
||||
function _angdiff(a1, a2)
|
||||
a1 = bit.band(a1, 2047)
|
||||
a2 = bit.band(a2, 2047)
|
||||
a1 = band(a1, 2047)
|
||||
a2 = band(a2, 2047)
|
||||
-- a1 and a2 are in [0, 2047]
|
||||
if (abs(a2-a1) < 1024) then
|
||||
return abs(a2-a1)
|
||||
|
@ -1535,7 +1558,6 @@ function _ifp(flags, pli, aci)
|
|||
local l = flags
|
||||
local ps = player[pli]
|
||||
local vel = sprite[ps.i].xvel
|
||||
local band = bit.band
|
||||
|
||||
if (band(l,8)~=0 and ps.on_ground and holdskey(pli, "CROUCH")) then
|
||||
return true
|
||||
|
@ -1591,7 +1613,7 @@ function _checkspace(sectnum, floorp)
|
|||
local sect = sector[sectnum]
|
||||
local picnum = floorp and sect.floorpicnum or sect.ceilingpicnum
|
||||
local stat = floorp and sect.floorstat or sect.ceilingstat
|
||||
return bit.band(stat,1)~=0 and sect.ceilingpal == 0 and
|
||||
return band(stat,1)~=0 and sect.ceilingpal == 0 and
|
||||
(ispic(picnum, "MOONSKY1") or ispic(picnum, "BIGORBIT1"))
|
||||
end
|
||||
|
||||
|
@ -1745,7 +1767,7 @@ function _startlevel(volume, level)
|
|||
ffiC.ud.display_bonus_screen = 0
|
||||
|
||||
-- TODO_MP
|
||||
player[0].gm = bit.bor(player[0].gm, 0x00000008) -- MODE_EOL
|
||||
player[0].gm = bor(player[0].gm, 0x00000008) -- MODE_EOL
|
||||
end
|
||||
|
||||
function _setaspect(viewingrange, yxaspect)
|
||||
|
|
|
@ -124,10 +124,109 @@ local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=false,
|
|||
-- Code generation and output options.
|
||||
local g_cgopt = { ["no"]=false, ["debug-lineinfo"]=false, ["gendir"]=nil,
|
||||
["cache-sap"]=false, ["error-nostate"]=true,
|
||||
["playervar"]=true, }
|
||||
["playervar"]=true, ["trapv"]=false, ["wrapv"]=false, }
|
||||
|
||||
local function csapp() return g_cgopt["cache-sap"] end
|
||||
|
||||
local function handle_cmdline_arg(str)
|
||||
if (str:sub(1,1)=="-") then
|
||||
if (#str == 1) then
|
||||
printf("Warning: input from stdin not supported")
|
||||
else
|
||||
local ok = false
|
||||
local kind = str:sub(2,2)
|
||||
|
||||
-- -W(no-)*: warnings
|
||||
if (kind=="W" and #str >= 3) then
|
||||
local val = true
|
||||
local warnstr = str:sub(3)
|
||||
|
||||
if (warnstr == "all") then
|
||||
-- Enable all warnings.
|
||||
for wopt in pairs(g_warn) do
|
||||
g_warn[wopt] = true
|
||||
end
|
||||
ok = true
|
||||
else
|
||||
-- Enable or disable a particular warning.
|
||||
if (warnstr:sub(1,3)=="no-") then
|
||||
val = false
|
||||
warnstr = warnstr:sub(4)
|
||||
end
|
||||
|
||||
if (type(g_warn[warnstr])=="boolean") then
|
||||
g_warn[warnstr] = val
|
||||
ok = true
|
||||
end
|
||||
end
|
||||
|
||||
-- -fno* special handling
|
||||
elseif (str:sub(2)=="fno") then
|
||||
-- Disable printing code entirely.
|
||||
g_cgopt["no"] = true
|
||||
ok = true
|
||||
elseif (str:sub(2)=="fno=onlycheck") then
|
||||
-- Disable printing code, only do syntax check of gen'd code.
|
||||
g_cgopt["no"] = "onlycheck"
|
||||
ok = true
|
||||
|
||||
-- -fgendir=<directory>: specify directory for generated code
|
||||
elseif (str:sub(2,9)=="fgendir=" and #str >= 10) then
|
||||
g_cgopt["gendir"] = str:sub(10)
|
||||
ok = true
|
||||
|
||||
-- -f(no-)*: code generation options
|
||||
elseif (kind=="f" and #str >= 3) then
|
||||
local val = true
|
||||
local cgstr = str:sub(3)
|
||||
|
||||
if (cgstr:sub(1,3)=="no-") then
|
||||
val = false
|
||||
cgstr = cgstr:sub(4)
|
||||
end
|
||||
|
||||
if (type(g_cgopt[cgstr])=="boolean") then
|
||||
g_cgopt[cgstr] = val
|
||||
ok = true
|
||||
end
|
||||
|
||||
-- -I<directory>: default search directory (only ONCE, not search path)
|
||||
elseif (kind=="I" and #str >= 3) then
|
||||
g_defaultDir = str:sub(3)
|
||||
ok = true
|
||||
end
|
||||
|
||||
if (not ffi and not ok) then
|
||||
printf("Warning: Unrecognized option %s", str)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle command line arguments. Has to happen before pattern construction,
|
||||
-- because some of them depend on codegen options (specifically, -ftrapv,
|
||||
-- -fwrapv).
|
||||
if (string.dump) then
|
||||
-- running stand-alone
|
||||
local i = 1
|
||||
while (arg[i]) do
|
||||
if (handle_cmdline_arg(arg[i])) then
|
||||
table.remove(arg, i) -- remove processed cmdline arg
|
||||
else
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
else
|
||||
-- running from EDuke32
|
||||
local i=0
|
||||
while (ffiC.g_argv[i] ~= nil) do
|
||||
handle_cmdline_arg(ffi.string(ffiC.g_argv[i]))
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
|
||||
-- Stack with *true* on top if the innermost block is a "whilevar*n".
|
||||
local g_isWhile = {}
|
||||
-- Sequence number of 'while' statements, used to implement CON "break" inside
|
||||
|
@ -199,6 +298,7 @@ local function new_initial_codetab()
|
|||
"local print, printf = print, printf",
|
||||
|
||||
-- Cache a couple of often-used functions.
|
||||
"local _div, _mod, _mulTR, _mulWR = _con._div, _con._mod, _con._mulTR, _con._mulWR",
|
||||
"local _band, _bor, _bxor = _bit.band, _bit.bor, _bit.bxor",
|
||||
"local _lsh, _rsh, _arsh = _bit.lshift, _bit.rshift, _bit.arshift",
|
||||
|
||||
|
@ -1616,20 +1716,25 @@ local Op = {}
|
|||
Op.var = cmd(W,D)
|
||||
Op.varvar = cmd(W,R)
|
||||
|
||||
function Op.varf(op)
|
||||
if (#op <= 2) then
|
||||
return Op.var / ("%1=%1"..op.."%2")
|
||||
function Op.var_common(thecmd, defaultop, trapop, wrapop)
|
||||
local theop =
|
||||
g_cgopt["trapv"] and trapop or
|
||||
g_cgopt["wrapv"] and wrapop or
|
||||
assert(defaultop)
|
||||
|
||||
if (#theop <= 2) then
|
||||
return thecmd / ("%1=%1"..theop.."%2")
|
||||
else
|
||||
return Op.var / ("%1="..op.."(%1,%2)")
|
||||
return thecmd / ("%1="..theop.."(%1,%2)")
|
||||
end
|
||||
end
|
||||
|
||||
function Op.varvarf(op)
|
||||
if (#op <= 2) then
|
||||
return Op.varvar / ("%1=%1"..op.."%2")
|
||||
else
|
||||
return Op.varvar / ("%1="..op.."(%1,%2)")
|
||||
end
|
||||
function Op.varf(...)
|
||||
return Op.var_common(Op.var, ...)
|
||||
end
|
||||
|
||||
function Op.varvarf(...)
|
||||
return Op.var_common(Op.varvar, ...)
|
||||
end
|
||||
|
||||
-- Allow nesting... stuff like
|
||||
|
@ -2085,9 +2190,9 @@ local Cinner = {
|
|||
-- NOTE the space after the minus sign so that e.g. "subvar x -1" won't get
|
||||
-- translated to "x=x--1" (-- being the Lua line comment start).
|
||||
subvarvar = Op.varvarf "- ",
|
||||
mulvarvar = Op.varvarf "*",
|
||||
divvarvar = Op.varvarf "_con._div",
|
||||
modvarvar = Op.varvarf "_con._mod",
|
||||
mulvarvar = Op.varvarf("*", "_mulTR", "_mulWR"),
|
||||
divvarvar = Op.varvarf "_div",
|
||||
modvarvar = Op.varvarf "_mod",
|
||||
andvarvar = Op.varvarf "_band",
|
||||
orvarvar = Op.varvarf "_bor",
|
||||
xorvarvar = Op.varvarf "_bxor",
|
||||
|
@ -2096,9 +2201,9 @@ local Cinner = {
|
|||
setvar = Op.var / "%1=%2",
|
||||
addvar = Op.varf "+",
|
||||
subvar = Op.varf "- ",
|
||||
mulvar = Op.varf "*",
|
||||
divvar = Op.varf "_con._div",
|
||||
modvar = Op.varf "_con._mod",
|
||||
mulvar = Op.varf("*", "_mulTR", "_mulWR"),
|
||||
divvar = Op.varf "_div",
|
||||
modvar = Op.varf "_mod",
|
||||
andvar = Op.varf "_band",
|
||||
orvar = Op.varf "_bor",
|
||||
xorvar = Op.varf "_bxor",
|
||||
|
@ -3474,83 +3579,6 @@ function parse(contents) -- local
|
|||
g_newlineidxs = newlineidxs
|
||||
end
|
||||
|
||||
local function handle_cmdline_arg(str)
|
||||
if (str:sub(1,1)=="-") then
|
||||
if (#str == 1) then
|
||||
printf("Warning: input from stdin not supported")
|
||||
else
|
||||
local ok = false
|
||||
local kind = str:sub(2,2)
|
||||
|
||||
-- -W(no-)*: warnings
|
||||
if (kind=="W" and #str >= 3) then
|
||||
local val = true
|
||||
local warnstr = str:sub(3)
|
||||
|
||||
if (warnstr == "all") then
|
||||
-- Enable all warnings.
|
||||
for wopt in pairs(g_warn) do
|
||||
g_warn[wopt] = true
|
||||
end
|
||||
ok = true
|
||||
else
|
||||
-- Enable or disable a particular warning.
|
||||
if (warnstr:sub(1,3)=="no-") then
|
||||
val = false
|
||||
warnstr = warnstr:sub(4)
|
||||
end
|
||||
|
||||
if (type(g_warn[warnstr])=="boolean") then
|
||||
g_warn[warnstr] = val
|
||||
ok = true
|
||||
end
|
||||
end
|
||||
|
||||
-- -fno* special handling
|
||||
elseif (str:sub(2)=="fno") then
|
||||
-- Disable printing code entirely.
|
||||
g_cgopt["no"] = true
|
||||
ok = true
|
||||
elseif (str:sub(2)=="fno=onlycheck") then
|
||||
-- Disable printing code, only do syntax check of gen'd code.
|
||||
g_cgopt["no"] = "onlycheck"
|
||||
ok = true
|
||||
|
||||
-- -fgendir=<directory>: specify directory for generated code
|
||||
elseif (str:sub(2,9)=="fgendir=" and #str >= 10) then
|
||||
g_cgopt["gendir"] = str:sub(10)
|
||||
ok = true
|
||||
|
||||
-- -f(no-)*: code generation options
|
||||
elseif (kind=="f" and #str >= 3) then
|
||||
local val = true
|
||||
local cgstr = str:sub(3)
|
||||
|
||||
if (cgstr:sub(1,3)=="no-") then
|
||||
val = false
|
||||
cgstr = cgstr:sub(4)
|
||||
end
|
||||
|
||||
if (type(g_cgopt[cgstr])=="boolean") then
|
||||
g_cgopt[cgstr] = val
|
||||
ok = true
|
||||
end
|
||||
|
||||
-- -I<directory>: default search directory (only ONCE, not search path)
|
||||
elseif (kind=="I" and #str >= 3) then
|
||||
g_defaultDir = str:sub(3)
|
||||
ok = true
|
||||
end
|
||||
|
||||
if (not ffi and not ok) then
|
||||
printf("Warning: Unrecognized option %s", str)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function reset_all()
|
||||
reset_labels()
|
||||
reset_gamedata()
|
||||
|
@ -3568,16 +3596,6 @@ if (string.dump) then
|
|||
-- running stand-alone
|
||||
local io = require("io")
|
||||
|
||||
-- Handle command-line arguments and remove those that have been processed.
|
||||
local i = 1
|
||||
while (arg[i]) do
|
||||
if (handle_cmdline_arg(arg[i])) then
|
||||
table.remove(arg, i)
|
||||
else
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
|
||||
local function compile(filename)
|
||||
reset_all()
|
||||
|
||||
|
@ -3654,13 +3672,8 @@ if (string.dump) then
|
|||
end
|
||||
end
|
||||
else
|
||||
local i=0
|
||||
while (ffiC.g_argv[i] ~= nil) do
|
||||
handle_cmdline_arg(ffi.string(ffiC.g_argv[i]))
|
||||
i = i+1
|
||||
end
|
||||
|
||||
-- running from EDuke32
|
||||
|
||||
function compile(filenames)
|
||||
-- TODO: pathsearchmode=1 set in G_CompileScripts
|
||||
|
||||
|
|
Loading…
Reference in a new issue