diff --git a/engine/client/cd_linux.c b/engine/client/cd_linux.c index 83d2a83ac..37e8ab8bd 100644 --- a/engine/client/cd_linux.c +++ b/engine/client/cd_linux.c @@ -74,8 +74,8 @@ int CDAudio_GetAudioDiskInfo(void) if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) { - Con_DPrintf("ioctl cdromreadtochdr failed\n"); - return -1; + Con_DPrintf("ioctl cdromreadtochdr failed\n"); + return -1; } if (tochdr.cdth_trk0 < 1) @@ -196,7 +196,7 @@ qboolean CDAudio_Startup(void) cd_dev[sizeof(cd_dev) - 1] = 0; } - if ((cdfile = open(cd_dev, O_RDONLY)) == -1) + if ((cdfile = open(cd_dev, O_RDONLY|O_NONBLOCK)) == -1) { Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno); cdfile = -1; diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index ad3b7538a..69cf6f079 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -30,6 +30,7 @@ extern cvar_t cl_predict_players_latency; extern cvar_t cl_predict_players_nudge; extern cvar_t cl_lerp_players; extern cvar_t cl_lerp_maxinterval; +extern cvar_t cl_lerp_maxdistance; extern cvar_t cl_solid_players; extern cvar_t cl_item_bobbing; @@ -37,6 +38,9 @@ extern cvar_t r_rocketlight; extern cvar_t r_lightflicker; extern cvar_t r_dimlight_colour; extern cvar_t r_brightlight_colour; +extern cvar_t r_redlight_colour; +extern cvar_t r_greenlight_colour; +extern cvar_t r_bluelight_colour; extern cvar_t cl_r2g; extern cvar_t r_powerupglow; extern cvar_t v_powerupshell; @@ -3449,6 +3453,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp vec3_t move; float a1, a2; + float maxdist = cl_lerp_maxdistance.value*cl_lerp_maxdistance.value; /* seeing as how dropped packets cannot be filled in due to the reliable networking stuff, @@ -3576,7 +3581,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp } VectorSubtract(snew__origin, sold__origin, move); - if (DotProduct(move, move) > 200*200 || cos_theta < 0.707 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT)) + if (DotProduct(move, move) > maxdist || cos_theta < 0.707 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT)) { isnew = true; //disable lerping (and indirectly trails) // VectorClear(move); @@ -4005,8 +4010,8 @@ void CL_LinkPacketEntities (void) if (state->effects & EF_BRIGHTLIGHT) { - radius = max(radius,r_dimlight_colour.vec4[3]); - VectorAdd(colour, r_dimlight_colour.vec4, colour); + radius = max(radius,r_brightlight_colour.vec4[3]); + VectorAdd(colour, r_brightlight_colour.vec4, colour); } if (state->effects & EF_DIMLIGHT) { @@ -4015,24 +4020,18 @@ void CL_LinkPacketEntities (void) } if (state->effects & EF_BLUE) { - radius = max(radius,200); - colour[0] += 0.5; - colour[1] += 0.5; - colour[2] += 3.0; + radius = max(radius,r_bluelight_colour.vec4[3]); + VectorAdd(colour, r_bluelight_colour.vec4, colour); } if (state->effects & EF_RED) { - radius = max(radius,200); - colour[0] += 3.0; - colour[1] += 0.5; - colour[2] += 0.5; + radius = max(radius,r_redlight_colour.vec4[3]); + VectorAdd(colour, r_redlight_colour.vec4, colour); } if (state->effects & EF_GREEN) { - radius = max(radius,200); - colour[0] += 0.5; - colour[1] += 3.0; - colour[2] += 0.5; + radius = max(radius,r_greenlight_colour.vec4[3]); + VectorAdd(colour, r_greenlight_colour.vec4, colour); } if (radius) @@ -5235,7 +5234,7 @@ void CL_LinkPlayers (void) // spawn light flashes, even ones coming from invisible objects if (r_powerupglow.value && !(r_powerupglow.value == 2 && j == cl.playerview[0].playernum) - && (state->effects & (EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_DIMLIGHT))) + && (state->effects & (EF_BLUE|EF_RED|EF_GREEN|EF_BRIGHTLIGHT|EF_DIMLIGHT))) { vec3_t colour; float radius; @@ -5246,31 +5245,28 @@ void CL_LinkPlayers (void) if (state->effects & EF_BRIGHTLIGHT) { - radius = max(radius,400); - colour[0] += 0.2; - colour[1] += 0.1; - colour[2] += 0.05; + radius = max(radius,r_brightlight_colour.vec4[3]); + VectorAdd(colour, r_brightlight_colour.vec4, colour); } if (state->effects & EF_DIMLIGHT) { - radius = max(radius,200); - colour[0] += 2.0; - colour[1] += 1.0; - colour[2] += 0.5; + radius = max(radius,r_dimlight_colour.vec4[3]); + VectorAdd(colour, r_dimlight_colour.vec4, colour); } if (state->effects & EF_BLUE) { - radius = max(radius,200); - colour[0] += 0.5; - colour[1] += 0.5; - colour[2] += 3.0; + radius = max(radius,r_bluelight_colour.vec4[3]); + VectorAdd(colour, r_bluelight_colour.vec4, colour); } if (state->effects & EF_RED) { - radius = max(radius,200); - colour[0] += 5.0; - colour[1] += 0.5; - colour[2] += 0.5; + radius = max(radius,r_redlight_colour.vec4[3]); + VectorAdd(colour, r_redlight_colour.vec4, colour); + } + if (state->effects & EF_GREEN) + { + radius = max(radius,r_greenlight_colour.vec4[3]); + VectorAdd(colour, r_greenlight_colour.vec4, colour); } if (radius) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a17b218a6..1883dfc9a 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -105,6 +105,7 @@ cvar_t m_forward = CVARF("m_forward","1", CVAR_ARCHIVE); cvar_t m_side = CVARF("m_side","0.8", CVAR_ARCHIVE); cvar_t cl_lerp_maxinterval = CVARD("cl_lerp_maxinterval", "0.3", "Maximum interval between keyframes, in seconds. Larger values can result in entities drifting very slowly when they move sporadically."); +cvar_t cl_lerp_maxdistance = CVARD("cl_lerp_maxdistance", "200", "Maximum distance that an entity may move between snapshots without being considered as having teleported."); cvar_t cl_lerp_players = CVARD("cl_lerp_players", "0", "Set this to make other players smoother, though it may increase effective latency. Affects only QuakeWorld."); cvar_t cl_predict_players = CVARD("cl_predict_players", "1", "Clear this cvar to see ents exactly how they are on the server."); cvar_t cl_predict_players_frac = CVARD("cl_predict_players_frac", "0.9", "How much of other players to predict. Values less than 1 will help minimize overruns."); @@ -4805,6 +4806,7 @@ void CL_Init (void) Cvar_Register (&rcon_address, cl_controlgroup); Cvar_Register (&cl_lerp_maxinterval, cl_controlgroup); + Cvar_Register (&cl_lerp_maxdistance, cl_controlgroup); Cvar_Register (&cl_lerp_players, cl_controlgroup); Cvar_Register (&cl_predict_players, cl_predictiongroup); Cvar_Register (&cl_predict_players_frac, cl_predictiongroup); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 88ddc902c..e6f0ea687 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3908,6 +3908,35 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut strcpy (cl.model_name[nummodels], str); if (*str != '*' && strcmp(str, "null")) //not inline models! CL_CheckOrEnqueDownloadFile(str, NULL, ((nummodels==1)?DLLF_REQUIRED|DLLF_ALLOWWEB:0)); + + //qw has a special network protocol for spikes. + if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl")) + cl_spikeindex = nummodels; + if (!strcmp(cl.model_name[nummodels],"progs/player.mdl")) + cl_playerindex = nummodels; +#ifdef HAVE_LEGACY + if (*cl.model_name_vwep[0] && !strcmp(cl.model_name[nummodels],cl.model_name_vwep[0]) && cl_playerindex == -1) + cl_playerindex = nummodels; +#endif + if (!strcmp(cl.model_name[nummodels],"progs/h_player.mdl")) + cl_h_playerindex = nummodels; + if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl")) + cl_flagindex = nummodels; + + //rocket to grenade + if (!strcmp(cl.model_name[nummodels],"progs/missile.mdl")) + cl_rocketindex = nummodels; + if (!strcmp(cl.model_name[nummodels],"progs/grenade.mdl")) + cl_grenadeindex = nummodels; + + //cl_gibfilter + if (!strcmp(cl.model_name[nummodels],"progs/gib1.mdl")) + cl_gib1index = nummodels; + if (!strcmp(cl.model_name[nummodels],"progs/gib2.mdl")) + cl_gib2index = nummodels; + if (!strcmp(cl.model_name[nummodels],"progs/gib3.mdl")) + cl_gib3index = nummodels; + Mod_TouchModel (str); } @@ -4099,7 +4128,10 @@ static void CLNQ_ParseClientdata (void) CL_SetStatInt(0, STAT_ITEMS, MSG_ReadLong()); pl->onground = (bits & SU_ONGROUND) != 0; -// cl.inwater = (bits & SU_INWATER) != 0; + if (bits & SU_INWATER) + pl->flags |= PF_INWATER; //mostly just means smartjump should be used. + else + pl->flags &= ~PF_INWATER; if (cls.protocol_nq == CPNQ_DP5) { @@ -5246,7 +5278,7 @@ void CL_NewTranslation (int slot) s = Skin_FindName (player); COM_StripExtension(s, s, MAX_QPATH); - if (player->qwskin && !stricmp(s, player->qwskin->name)) + if (player->qwskin && stricmp(s, player->qwskin->name)) player->qwskin = NULL; player->skinid = 0; player->model = NULL; @@ -8243,9 +8275,9 @@ void CLNQ_ParseServerMessage (void) // cl.players[i].rbottomcolor = (a&0xf0)>>4; // sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor); - InfoBuf_SetValueForKey(&cl.players[i].userinfo, "topcolor", va("%i", a&0x0f)); - InfoBuf_SetValueForKey(&cl.players[i].userinfo, "bottomcolor", va("%i", (a&0xf0)>>4)); - InfoBuf_SetValueForKey(&cl.players[i].userinfo, "team", va("%i", (a&0xf0)>>4)); + InfoBuf_SetValueForKey(&cl.players[i].userinfo, "topcolor", va("%i", (a&0xf0)>>4)); + InfoBuf_SetValueForKey(&cl.players[i].userinfo, "bottomcolor", va("%i", (a&0x0f))); + InfoBuf_SetValueForKey(&cl.players[i].userinfo, "team", va("%i", (a&0x0f)+1)); CL_ProcessUserInfo (i, &cl.players[i]); // CLNQ_CheckPlayerIsSpectator(i); diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index f28e15e48..eee200b61 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -776,6 +776,7 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st { vec3_t a; int pmtype; + unsigned int flags = plstate->flags; qboolean onground = plstate->onground; qboolean jumpheld = plstate->jump_held; vec3_t vel; @@ -827,6 +828,7 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st plstate->jump_held = !!(state->u.q1.pmovetype&64); } plstate->pm_type = pmtype; + plstate->flags = flags & PF_INWATER; plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]); plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]); @@ -1383,7 +1385,19 @@ void CL_PredictMovePNum (int seat) } } if (cls.protocol == CP_NETQUAKE && nopred) + { pv->onground = to.state->onground; + if (to.state->flags & PF_INWATER) + { + pmove.watertype = FTECONTENTS_WATER; //don't really know. + pmove.waterlevel = 3; //pick one at random. + } + else + { + pmove.watertype = FTECONTENTS_EMPTY; + pmove.waterlevel = 0; + } + } else CL_CatagorizePosition(pv, to.state->origin); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 65fc1235b..1031c433e 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -222,7 +222,7 @@ qboolean scr_drawloading; float scr_disabled_time; cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); -cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n1: framerate average over a second.\n2: Slowest frame over the last second (the game will play like shit if this is significantly lower than the average).\n3: Shows the rate of the fastest frame (not very useful).\n4: Shows the current frame's timings (this depends upon timer precision).\n5: Display a graph of how long it took to render each frame, large spikes are BAD BAD BAD.\n6: Displays the standard deviation of the frame times, if its greater than 3 then something is probably badly made, or you've a virus scanner running...\n7: Framegraph, for use with slower frames."); +cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n0: Off.\n1: framerate average over a second.\n2: Show a frametimes graph (with additional timing info).\n-1: Normalized graph that focuses on the variation ignoring base times."); cvar_t show_fps_x = CVAR("show_fps_x", "-1"); cvar_t show_fps_y = CVAR("show_fps_y", "-1"); cvar_t show_clock = CVAR("cl_clock", "0"); @@ -1720,11 +1720,7 @@ void SCR_DrawFPS (void) double t; extern int fps_count; static float lastfps; - static double deviationtimes[64]; - static int deviationframe; char str[80]; - int sfps, frame; - qboolean usemsecs = false; float frametime; @@ -1741,76 +1737,11 @@ void SCR_DrawFPS (void) frametime = t - lastsystemtime; lastsystemtime = t; - sfps = show_fps.ival; - if (sfps < 0) - { - sfps = -sfps; - usemsecs = true; - } - - switch (sfps) - { - case 1: - default: - break; - case 2: // lowest FPS, highest MS encountered - if (lastfps > 1/frametime) - { - lastfps = 1/frametime; - fps_count = 0; - lastupdatetime = t; - } - break; - case 3: // highest FPS, lowest MS encountered - if (lastfps < 1/frametime) - { - lastfps = 1/frametime; - fps_count = 0; - lastupdatetime = t; - } - break; - case 4: // immediate FPS/MS - lastfps = 1/frametime; - lastupdatetime = t; - break; - case 5: - R_FrameTimeGraph(1000.0*2*frametime); - break; - case 7: - R_FrameTimeGraph(1000.0*1*frametime); - break; - case 6: - { - float mean, deviation; - deviationtimes[deviationframe++&63] = frametime*1000; - mean = 0; - for (frame = 0; frame < 64; frame++) - { - mean += deviationtimes[frame]; - } - mean /= 64; - deviation = 0; - for (frame = 0; frame < 64; frame++) - { - deviation += (deviationtimes[frame] - mean)*(deviationtimes[frame] - mean); - } - deviation /= 64; - deviation = sqrt(deviation); - - - SCR_StringXY(va("%f deviation", deviation), show_fps_x.value, show_fps_y.value-8); - } - break; - case 8: - if (cls.timedemo) - Con_Printf("%f\n", frametime); - break; - } - - if (usemsecs) - sprintf(str, "%4.1f MS", 1000.0/lastfps); - else - sprintf(str, "%3.1f FPS", lastfps); + if (show_fps.value < 0) + R_FrameTimeGraph(frametime, 0); + else if (show_fps.value > 1) + R_FrameTimeGraph(frametime, show_fps.value-1); + sprintf(str, "%3.1f FPS", lastfps); SCR_StringXY(str, show_fps_x.value, show_fps_y.value); } diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index dababa11b..19aa07c76 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -281,13 +281,16 @@ sfx_t *cl_sfx_r_exp3; cvar_t cl_expsprite = CVARFD("cl_expsprite", "1", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol)."); cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback); -static cvar_t r_explosionlight_colour = CVARF("r_explosionlight_colour", "4.0 2.0 0.5", CVAR_ARCHIVE); -static cvar_t r_explosionlight_fade = CVARF("r_explosionlight_fade", "0.784 0.92 0.48", CVAR_ARCHIVE); -cvar_t r_dimlight_colour = CVARF("r_dimlight_colour", "2.0 1.0 0.5 200", CVAR_ARCHIVE); -cvar_t r_brightlight_colour = CVARF("r_brightlight_colour", "2.0 1.0 0.5 400", CVAR_ARCHIVE); -cvar_t r_rocketlight_colour = CVARF("r_rocketlight_colour", "2.0 1.0 0.25 200", CVAR_ARCHIVE); -cvar_t r_muzzleflash_colour = CVARF("r_muzzleflash_colour", "1.5 1.3 1.0 200", CVAR_ARCHIVE); -cvar_t r_muzzleflash_fade = CVARF("r_muzzleflash_fade", "1.5 0.75 0.375 1000", CVAR_ARCHIVE); +static cvar_t r_explosionlight_colour = CVARFD("r_explosionlight_colour", "4.0 2.0 0.5", CVAR_ARCHIVE, "This controls the initial RGB values of EF_EXPLOSION effects."); +static cvar_t r_explosionlight_fade = CVARFD("r_explosionlight_fade", "0.784 0.92 0.48", CVAR_ARCHIVE, "This controls the per-second RGB decay values of EF_EXPLOSION effects."); +cvar_t r_dimlight_colour = CVARFD("r_dimlight_colour", "2.0 1.0 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_DIMLIGHT effects (used for quad+pent in vanilla quake)."); +cvar_t r_brightlight_colour = CVARFD("r_brightlight_colour", "2.0 1.0 0.5 400", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_BRIGHTLIGHT effects (unused in vanilla quake)."); +cvar_t r_redlight_colour = CVARFD("r_redlight_colour", "3.0 0.5 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_RED effects (typically used for pentagram in quakeworld)."); +cvar_t r_greenlight_colour = CVARFD("r_greenlight_colour", "0.5 3.0 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_GREEN effects (rarely used)."); +cvar_t r_bluelight_colour = CVARFD("r_bluelight_colour", "0.5 0.5 3.0 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_BLUE effects (typically used for quad-damage in quakeworld)"); +cvar_t r_rocketlight_colour = CVARFD("r_rocketlight_colour", "2.0 1.0 0.25 200", CVAR_ARCHIVE, "This controls the RGB+radius values of MF_ROCKET effects."); +cvar_t r_muzzleflash_colour = CVARFD("r_muzzleflash_colour", "1.5 1.3 1.0 200", CVAR_ARCHIVE, "This controls the initial RGB+radius of EF_MUZZLEFLASH/svc_muzzleflash effects."); +cvar_t r_muzzleflash_fade = CVARFD("r_muzzleflash_fade", "1.5 0.75 0.375 1000", CVAR_ARCHIVE, "This controls the per-second RGB+radius decay of EF_MUZZLEFLASH/svc_muzzleflash effects."); cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT); static cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0"); static cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says! @@ -424,6 +427,9 @@ void CL_InitTEnts (void) Cvar_Register (&r_muzzleflash_colour, "Temporary entity control"); Cvar_Register (&r_muzzleflash_fade, "Temporary entity control"); Cvar_Register (&r_dimlight_colour, "Temporary entity control"); + Cvar_Register (&r_redlight_colour, "Temporary entity control"); + Cvar_Register (&r_greenlight_colour, "Temporary entity control"); + Cvar_Register (&r_bluelight_colour, "Temporary entity control"); Cvar_Register (&r_brightlight_colour, "Temporary entity control"); Cvar_Register (&r_rocketlight_colour, "Temporary entity control"); Cvar_Register (&cl_legacystains, "Temporary entity control"); diff --git a/engine/client/image.c b/engine/client/image.c index 9c4dcfe39..2c274d2d4 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -2,6 +2,10 @@ #include "shader.h" #include "glquake.h" //we need some of the gl format enums +#ifdef __GNUC__ +#pragma +#endif + #ifndef HAVE_CLIENT //#define Con_Printf(f, ...) //hope you're on a littleendian machine @@ -2449,6 +2453,7 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression int ic; qboolean byteswap; + switch(fmt) { case PTI_RGB8: //yay! nothing to do. diff --git a/engine/client/m_download.c b/engine/client/m_download.c index bc10f92a9..6340bf713 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -216,8 +216,14 @@ static struct { char *url; char *prefix; - qboolean trustworthy; //trusted - char received; //says if we got a response yet or not + enum + { + SRCSTAT_UNKNOWN, //we don't know whether the user wants to allow or block this source. + SRCSTAT_DISABLED, //do NOT query this source + SRCSTAT_FAILED, //tried but failed. FIXME: add some reasons. + SRCSTAT_PENDING, //waiting for response (or queued). don't show package list yet. + SRCSTAT_OBTAINED, //we got a response. + } status; qboolean save; //written into our local file struct dl_download *curdl; //the download context } downloadablelist[32]; @@ -832,7 +838,7 @@ static qboolean PM_CheckFile(const char *filename, enum fs_relative base) return false; } -static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean trustworthy) +static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean enabled) { int i; if (!*url) @@ -849,10 +855,10 @@ static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qb } if (i == numdownloadablelists && i < countof(downloadablelist)) { - if (!strncmp(url, "https:", 6)) - downloadablelist[i].trustworthy = trustworthy; + if (enabled) + downloadablelist[i].status = SRCSTAT_PENDING; else - downloadablelist[i].trustworthy = false; //if its not a secure url, never consider it as trustworthy + downloadablelist[i].status = SRCSTAT_DISABLED; downloadablelist[i].save = save; downloadablelist[i].url = BZ_Malloc(strlen(url)+1); @@ -974,6 +980,7 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u { char *subprefix; char url[MAX_OSPATH]; + char enablement[MAX_OSPATH]; tokstart = COM_StringParse (tokstart, url, sizeof(url), false, false); tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false); if (*prefix) @@ -981,7 +988,11 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u else subprefix = com_token; - PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, (parseflags&DPF_TRUSTED)); + tokstart = COM_StringParse (tokstart, enablement, sizeof(enablement), false, false); + if (!Q_strcasecmp(enablement, "enabled") && (parseflags & DPF_ENABLED)) + PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, true); + else + PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, false); continue; } if (!strcmp(com_token, "set")) @@ -1594,7 +1605,7 @@ void PM_Shutdown(qboolean soft) downloadablelist[numdownloadablelists].curdl = NULL; } #endif - downloadablelist[numdownloadablelists].received = 0; + downloadablelist[numdownloadablelists].status = SRCSTAT_UNKNOWN; Z_Free(downloadablelist[numdownloadablelists].url); downloadablelist[numdownloadablelists].url = NULL; Z_Free(downloadablelist[numdownloadablelists].prefix); @@ -2110,12 +2121,12 @@ static void PM_ListDownloaded(struct dl_download *dl) if (f) { - downloadablelist[listidx].received = 1; + downloadablelist[listidx].status = SRCSTAT_OBTAINED; PM_ParsePackageList(f, 0, dl->url, downloadablelist[listidx].prefix); BZ_Free(f); } else - downloadablelist[listidx].received = -1; + downloadablelist[listidx].status = SRCSTAT_FAILED; if (!doautoupdate && !domanifestinstall) return; //don't spam this. @@ -2123,7 +2134,7 @@ static void PM_ListDownloaded(struct dl_download *dl) //check if we're still waiting for (listidx = 0; listidx < numdownloadablelists; listidx++) { - if (!downloadablelist[listidx].received) + if (downloadablelist[listidx].status == SRCSTAT_PENDING) break; } /* @@ -2189,8 +2200,8 @@ static void PM_AllowPackageListQuery_Callback(void *ctx, promptbutton_t opt) //something changed, let it download now. for (i = 0; i < numdownloadablelists; i++) { - if (downloadablelist[i].received == -2) - downloadablelist[i].received = 0; + if (downloadablelist[i].status == SRCSTAT_UNKNOWN) + downloadablelist[i].status = SRCSTAT_PENDING; } PM_UpdatePackageList(false, 0); } @@ -2207,7 +2218,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) //make sure our sources are okay. if (*pkg_downloads_url.string) - PM_AddSubList(pkg_downloads_url.string, "", false, true); + PM_AddSubList(pkg_downloads_url.string, "", false, pkg_autoupdate.ival>=0); #ifndef WEBCLIENT for (i = 0; i < numdownloadablelists; i++) @@ -2230,7 +2241,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) //kick off the initial tier of list-downloads. for (i = 0; i < numdownloadablelists; i++) { - if (downloadablelist[i].received && allowphonehome>=0) + if (downloadablelist[i].status != SRCSTAT_PENDING && allowphonehome>=0) continue; autoupdate = false; if (downloadablelist[i].curdl) @@ -2238,7 +2249,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) if (allowphonehome<=0) { - downloadablelist[i].received = -2; + downloadablelist[i].status = SRCSTAT_UNKNOWN; continue; } downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded); @@ -2253,7 +2264,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) else { Con_Printf("Could not contact updates server - %s\n", downloadablelist[i].url); - downloadablelist[i].received = -1; + downloadablelist[i].status = SRCSTAT_FAILED; } } @@ -2322,7 +2333,12 @@ static void PM_WriteInstalledPackages(void) { if (downloadablelist[i].save) { - s = va("sublist \"%s\" \"%s\"\n", downloadablelist[i].url, downloadablelist[i].prefix); + if (downloadablelist[i].status == SRCSTAT_DISABLED) + s = va("sublist \"%s\" \"%s\" \"disabled\"\n", downloadablelist[i].url, downloadablelist[i].prefix); + else if (downloadablelist[i].status != SRCSTAT_UNKNOWN) + s = va("sublist \"%s\" \"%s\" \"enabled\"\n", downloadablelist[i].url, downloadablelist[i].prefix); + else + s = va("sublist \"%s\" \"%s\"\n", downloadablelist[i].url, downloadablelist[i].prefix); VFS_WRITE(f, s, strlen(s)); } } @@ -3835,7 +3851,7 @@ void PM_Command_f(void) { //flush package cache, make a new request even if we already got a response from the server. int i; for (i = 0; i < numdownloadablelists; i++) - downloadablelist[i].received = 0; + downloadablelist[i].status = SRCSTAT_PENDING; if (!allowphonehome) allowphonehome = -1; //trigger a prompt, instead of ignoring it. PM_UpdatePackageList(false, 0); @@ -4506,6 +4522,50 @@ static qboolean MD_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsi } #ifdef WEBCLIENT +static void MD_Source_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) +{ + char *text; + switch(downloadablelist[c->dint].status) + { + case SRCSTAT_OBTAINED: + case SRCSTAT_PENDING: + Draw_FunStringWidth (x, y, "^&02 ", 48, 2, false); //green + break; + case SRCSTAT_FAILED: + case SRCSTAT_UNKNOWN: + Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow + break; + case SRCSTAT_DISABLED: + Draw_FunStringWidth (x, y, "^&04 ", 48, 2, false); //red + break; + } + + text = va("Source %s", downloadablelist[c->dint].url); + Draw_FunString (x+48, y, text); +} +static qboolean MD_Source_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) +{ + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1) + { + switch(downloadablelist[c->dint].status) + { + case SRCSTAT_OBTAINED: + case SRCSTAT_PENDING: + case SRCSTAT_FAILED: + case SRCSTAT_UNKNOWN: + downloadablelist[c->dint].status = SRCSTAT_DISABLED; + break; + case SRCSTAT_DISABLED: + downloadablelist[c->dint].status = SRCSTAT_PENDING; + break; + } + downloadablelist[c->dint].save = true; + PM_WriteInstalledPackages(); + PM_UpdatePackageList(true, 2); + } + return false; +} + static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) { char *settings[] = @@ -4794,7 +4854,7 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) { for (i = 0; i < numdownloadablelists; i++) { - if (!downloadablelist[i].received) + if (downloadablelist[i].status == SRCSTAT_PENDING) { Draw_FunStringWidth(0, vid.height - 8, "Querying for package list", vid.width, 2, false); return; @@ -4804,6 +4864,18 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) info->populated = true; MC_AddFrameStart(m, 48); y = 48; +#ifdef WEBCLIENT + for (i = 0; i < numdownloadablelists; i++) + { + c = MC_AddCustom(m, 0, y, p, i, NULL); + c->draw = MD_Source_Draw; + c->key = MD_Source_Key; + c->common.width = 320-48-16; + c->common.height = 8; + y += 8; + } + y+=4; //small gap +#endif b = MC_AddCommand(m, 48, 320-16, y, info->applymessage, MD_ApplyDownloads); b->rightalign = false; b->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made)."; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 732182e60..b0b5dc223 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -688,6 +688,9 @@ void CD_f (void) if (Q_strcasecmp(command, "eject") == 0) { + if (Cmd_IsInsecure()) + return; + if (cdplayingtrack || cdpausedtrack) CDAudio_Stop(); CDAudio_Eject(); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index af033c6c9..d5a917eda 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1313,16 +1313,10 @@ void M_Menu_FPS_f (void) { "Disabled", "Average FPS", - "Worst FPS", - "Best FPS", - "Immediate FPS", - "Average MSEC", - "Worst MSEC", - "Best MSEC", - "Immediate MSEC", + "Timing Graph", NULL }; - static const char *fpsvalues[] = {"0", "1", "2", "3", "4", "-1", "-2", "-3", "-4", NULL}; + static const char *fpsvalues[] = {"0", "1", "2", NULL}; static const char *entlerpopts[] = { "Enabled (always)", diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index d24fac2ea..3a15d992a 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -3387,6 +3387,16 @@ static void QCBUILTIN PF_ReadFloat(pubprogfuncs_t *prinst, struct globalvars_s * } G_FLOAT(OFS_RETURN) = MSG_ReadFloat(); } +static void QCBUILTIN PF_ReadDouble(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + if (!csqc_mayread) + { + CSQC_Abort("PF_ReadDouble is not valid at this time"); + G_FLOAT(OFS_RETURN) = -1; + return; + } + G_DOUBLE(OFS_RETURN) = MSG_ReadDouble(); +} static void QCBUILTIN PF_ReadInt(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { if (!csqc_mayread) @@ -3397,6 +3407,16 @@ static void QCBUILTIN PF_ReadInt(pubprogfuncs_t *prinst, struct globalvars_s *pr } G_INT(OFS_RETURN) = MSG_ReadLong(); } +static void QCBUILTIN PF_ReadInt64(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + if (!csqc_mayread) + { + CSQC_Abort("PF_ReadInt is not valid at this time"); + G_INT(OFS_RETURN) = -1; + return; + } + G_INT64(OFS_RETURN) = MSG_ReadInt64(); +} static void QCBUILTIN PF_ReadString(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -3681,11 +3701,31 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars MSG_WriteByte(&cls.netchan.message, ev_float); MSG_WriteFloat(&cls.netchan.message, G_FLOAT(OFS_PARM2+i*3)); } + else if (argtypes[i] == 'F') + { + MSG_WriteByte(&cls.netchan.message, ev_double); + MSG_WriteDouble(&cls.netchan.message, G_DOUBLE(OFS_PARM2+i*3)); + } else if (argtypes[i] == 'i') { MSG_WriteByte(&cls.netchan.message, ev_integer); MSG_WriteLong(&cls.netchan.message, G_INT(OFS_PARM2+i*3)); } + else if (argtypes[i] == 'u') + { + MSG_WriteByte(&cls.netchan.message, ev_uint); + MSG_WriteLong(&cls.netchan.message, G_UINT(OFS_PARM2+i*3)); + } + else if (argtypes[i] == 'I') + { + MSG_WriteByte(&cls.netchan.message, ev_int64); + MSG_WriteInt64(&cls.netchan.message, G_INT64(OFS_PARM2+i*3)); + } + else if (argtypes[i] == 'U') + { + MSG_WriteByte(&cls.netchan.message, ev_uint64); + MSG_WriteInt64(&cls.netchan.message, G_UINT64(OFS_PARM2+i*3)); + } else if (argtypes[i] == 'v') { MSG_WriteByte(&cls.netchan.message, ev_vector); @@ -6936,8 +6976,10 @@ static struct { {"readangle", PF_ReadAngle, 365}, // #365 float() readangle (EXT_CSQC) {"readstring", PF_ReadString, 366}, // #366 string() readstring (EXT_CSQC) - {"readfloat", PF_ReadFloat, 367}, // #367 string() readfloat (EXT_CSQC) - {"readint", PF_ReadInt, 0}, // #0 string() readint + {"readfloat", PF_ReadFloat, 367}, // #367 float() readfloat (EXT_CSQC) + {"readdouble", PF_ReadDouble, 0}, // #367 __double() readdouble (EXT_CSQC) + {"readint", PF_ReadInt, 0}, // #0 int() readint + {"readint64", PF_ReadInt64, 0}, // #0 __int64() readint64 {"readentitynum", PF_ReadEntityNum, 368}, // #368 float() readentitynum (EXT_CSQC) // {"readserverentitystate", PF_ReadServerEntityState, 369}, // #369 void(float flags, float simtime) readserverentitystate (EXT_CSQC_1) diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index f89a3fac7..1cb014166 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -397,7 +397,7 @@ void COM_AssertMainThread(const char *msg); #define COM_HasWork() false #define COM_DoWork(t,l) false #define COM_AssertMainThread(msg) -#define COM_MainThreadWork() +#define COM_MainThreadWork() while(0) #define COM_MainThreadFlush() #define COM_DestroyWorkerThread() #define COM_WorkerAbort(m) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a92db6716..43418bb5a 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -30,6 +30,7 @@ int r_regsequence; int rspeeds[RSPEED_MAX]; int rquant[RQUANT_MAX]; +static void R_RegisterBuiltinRenderers(void); void R_InitParticleTexture (void); void R_RestartRenderer (rendererstate_t *newr); static void R_UpdateRendererOpts(void); @@ -1080,6 +1081,9 @@ void Renderer_Init(void) P_InitParticleSystem(); R_InitTextures(); + + + R_RegisterBuiltinRenderers(); } qboolean Renderer_Started(void) @@ -1128,9 +1132,49 @@ qboolean (*SCR_UpdateScreen) (void); r_qrenderer_t qrenderer; char *q_renderername = "Non-Selected renderer"; +static struct +{ + void *module; + rendererinfo_t *ri; +} rendererinfo[16]; + +qboolean R_RegisterRenderer(void *module, rendererinfo_t *ri) +{ + size_t i; + for (i = 0; i < countof(rendererinfo); i++) + { //already registered + if (rendererinfo[i].ri == ri) + return true; + } + for (i = 0; i < countof(rendererinfo); i++) + { //register it in the first empty slot + if (!rendererinfo[i].ri) + { + rendererinfo[i].module = module; + rendererinfo[i].ri = ri; + return true; + } + } + Sys_Printf("unable to register renderer %s\n", ri->description); + return false; +} + +static plugvrfuncs_t *vrfuncs; +qboolean R_RegisterVRDriver(void *module, plugvrfuncs_t *vr) +{ + if (!vrfuncs) + { + vrfuncs = vr; + return true; + } + + Sys_Printf("unable to register renderer %s\n", vr->description); + return false; +} -rendererinfo_t dedicatedrendererinfo = { + +static rendererinfo_t dedicatedrendererinfo = { //ALL builds need a 'none' renderer, as 0. "No renderer", { @@ -1188,139 +1232,105 @@ rendererinfo_t dedicatedrendererinfo = { "" }; - -#ifdef GLQUAKE - extern rendererinfo_t openglrendererinfo; - #ifdef USE_EGL - extern rendererinfo_t eglrendererinfo; - #endif - extern rendererinfo_t rpirendererinfo; - #ifdef WAYLANDQUAKE - extern rendererinfo_t rendererinfo_wayland_gl; - #endif - rendererinfo_t fbdevrendererinfo; -#endif -#ifdef D3D8QUAKE - extern rendererinfo_t d3d8rendererinfo; -#endif -#ifdef D3D9QUAKE - extern rendererinfo_t d3d9rendererinfo; -#endif -#ifdef D3D11QUAKE - extern rendererinfo_t d3d11rendererinfo; -#endif -#ifdef SWQUAKE - extern rendererinfo_t swrendererinfo; -#endif -#ifdef VKQUAKE - extern rendererinfo_t vkrendererinfo; - //rendererinfo_t headlessvkrendererinfo; - #if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL) - extern rendererinfo_t nvvkrendererinfo; - #endif - #ifdef WAYLANDQUAKE - extern rendererinfo_t rendererinfo_wayland_vk; - #endif -#endif -#ifdef HEADLESSQUAKE - extern rendererinfo_t headlessrenderer; -#endif -#if defined(GLQUAKE) && defined(USE_EGL) - extern rendererinfo_t rendererinfo_headless_egl; -#endif - -static struct +static void R_RegisterBuiltinRenderers(void) { - void *module; - rendererinfo_t *ri; -} rendererinfo[16] = -{ -#ifdef GLQUAKE - #ifdef FTE_RPI - {NULL, &rpirendererinfo}, - #endif - {NULL, &openglrendererinfo}, - #ifdef USE_EGL - {NULL, &eglrendererinfo}, - #endif -#endif -#ifdef D3D9QUAKE - {NULL, &d3d9rendererinfo}, -#endif -#ifdef VKQUAKE - {NULL, &vkrendererinfo}, - #if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL) - {NULL, &nvvkrendererinfo}, - #endif -#endif -#ifdef D3D11QUAKE - {NULL, &d3d11rendererinfo}, -#endif -#ifdef SWQUAKE - {NULL, &swrendererinfo}, -#endif -#ifdef D3D8QUAKE - {NULL, &d3d8rendererinfo}, -#endif -#ifdef WAYLANDQUAKE #ifdef GLQUAKE - {NULL, &rendererinfo_wayland_gl}, - #endif - #ifdef VKQUAKE - {NULL, &rendererinfo_wayland_vk}, - #endif -#endif -#ifdef GLQUAKE - {NULL, &fbdevrendererinfo}, //direct stuff that doesn't interact well with the system should always be low priority -#endif -#ifndef NPQTV - {NULL, &dedicatedrendererinfo}, -#endif -#ifdef HEADLESSQUAKE - {NULL, &headlessrenderer}, - #ifdef VKQUAKE - //{NULL, &headlessvkrendererinfo}, - #endif -#endif -#if defined(GLQUAKE) && defined(USE_EGL) - {NULL, &rendererinfo_headless_egl}, -#endif -}; - -qboolean R_RegisterRenderer(void *module, rendererinfo_t *ri) -{ - size_t i; - for (i = 0; i < countof(rendererinfo); i++) - { //already registered - if (rendererinfo[i].ri == ri) - return true; - } - for (i = 0; i < countof(rendererinfo); i++) - { //register it in the first empty slot - if (!rendererinfo[i].ri) - { - rendererinfo[i].module = module; - rendererinfo[i].ri = ri; - return true; - } - } - Sys_Printf("unable to register renderer %s\n", ri->description); - return false; -} - -static plugvrfuncs_t *vrfuncs; -qboolean R_RegisterVRDriver(void *module, plugvrfuncs_t *vr) -{ - if (!vrfuncs) { - vrfuncs = vr; - return true; + extern rendererinfo_t openglrendererinfo; + #ifdef FTE_RPI + { + extern rendererinfo_t rpirendererinfo; + R_RegisterRenderer(NULL, &rpirendererinfo); + } + #endif + R_RegisterRenderer(NULL, &openglrendererinfo); + #ifdef USE_EGL + { + extern rendererinfo_t eglrendererinfo; + R_RegisterRenderer(NULL, &eglrendererinfo); + } + #endif } + #endif - Sys_Printf("unable to register renderer %s\n", vr->description); - return false; + + #ifdef D3D9QUAKE + { + extern rendererinfo_t d3d9rendererinfo; + R_RegisterRenderer(NULL, &d3d9rendererinfo); + } + #endif + #ifdef VKQUAKE + { + extern rendererinfo_t vkrendererinfo; + R_RegisterRenderer(NULL, &vkrendererinfo); + #if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL) + { + extern rendererinfo_t nvvkrendererinfo; + R_RegisterRenderer(NULL, &nvvkrendererinfo); + } + #endif + } + #endif + #ifdef D3D11QUAKE + { + extern rendererinfo_t d3d11rendererinfo; + R_RegisterRenderer(NULL, &d3d11rendererinfo); + } + #endif + #ifdef SWQUAKE + { + extern rendererinfo_t swrendererinfo; + R_RegisterRenderer(NULL, &swrendererinfo); + } + #endif + #ifdef D3D8QUAKE + { + extern rendererinfo_t d3d8rendererinfo; + R_RegisterRenderer(NULL, &d3d8rendererinfo); + } + #endif + #ifdef WAYLANDQUAKE + #ifdef GLQUAKE + { + extern rendererinfo_t rendererinfo_wayland_gl; + R_RegisterRenderer(NULL, &rendererinfo_wayland_gl); + } + #endif + #ifdef VKQUAKE + { + extern rendererinfo_t rendererinfo_wayland_vk; + R_RegisterRenderer(NULL, &rendererinfo_wayland_vk); + } + #endif + #endif + #if defined(GLQUAKE) && defined(USE_FBDEV) + { + extern rendererinfo_t fbdevrendererinfo; + R_RegisterRenderer(NULL, &fbdevrendererinfo); //direct stuff that doesn't interact well with the system should always be low priority + } + #endif + #ifndef NPQTV + R_RegisterRenderer(NULL, &dedicatedrendererinfo); + #endif + #ifdef HEADLESSQUAKE + { + extern rendererinfo_t headlessrenderer; + R_RegisterRenderer(NULL, &headlessrenderer); + #ifdef VKQUAKE + //R_RegisterRenderer(NULL, &headlessvkrendererinfo); + #endif + } + #endif + #if defined(GLQUAKE) && defined(USE_EGL) + { + extern rendererinfo_t rendererinfo_headless_egl; + R_RegisterRenderer(NULL, &rendererinfo_headless_egl); + } + #endif } + void R_SetRenderer(rendererinfo_t *ri) { currentrendererstate.renderer = ri; @@ -2282,7 +2292,7 @@ void R_RestartRenderer (rendererstate_t *newr) //if we ended up resorting to our last choice (dedicated) then print some informative message about it //fixme: on unixy systems, we should make sure we're actually printing to something (ie: that we're not running via some x11 shortcut with our stdout redirected to /dev/nul - if (!failed && newr->renderer == &dedicatedrendererinfo) + if (!failed && (!newr->renderer || newr->renderer->rtype == QR_NONE)) { Con_Printf(CON_ERROR "Video mode switch failed. Console forced.\n\nPlease change the following vars to something useable, and then use the setrenderer command.\n"); Con_Printf("%s: %s\n", vid_width.name, vid_width.string); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 547940e9e..b4e50ed05 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -3020,7 +3020,7 @@ void Sbar_IntermissionNumber (float x, float y, int num, int digits, int color, else frame = *ptr -'0'; - R2D_ScalePicAtlas (x,y, 16, 24, sb_nums[color][frame]); + R2D_ScalePicAtlas (x,y, 24, 24, sb_nums[color][frame]); x += 24; ptr++; } @@ -3800,17 +3800,17 @@ void Sbar_CoopIntermission (playerview_t *pv) dig = cl.completed_time/60; Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 64, dig, 4, 0, false); num = cl.completed_time - dig*60; - R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 64, 16, 24, sb_colon); - R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 254,(sbar_rect.height - 200)/2 + 64, 16, 26, sb_nums[0][num/10]); - R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 278,(sbar_rect.height - 200)/2 + 64, 16, 24, sb_nums[0][num%10]); + R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_colon); + R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 254,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_nums[0][num/10]); + R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 278,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_nums[0][num%10]); //it is assumed that secrits/monsters are going to be constant for any player... Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_SECRETS], 4, 0, false); - R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230, (sbar_rect.height - 200)/2 + 104, 16, 24, sb_slash); + R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230, (sbar_rect.height - 200)/2 + 104, 24, 24, sb_slash); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_TOTALSECRETS], 4, 0, true); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_MONSTERS], 4, 0, false); - R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 144, 16, 24, sb_slash); + R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 144, 24, 24, sb_slash); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_TOTALMONSTERS], 4, 0, true); } /* diff --git a/engine/client/screen.h b/engine/client/screen.h index a1a35456e..89ee9cf47 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -387,4 +387,4 @@ fte_inline float M_LinearToSRGB(float x, float mag) void R_NetgraphInit(void); void R_NetGraph (void); -void R_FrameTimeGraph (float frametime); +void R_FrameTimeGraph (float frametime, float scale); diff --git a/engine/client/view.c b/engine/client/view.c index 9bf9d5141..936900dfe 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -157,7 +157,7 @@ static cvar_t v_depthsortentities = CVARAD("v_depthsortentities", "0", "v_reord #ifdef QUAKESTATS static cvar_t scr_autoid = CVARD("scr_autoid", "1", "Display nametags above all players while spectating."); -static cvar_t scr_autoid_team = CVARD("scr_autoid_team", "2", "Display nametags above team members. 0: off. 1: display with half-alpha if occluded. 2: hide when occluded."); +static cvar_t scr_autoid_team = CVARD("scr_autoid_team", "0", "Display nametags above team members. 0: off. 1: display with half-alpha if occluded. 2: hide when occluded."); static cvar_t scr_autoid_health = CVARD("scr_autoid_health", "1", "Display health as part of nametags (when known)."); static cvar_t scr_autoid_armour = CVARD("scr_autoid_armor", "1", "Display armour as part of nametags (when known)."); static cvar_t scr_autoid_weapon = CVARD("scr_autoid_weapon", "1", "Display the player's best weapon as part of their nametag (when known)."); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index d884a2da4..c63be4407 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -746,6 +746,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define fte_alignof(type) sizeof(qintptr_t) #endif +//safeswitch(foo){safedefault: break;} +//switch, but errors for any omitted enum values despite the presence of a default case. +//(gcc will generally give warnings without the default, but sometimes you don't have control over the source of your enumeration values) +#if (__GNUC__ >= 4) + #define safeswitch \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic error \"-Wswitch-enum\"") \ + _Pragma("GCC diagnostic error \"-Wswitch-default\"") \ + switch + #define safedefault _Pragma("GCC diagnostic pop") default +#else + #define safeswitch switch + #define safedefault default +#endif + //fte_inline must only be used in headers, and requires one and ONLY one fte_inlinebody elsewhere. //fte_inlinebody must be used on a prototype OUTSIDE of a header. //fte_inlinestatic must not be used inside any headers at all. diff --git a/engine/common/common.c b/engine/common/common.c index 32d1d38cd..ab8916806 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -887,7 +887,7 @@ void MSG_WriteByte (sizebuf_t *sb, int c) #endif buf = (qbyte*)SZ_GetSpace (sb, 1); - buf[0] = c; + buf[0] = c&0xff; } void MSG_WriteShort (sizebuf_t *sb, int c) @@ -901,7 +901,7 @@ void MSG_WriteShort (sizebuf_t *sb, int c) buf = (qbyte*)SZ_GetSpace (sb, 2); buf[0] = c&0xff; - buf[1] = c>>8; + buf[1] = (c>>8)&0xff; } void MSG_WriteLong (sizebuf_t *sb, int c) @@ -912,7 +912,21 @@ void MSG_WriteLong (sizebuf_t *sb, int c) buf[0] = c&0xff; buf[1] = (c>>8)&0xff; buf[2] = (c>>16)&0xff; - buf[3] = c>>24; + buf[3] = (c>>24)&0xff; +} +void MSG_WriteInt64 (sizebuf_t *sb, qint64_t c) +{ + qbyte *buf; + + buf = (qbyte*)SZ_GetSpace (sb, 8); + buf[0] = c&0xff; + buf[1] = (c>>8)&0xff; + buf[2] = (c>>16)&0xff; + buf[3] = (c>>24)&0xff; + buf[4] = (c>>32)&0xff; + buf[5] = (c>>40)&0xff; + buf[6] = (c>>48)&0xff; + buf[7] = (c>>52)&0xff; } void MSG_WriteFloat (sizebuf_t *sb, float f) @@ -929,6 +943,17 @@ void MSG_WriteFloat (sizebuf_t *sb, float f) SZ_Write (sb, &dat.l, 4); } +void MSG_WriteDouble (sizebuf_t *sb, double f) +{ + union + { + double f; + qint64_t l; + } dat; + + dat.f = f; + MSG_WriteInt64(sb, dat.l); +} void MSG_WriteString (sizebuf_t *sb, const char *s) { @@ -1586,6 +1611,36 @@ int MSG_ReadLong (void) return c; } +qint64_t MSG_ReadInt64 (void) +{ + qint64_t c; + + if (net_message.packing!=SZ_RAWBYTES) + { + c = (unsigned int)MSG_ReadBits(32) + | ((qint64_t)(unsigned int)MSG_ReadBits(32)<<32); + return c; + } + + if (msg_readcount+4 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (net_message.data[msg_readcount+0]<<0) + | (net_message.data[msg_readcount+1]<<8) + | (net_message.data[msg_readcount+2]<<16) + | (net_message.data[msg_readcount+3]<<24) + | ((qint64_t)net_message.data[msg_readcount+5]<<32) + | ((qint64_t)net_message.data[msg_readcount+6]<<40) + | ((qint64_t)net_message.data[msg_readcount+7]<<48) + | ((qint64_t)net_message.data[msg_readcount+8]<<52); + + msg_readcount += 8; + + return c; +} float MSG_ReadFloat (void) { @@ -1614,10 +1669,21 @@ float MSG_ReadFloat (void) dat.b[3] = net_message.data[msg_readcount+3]; msg_readcount += 4; - dat.l = LittleLong (dat.l); + if (bigendian) + dat.l = LittleLong (dat.l); return dat.f; } +double MSG_ReadDouble (void) +{ //type-pun it as an int64 over the network for easier handling of endian. + union + { + double d; + qint64_t l; + } dat; + dat.l = MSG_ReadInt64(); + return dat.d; +} char *MSG_ReadStringBuffer (char *out, size_t outsize) { @@ -5188,6 +5254,7 @@ static cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSER void *com_resourcemutex; static int com_liveworkers[WG_COUNT]; static void *com_workercondition[WG_COUNT]; +int com_hadwork[WG_COUNT]; static volatile int com_workeracksequence; static struct com_worker_s { @@ -5332,6 +5399,7 @@ qboolean COM_DoWork(int tg, qboolean leavelocked) if (work) { + com_hadwork[tg]++; // Sys_Printf("%x: Doing work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?"); Sys_UnlockConditional(com_workercondition[tg]); diff --git a/engine/common/common.h b/engine/common/common.h index 659c0f6eb..b75ccfca9 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -277,8 +277,10 @@ void MSG_WriteChar (sizebuf_t *sb, int c); void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteInt64 (sizebuf_t *sb, qint64_t c); void MSG_WriteEntity (sizebuf_t *sb, unsigned int e); void MSG_WriteFloat (sizebuf_t *sb, float f); +void MSG_WriteDouble (sizebuf_t *sb, double f); void MSG_WriteString (sizebuf_t *sb, const char *s); void MSG_WriteCoord (sizebuf_t *sb, float f); void MSG_WriteBigCoord (sizebuf_t *sb, float f); @@ -300,10 +302,12 @@ int MSG_ReadBits(int bits); int MSG_ReadByte (void); int MSG_ReadShort (void); int MSG_ReadLong (void); +qint64_t MSG_ReadInt64 (void); struct client_s; unsigned int MSGSV_ReadEntity (struct client_s *fromclient); unsigned int MSGCL_ReadEntity (void); float MSG_ReadFloat (void); +double MSG_ReadDouble (void); char *MSG_ReadStringBuffer (char *out, size_t outsize); char *MSG_ReadString (void); char *MSG_ReadStringLine (void); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 5f6dbd621..efc7b7a96 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -1154,6 +1154,8 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) // check to see if it has already been defined old = Cvar_FindVar (variable->name); + if (old && variable->name2) + old = Cvar_FindVar (variable->name2); if (old) { if ((old->flags & CVAR_POINTER) && !(variable->flags & CVAR_POINTER)) diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 49e6b1672..7f1e90394 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -891,8 +891,9 @@ vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize) } vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize) { +#define fullchainname "fullchain.pem" #define pubname "cert.pem" - vfsfile_t *pubf; + vfsfile_t *pubf = NULL; const char *mode = nativename?"wb":"rb"; int i = COM_CheckParm("-pubkey"); if (i++) @@ -903,10 +904,10 @@ vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize) } else { - if (nativename) - if (!FS_NativePath(pubname, FS_ROOT, nativename, nativesize)) - return NULL; - pubf = FS_OpenVFS(pubname, mode, FS_ROOT); + if (!pubf && (!nativename || FS_NativePath(fullchainname, FS_ROOT, nativename, nativesize))) + pubf = FS_OpenVFS(fullchainname, mode, FS_ROOT); + if (!pubf && (!nativename || FS_NativePath(pubname, FS_ROOT, nativename, nativesize))) + pubf = FS_OpenVFS(pubname, mode, FS_ROOT); } return pubf; #undef pubname diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 678de5a63..9701969a7 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1230,7 +1230,8 @@ void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_ //chained search for float reference fields void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int i, ff, cf; + int i; + unsigned int ff, cf; int s; wedict_t *ent, *chain; @@ -1242,6 +1243,11 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p cf = G_INT(OFS_PARM2)+prinst->fieldadjust; else cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL; + if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindChain: bad field reference"); + return; + } for (i = 1; i < *prinst->parms->num_edicts; i++) { @@ -1262,7 +1268,8 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p //chained search for float, int, and entity reference fields void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int i, ff, cf; + int i; + unsigned int ff, cf; float s; wedict_t *ent, *chain; @@ -1274,6 +1281,11 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p cf = G_INT(OFS_PARM2)+prinst->fieldadjust; else cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL; + if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindChain: bad field reference"); + return; + } for (i = 1; i < *prinst->parms->num_edicts; i++) { @@ -1294,7 +1306,8 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p //chained search for strings in entity fields void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int i, ff, cf; + int i; + unsigned int ff, cf; const char *s; string_t t; wedict_t *ent, *chain; @@ -1307,6 +1320,11 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo cf = G_INT(OFS_PARM2)+prinst->fieldadjust; else cf = &((comentvars_t*)NULL)->chain - (int*)NULL; + if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindChain: bad field reference"); + return; + } for (i = 1; i < *prinst->parms->num_edicts; i++) { @@ -1330,12 +1348,18 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo //entity(entity start, float fld, float match) findflags = #449 void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int e, f; + int e; + unsigned int f; int s; wedict_t *ed; e = G_EDICTNUM(prinst, OFS_PARM0); f = G_INT(OFS_PARM1)+prinst->fieldadjust; + if (f >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindFlags: bad field reference"); + return; + } s = G_FLOAT(OFS_PARM2); for (e++; e < *prinst->parms->num_edicts; e++) @@ -1356,7 +1380,8 @@ void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo //entity(entity start, float fld, float match) findfloat = #98 void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int e, f; + int e; + unsigned int f; int s; wedict_t *ed; @@ -1370,6 +1395,11 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo e = G_EDICTNUM(prinst, OFS_PARM0); f = G_INT(OFS_PARM1)+prinst->fieldadjust; + if (f >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindFloat: bad field reference"); + return; + } s = G_INT(OFS_PARM2); for (e++; e < *prinst->parms->num_edicts; e++) @@ -1391,13 +1421,18 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int e; - int f; + unsigned int f; const char *s; string_t t; wedict_t *ed; e = G_EDICTNUM(prinst, OFS_PARM0); f = G_INT(OFS_PARM1)+prinst->fieldadjust; + if (f >= prinst->activefieldslots) + { + PR_BIError (prinst, "PF_FindString: bad field reference"); + return; + } s = PR_GetStringOfs(prinst, OFS_PARM2); if (!s) { @@ -1430,8 +1465,7 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob { world_t *w = prinst->parms->user; int e; - int f = G_INT(OFS_PARM0)+prinst->fieldadjust; - string_t t; + unsigned int f = G_INT(OFS_PARM0)+prinst->fieldadjust; wedict_t *ed; etype_t type = G_INT(OFS_PARM2); @@ -1439,11 +1473,25 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob int *retlist; unsigned found = 0; - //FIXME: bound f + if (type <= ev_double) + { + extern const unsigned int type_size[]; + if (f < 0 || f+type_size[type] > prinst->activefieldslots) + { //invalid field. + G_INT(OFS_PARM3) = G_INT(OFS_RETURN) = 0; + return; + } + } + else + { //unsupported field type. + G_INT(OFS_PARM3) = G_INT(OFS_RETURN) = 0; + return; + } if (type == ev_string) { const char *s = PR_GetStringOfs(prinst, OFS_PARM1); + string_t t; if (!s) s = ""; /* o.O */ for (e=1 ; e < *prinst->parms->num_edicts ; e++) @@ -1460,39 +1508,63 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } else if (type == ev_float) { //handling -0 properly requires care - float s = G_FLOAT(OFS_PARM1); + pvec_t s = G_FLOAT(OFS_PARM1); for (e=1 ; e < *prinst->parms->num_edicts ; e++) { ed = WEDICT_NUM_PB(prinst, e); if (ED_ISFREE(ed)) continue; - if (((float*)ed->v)[f] == s) + if (((pvec_t*)ed->v)[f] == s) + list[found++] = EDICT_TO_PROG(prinst, ed); + } + } + else if (type == ev_double) + { //handling 64bit -0 properly requires care + double s = G_DOUBLE(OFS_PARM1); + for (e=1 ; e < *prinst->parms->num_edicts ; e++) + { + ed = WEDICT_NUM_PB(prinst, e); + if (ED_ISFREE(ed)) + continue; + if (*(double*)((pvec_t*)ed->v+f) == s) + list[found++] = EDICT_TO_PROG(prinst, ed); + } + } + else if (type == ev_int64 || type == ev_uint64) + { //handling -0 properly requires care + pint64_t s = G_INT64(OFS_PARM1); + for (e=1 ; e < *prinst->parms->num_edicts ; e++) + { + ed = WEDICT_NUM_PB(prinst, e); + if (ED_ISFREE(ed)) + continue; + if (*(pint64_t*)((pint_t*)ed->v+f) == s) list[found++] = EDICT_TO_PROG(prinst, ed); } } else if (type == ev_vector) { //big types... - float *s = G_VECTOR(OFS_PARM1); + pvec_t *s = G_VECTOR(OFS_PARM1); for (e=1 ; e < *prinst->parms->num_edicts ; e++) { ed = WEDICT_NUM_PB(prinst, e); if (ED_ISFREE(ed)) continue; - if (((float*)ed->v)[f+0] == s[0]&& - ((float*)ed->v)[f+1] == s[1]&& - ((float*)ed->v)[f+2] == s[2]) + if (((pvec_t*)ed->v)[f+0] == s[0]&& + ((pvec_t*)ed->v)[f+1] == s[1]&& + ((pvec_t*)ed->v)[f+2] == s[2]) list[found++] = EDICT_TO_PROG(prinst, ed); } } else { //generic references and other stuff that can just be treated as ints - int s = G_INT(OFS_PARM1); + pint_t s = G_INT(OFS_PARM1); for (e=1 ; e < *prinst->parms->num_edicts ; e++) { ed = WEDICT_NUM_PB(prinst, e); if (ED_ISFREE(ed)) continue; - if (((int*)ed->v)[f] == s) + if (((pint_t*)ed->v)[f] == s) list[found++] = EDICT_TO_PROG(prinst, ed); } } @@ -6497,7 +6569,7 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa G_FLOAT(OFS_RETURN) = realtime; break; case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure - G_FLOAT(OFS_RETURN) = (qint64_t)(Sys_DoubleTime()*1000) / 1000.0; + G_FLOAT(OFS_RETURN) = (qint64_t)Sys_Milliseconds(); break; //case 2: //highres.. looks like time into the frame //case 3: //uptime diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 207b859e7..5b6cd245b 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -539,6 +539,7 @@ enum { #define PF_GIB (1<<10) // offset the view height differently //ZQuake. +#define PF_PMC_SHIFT 11 #define PF_PMC_MASK ((1<<11) | \ (1<<12) | \ (1<<13)) @@ -565,7 +566,8 @@ enum { #define PF_SOLID (1<<23) //or 15, depending on extensions... messy. -#define PF_PMC_SHIFT 11 +//not networked +#define PF_INWATER (1u<<31) //for network smartjump. diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 04fdfd7c3..d0c027c6d 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -627,7 +627,7 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan Q1BSP_ClipDecalToNodes(mod, &dec, mod->rootnode); #endif #ifdef Q3BSPS - else if (cl.worldmodel->fromgame == fg_quake3) + else if (mod->fromgame == fg_quake3) { if (mod->submodelof) { @@ -641,7 +641,7 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan #endif #ifdef TERRAIN - if (cl.worldmodel && cl.worldmodel->terrain) + if (mod->terrain) Terrain_ClipDecal(&dec, center, dec.radius, mod); #endif } diff --git a/engine/gl/gl_ngraph.c b/engine/gl/gl_ngraph.c index f1524ca87..69bff53b9 100644 --- a/engine/gl/gl_ngraph.c +++ b/engine/gl/gl_ngraph.c @@ -218,58 +218,118 @@ void R_NetGraph (void) #endif } -void R_FrameTimeGraph (float frametime) +void R_FrameTimeGraph (float frametime, float scale) { - int a, x, i, y; + float bias = 0; + int a, x, i, y, h, col; vec2_t p[4]; vec2_t tc[4]; vec4_t rgba[4]; extern shader_t *shader_draw_fill; - timehistory[findex++&NET_TIMINGSMASK] = frametime; + conchar_t line[128]; + int textheight; + float minv=FLT_MAX, maxv=FLT_MIN, avg=0, dev=0; + + static struct + { + float time; + int col; + } history[NET_TIMINGS]; + static unsigned int findex; + + extern int com_hadwork[WG_COUNT]; + + history[findex&NET_TIMINGSMASK].time = frametime; + history[findex&NET_TIMINGSMASK].col = 0xffffffff; + findex++; + +#ifdef LOADERTHREAD + if (com_hadwork[WG_MAIN]) + { //recolour the graph red if the main thread processed something from a worker. + //show three, because its not so easy to see when its whizzing past. + com_hadwork[WG_MAIN] = 0; + history[(findex-1)&NET_TIMINGSMASK].col = 0xff0000ff; + history[(findex-2)&NET_TIMINGSMASK].col = 0xff0000ff; + history[(findex-3)&NET_TIMINGSMASK].col = 0xff0000ff; + } +#endif x = 0; for (a=0 ; a history[a].time) + minv = history[a].time; + if (maxv < history[a].time) + maxv = history[a].time; } + if (!scale) + { + bias = minv; + scale = NET_GRAPHHEIGHT/(maxv-minv); + } + else + scale *= 1000; + avg/=a; + for (a = 0; a < NET_TIMINGS; a++) + dev += 1000*1000*(history[a].time - avg)*(history[a].time - avg); + dev /= a; + dev = sqrt(dev); + x = ((vid.width - 320)>>1); x=-x; - y = vid.height - sb_lines - 16 - NET_GRAPHHEIGHT; - M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8); + textheight = 4; + textheight = ceil(textheight*Font_CharVHeight(font_console)/8)*8; //might have a small gap underneath + + y = vid.height - sb_lines - 16 - NET_GRAPHHEIGHT - textheight; + + M_DrawTextBox (x, y, NET_TIMINGS/8, (textheight + NET_GRAPHHEIGHT)/8); x=8; y += 8; -#ifdef GRAPHTEX - Image_Upload(netgraphtexture, TF_RGBA32, ngraph_texels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP); - x=8; - R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader); -#else + COM_ParseFunString(CON_WHITEMASK, va("mean: %.3ffps (%.3fms)", 1/avg, 1000*avg), line, sizeof(line), false); + Draw_ExpandedString(font_console, x, y, line); + y += Font_CharVHeight(font_console); + COM_ParseFunString(CON_WHITEMASK, va("fastest: %.3ffps (%.3fms)", 1/minv, 1000*minv), line, sizeof(line), false); + Draw_ExpandedString(font_console, x, y, line); + y += Font_CharVHeight(font_console); + COM_ParseFunString(CON_WHITEMASK, va("slowest: %.3ffps (%.3fms)", 1/maxv, 1000*maxv), line, sizeof(line), false); + Draw_ExpandedString(font_console, x, y, line); + y += Font_CharVHeight(font_console); + COM_ParseFunString(CON_WHITEMASK, va("deviation: %.3fms (max %.3fms)", dev, (maxv-minv)*1000/2), line, sizeof(line), false); + Draw_ExpandedString(font_console, x, y, line); + y += Font_CharVHeight(font_console); + Vector2Set(p[2], 0,0); Vector2Set(p[3], 0,0); Vector4Set(rgba[2], 0,0,0,0); Vector4Set(rgba[3], 0,0,0,0); for (a=0 ; a NET_GRAPHHEIGHT) + h = NET_GRAPHHEIGHT; Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]); Vector2Copy(p[2], p[1]); Vector4Copy(rgba[2], rgba[1]); - Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT); + Vector2Set(p[2+0], x+a, y+(NET_GRAPHHEIGHT-h)); Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT); - Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height)); + Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (NET_GRAPHHEIGHT-h)/NET_GRAPHHEIGHT); Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1); - Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0); + Vector4Set(rgba[2+0], ((col>>0)&0xff)/255.0, ((col>>8)&0xff)/255.0, ((col>>16)&0xff)/255.0, ((col>>24)&0xff)/255.0); Vector4Copy(rgba[2+0], rgba[2+1]); if (a) R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill); } -#endif } void R_NetgraphInit(void) diff --git a/engine/qclib/cmdlib.h b/engine/qclib/cmdlib.h index 98f452ae8..08eb38f9b 100644 --- a/engine/qclib/cmdlib.h +++ b/engine/qclib/cmdlib.h @@ -74,6 +74,23 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) #define LIKEPRINTF(x) #endif + + +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) + #define FTE_DEPRECATED __attribute__((__deprecated__)) //no idea about the actual gcc version + #ifdef _WIN32 + #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #else + #define LIKEPRINTF(x) __attribute__((format(printf,x,x+1))) + #endif +#endif +#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) + #define NORETURN __attribute__((noreturn)) +#endif +#ifndef NORETURN + #define NORETURN +#endif + double I_FloatTime (void); void VARGS QCC_Error (int errortype, const char *error, ...) LIKEPRINTF(2); @@ -114,7 +131,6 @@ char *QCC_COM_Parse2 (char *data); unsigned int utf8_check(const void *in, unsigned int *value); extern char qcc_token[1024]; -extern int qcc_eof; #define qcc_iswhite(c) ((c) == ' ' || (c) == '\r' || (c) == '\n' || (c) == '\t' || (c) == '\v') diff --git a/engine/qclib/decomp.c b/engine/qclib/decomp.c index 35098f048..6434bb513 100644 --- a/engine/qclib/decomp.c +++ b/engine/qclib/decomp.c @@ -58,6 +58,14 @@ QCC_ddef_t *GetField(const char *name); return p; }*/ +const char *GetString(dstring_t str) +{ + if (str >= strofs) + return "INVALIDSTRING"; + else + return strings+str; +} + extern QCC_opcode_t pr_opcodes []; int endofsystemfields; @@ -137,7 +145,7 @@ const char *temp_type (int temp, dstatement_t *start, dfunction_t *df) } } - printf("warning: Could not determine return type for %s\n", df->s_name + strings); + printf("warning: Could not determine return type for %s\n", GetString(df->s_name)); return "float"; @@ -172,13 +180,6 @@ pbool IsConstant(QCC_ddef_t *def) return true; } -const char *qcstring(int str) -{ - if ((unsigned)str >= strofs) - return ""; - return strings+str; -} - char *type_name (QCC_ddef_t *def) { QCC_ddef_t *j; @@ -187,7 +188,7 @@ char *type_name (QCC_ddef_t *def) { case ev_field: case ev_pointer: - j = GetField(def->s_name + strings); + j = GetField(GetString(def->s_name)); if (j) return qcva(".%s",type_names[j->type]); else @@ -280,7 +281,7 @@ static char *PR_ValueString (etype_t type, void *val) switch (type) { case ev_string: - QC_snprintfz(line, sizeof(line), "%s", PR_String(strings + *(int *)val)); + QC_snprintfz(line, sizeof(line), "%s", PR_String(GetString(*(int *)val))); break; case ev_entity: QC_snprintfz(line, sizeof(line), "entity %i", *(int *)val); @@ -290,7 +291,7 @@ static char *PR_ValueString (etype_t type, void *val) if (!f) QC_snprintfz(line, sizeof(line), "undefined function"); else - QC_snprintfz(line, sizeof(line), "%s()", strings + f->s_name); + QC_snprintfz(line, sizeof(line), "%s()", GetString(f->s_name)); break; /* case ev_field: @@ -822,7 +823,7 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize) // fix up the functions for (i = 1; i < numfunctions; i++) { - if ((unsigned)functions[i].s_name >= (unsigned)strofs || strlen(functions[i].s_name + strings) <= 0) + if ((unsigned)functions[i].s_name >= (unsigned)strofs || strlen(GetString(functions[i].s_name)) <= 0) { fd = DecompileFunctionGlobal(i); if (fd) @@ -853,7 +854,7 @@ DecompileGetFunctionIdxByName(const char *name) int i; for (i = 1; i < numfunctions; i++) - if (!strcmp(name, strings + functions[i].s_name)) + if (!strcmp(name, GetString(functions[i].s_name))) { return i; } @@ -868,7 +869,7 @@ const etype_t DecompileGetFieldTypeByDef(QCC_ddef_t *def) for (i = 1; i < numfielddefs; i++) if (fields[i].ofs == ofs) { - if (!strcmp(strings+def->s_name, strings+fields[i].s_name)) + if (!strcmp(GetString(def->s_name), GetString(fields[i].s_name))) return fields[i].type; } return ev_void; @@ -880,7 +881,7 @@ const char *DecompileGetFieldNameIdxByFinalOffset(int ofs) for (i = 1; i < numfielddefs; i++) if (fields[i].ofs == ofs) { - return fields[i].s_name+strings; + return GetString(fields[i].s_name); } return "UNKNOWN FIELD"; } @@ -892,17 +893,17 @@ void DecompileGetFieldNameIdxByFinalOffset2(char *out, size_t outsize, int ofs) { if (fields[i].ofs == ofs) { - QC_snprintfz(out, outsize, "%s", fields[i].s_name+strings); + QC_snprintfz(out, outsize, "%s", GetString(fields[i].s_name)); return; } else if (fields[i].type == ev_vector && fields[i].ofs+1 == ofs) { - QC_snprintfz(out, outsize, "%s_y", fields[i].s_name+strings); + QC_snprintfz(out, outsize, "%s_y", GetString(fields[i].s_name)); return; } else if (fields[i].type == ev_vector && fields[i].ofs+2 == ofs) { - QC_snprintfz(out, outsize, "%s_z", fields[i].s_name+strings); + QC_snprintfz(out, outsize, "%s_z", GetString(fields[i].s_name)); return; } } @@ -975,9 +976,9 @@ static unsigned int DecompileBuiltin(dfunction_t *df) bi = -df->first_statement; //okay, so this is kinda screwy, different mods have different sets of builtins, and a load of fte's are #0 too //so just try to match by name first... lots of scanning. :( - if (df->s_name>0) + if (df->s_name>0 && df->s_name < strofs) { - char *biname = strings + df->s_name; + const char *biname = GetString(df->s_name); for (i = 0; i < (sizeof(builtins)/sizeof(builtins[0])); i++) { if (!builtins[i].name) @@ -1100,11 +1101,11 @@ void DecompileCalcProfiles(void) { unsigned int bi = DecompileBuiltin(df); if (bi && builtins[bi].text) - QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[bi].text, strings + functions[i].s_name); + QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[bi].text, GetString(functions[i].s_name)); else { - QC_snprintfz(fname, sizeof(fname), "__variant(...) %s", strings + functions[i].s_name); - printf("warning: unknown builtin %s\n", strings + functions[i].s_name); + QC_snprintfz(fname, sizeof(fname), "__variant(...) %s", GetString(functions[i].s_name)); + printf("warning: unknown builtin %s\n", GetString(functions[i].s_name)); } } else @@ -1178,7 +1179,7 @@ void DecompileCalcProfiles(void) } strcat(fname, ") "); line[0] = '\0'; - QC_snprintfz(line, sizeof(line), "%s", strings + functions[i].s_name); + QC_snprintfz(line, sizeof(line), "%s", GetString(functions[i].s_name)); strcat(fname, line); } @@ -1206,7 +1207,7 @@ QCC_ddef_t *GlobalAtOffset(dfunction_t *df, gofs_t ofs) if (def->ofs == ofs) { - /*if (!strings[def->s_name]) + /*if (!GetString(def->s_name)) { char line[16]; char *buf; @@ -1241,7 +1242,7 @@ QCC_ddef_t *GlobalAtOffset(dfunction_t *df, gofs_t ofs) if (def->ofs == ofs) { char line[256], *buf; - sprintf(line, "%s_%c", strings+def->s_name, 'x'+parmofs); //globals, which are defined after the locals of the function they are first used in... + sprintf(line, "%s_%c", GetString(def->s_name), 'x'+parmofs); //globals, which are defined after the locals of the function they are first used in... def = malloc(sizeof(*def)+strlen(line)+1); //must be static variables, but we can't handle them very well buf = (char*)(def+1); strcpy(buf, line); @@ -1290,7 +1291,7 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t) if (def) { - const char *defname = qcstring(def->s_name); + const char *defname = GetString(def->s_name); if (!strcmp(defname, "IMMEDIATE") || !strcmp(defname, ".imm") || !def->s_name) { @@ -1316,14 +1317,14 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t) goto lookslikealocal; else if ((parent = GlobalAtOffset(df, ofs-1)) && parent->type == ev_vector) { // _y - QC_snprintfz(line, sizeof(line), "%s_y", strings+parent->s_name); //globals, which are defined after the locals of the function they are first used in... + QC_snprintfz(line, sizeof(line), "%s_y", GetString(parent->s_name)); //globals, which are defined after the locals of the function they are first used in... buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well strcpy(buf, line); def->s_name = buf - strings; } else if ((parent = GlobalAtOffset(df, ofs-2)) && parent->type == ev_vector) { // _z - QC_snprintfz(line, sizeof(line), "%s_z", strings+parent->s_name); //globals, which are defined after the locals of the function they are first used in... + QC_snprintfz(line, sizeof(line), "%s_z", GetString(parent->s_name)); //globals, which are defined after the locals of the function they are first used in... buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well strcpy(buf, line); def->s_name = buf - strings; @@ -1337,7 +1338,7 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t) } } - QC_snprintfz(line, sizeof(line), "%s", strings + def->s_name); + QC_snprintfz(line, sizeof(line), "%s", GetString(def->s_name)); if (def->type == ev_field && req_t == type_field && req_t->aux_type == type_float && DecompileGetFieldTypeByDef(def) == ev_vector) strcat(line, "_x"); else if (def->type == ev_vector && req_t == type_float) @@ -1442,7 +1443,7 @@ void DecompileImmediate_Insert(dfunction_t *df, gofs_t ofs, char *knew, QCC_type d = GlobalAtOffset(df, ofs); - if (d && d->s_name)// && strcmp(strings+d->s_name, "IMMEDIATE")) + if (d && d->s_name)// && strcmp(GetString(d->s_name), "IMMEDIATE")) { //every operator has a src (or two) and a dest. //many compilers optimise by using the dest of a maths/logic operator to store to a local/global //they then skip off the storeopcode. @@ -1450,7 +1451,7 @@ void DecompileImmediate_Insert(dfunction_t *df, gofs_t ofs, char *knew, QCC_type IMMEDIATES[nofs].text = NULL; IMMEDIATES[nofs].type = NULL; - QCC_CatVFile(Decompileofile, "%s = %s;\n", strings + d->s_name, knew); + QCC_CatVFile(Decompileofile, "%s = %s;\n", GetString(d->s_name), knew); } else { @@ -1538,11 +1539,11 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t) char *out; if (((int*)pr_globals)[ofs] < 0 || ((int*)pr_globals)[ofs] > strofs) { - printf("Hey! That's not a string! error in %s\n", strings + df->s_name); + printf("Hey! That's not a string! error in %s\n", GetString(df->s_name)); QC_snprintfz(temp, sizeof(temp), "%f", pr_globals[ofs]); break; } - in = &strings[((int*)pr_globals)[ofs]]; + in = GetString(((int*)pr_globals)[ofs]); out = temp; if (req_t->type != ev_string) { @@ -1639,7 +1640,7 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t) if (!((int*)pr_globals)[ofs]) QC_snprintfz(temp, sizeof(temp), "__NULL__/*func*/"); else if (((int*)pr_globals)[ofs] > 0 && ((int*)pr_globals)[ofs] < numfunctions && functions[((int*)pr_globals)[ofs]].s_name>0) - QC_snprintfz(temp, sizeof(temp), "%s/*immediate*/", strings+functions[((int*)pr_globals)[ofs]].s_name); + QC_snprintfz(temp, sizeof(temp), "%s/*immediate*/", GetString(functions[((int*)pr_globals)[ofs]].s_name)); else QC_snprintfz(temp, sizeof(temp), "((__variant(...))%i)", ((int*)pr_globals)[ofs]); break; @@ -2317,7 +2318,7 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent if (s->c) QCC_CatVFile(Decompileofile, ", %s", DecompileGet(df, s->c, typ1)); QCC_CatVFile(Decompileofile, "]\n"); - printf("warning: Unknown opcode %i in %s\n", op, strings + df->s_name); + printf("warning: Unknown opcode %i in %s\n", op, GetString(df->s_name)); } } @@ -2367,7 +2368,7 @@ pbool DecompileDecompileFunction(dfunction_t * df, dstatement_t *altdone) if (indent != 1) { - printf("warning: Indentation structure corrupt (in func %s)\n", strings+df->s_name); + printf("warning: Indentation structure corrupt (in func %s)\n", GetString(df->s_name)); return false; } return true; @@ -2378,7 +2379,7 @@ char *DecompileString(int qcstring) static char buf[8192]; char *s; int c = 1; - const char *string = strings+qcstring; + const char *string = GetString(qcstring); if (qcstring < 0 || qcstring >= strofs) return "Invalid String"; @@ -2468,7 +2469,7 @@ char *DecompileValueString(etype_t type, void *val) break; case ev_function: if (*(int *)val>0 && *(int *)valofs, debug); } - else if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm")) + else if (!strcmp(GetString(def->s_name), "IMMEDIATE") || !strcmp(GetString(def->s_name), ".imm")) { QC_snprintfz(line, sizeof(line), "%s%s", DecompileValueString((etype_t)(def->type), &pr_globals[def->ofs]), debug); } else { - QC_snprintfz(line, sizeof(line), "%s %s%s", type_name(def), strings + def->s_name, debug); + QC_snprintfz(line, sizeof(line), "%s %s%s", type_name(def), GetString(def->s_name), debug); } return line; } @@ -2527,18 +2528,18 @@ const char *GetMatchingField(QCC_ddef_t *field) { if (((int*)pr_globals)[def->ofs] == field->ofs) { - if (!strcmp(strings+def->s_name, strings+field->s_name)) + if (!strcmp(GetString(def->s_name), GetString(field->s_name))) return NULL; //found ourself, give up. - lf = strlen(strings + field->s_name); - ld = strlen(strings + def->s_name); + lf = strlen(GetString(field->s_name)); + ld = strlen(GetString(def->s_name)); if (lf - 2 == ld) { - if ((strings + field->s_name)[lf-2] == '_' && (strings + field->s_name)[lf-1] == 'x') - if (!strncmp(strings + field->s_name, strings + def->s_name, ld)) + if ((GetString(field->s_name)[lf-2]) == '_' && (GetString(field->s_name)[lf-1]) == 'x') + if (!strncmp(GetString(field->s_name), GetString(def->s_name), ld)) return NULL; //vector found foo_x } if (!ret) - ret = def->s_name+strings; + ret = GetString(def->s_name); } } } @@ -2560,7 +2561,7 @@ QCC_ddef_t *GetField(const char *name) { d = &fields[i]; - if (!strcmp(strings + d->s_name, name)) + if (!strcmp(GetString(d->s_name), name)) return d; } return NULL; @@ -2595,7 +2596,7 @@ QCC_ddef_t *DecompileFindGlobal(const char *findname) for (i = 0; i < numglobaldefs; i++) { def = &globals[i]; - defname = strings + def->s_name; + defname = GetString(def->s_name); if (!strcmp(findname, defname)) { @@ -2651,19 +2652,19 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) if (par->type == ev_function) { - if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm")) + if (strcmp(GetString(par->s_name), "IMMEDIATE") && strcmp(GetString(par->s_name), ".imm")) { - if (strcmp(strings + par->s_name, name)) + if (strcmp(GetString(par->s_name), name)) { int f = ((int*)pr_globals)[par->ofs]; //DecompileGetFunctionIdxByName(strings + par->s_name); - if (f && strcmp(strings+functions[f].s_name, strings + par->s_name)) + if (f && strcmp(GetString(functions[f].s_name), GetString(par->s_name))) { char *s = strrchr(DecompileProfiles[f], ' '); //happens with void() func = otherfunc; //such functions thus don't have their own type+body *s = 0; - QCC_CatVFile(Decompileofile, "var %s %s = %s;\n", DecompileProfiles[f], strings + par->s_name, s+1); + QCC_CatVFile(Decompileofile, "var %s %s = %s;\n", DecompileProfiles[f], GetString(par->s_name), s+1); *s = ' '; } else @@ -2673,18 +2674,18 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) } else if (par->type != ev_pointer) { - if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm") && par->s_name) + if (strcmp(GetString(par->s_name), "IMMEDIATE") && strcmp(GetString(par->s_name), ".imm") && par->s_name) { if (par->type == ev_field) { - ef = GetField(strings + par->s_name); + ef = GetField(GetString(par->s_name)); if (!ef) { - QCC_CatVFile(Decompileofile, "var .unknowntype %s;\n", strings + par->s_name); - printf("Fatal Error: Could not locate a field named \"%s\"\n", strings + par->s_name); + QCC_CatVFile(Decompileofile, "var .unknowntype %s;\n", GetString(par->s_name)); + printf("Fatal Error: Could not locate a field named \"%s\"\n", GetString(par->s_name)); } else { @@ -2694,7 +2695,7 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) matchingfield = GetMatchingField(ef); #ifndef DONT_USE_DIRTY_TRICKS //could try scanning for an op_address+op_storep_fnc pair - if ((ef->type == ev_function) && !strcmp(strings + ef->s_name, "th_pain")) + if ((ef->type == ev_function) && !strcmp(GetString(ef->s_name), "th_pain")) { QCC_CatVFile(Decompileofile, ".void(entity attacker, float damage) th_pain;\n"); } @@ -2702,9 +2703,9 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) #endif { if (matchingfield) - QCC_CatVFile(Decompileofile, "var .%s %s = %s;\n", type_name(ef), strings + ef->s_name, matchingfield); + QCC_CatVFile(Decompileofile, "var .%s %s = %s;\n", type_name(ef), GetString(ef->s_name), matchingfield); else - QCC_CatVFile(Decompileofile, ".%s %s;\n", type_name(ef), strings + ef->s_name); + QCC_CatVFile(Decompileofile, ".%s %s;\n", type_name(ef), GetString(ef->s_name)); // fprintf(Decompileofile, "//%i %i %i %i\n", ef->ofs, ((int*)pr_globals)[ef->ofs], par->ofs, ((int*)pr_globals)[par->ofs]); } @@ -2719,7 +2720,7 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) if (par->type == ev_entity || par->type == ev_void) { - QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), strings + par->s_name); + QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), GetString(par->s_name)); } else @@ -2730,14 +2731,14 @@ void DecompilePreceedingGlobals(int start, int end, const char *name) if (IsConstant(par)) { - QCC_CatVFile(Decompileofile, "%s %s = %s;\n", type_name(par), strings + par->s_name, line); + QCC_CatVFile(Decompileofile, "%s %s = %s;\n", type_name(par), GetString(par->s_name), line); } else { if (pr_globals[par->ofs] != 0) - QCC_CatVFile(Decompileofile, "%s %s /* = %s */;\n", type_name(par), strings + par->s_name, line); + QCC_CatVFile(Decompileofile, "%s %s /* = %s */;\n", type_name(par), GetString(par->s_name), line); else - QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), strings + par->s_name, line); + QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), GetString(par->s_name), line); } } } @@ -2763,7 +2764,7 @@ void DecompileFunction(const char *name, int *lastglobal) for (i = 1; i < numfunctions; i++) - if (!strcmp(name, strings + functions[i].s_name)) + if (!strcmp(name, GetString(functions[i].s_name))) break; if (i == numfunctions) { @@ -3032,10 +3033,10 @@ void DecompileFunction(const char *name, int *lastglobal) } else { - if (!strcmp(strings + par->s_name, "IMMEDIATE") || !strcmp(strings + par->s_name, ".imm")) + if (!strcmp(GetString(par->s_name), "IMMEDIATE") || !strcmp(GetString(par->s_name), ".imm")) continue; // immediates don't belong - if (!strings[par->s_name]) + if (!GetString(par->s_name)) { QC_snprintfz(line, sizeof(line), "_l_%i", par->ofs); arg2 = malloc(strlen(line)+1); @@ -3069,7 +3070,7 @@ void DecompileFunction(const char *name, int *lastglobal) if (!DecompileDecompileFunction(df, altdone)) { - QCC_InsertVFile(Decompileofile, startpos, "#error Corrupt Function: %s\n#if 0\n", strings+df->s_name); + QCC_InsertVFile(Decompileofile, startpos, "#error Corrupt Function: %s\n#if 0\n", GetString(df->s_name)); QCC_CatVFile(Decompileofile, "#endif\n"); } @@ -3157,7 +3158,7 @@ void DecompileDecompileFunctions(const char *origcopyright) lastfileofs = d->s_file; fname[0] = '\0'; if (d->s_file <= strofs && d->s_file >= 0) - sprintf(fname, "%s", strings + d->s_file); + sprintf(fname, "%s", GetString(d->s_file)); // FrikaC -- not sure if this is cool or what? bogusname = false; if (strlen(fname) <= 0) @@ -3187,7 +3188,7 @@ void DecompileDecompileFunctions(const char *origcopyright) { synth_name[0] = 0; } - if(!TrySynthName(qcva("%s", strings + d->s_name)) && !synth_name[0]) + if(!TrySynthName(qcva("%s", GetString(d->s_name))) && !synth_name[0]) QC_snprintfz(synth_name, sizeof(synth_name), "frik%i.qc", fake_name++); QC_snprintfz(fname, sizeof(fname), "%s", synth_name); @@ -3210,7 +3211,7 @@ void DecompileDecompileFunctions(const char *origcopyright) } } Decompileofile = f; - DecompileFunction(strings + d->s_name, &lastglob); + DecompileFunction(GetString(d->s_name), &lastglob); } } @@ -3266,7 +3267,7 @@ char *DecompileGlobalStringNoContents(gofs_t ofs) if (def->ofs == ofs) { line[0] = '0'; - QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, strings + def->s_name); + QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, GetString(def->s_name)); break; } } @@ -3297,13 +3298,13 @@ char *DecompileGlobalString(gofs_t ofs) { line[0] = '0'; - if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm")) + if (!strcmp(GetString(def->s_name), "IMMEDIATE") || !strcmp(GetString(def->s_name), ".imm")) { s = PR_ValueString((etype_t)(def->type), &pr_globals[ofs]); QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, s); } else - QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, strings + def->s_name); + QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, GetString(def->s_name)); } } @@ -3356,7 +3357,7 @@ void DecompilePrintFunction(char *name) dfunction_t *df; for (i = 0; i < numfunctions; i++) - if (!strcmp(name, strings + functions[i].s_name)) + if (!strcmp(name, GetString(functions[i].s_name))) break; if (i == numfunctions) { diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 822ffad60..b08644025 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -411,6 +411,24 @@ reeval: ptr = QCPOINTERM(i); ptr->_int = OPA->_int; break; + case OP_STOREP_I64: // 64bit + i = OPB->_int + OPC->_int*sizeof(ptr->_int); + errorif (QCPOINTERWRITEFAIL(i, sizeof(ptr->_int64))) + { + if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(ptr->_int), sizeof(ptr->_int64)))) + { + if (i == -1) + break; + if (i == 0) + QCFAULT(&progfuncs->funcs, "bad pointer write in %s (null pointer)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)); + else + QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused); + } + } + else + ptr = QCPOINTERM(i); + ptr->_int64 = OPA->_int64; + break; case OP_STOREP_V: i = OPB->_int + (OPC->_int*sizeof(ptr->_int)); errorif (QCPOINTERWRITEFAIL(i, sizeof(pvec3_t))) @@ -504,6 +522,48 @@ reeval: ptr = (eval_t *)(((int *)edvars(ed)) + i); ptr->_int = OPC->_int; break; + case OP_STOREF_I64: + errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); + errorif (!ed || ed->readonly) + { //boot it over to the debugger +#if INTSIZE == 16 + ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a); +#else + ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a); +#endif + fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust); + if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??")) + return prinst.pr_xstatement; + break; + } + +//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods. +#ifdef NOLEGACY + errorif (ed->ereftype == ER_FREE) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } +#endif + + i = OPB->_int + progfuncs->funcs.fieldadjust; + errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + + ptr = (eval_t *)(((int *)edvars(ed)) + i); + ptr->_int64 = OPC->_int64; + break; case OP_STOREF_V: errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) { @@ -634,7 +694,7 @@ reeval: #endif { i = OPB->_int + progfuncs->funcs.fieldadjust; - errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check + errorif ((unsigned int)(i+1)*4 > ed->fieldsize) //FIXME:lazy size check { if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) return prinst.pr_xstatement; @@ -645,7 +705,44 @@ reeval: OPC->_int = ptr->_int; } break; - + case OP_LOAD_I64: + errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD_V references invalid entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + OPC->_vector[0] = 0; + OPC->_vector[1] = 0; + OPC->_vector[2] = 0; + break; + } + ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif +#ifdef NOLEGACY + if (ed->ereftype == ER_FREE) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references free entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + OPC->_vector[0] = 0; + OPC->_vector[1] = 0; + OPC->_vector[2] = 0; + } + else +#endif + { + i = OPB->_int + progfuncs->funcs.fieldadjust; + errorif ((unsigned int)(i+2)*4 > ed->fieldsize) //FIXME:lazy size check + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + OPC->_int = 0; + break; + } + ptr = (eval_t *)(((int *)edvars(ed)) + i); + OPC->_int64 = ptr->_int64; + } + break; case OP_LOAD_V: errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) { @@ -673,7 +770,7 @@ reeval: #endif { i = OPB->_int + progfuncs->funcs.fieldadjust; - errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check + errorif ((unsigned int)(i+3)*4 > ed->fieldsize) //FIXME:lazy size check { if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) return prinst.pr_xstatement; @@ -685,7 +782,7 @@ reeval: OPC->_vector[1] = ptr->_vector[1]; OPC->_vector[2] = ptr->_vector[2]; } - break; + break; //================== @@ -948,7 +1045,15 @@ reeval: else OPC->_int = ((eval_t *)&glob[i])->_int; break; - + case OP_LOADA_I64: + i = st->a + OPB->_int; + if ((size_t)i >= (size_t)(current_progstate->globals_bytes>>2)) + { + QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int); + } + else + OPC->_int64 = ((eval_t *)&glob[i])->_int64; + break; case OP_LOADA_V: i = st->a + OPB->_int; if ((size_t)(i) >= (size_t)(current_progstate->globals_bytes>>2)-2u) @@ -1480,6 +1585,48 @@ reeval: } break; */ + + + //[u]int64+double opcodes + case OP_ADD_I64: OPC->_int64 = OPA->_int64 + OPB->_int64; break; + case OP_SUB_I64: OPC->_int64 = OPA->_int64 - OPB->_int64; break; + case OP_MUL_I64: OPC->_int64 = OPA->_int64 * OPB->_int64; break; + case OP_DIV_I64: OPC->_int64 = OPA->_int64 / OPB->_int64; break; + case OP_BITAND_I64: OPC->_int64 = OPA->_int64 & OPB->_int64; break; + case OP_BITOR_I64: OPC->_int64 = OPA->_int64 | OPB->_int64; break; + case OP_BITXOR_I64: OPC->_int64 = OPA->_int64 ^ OPB->_int64; break; + case OP_LSHIFT_I64I: OPC->_int64 = OPA->_int64 << OPB->_int; break; + case OP_RSHIFT_I64I: OPC->_int64 = OPA->_int64 >> OPB->_int; break; + case OP_LT_I64: OPC->_int = OPA->_int64 < OPB->_int64; break; + case OP_LE_I64: OPC->_int = OPA->_int64 <= OPB->_int64; break; + case OP_EQ_I64: OPC->_int = OPA->_int64 == OPB->_int64; break; + case OP_NE_I64: OPC->_int = OPA->_int64 != OPB->_int64; break; + case OP_LT_U64: OPC->_int = OPA->_uint64 < OPB->_uint64; break; + case OP_LE_U64: OPC->_int = OPA->_uint64 <= OPB->_uint64; break; + case OP_DIV_U64: OPC->_uint64 = OPA->_uint64 / OPB->_uint64; break; + case OP_RSHIFT_U64I: OPC->_uint64 = OPA->_uint64 >> OPB->_int; break; + case OP_STORE_I64: OPB->_int64 = OPA->_int64; +// case OP_LOADF_I64: OPC->_int64 = OPA->_int64 X OPB->_int64; break; +// case OP_LOADP_I64: OPC->_int64 = OPA->_int64 X OPB->_int64; break; + case OP_CONV_UI64: OPC->_int64 = OPA->_uint; break; + case OP_CONV_II64: OPC->_int64 = OPA->_int; break; + case OP_CONV_I64I: OPC->_int = OPA->_int64; break; + case OP_CONV_FD: OPC->_double = OPA->_float; break; + case OP_CONV_DF: OPC->_float = OPA->_double; break; + case OP_CONV_I64F: OPC->_float = OPA->_int64; break; + case OP_CONV_FI64: OPC->_int64 = OPA->_float; break; + case OP_CONV_I64D: OPC->_double = OPA->_int64; break; + case OP_CONV_DI64: OPC->_int64 = OPA->_double; break; + case OP_ADD_D: OPC->_double = OPA->_double + OPB->_double; break; + case OP_SUB_D: OPC->_double = OPA->_double - OPB->_double; break; + case OP_MUL_D: OPC->_double = OPA->_double * OPB->_double; break; + case OP_DIV_D: OPC->_double = OPA->_double / OPB->_double; break; + case OP_LT_D: OPC->_double = OPA->_double < OPB->_double; break; + case OP_LE_D: OPC->_double = OPA->_double <= OPB->_double; break; + case OP_EQ_D: OPC->_double = OPA->_double == OPB->_double; break; + case OP_NE_D: OPC->_double = OPA->_double != OPB->_double; break; + + default: if (op & OP_BIT_BREAKPOINT) //break point! { diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index bf2f5fe5b..83cbb6e86 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -1574,6 +1574,7 @@ static pubprogfuncs_t deffuncs = { 0, //string table size 0, //max size 0, //field adjust(aditional field offset) + 0, //field slots allocated (for builtins to clamp field reference args). PR_ForkStack, PR_ResumeThread, diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 5965a69a5..3ddd0a888 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -342,6 +342,62 @@ enum qcop_e { OP_STOREP_B,//((char*)b)[(int)c] = (int)a OP_LOADP_B, //(int)c = *(char*) +//r5768+ +//opcodes for 32bit uints + OP_LE_U, //aka GT + OP_LT_U, //aka GE + OP_DIV_U, //don't need mul+add+sub + OP_RSHIFT_U, //lshift is the same for signed+unsigned + +//opcodes for 64bit ints + OP_ADD_I64, + OP_SUB_I64, + OP_MUL_I64, + OP_DIV_I64, + OP_BITAND_I64, + OP_BITOR_I64, + OP_BITXOR_I64, + OP_LSHIFT_I64I, + OP_RSHIFT_I64I, + OP_LE_I64, //aka GT + OP_LT_I64, //aka GE + OP_EQ_I64, + OP_NE_I64, +//extra opcodes for 64bit uints + OP_LE_U64, //aka GT + OP_LT_U64, //aka GE + OP_DIV_U64, + OP_RSHIFT_U64I, + +//general 64bitness + OP_STORE_I64, + OP_STOREP_I64, + OP_STOREF_I64, + OP_LOAD_I64, + OP_LOADA_I64, + OP_LOADP_I64, +//various conversions for our 64bit types (yay type promotion) + OP_CONV_UI64, //zero extend + OP_CONV_II64, //sign extend + OP_CONV_I64I, //truncate + OP_CONV_FD, //extension + OP_CONV_DF, //truncation + OP_CONV_I64F, //logically a promotion (always signed) + OP_CONV_FI64, //demotion (always signed) + OP_CONV_I64D, //'promotion' (always signed) + OP_CONV_DI64, //demotion (always signed) + +//opcodes for doubles. + OP_ADD_D, + OP_SUB_D, + OP_MUL_D, + OP_DIV_D, + OP_LE_D, + OP_LT_D, + OP_EQ_D, + OP_NE_D, + + OP_NUMREALOPS, /* @@ -453,13 +509,61 @@ enum qcop_e { OP_SPACESHIP_F, //lame OP_SPACESHIP_S, //basically strcmp. + + //uint32 opcodes. they match the int32 ones so emulation is basically swapping them over. + OP_ADD_U, + OP_SUB_U, + OP_MUL_U, + OP_MOD_U, //complex + OP_BITAND_U, + OP_BITOR_U, + OP_BITXOR_U, + OP_BITNOT_U, //BITXOR ~0 + OP_BITCLR_U, + OP_LSHIFT_U, //same as signed (unlike rshift) + OP_GE_U, //LT_U + OP_GT_U, //LE_U +// OP_AND_U, +// OP_OR_U, + OP_EQ_U, + OP_NE_U, + + //uint64 opcodes. they match the int32 ones so emulation is basically swapping them over. + OP_BITNOT_I64, //BITXOR ~0 + OP_BITCLR_I64, + OP_GE_I64, //LT_I64 + OP_GT_I64, //LE_I64 + + OP_ADD_U64, + OP_SUB_U64, + OP_MUL_U64, + OP_MOD_U64, //complex + OP_BITAND_U64, + OP_BITOR_U64, + OP_BITXOR_U64, + OP_BITNOT_U64, //BITXOR ~0 + OP_BITCLR_U64, + OP_LSHIFT_U64I, + OP_GE_U64, //LT_U64 + OP_GT_U64, //LE_U64 + OP_EQ_U64, + OP_NE_U64, + + //generally implemented by forcing to int64. + OP_BITAND_D, + OP_BITOR_D, + OP_BITXOR_D, + OP_BITNOT_D, + OP_BITCLR_D, + OP_LSHIFT_DI, + OP_RSHIFT_DI, + //special/fake opcodes used by the decompiler. OPD_GOTO_FORSTART, OPD_GOTO_WHILE1, + OP_NUMOPS, OP_BIT_BREAKPOINT = 0x8000, - - OP_NUMOPS }; #define MAX_PARMS 8 diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 49516c53e..6b067f6e9 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -610,8 +610,20 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v case ev_float: QC_snprintfz (line, sizeof(line), "%g", val->_float); break; + case ev_double: + QC_snprintfz (line, sizeof(line), "%g", val->_double); + break; case ev_integer: - QC_snprintfz (line, sizeof(line), "%i", val->_int); + QC_snprintfz (line, sizeof(line), "%"pPRIi, val->_int); + break; + case ev_uint: + QC_snprintfz (line, sizeof(line), "%"pPRIu, val->_uint); + break; + case ev_int64: + QC_snprintfz (line, sizeof(line), "%"pPRIi64, val->_int64); + break; + case ev_uint64: + QC_snprintfz (line, sizeof(line), "%"pPRIu64, val->_uint64); break; case ev_vector: QC_snprintfz (line, sizeof(line), "'%g %g %g'", val->_vector[0], val->_vector[1], val->_vector[2]); @@ -749,8 +761,23 @@ char *PDECL PR_UglyValueString (pubprogfuncs_t *ppf, etype_t type, eval_t *val) else sprintf (line, "%f", val->_float); break; + case ev_double: + if (val->_double == (pint64_t)val->_double) + sprintf (line, "%"pPRIi64, (pint64_t)val->_double); //an attempt to cut down on the number of .000000 vars.. + else + sprintf (line, "%f", val->_double); + break; case ev_integer: - sprintf (line, "%i", val->_int); + sprintf (line, "%"pPRIi, val->_int); + break; + case ev_uint: + sprintf (line, "%"pPRIu, val->_uint); + break; + case ev_int64: + sprintf (line, "%"pPRIi64, val->_int64); + break; + case ev_uint64: + sprintf (line, "%"pPRIu64, val->_int64); break; case ev_vector: if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2]) @@ -815,8 +842,23 @@ char *PR_UglyOldValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val) else QC_snprintfz (line, sizeof(line), "%f", val->_float); break; + case ev_double: + if (val->_double == (int)val->_double) + QC_snprintfz (line, sizeof(line), "%i", (int)val->_double); //an attempt to cut down on the number of .000000 vars.. + else + QC_snprintfz (line, sizeof(line), "%f", val->_double); + break; case ev_integer: - QC_snprintfz (line, sizeof(line), "%i", val->_int); + QC_snprintfz (line, sizeof(line), "%"pPRIi, val->_int); + break; + case ev_uint: + QC_snprintfz (line, sizeof(line), "%"pPRIu, val->_uint); + break; + case ev_int64: + QC_snprintfz (line, sizeof(line), "%"pPRIi64, val->_int64); + break; + case ev_uint64: + QC_snprintfz (line, sizeof(line), "%"pPRIu64, val->_uint64); break; case ev_vector: if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2]) @@ -862,10 +904,18 @@ char *PR_TypeString(progfuncs_t *progfuncs, etype_t type) return "void"; case ev_float: return "float"; + case ev_double: + return "double"; case ev_vector: return "vector"; case ev_integer: return "integer"; + case ev_uint: + return "uint"; + case ev_int64: + return "int64"; + case ev_uint64: + return "uint64"; default: return "BAD TYPE"; } @@ -1192,9 +1242,21 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha case ev_float: eval->_float = (float)atof (s); break; + case ev_double: + eval->_double = atof (s); + break; case ev_integer: - eval->_int = atoi (s); + eval->_int = strtol (s, NULL, 0); + break; + case ev_uint: + eval->_uint = strtoul (s, NULL, 0); + break; + case ev_int64: + eval->_int64 = strtoll (s, NULL, 0); + break; + case ev_uint64: + eval->_uint64 = strtoull (s, NULL, 0); break; case ev_vector: @@ -1259,14 +1321,15 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, int fldtype, char *s) { - int i; + pint64_t i; + puint64_t u; progsnum_t module; fdef_t *def; string_t st; mfunction_t *func; int type = fldtype & ~DEF_SAVEGLOBAL; double d; - qcptr += fldofs*sizeof(int); + eval_t *eval = (eval_t *)(progfuncs->funcs.stringtable + qcptr + (fldofs*sizeof(int))); switch (type) { @@ -1276,7 +1339,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, #else st = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, s, 0, true)); #endif - *(string_t *)(progfuncs->funcs.stringtable + qcptr) = st; + eval->string = st; break; case ev_float: @@ -1285,19 +1348,60 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, d = strtod(s, &s); while(*s == ' ' || *s == '\t') s++; - *(float *)(progfuncs->funcs.stringtable + qcptr) = d; + eval->_float = d; + if (*s) + return false; //some kind of junk in there. + break; + case ev_double: + while(*s == ' ' || *s == '\t') + s++; + d = strtod(s, &s); + while(*s == ' ' || *s == '\t') + s++; + eval->_double = d; if (*s) return false; //some kind of junk in there. break; - case ev_entity: //ent references are simple ints for us. case ev_integer: while(*s == ' ' || *s == '\t') s++; i = strtol(s, &s, 0); while(*s == ' ' || *s == '\t') s++; - *(int *)(progfuncs->funcs.stringtable + qcptr) = i; + eval->_int = i; + if (*s) + return false; //some kind of junk in there. + break; + case ev_entity: //ent references are simple ints for us. + case ev_uint: + while(*s == ' ' || *s == '\t') + s++; + u = strtoul(s, &s, 0); + while(*s == ' ' || *s == '\t') + s++; + eval->_uint = u; + if (*s) + return false; //some kind of junk in there. + break; + + case ev_int64: + while(*s == ' ' || *s == '\t') + s++; + i = strtoll(s, &s, 0); + while(*s == ' ' || *s == '\t') + s++; + eval->_int64 = i; + if (*s) + return false; //some kind of junk in there. + break; + case ev_uint64: + while(*s == ' ' || *s == '\t') + s++; + u = strtoull(s, &s, 0); + while(*s == ' ' || *s == '\t') + s++; + eval->_uint64 = u; if (*s) return false; //some kind of junk in there. break; @@ -1308,7 +1412,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, while(*s == ' ' || *s == '\t') s++; d = strtod(s, &s); - ((float *)(progfuncs->funcs.stringtable + qcptr))[i] = d; + eval->_vector[i] = d; } while(*s == ' ' || *s == '\t') s++; @@ -1323,13 +1427,13 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, externs->Printf ("Can't find field %s\n", s); return false; } - *(int *)(progfuncs->funcs.stringtable + qcptr) = def->ofs; + eval->_int = def->ofs; break; case ev_function: if (s[0] && s[1]==':'&&s[2]=='\0') //this isn't right... { - *(func_t *)(progfuncs->funcs.stringtable + qcptr) = 0; + eval->function = 0; return true; } func = ED_FindFunction (progfuncs, s, &module, -1); @@ -1338,7 +1442,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, externs->Printf ("Can't find function %s\n", s); return false; } - *(func_t *)(progfuncs->funcs.stringtable + qcptr) = (func - pr_progstate[module].functions) | (module<<24); + eval->function = (func - pr_progstate[module].functions) | (module<<24); break; default: @@ -1564,7 +1668,11 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t } else if (type != ev_string //anything other than these is not saved && type != ev_float + && type != ev_double && type != ev_integer + && type != ev_uint + && type != ev_int64 + && type != ev_uint64 && type != ev_entity && type != ev_vector) continue; @@ -1621,7 +1729,11 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t } else if (type != ev_string //anything other than these is not saved && type != ev_float + && type != ev_double && type != ev_integer + && type != ev_uint + && type != ev_int64 + && type != ev_uint64 && type != ev_entity && type != ev_vector) continue; @@ -3098,8 +3210,11 @@ retry: nf->progsofs = fld16[i].ofs; nf->ofs = fld16[i].ofs; - if (prinst.fields_size < (nf->ofs+type_size[nf->type])*4) - prinst.fields_size = (nf->ofs+type_size[nf->type])*4; + if (prinst.fields_size < (nf->ofs+type_size[nf->type])*sizeof(pvec_t)) + { + prinst.fields_size = (nf->ofs+type_size[nf->type])*sizeof(pvec_t); + progfuncs->funcs.activefieldslots = nf->ofs+type_size[nf->type]; + } prinst.numfields++; } diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index bc45b1eca..32f3c0a76 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -244,7 +244,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char prinst.reorganisefields = 2; else if (engineofs) { - progfuncs->funcs.fieldadjust = prinst.fields_size/4; + progfuncs->funcs.fieldadjust = prinst.fields_size/sizeof(pvec_t); #ifdef MAPPING_DEBUG externs->Printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, prinst.fields_size, (int)prinst.fields_size/4); #endif @@ -329,7 +329,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char } else { //we just found a new fieldname inside a progs - prinst.field[fnum].ofs = ofs = prinst.fields_size/4; //add on the end + prinst.field[fnum].ofs = ofs = prinst.fields_size/sizeof(pvec_t); //add on the end //if the progs field offset matches annother offset in the same progs, make it match up with the earlier one. if (progsofs>=0) @@ -368,8 +368,11 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char } } // if (type != ev_vector) - if (prinst.fields_size < (ofs+type_size[type])*4) - prinst.fields_size = (ofs+type_size[type])*4; + if (prinst.fields_size < (ofs+type_size[type])*sizeof(pvec_t)) + { + prinst.fields_size = (ofs+type_size[type])*sizeof(pvec_t); + progfuncs->funcs.activefieldslots = prinst.fields_size/sizeof(pvec_t); + } if (prinst.max_fields_size && prinst.fields_size > prinst.max_fields_size) externs->Sys_Error("Allocated too many additional fields after ents were inited."); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 39e17e14f..745702c96 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -67,7 +67,30 @@ typedef struct { int spare[2]; } evalc_t; #define sizeofevalc sizeof(evalc_t) -typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union, ev_accessor, ev_enum, ev_boolean} etype_t; +typedef enum { +//vanilla types +ev_void, +ev_string, //offset into the string table - but if the high bit is set then its probably some special thing. +ev_float, //can hold up to 24 bits... sucks, but this is our basic numeric type. +ev_vector, //3 floats. +ev_entity, //index into the edicts array (vanilla used byte offsets from world). +ev_field, //index into the per-entity field table. +ev_function,//all functions are called via reference. +ev_pointer, //exists in vanilla - *(&ent.fld) opcodes are valid there - how else would you store to a field? +//extended types +ev_integer, //our first extended type... probably won't help performance much but at least it doesn't have the imprecision issue of floats. +ev_uint, //mostly just reuses int opcodes. +ev_int64, //large int type, because we can. might be useful for system handles perhaps? dunno, probably not that useful. +ev_uint64, //mostly just reuses int64 opcodes. +ev_double, //useful for timers, for the extra precision. +//qc-only types +ev_variant, //used primarily for builtin args, or for type punning casts without using pointers. should never be used for a global. +ev_struct, //big complex type +ev_union, //not really sure why this is separate from struct +ev_accessor,//some weird type to provide class-like functions over a basic type. +ev_enum, //just a numeric type +ev_boolean //exists to optimise if(-0) workarounds. +} etype_t; enum { DEBUG_TRACE_OFF, //debugging should be off. DEBUG_TRACE_INTO, //debug into functions @@ -154,6 +177,8 @@ struct pubprogfuncs_s int stringtablesize; int stringtablemaxsize; int fieldadjust; //FrikQCC style arrays can cause problems due to field remapping. This causes us to leave gaps but offsets identical. except for system fields, qc-addressable variables use their old offsets, this is the bias so that the offset pokes the correct memory. + unsigned int activefieldslots; //f+=fieldadjust; invalidfield = (f<0)||(f+fldsize>=activefieldslots); note that this does NOT apply to 'object' entities which are variable sized, use ed->fieldsize for those. + struct qcthread_s *(PDECL *Fork) (pubprogfuncs_t *prinst); //returns a pointer to a thread which can be resumed via RunThread. void (PDECL *RunThread) (pubprogfuncs_t *prinst, struct qcthread_s *thread); @@ -260,12 +285,16 @@ pubprogfuncs_t * PDECL InitProgs(progparms_t *ext); typedef union eval_s { string_t string; - float _float; - float _vector[3]; - func_t function; - int _int; - int edict; - float prog; //so it can easily be changed + pvec_t _float; + pvec_t _vector[3]; + func_t function; //module=0xff000000, func=0x00ffffff + pint_t _int; + puint_t _uint; + pint64_t _int64; + puint64_t _uint64; + double _double; + pint_t edict; + pvec_t prog; //so it can easily be changed } eval_t; #define PR_CURRENT -1 @@ -334,7 +363,11 @@ typedef union eval_s //To use these outside of builtins, you will likly have to use the 'globals' method. #define G_FLOAT(o) (((pvec_t *)pr_globals)[o]) #define G_FLOAT2(o) (((pvec_t *)pr_globals)[OFS_PARM0 + o*3]) +#define G_DOUBLE(o) (*(double *)(((pvec_t *)pr_globals+(o)))) #define G_INT(o) (((pint_t *)pr_globals)[o]) +#define G_UINT(o) (((puint_t *)pr_globals)[o]) +#define G_INT64(o) (*(pint64_t *)((pint_t *)pr_globals+(o))) +#define G_UINT64(o) (*(puint64_t *)((puint_t *)pr_globals+(o))) #define G_EDICT(pf, o) PROG_TO_EDICT(pf, G_INT(o)) //((edict_t *)((char *) sv.edicts+ *(int *)&((float *)pr_globals)[o])) #define G_EDICTNUM(pf, o) NUM_FOR_EDICT(pf, G_EDICT(pf, o)) #define G_VECTOR(o) (&((pvec_t *)pr_globals)[o]) diff --git a/engine/qclib/progtype.h b/engine/qclib/progtype.h index f2320d95c..09d508353 100644 --- a/engine/qclib/progtype.h +++ b/engine/qclib/progtype.h @@ -23,10 +23,30 @@ typedef uint64_t puint_t; typedef float pvec_t; typedef int pint_t; typedef unsigned int puint_t; -#define pPRId "d" -#define pPRIi "i" -#define pPRIu "u" -#define pPRIx "x" +#ifdef _MSC_VER + typedef __int64 pint64_t; + typedef unsigned __int64 puint64_t; + + #define pPRId "d" + #define pPRIi "i" + #define pPRIu "u" + #define pPRIx "x" + #define pPRIi64 "I64i" + #define pPRIu64 "I64u" + #define pPRIx64 "I64x" +#else + #include + typedef int64_t pint64_t; + typedef uint64_t puint64_t; + + #define pPRId PRId32 + #define pPRIi PRIi32 + #define pPRIu PRIu32 + #define pPRIx PRIx32 + #define pPRIi64 PRIi64 + #define pPRIu64 PRIu64 + #define pPRIx64 PRIx64 +#endif #define QCVM_32 #endif diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 89ae661ec..a295b4832 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -317,7 +317,7 @@ typedef struct QCC_function_s QCC_function_t; #define MAX_PARMS 8 //keep this sizeof(float) -typedef union QCC_eval_s +typedef union QCC_eval_basic_s { QCC_string_t string; pvec_t _float; @@ -328,19 +328,24 @@ typedef union QCC_eval_s #endif func_t function; pint_t _int; + puint_t _uint; // union QCC_eval_s *ptr; -} QCC_eval_t; +} QCC_eval_basic_t; //must be the maximum size possible for a single basic type. -typedef union QCC_evalstorage_s +typedef union QCC_eval_s { QCC_string_t string; pvec_t _float; + double _double; pvec_t vector[3]; func_t function; pint_t _int; + puint_t _uint; + pint64_t _int64; + puint64_t _uint64; // union QCC_eval_s *ptr; -} QCC_evalstorage_t; +} QCC_eval_t; struct QCC_typeparam_s { @@ -349,7 +354,7 @@ struct QCC_typeparam_s pbool optional:1; //argument may safely be omitted, for builtin functions. for qc functions use the defltvalue instead. pbool isvirtual:1; //const, with implicit initialisation only. valid for structs unsigned char out; //0=in,1==inout,2=out - unsigned int ofs; + unsigned int ofs; //FIXME: make byte offsets, for bytes/shorts. unsigned int arraysize; char *paramname; }; @@ -375,8 +380,8 @@ typedef struct QCC_type_s struct QCC_typeparam_s *params; //[num_parms] unsigned int num_parms; - unsigned int size; - pbool typedefed:1; + unsigned int size; //FIXME: make bytes, for bytes+shorts + pbool typedefed:1; //name is in the typenames list. pbool vargs:1; //function has vargs pbool vargcount:1; //function has special varg count param const char *name; @@ -412,7 +417,7 @@ typedef struct QCC_def_s struct QCC_def_s *reloc; //the symbol that we're a reloc for struct QCC_def_s *gaddress; //a def that holds our offset. struct QCC_def_s *symbolheader; //this is the original symbol within which the def is stored. - union QCC_eval_s *symboldata; //null if uninitialised. use sym->symboldata[sym->ofs] to index. + union QCC_eval_basic_s *symboldata; //null if uninitialised. use sym->symboldata[sym->ofs] to index. unsigned int symbolsize; //total byte size of symbol int refcount; //if 0, temp can be reused. tracked on globals too in order to catch bugs that would otherwise be a little too obscure. @@ -497,7 +502,7 @@ extern int QCC_packid; extern const unsigned int type_size[]; //extern QCC_def_t *def_for_type[9]; -extern QCC_type_t *type_void, *type_string, *type_float, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_integer, *type_variant, *type_floatfield; +extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_variant, *type_floatfield; extern char *basictypenames[]; struct QCC_function_s @@ -581,7 +586,7 @@ extern token_type_t pr_token_type; extern int pr_token_line; extern int pr_token_line_last; extern QCC_type_t *pr_immediate_type; -extern QCC_evalstorage_t pr_immediate; +extern QCC_eval_t pr_immediate; extern pbool keyword_asm; extern pbool keyword_break; @@ -596,10 +601,17 @@ extern pbool keyword_default; extern pbool keyword_do; extern pbool keyword_entity; extern pbool keyword_float; +extern pbool keyword_double; extern pbool keyword_for; extern pbool keyword_goto; +extern pbool keyword_char; +extern pbool keyword_byte; +extern pbool keyword_short; extern pbool keyword_int; extern pbool keyword_integer; +extern pbool keyword_long; +extern pbool keyword_signed; +extern pbool keyword_unsigned; extern pbool keyword_state; extern pbool keyword_string; extern pbool keyword_struct; @@ -642,6 +654,7 @@ extern pbool flag_laxcasts; extern pbool flag_hashonly; extern pbool flag_fasttrackarrays; extern pbool flag_assume_integer; +extern pbool flag_assume_double; extern pbool flag_msvcstyle; extern pbool flag_debugmacros; extern pbool flag_filetimes; @@ -656,6 +669,7 @@ extern pbool flag_assumevar; extern pbool flag_dblstarexp; extern pbool flag_allowuninit; extern pbool flag_cpriority; +extern pbool flag_qcfuncs; extern pbool flag_embedsrc; extern pbool flag_nopragmafileline; extern pbool flag_utf8strings; @@ -740,14 +754,14 @@ void QCC_PR_Expect (const char *string); pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string); #endif pbool QCC_PR_CheckTokenComment(const char *string, char **comment); -void VARGS QCC_PR_ParseError (int errortype, const char *error, ...); +NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...); pbool VARGS QCC_PR_ParseWarning (int warningtype, const char *error, ...); pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *error, ...); void VARGS QCC_PR_Note (int type, const char *file, int line, const char *error, ...); void QCC_PR_ParsePrintDef (int warningtype, QCC_def_t *def); void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref); -void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...); -void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...); +NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...); +NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...); QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype); @@ -845,6 +859,7 @@ enum { WARN_REDECLARATIONMISMATCH, WARN_PARAMWITHNONAME, WARN_ARGUMENTCHECK, + WARN_IGNOREDKEYWORD, //use of a keyword that fteqcc does not support at this time. ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called. @@ -1066,6 +1081,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype); void QCC_PR_ParseDefs (char *classname, pbool fatal); +void QCC_PR_ParseTypedef(void); QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *scope, int arraysize, QCC_def_t *rootsymbol, unsigned int ofs, int referable, unsigned int flags); void QCC_PR_ParseInitializerDef(QCC_def_t *def, unsigned int flags); void QCC_PR_FinaliseFunctions(void); @@ -1084,7 +1100,7 @@ void QCC_Cleanup(void); extern char pr_immediate_string[8192]; extern size_t pr_immediate_strlen; -extern QCC_eval_t *qcc_pr_globals; +extern QCC_eval_basic_t *qcc_pr_globals; extern unsigned int numpr_globals; extern char *strings; diff --git a/engine/qclib/qcc_cmdlib.c b/engine/qclib/qcc_cmdlib.c index 8d7e6ca6f..54b1de0e5 100644 --- a/engine/qclib/qcc_cmdlib.c +++ b/engine/qclib/qcc_cmdlib.c @@ -19,7 +19,7 @@ const char **myargv; char qcc_token[1024]; int qcc_eof; -const unsigned int type_size[12] = {1, //void +const unsigned int type_size[] = {1, //void sizeof(string_t)/4, //string 1, //float 3, //vector @@ -28,12 +28,18 @@ const unsigned int type_size[12] = {1, //void sizeof(func_t)/4,//function 1, //pointer (its an int index) 1, //integer + 1, //uint + 2, //long + 2, //ulong + 2, //double 3, //fixme: how big should a variant be? 0, //ev_struct. variable sized. - 0 //ev_union. variable sized. + 0, //ev_union. variable sized. + 0, //ev_accessor... + 0, //ev_enum... + 1, //ev_bool... }; - char *basictypenames[] = { "void", "string", @@ -44,11 +50,16 @@ char *basictypenames[] = { "function", "pointer", "integer", + "uint", + "long", + "ulong", + "double", "variant", "struct", "union", "accessor", - "enum" + "enum", + "bool" }; /* @@ -291,10 +302,7 @@ skipwhite: while ((c = *data) && qcc_iswhite(c)) data++; if (!c) - { - qcc_eof = true; return NULL; - } // skip // comments if (c=='/' && data[1] == '/') @@ -415,10 +423,7 @@ skipwhite: while ((c = *data) && qcc_iswhite(c)) data++; if (!c) - { - qcc_eof = true; return NULL; - } // skip // comments if (c=='/' && data[1] == '/') diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index ad1b38098..183a5e459 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -67,10 +67,16 @@ pbool keyword_optional; pbool keyword_const; //fixme pbool keyword_entity; //for skipping the local pbool keyword_float; //for skipping the local +pbool keyword_double; pbool keyword_for; pbool keyword_goto; +pbool keyword_char; +pbool keyword_short; pbool keyword_int; //for skipping the local pbool keyword_integer; //for skipping the local +pbool keyword_long; +pbool keyword_signed; +pbool keyword_unsigned; pbool keyword_state; pbool keyword_string; //for skipping the local pbool keyword_struct; @@ -130,6 +136,7 @@ pbool flag_fasttrackarrays; //Faster arrays, dynamically detected, activated onl pbool flag_msvcstyle; //MSVC style warnings, so msvc's ide works properly pbool flag_debugmacros; //Print out #defines as they are expanded, for debugging. pbool flag_assume_integer; //5 - is that an integer or a float? qcc says float. but we support int too, so maybe we want that instead? +pbool flag_assume_double; //5.0 - is that single or double precision? QC says float, but C says double. should probably only be used with assume-int enabled too. pbool flag_filetimes; pbool flag_typeexplicit; //no implicit type conversions, you must do the casts yourself. pbool flag_boundchecks; //Disable generation of bound check instructions. @@ -141,6 +148,7 @@ pbool flag_attributes; //gmqcc-style attributes pbool flag_assumevar; //initialised globals will no longer be considered constant pbool flag_dblstarexp; // a**b is pow(a,b) instead of a*(*b) pbool flag_cpriority; //operator precidence should adhere to C standards, instead of QC compatibility. +pbool flag_qcfuncs; //void() is a function type, and not a syntax error. pbool flag_allowuninit; //ignore uninitialised locals, avoiding all private locals. pbool flag_embedsrc; //embed all source files inside the .dat (can be opened with any zip program) pbool flag_nopragmafileline;//ignore #pragma file and #pragma line, so that I can actually read+debug xonotic's code. @@ -249,8 +257,13 @@ QCC_sref_t QCC_MakeTranslateStringConst(const char *value); QCC_sref_t QCC_MakeStringConst(const char *value); QCC_sref_t QCC_MakeStringConstLength(const char *value, int length); QCC_sref_t QCC_MakeFloatConst(pvec_t value); +QCC_sref_t QCC_MakeDoubleConst(double value); QCC_sref_t QCC_MakeFloatConstFromInt(longlong llvalue); -QCC_sref_t QCC_MakeIntConst(longlong llvalue); +QCC_sref_t QCC_MakeIntConst(longlong llvalue); //longlongs for warnings +QCC_sref_t QCC_MakeUIntConst(unsigned longlong llvalue); +QCC_sref_t QCC_MakeInt64Const(longlong llvalue); +QCC_sref_t QCC_MakeUInt64Const(unsigned longlong llvalue); +static QCC_sref_t QCC_MakeUniqueConst(QCC_type_t *type, void *data); QCC_sref_t QCC_MakeVectorConst(pvec_t a, pvec_t b, pvec_t c); static QCC_sref_t QCC_MakeGAddress(QCC_type_t *type, QCC_def_t *relocof); @@ -359,92 +372,92 @@ static int priority_class[MAX_PRIORITY_CLASSES+1]; //to simplify implementation //if true, effectivly {b=a; return a;} QCC_opcode_t pr_opcodes[] = { - {6, "", "DONE", PC_NONE, ASSOC_LEFT, &type_void, &type_void, &type_void}, + {6, "", "DONE", PC_NONE, ASSOC_LEFT, &type_void, &type_void, &type_void}, - {6, "*", "MUL_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "*", "MUL_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_float, OPF_STD}, - {6, "*", "MUL_FV", PC_MULDIV, ASSOC_LEFT, &type_float, &type_vector, &type_vector, OPF_STD}, - {6, "*", "MUL_VF", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_float, &type_vector, OPF_STD}, + {6, "*", "MUL_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "*", "MUL_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_float, OPF_STD}, + {6, "*", "MUL_FV", PC_MULDIV, ASSOC_LEFT, &type_float, &type_vector, &type_vector, OPF_STD}, + {6, "*", "MUL_VF", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_float, &type_vector, OPF_STD}, - {6, "/", "DIV_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "/", "DIV_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "+", "ADD_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "+", "ADD_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STD}, + {6, "+", "ADD_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "+", "ADD_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STD}, - {6, "-", "SUB_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "-", "SUB_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STD}, + {6, "-", "SUB_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "-", "SUB_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STD}, - {6, "==", "EQ_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "==", "EQ_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_float, OPF_STD}, - {6, "==", "EQ_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, - {6, "==", "EQ_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_float, OPF_STD}, - {6, "==", "EQ_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_float,OPF_STD}, + {6, "==", "EQ_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, "==", "EQ_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_bfloat, OPF_STD}, + {6, "==", "EQ_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_bfloat, OPF_STD}, + {6, "==", "EQ_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_bfloat, OPF_STD}, + {6, "==", "EQ_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_bfloat, OPF_STD}, - {6, "!=", "NE_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "!=", "NE_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_float, OPF_STD}, - {6, "!=", "NE_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, - {6, "!=", "NE_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_float, OPF_STD}, - {6, "!=", "NE_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_float,OPF_STD}, + {6, "!=", "NE_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, "!=", "NE_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_bfloat, OPF_STD}, + {6, "!=", "NE_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_bfloat, OPF_STD}, + {6, "!=", "NE_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_bfloat, OPF_STD}, + {6, "!=", "NE_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_bfloat, OPF_STD}, - {6, "<=", "LE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, ">=", "GE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "<", "LT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, ">", "GT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "<=", "LE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, ">=", "GE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, "<", "LT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, ">", "GT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, - {6, ".", "LOADF_F", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_float}, - {6, ".", "LOADF_V", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_vector}, - {6, ".", "LOADF_S", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_string}, - {6, ".", "LOADF_E", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_entity}, - {6, ".", "LOADF_FI", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_field}, - {6, ".", "LOADF_FU", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_function}, + {6, ".", "LOADF_F", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_float}, + {6, ".", "LOADF_V", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_vector}, + {6, ".", "LOADF_S", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_string}, + {6, ".", "LOADF_ENT", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_entity}, + {6, ".", "LOADF_FLD", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_field}, + {6, ".", "LOADF_FNC", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_function}, - {6, ".", "FLDADDRESS", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, + {6, ".", "FLDADDRESS", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, - {6, "=", "STORE_F", PC_STORE, ASSOC_RIGHT, &type_float, &type_float, &type_float, OPF_STORE}, - {6, "=", "STORE_V", PC_STORE, ASSOC_RIGHT, &type_vector, &type_vector, &type_vector, OPF_STORE}, - {6, "=", "STORE_S", PC_STORE, ASSOC_RIGHT, &type_string, &type_string, &type_string, OPF_STORE}, - {6, "=", "STORE_ENT", PC_STORE, ASSOC_RIGHT, &type_entity, &type_entity, &type_entity, OPF_STORE}, - {6, "=", "STORE_FLD", PC_STORE, ASSOC_RIGHT, &type_field, &type_field, &type_field, OPF_STORE}, - {6, "=", "STORE_FNC", PC_STORE, ASSOC_RIGHT, &type_function, &type_function, &type_function, OPF_STORE}, + {6, "=", "STORE_F", PC_STORE, ASSOC_RIGHT, &type_float, &type_float, &type_float, OPF_STORE}, + {6, "=", "STORE_V", PC_STORE, ASSOC_RIGHT, &type_vector, &type_vector, &type_vector, OPF_STORE}, + {6, "=", "STORE_S", PC_STORE, ASSOC_RIGHT, &type_string, &type_string, &type_string, OPF_STORE}, + {6, "=", "STORE_ENT", PC_STORE, ASSOC_RIGHT, &type_entity, &type_entity, &type_entity, OPF_STORE}, + {6, "=", "STORE_FLD", PC_STORE, ASSOC_RIGHT, &type_field, &type_field, &type_field, OPF_STORE}, + {6, "=", "STORE_FNC", PC_STORE, ASSOC_RIGHT, &type_function, &type_function, &type_function, OPF_STORE}, - {6, "=", "STOREP_F", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_float, OPF_STOREPTROFS}, - {6, "=", "STOREP_V", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_vector, &type_vector, OPF_STOREPTROFS}, - {6, "=", "STOREP_S", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_string, &type_string, OPF_STOREPTROFS}, - {6, "=", "STOREP_ENT", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_entity, &type_entity, OPF_STOREPTROFS}, - {6, "=", "STOREP_FLD", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_field, &type_field, OPF_STOREPTROFS}, - {6, "=", "STOREP_FNC", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_function, &type_function, OPF_STOREPTROFS}, + {6, "=", "STOREP_F", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_float, OPF_STOREPTROFS}, + {6, "=", "STOREP_V", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_vector, &type_vector, OPF_STOREPTROFS}, + {6, "=", "STOREP_S", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_string, &type_string, OPF_STOREPTROFS}, + {6, "=", "STOREP_ENT", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_entity, &type_entity, OPF_STOREPTROFS}, + {6, "=", "STOREP_FLD", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_field, &type_field, OPF_STOREPTROFS}, + {6, "=", "STOREP_FNC", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_function, &type_function, OPF_STOREPTROFS}, - {6, "", "RETURN", PC_NONE, ASSOC_LEFT, &type_vector, &type_void, &type_void}, + {6, "", "RETURN", PC_NONE, ASSOC_LEFT, &type_vector, &type_void, &type_void}, - {6, "!", "NOT_F", PC_UNARY, ASSOC_LEFT, &type_float, &type_void, &type_float}, - {6, "!", "NOT_V", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_float}, - {6, "!", "NOT_S", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_float}, - {6, "!", "NOT_ENT", PC_UNARY, ASSOC_LEFT, &type_entity, &type_void, &type_float}, - {6, "!", "NOT_FNC", PC_UNARY, ASSOC_LEFT, &type_function, &type_void, &type_float}, + {6, "!", "NOT_F", PC_UNARY, ASSOC_LEFT, &type_float, &type_void, &type_bfloat}, + {6, "!", "NOT_V", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_bfloat}, + {6, "!", "NOT_S", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_bfloat}, + {6, "!", "NOT_ENT", PC_UNARY, ASSOC_LEFT, &type_entity, &type_void, &type_bfloat}, + {6, "!", "NOT_FNC", PC_UNARY, ASSOC_LEFT, &type_function, &type_void, &type_bfloat}, - {6, "", "IF", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, - {6, "", "IFNOT", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, + {6, "", "IF", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, + {6, "", "IFNOT", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, // calls returns REG_RETURN - {6, "", "CALL0", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL1", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL2", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL3", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL4", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL5", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL6", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL7", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL8", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL0", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL1", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL2", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL3", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL4", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL5", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL6", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL7", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL8", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "STATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void}, + {6, "", "STATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void}, - {6, "", "GOTO", PC_NONE, ASSOC_RIGHT, NULL, &type_void, &type_void}, + {6, "", "GOTO", PC_NONE, ASSOC_RIGHT, NULL, &type_void, &type_void}, - {6, "&&", "AND_F", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "||", "OR_F", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "&&", "AND_F", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, + {6, "||", "OR_F", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_float, &type_bfloat, OPF_STD}, - {6, "&", "BITAND", PC_BITAND, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, - {6, "|", "BITOR", PC_BITOR, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "&", "BITAND", PC_BITAND, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {6, "|", "BITOR", PC_BITOR, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, //version 6 are in normal progs. @@ -541,13 +554,13 @@ QCC_opcode_t pr_opcodes[] = {7, "*", "MUL_I", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_integer, &type_integer,OPF_STD}, {7, "/", "DIV_I", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_integer, &type_integer,OPF_STD}, - {7, "==", "EQ_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_integer,OPF_STD}, - {7, "!=", "NE_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_integer,OPF_STD}, + {7, "==", "EQ_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_bint ,OPF_STD}, + {7, "!=", "NE_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_bint ,OPF_STD}, {7, "", "IFNOTS", PC_NONE, ASSOC_RIGHT, &type_string, NULL, &type_void}, {7, "", "IFS", PC_NONE, ASSOC_RIGHT, &type_string, NULL, &type_void}, - {7, "!", "NOT_I", PC_UNARY, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, + {7, "!", "NOT_I", PC_UNARY, ASSOC_LEFT, &type_integer, &type_void, &type_bint}, {7, "/", "DIV_VF", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_float, &type_vector, OPF_STD}, @@ -579,30 +592,30 @@ QCC_opcode_t pr_opcodes[] = {7, "=", "LOADP_I", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_integer, OPF_LOADPTR}, - {7, "<=", "LE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, - {7, ">=", "GE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, - {7, "<", "LT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, - {7, ">", "GT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, + {7, "<=", "LE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, + {7, ">=", "GE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, + {7, "<", "LT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, + {7, ">", "GT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, - {7, "<=", "LE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, - {7, ">=", "GE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, - {7, "<", "LT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, - {7, ">", "GT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, + {7, "<=", "LE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, + {7, ">=", "GE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, + {7, "<", "LT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, + {7, ">", "GT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, - {7, "<=", "LE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, - {7, ">=", "GE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, - {7, "<", "LT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, - {7, ">", "GT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, + {7, "<=", "LE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, + {7, ">=", "GE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, + {7, "<", "LT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, + {7, ">", "GT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, - {7, "==", "EQ_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, - {7, "==", "EQ_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, + {7, "==", "EQ_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, + {7, "==", "EQ_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, //------------------------------------- //string manipulation. - {7, "+", "ADD_SF", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_float, &type_string, OPF_STD}, - {7, "-", "SUB_S", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, - {7, "", "STOREP_C", PC_STORE, ASSOC_RIGHT, &type_string, &type_float, &type_float, OPF_STOREPTROFS}, - {7, "", "LOADP_C", PC_STORE, ASSOC_LEFT, &type_string, &type_float, &type_float, OPF_LOADPTR}, + {7, "+", "ADD_SF", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_float, &type_string, OPF_STD}, + {7, "-", "SUB_S", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, + {7, "", "STOREP_C", PC_STORE, ASSOC_RIGHT, &type_string, &type_float, &type_float, OPF_STOREPTROFS}, + {7, "", "LOADP_C", PC_STORE, ASSOC_LEFT, &type_string, &type_float, &type_float, OPF_LOADPTR}, //------------------------------------- @@ -620,14 +633,14 @@ QCC_opcode_t pr_opcodes[] = {7, "&", "BITAND_FI", PC_BITAND, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, {7, "|", "BITOR_FI", PC_BITOR, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, -{7, "&&", "AND_I", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, -{7, "||", "OR_I", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STD}, -{7, "&&", "AND_IF", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, -{7, "||", "OR_IF", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, -{7, "&&", "AND_FI", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, -{7, "||", "OR_FI", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, -{7, "!=", "NE_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_integer, OPF_STD}, -{7, "!=", "NE_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, +{7, "&&", "AND_I", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, +{7, "||", "OR_I", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_integer, &type_bint, OPF_STD}, +{7, "&&", "AND_IF", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, +{7, "||", "OR_IF", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, +{7, "&&", "AND_FI", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, +{7, "||", "OR_FI", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, +{7, "!=", "NE_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_bint, OPF_STD}, +{7, "!=", "NE_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_bint, OPF_STD}, @@ -663,13 +676,61 @@ QCC_opcode_t pr_opcodes[] = {7, "", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, {7, "","IFNOT_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, -{7, "<=>", "STOREF_V", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector, OPF_STOREFLD}, //ent.fld=c -{7, "<=>", "STOREF_F", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_float, OPF_STOREFLD}, -{7, "<=>", "STOREF_S", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_string, OPF_STOREFLD}, -{7, "<=>", "STOREF_I", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_integer, OPF_STOREFLD}, +{7, "=", "STOREF_V", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector, OPF_STOREFLD}, //ent.fld=c +{7, "=", "STOREF_F", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_float, OPF_STOREFLD}, +{7, "=", "STOREF_S", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_string, OPF_STOREFLD}, +{7, "=", "STOREF_I", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_integer, OPF_STOREFLD}, - {7, "", "STOREP_B", PC_STORE, ASSOC_RIGHT, &type_string, &type_integer, &type_integer, OPF_STOREPTROFS}, - {7, "", "LOADP_B", PC_STORE, ASSOC_LEFT, &type_string, &type_integer, &type_integer, OPF_LOADPTR}, +{7, "", "STOREP_B", PC_STORE, ASSOC_RIGHT, &type_string, &type_integer, &type_integer, OPF_STOREPTROFS}, +{7, "", "LOADP_B", PC_STORE, ASSOC_LEFT, &type_string, &type_integer, &type_integer, OPF_LOADPTR}, + +//uint opcodes (not many, they're shared with ints for the most part) +{7, "<=", "LE_U32", PC_RELATION, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_LOADPTR}, +{7, "<", "LT_U32", PC_RELATION, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_LOADPTR}, +{7, "/", "DIV_U32", PC_MULDIV, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_LOADPTR}, +{7, ">>", "RSHIFT_U32", PC_SHIFT, ASSOC_LEFT, &type_uint, &type_integer, &type_uint, OPF_LOADPTR}, + +//[u]int64+double opcodes +{7, "+", "ADD_I64", PC_ADDSUB, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "-", "SUB_I64", PC_ADDSUB, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "*", "MUL_I64", PC_MULDIV, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "/", "DIV_I64", PC_MULDIV, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "&", "BITAND_L", PC_BITAND, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "|", "BITOR_I64", PC_BITOR, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "^", "BITXOR_I64", PC_BITXOR, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STD}, +{7, "<<", "LSHIFT_I64I", PC_SHIFT, ASSOC_LEFT, &type_int64, &type_integer, &type_int64, OPF_STD}, +{7, ">>", "RSHIFT_I64I", PC_SHIFT, ASSOC_LEFT, &type_int64, &type_integer, &type_int64, OPF_STD}, +{7, "<=", "LE_I64", PC_RELATION, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, +{7, "<", "LT_I64", PC_RELATION, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, +{7, "==", "EQ_I64", PC_EQUALITY, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, +{7, "!=", "NE_I64", PC_EQUALITY, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, +{7, "<", "LE_U64", PC_RELATION, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, +{7, "<", "LT_U64", PC_RELATION, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, +{7, "%", "DIV_U64", PC_MULDIV, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, ">>", "RSHIFT_U64I", PC_SHIFT, ASSOC_LEFT, &type_uint64, &type_uint, &type_uint64, OPF_STD}, +{7, "=", "STORE_I64", PC_STORE, ASSOC_RIGHT, &type_int64, &type_int64, &type_int64, OPF_STORE}, +{7, "=", "STOREP_I64", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_int64, &type_int64, OPF_STOREPTROFS}, +{7, "<=>", "STOREF_I64", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_int64, OPF_STOREFLD}, +{7, ".", "LOADF_I64", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, +{7, "=", "LOADA_I64", PC_STORE, ASSOC_LEFT, &type_int64, &type_integer, &type_int64}, +{7, "=", "LOADP_I64", PC_STORE, ASSOC_LEFT, &type_pointer, &type_int64, &type_int64, OPF_LOADPTR}, +{7, "=", "CONV_UI64", PC_STORE, ASSOC_LEFT, &type_uint, &type_void, &type_int64}, +{7, "=", "CONV_II64", PC_STORE, ASSOC_LEFT, &type_integer, &type_void, &type_int64}, +{7, "=", "CONV_I64I", PC_STORE, ASSOC_LEFT, &type_int64, &type_void, &type_integer}, +{7, "=", "CONV_FD", PC_STORE, ASSOC_LEFT, &type_float, &type_void, &type_double}, +{7, "=", "CONV_DF", PC_STORE, ASSOC_LEFT, &type_double, &type_void, &type_float}, +{7, "=", "CONV_I64F", PC_STORE, ASSOC_LEFT, &type_int64, &type_void, &type_float}, +{7, "=", "CONV_FI64", PC_STORE, ASSOC_LEFT, &type_float, &type_void, &type_int64}, +{7, "=", "CONV_I64D", PC_STORE, ASSOC_LEFT, &type_int64, &type_void, &type_double}, +{7, "=", "CONV_DI64", PC_STORE, ASSOC_LEFT, &type_double, &type_void, &type_int64}, +{7, "+", "ADD_D", PC_ADDSUB, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "-", "SUB_D", PC_ADDSUB, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "*", "MUL_D", PC_MULDIV, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "/", "DIV_D", PC_MULDIV, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "<=", "LE_D", PC_RELATION, ASSOC_LEFT, &type_double, &type_double, &type_bint, OPF_STD}, +{7, "<", "LT_D", PC_RELATION, ASSOC_LEFT, &type_double, &type_double, &type_bint, OPF_STD}, +{7, "==", "EQ_D", PC_EQUALITY, ASSOC_LEFT, &type_double, &type_double, &type_bint, OPF_STD}, +{7, "!=", "NE_D", PC_EQUALITY, ASSOC_LEFT, &type_double, &type_double, &type_bint, OPF_STD}, /* emulated ops begin here */ {7, "<>", "OP_EMULATED", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, @@ -718,12 +779,12 @@ QCC_opcode_t pr_opcodes[] = {7, "~", "BITNOT_F", PC_UNARY, ASSOC_LEFT, &type_float, &type_void, &type_float}, {7, "~", "BITNOT_I", PC_UNARY, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, - {7, "==", "EQ_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, - {7, "!=", "NE_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, - {7, "<=", "LE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, - {7, ">=", "GE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, - {7, "<", "LT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, - {7, ">", "GT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float, OPF_STD}, + {7, "==", "EQ_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, + {7, "!=", "NE_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, + {7, "<=", "LE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, + {7, ">=", "GE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, + {7, "<", "LT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, + {7, ">", "GT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_bfloat, OPF_STD}, {7, "&=", "ANDSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float, OPF_STORE}, {7, "&~=", "BITCLR_F", PC_STORE, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STORE}, @@ -755,8 +816,8 @@ QCC_opcode_t pr_opcodes[] = {7, ">>", "RSHIFT_FI", PC_SHIFT, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, {7, "<<", "LSHIFT_FI", PC_SHIFT, ASSOC_LEFT, &type_float, &type_integer, &type_integer, OPF_STD}, - {7, "&&", "AND_ANY", PC_LOGICAND, ASSOC_LEFT, &type_variant, &type_variant, &type_float, OPF_STD}, - {7, "||", "OR_ANY", PC_LOGICOR, ASSOC_LEFT, &type_variant, &type_variant, &type_float, OPF_STD}, + {7, "&&", "AND_ANY", PC_LOGICAND, ASSOC_LEFT, &type_variant, &type_variant, &type_bfloat, OPF_STD}, + {7, "||", "OR_ANY", PC_LOGICOR, ASSOC_LEFT, &type_variant, &type_variant, &type_bfloat, OPF_STD}, {7, "+", "ADD_EI", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_integer, &type_entity, OPF_STD}, {7, "+", "ADD_EF", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_float, &type_entity, OPF_STD}, @@ -774,12 +835,59 @@ QCC_opcode_t pr_opcodes[] = {7, "*^", "POW_IF", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_float, &type_float, OPF_STD}, {7, "><", "CROSS_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STD}, - {7, "==", "EQ_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float, OPF_STD}, - {7, "!=", "NE_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float, OPF_STD}, + {7, "==", "EQ_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_bfloat, OPF_STD}, + {7, "!=", "NE_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_bfloat, OPF_STD}, {7, "<=>", "SPACESHIP_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, {7, "<=>", "SPACESHIP_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, + //uint32 opcodes. they match the int32 ones so emulation is basically swapping them over. +{7, "+", "ADD_U", PC_ADDSUB, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "-", "SUB_U", PC_ADDSUB, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "*", "MUL_U", PC_MULDIV, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "%", "MOD_U", PC_MULDIV, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "&", "BITAND_U", PC_BITAND, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "|", "BITOR_U", PC_BITOR, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "^", "BITXOR_U", PC_BITXOR, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, "~", "BITNOT_U", PC_UNARY, ASSOC_LEFT, &type_uint, &type_void, &type_uint}, +{7, "&~=", "BITCLR_U", PC_STORE, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STORE}, +{7, "<<", "LSHIFT_U", PC_SHIFT, ASSOC_LEFT, &type_uint, &type_uint, &type_uint, OPF_STD}, +{7, ">=", "GE_U", PC_RELATION, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_STD}, +{7, ">", "GT_U", PC_RELATION, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_STD}, +{7, "==", "EQ_U", PC_EQUALITY, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_STD}, +{7, "!=", "NE_U", PC_EQUALITY, ASSOC_LEFT, &type_uint, &type_uint, &type_bint, OPF_STD}, + +//64bit ones that we can emulate cheaply or are rare. +{7, "~", "BITNOT_I64", PC_UNARY, ASSOC_LEFT, &type_int64, &type_void, &type_int64}, +{7, "&~=", "BITCLR_I64", PC_STORE, ASSOC_LEFT, &type_int64, &type_int64, &type_int64, OPF_STORE}, +{7, ">", "GT_I64", PC_RELATION, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, +{7, ">=", "GE_I64", PC_RELATION, ASSOC_LEFT, &type_int64, &type_int64, &type_bint, OPF_STD}, + +//unsigned versions (emulated via signed int64 ones, just with different types). +{7, "+", "ADD_U64", PC_ADDSUB, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "-", "SUB_U64", PC_ADDSUB, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "*", "MUL_U64", PC_MULDIV, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "%", "MOD_U64", PC_MULDIV, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "&", "BITAND_U64", PC_BITAND, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "|", "BITOR_U64", PC_BITOR, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "^", "BITXOR_U64", PC_BITXOR, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STD}, +{7, "~", "BITNOT_U64", PC_UNARY, ASSOC_LEFT, &type_uint64, &type_void, &type_uint64}, +{7, "&~=", "BITCLR_U64", PC_STORE, ASSOC_LEFT, &type_uint64, &type_uint64, &type_uint64, OPF_STORE}, +{7, "<<", "LSHIFT_U64I", PC_SHIFT, ASSOC_LEFT, &type_uint64, &type_integer, &type_uint64, OPF_STD}, +{7, ">", "GT_U64", PC_RELATION, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, +{7, ">=", "GE_U64", PC_RELATION, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, +{7, "==", "EQ_U64", PC_EQUALITY, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, +{7, "!=", "NE_U64", PC_EQUALITY, ASSOC_LEFT, &type_uint64, &type_uint64, &type_bint, OPF_STD}, + + +{7, "&", "BITAND_D", PC_BITAND, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "|", "BITOR_D", PC_BITOR, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "^", "BITXOR_D", PC_BITXOR, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STD}, +{7, "~", "BITNOT_D", PC_UNARY, ASSOC_LEFT, &type_double, &type_void, &type_bint}, +{7, "&~=", "BITCLR_D", PC_STORE, ASSOC_LEFT, &type_double, &type_double, &type_double, OPF_STORE}, +{7, "<<", "LSHIFT_DI", PC_SHIFT, ASSOC_LEFT, &type_double, &type_integer, &type_double, OPF_STD}, +{7, ">>", "RSHIFT_DI", PC_SHIFT, ASSOC_LEFT, &type_double, &type_integer, &type_double, OPF_STD}, + {0, NULL, "OPD_GOTO_FORSTART"}, {0, NULL, "OPD_GOTO_WHILE1"}, @@ -804,13 +912,13 @@ static pbool OpAssignsToC(unsigned int op) return false; <- add STOREP_*?*/ if(op == OP_STOREP_C || op == OP_STOREP_B) return false; - if (op >= OP_STORE_F && op <= OP_STOREP_FNC) - return false; //actually they do. + if((op >= OP_STORE_F && op <= OP_STOREP_FNC) || op == OP_STOREP_P || op == OP_STORE_P || op == OP_STORE_I64) + return false; if(op >= OP_MULSTORE_F && op <= OP_SUBSTOREP_V) - return false; //actually they do. + return false; if (op >= OP_STORE_I && op <= OP_STORE_FI) return false; - if (op >= OP_STOREF_V && op <= OP_STOREF_I) + if ((op >= OP_STOREF_V && op <= OP_STOREF_I) || op == OP_STOREF_I64) return false; //reads it, doesn't write. if (op == OP_BOUNDCHECK || op == OP_UNUSED || op == OP_POP) return false; @@ -826,7 +934,7 @@ static pbool OpAssignsToB(unsigned int op) return true; if(op >= OP_MULSTORE_F && op <= OP_SUBSTOREP_V) return true; - if((op >= OP_STORE_F && op <= OP_STOREP_FNC) || op == OP_STOREP_P || op == OP_STORE_P) + if((op >= OP_STORE_F && op <= OP_STOREP_FNC) || op == OP_STOREP_P || op == OP_STORE_P || op == OP_STORE_I64) return true; return false; } @@ -893,6 +1001,7 @@ static int OpAssignsCount(unsigned int op) case OP_STOREF_F: case OP_STOREF_S: case OP_STOREF_I: + case OP_STOREF_I64: return 0; //stores to a.b rather than any direct value... case OP_BOUNDCHECK: return 0; @@ -955,6 +1064,10 @@ QCC_opcode_t *opcodes_addstore[] = &pr_opcodes[OP_ADD_F], &pr_opcodes[OP_ADD_V], &pr_opcodes[OP_ADD_I], + &pr_opcodes[OP_ADD_U], + &pr_opcodes[OP_ADD_I64], + &pr_opcodes[OP_ADD_U64], + &pr_opcodes[OP_ADD_D], &pr_opcodes[OP_ADD_FI], &pr_opcodes[OP_ADD_IF], &pr_opcodes[OP_ADD_SF], @@ -982,6 +1095,7 @@ QCC_opcode_t *opcodes_substore[] = &pr_opcodes[OP_SUB_F], &pr_opcodes[OP_SUB_V], &pr_opcodes[OP_SUB_I], + &pr_opcodes[OP_SUB_U], &pr_opcodes[OP_SUB_FI], &pr_opcodes[OP_SUB_IF], &pr_opcodes[OP_SUB_S], @@ -991,6 +1105,9 @@ QCC_opcode_t *opcodes_substore[] = &pr_opcodes[OP_SUB_SI], &pr_opcodes[OP_SUB_EI], &pr_opcodes[OP_SUB_EF], + &pr_opcodes[OP_SUB_I64], + &pr_opcodes[OP_SUB_U64], + &pr_opcodes[OP_SUB_D], NULL }; QCC_opcode_t *opcodes_substorep[] = @@ -1011,8 +1128,12 @@ QCC_opcode_t *opcodes_mulstore[] = &pr_opcodes[OP_MUL_VF], &pr_opcodes[OP_MUL_VI], &pr_opcodes[OP_MUL_I], + &pr_opcodes[OP_MUL_U], &pr_opcodes[OP_MUL_FI], &pr_opcodes[OP_MUL_IF], + &pr_opcodes[OP_MUL_I64], + &pr_opcodes[OP_MUL_U64], + &pr_opcodes[OP_MUL_D], NULL }; QCC_opcode_t *opcodes_mulstorep[] = @@ -1029,9 +1150,13 @@ QCC_opcode_t *opcodes_divstore[] = { &pr_opcodes[OP_DIV_F], &pr_opcodes[OP_DIV_I], + &pr_opcodes[OP_DIV_U], &pr_opcodes[OP_DIV_FI], &pr_opcodes[OP_DIV_IF], &pr_opcodes[OP_DIV_VF], + &pr_opcodes[OP_DIV_I64], + &pr_opcodes[OP_DIV_U64], + &pr_opcodes[OP_DIV_D], NULL }; QCC_opcode_t *opcodes_divstorep[] = @@ -1043,9 +1168,13 @@ QCC_opcode_t *opcodes_orstore[] = { &pr_opcodes[OP_BITOR_F], &pr_opcodes[OP_BITOR_I], + &pr_opcodes[OP_BITOR_U], &pr_opcodes[OP_BITOR_IF], &pr_opcodes[OP_BITOR_FI], &pr_opcodes[OP_BITOR_V], + &pr_opcodes[OP_BITOR_I64], + &pr_opcodes[OP_BITOR_U64], + &pr_opcodes[OP_BITOR_D], NULL }; QCC_opcode_t *opcodes_orstorep[] = @@ -1056,24 +1185,36 @@ QCC_opcode_t *opcodes_orstorep[] = QCC_opcode_t *opcodes_xorstore[] = { &pr_opcodes[OP_BITXOR_I], + &pr_opcodes[OP_BITXOR_U], &pr_opcodes[OP_BITXOR_F], &pr_opcodes[OP_BITXOR_V], + &pr_opcodes[OP_BITXOR_I64], + &pr_opcodes[OP_BITXOR_U64], + &pr_opcodes[OP_BITXOR_D], NULL }; QCC_opcode_t *opcodes_andstore[] = { &pr_opcodes[OP_BITAND_F], &pr_opcodes[OP_BITAND_I], + &pr_opcodes[OP_BITAND_U], &pr_opcodes[OP_BITAND_IF], &pr_opcodes[OP_BITAND_FI], &pr_opcodes[OP_BITAND_V], + &pr_opcodes[OP_BITAND_I64], + &pr_opcodes[OP_BITAND_U64], + &pr_opcodes[OP_BITAND_D], NULL }; QCC_opcode_t *opcodes_clearstore[] = { &pr_opcodes[OP_BITCLR_F], &pr_opcodes[OP_BITCLR_I], + &pr_opcodes[OP_BITCLR_U], &pr_opcodes[OP_BITCLR_V], + &pr_opcodes[OP_BITCLR_I64], + &pr_opcodes[OP_BITCLR_U64], + &pr_opcodes[OP_BITCLR_D], NULL }; QCC_opcode_t *opcodes_clearstorep[] = @@ -1085,16 +1226,24 @@ QCC_opcode_t *opcodes_shlstore[] = { &pr_opcodes[OP_LSHIFT_F], &pr_opcodes[OP_LSHIFT_I], + &pr_opcodes[OP_LSHIFT_U], &pr_opcodes[OP_LSHIFT_IF], &pr_opcodes[OP_LSHIFT_FI], + &pr_opcodes[OP_LSHIFT_I64I], + &pr_opcodes[OP_LSHIFT_U64I], + &pr_opcodes[OP_LSHIFT_DI], NULL }; QCC_opcode_t *opcodes_shrstore[] = { &pr_opcodes[OP_RSHIFT_F], &pr_opcodes[OP_RSHIFT_I], + &pr_opcodes[OP_RSHIFT_U], &pr_opcodes[OP_RSHIFT_IF], &pr_opcodes[OP_RSHIFT_FI], + &pr_opcodes[OP_RSHIFT_I64I], + &pr_opcodes[OP_RSHIFT_U64I], + &pr_opcodes[OP_RSHIFT_DI], NULL }; @@ -1102,6 +1251,11 @@ QCC_opcode_t *opcodes_spaceship[] = { &pr_opcodes[OP_SPACESHIP_F], &pr_opcodes[OP_SPACESHIP_S], +// &pr_opcodes[OP_SPACESHIP_I], +// &pr_opcodes[OP_SPACESHIP_U], +// &pr_opcodes[OP_SPACESHIP_I64], +// &pr_opcodes[OP_SPACESHIP_U64], +// &pr_opcodes[OP_SPACESHIP_D], NULL }; @@ -1118,8 +1272,8 @@ __cdecl #endif sort_opcodenames(const void*a,const void*b) { - QCC_opcode_t *opa = *(QCC_opcode_t**)a; - QCC_opcode_t *opb = *(QCC_opcode_t**)b; + const QCC_opcode_t *opa = *(QCC_opcode_t*const*)a; + const QCC_opcode_t *opb = *(QCC_opcode_t*const*)b; if (opa == NULL) return opb?1:0; if (opb == NULL) @@ -1189,7 +1343,7 @@ void QCC_PrioritiseOpcodes(void) qsort (&opcodeprioritized[j][0], pcount[j], sizeof(opcodeprioritized[j][0]), sort_opcodenames); } -static pbool QCC_OPCodeValidForTarget(qcc_targetformat_t targfmt, QCC_opcode_t *op) +static pbool QCC_OPCodeValidForTarget(qcc_targetformat_t targfmt, unsigned int qcc_targetversion, QCC_opcode_t *op) { int num; num = op - pr_opcodes; @@ -1218,10 +1372,15 @@ static pbool QCC_OPCodeValidForTarget(qcc_targetformat_t targfmt, QCC_opcode_t * case QCF_FTEH2: case QCF_FTE: case QCF_FTEDEBUG: - if (num >= OP_STOREP_B) +#define QCTARGVER_FTE_MAX 5768 + if (num >= OP_LT_U) //uint+double+int64+uint64 ops + return (qcc_targetversion>=5768); + if (num >= OP_STOREP_B) //byte return (qcc_targetversion>=5744); - if (num >= OP_STOREF_V) //to be enabled at a later date - opcodes added in r5698. + if (num >= OP_STOREF_V) //field stores return (qcc_targetversion>=5698); + if (num >= OP_IF_F) //iffloat fixes + return (qcc_targetversion>=3349); return true; case QCF_QSS: if (num < OP_MULSTORE_F) @@ -1370,28 +1529,33 @@ static pbool QCC_OPCodeValidForTarget(qcc_targetformat_t targfmt, QCC_opcode_t * //extended opcodes. switch(num) { + //opcodes that were buggy in DP. + case OP_ADD_IF: //dp wrote these to ints, which doesn't match our defined opcodes. not really a problem. + case OP_SUB_IF: //dp wrote these to ints, which doesn't match our defined opcodes. revert to _F. + case OP_MUL_IF: //dp wrote these to ints, which doesn't match our defined opcodes. revert to _F + case OP_DIV_IF: //dp wrote these to ints, which doesn't match our defined opcodes. revert to _F + case OP_BITAND_FI: //dp outputs floats, which doesn't match our defined opcodes. + case OP_BITOR_FI: //dp outputs floats, which doesn't match our defined opcodes. + case OP_STORE_I: //was omitted. + case OP_STORE_P: //was omitted. + return (qcc_targetversion>=12901); + //maths and conditionals (simple opcodes that read from specific globals and write to a global) case OP_ADD_I: -// case OP_ADD_IF: //dp rounds these to ints, which doesn't match our defined opcodes. not really a problem. case OP_ADD_FI: case OP_SUB_I: -// case OP_SUB_IF: //dp rounds these to ints, which doesn't match our defined opcodes. revert to _F. case OP_SUB_FI: case OP_MUL_I: -// case OP_MUL_IF: //dp rounds these to ints, which doesn't match our defined opcodes. revert to _F case OP_MUL_FI: case OP_MUL_VI: case OP_DIV_VF: case OP_DIV_I: -// case OP_DIV_IF: //dp rounds these to ints, which doesn't match our defined opcodes. revert to _F case OP_DIV_FI: case OP_BITAND_I: case OP_BITOR_I: case OP_BITAND_IF: case OP_BITOR_IF: -// case OP_BITAND_FI: //dp outputs floats, which doesn't match our defined opcodes. -// case OP_BITOR_FI: //dp outputs floats, which doesn't match our defined opcodes. - case OP_GE_I: //dp outputs floats for ALL of these boolean comparisons. + case OP_GE_I: case OP_LE_I: case OP_GT_I: case OP_LT_I: @@ -1453,7 +1617,7 @@ static pbool QCC_OPCodeValidForTarget(qcc_targetformat_t targfmt, QCC_opcode_t * case OP_GLOAD_V: return true; - default: //anything I forgot to mention is new. + default: //anything I forgot to mention is new, and doesn't work in DP that I'm aware of. return false; } } @@ -1478,6 +1642,10 @@ static pbool QCC_OPCode_StorePOffset(void) return false; } } + +#define QCTARGVER_FTE_DEF 5529 +#define QCTARGVER_QSS_MAX 0 +#define QCTARGVER_DP_MAX 12901 void QCC_OPCodeSetTarget(qcc_targetformat_t targfmt, unsigned int targver) { size_t i; @@ -1489,11 +1657,27 @@ void QCC_OPCodeSetTarget(qcc_targetformat_t targfmt, unsigned int targver) case QCF_FTE: case QCF_FTEH2: case QCF_FTEDEBUG: - if (qcc_targetversion > 5744) + if (qcc_targetversion > QCTARGVER_FTE_MAX) { if (qcc_targetversion != ~0u) - QCC_PR_ParseWarning(WARN_BADTARGET, "target revision %u is unknown, assuming revision %u", qcc_targetversion, 5744); - qcc_targetversion = 5744; + QCC_PR_ParseWarning(WARN_BADTARGET, "target revision %u is unknown, assuming revision %u", qcc_targetversion, QCTARGVER_FTE_MAX); + qcc_targetversion = QCTARGVER_FTE_MAX; + } + break; + case QCF_DARKPLACES: + if (qcc_targetversion > QCTARGVER_DP_MAX) + { + if (qcc_targetversion != ~0u) + QCC_PR_ParseWarning(WARN_BADTARGET, "target revision %u is unknown, assuming revision %u", qcc_targetversion, QCTARGVER_DP_MAX); + qcc_targetversion = QCTARGVER_DP_MAX; + } + break; + case QCF_QSS: + if (qcc_targetversion > QCTARGVER_QSS_MAX) + { + if (qcc_targetversion != ~0u) + QCC_PR_ParseWarning(WARN_BADTARGET, "target revision %u is unknown, assuming revision %u", qcc_targetversion, QCTARGVER_QSS_MAX); + qcc_targetversion = QCTARGVER_QSS_MAX; } break; default: @@ -1506,10 +1690,10 @@ void QCC_OPCodeSetTarget(qcc_targetformat_t targfmt, unsigned int targver) break; } - for (i = 0; i < OP_NUMREALOPS; i++) + for (i = 0; i < OP_NUMOPS; i++) { QCC_opcode_t *op = &pr_opcodes[i]; - if (QCC_OPCodeValidForTarget(targfmt, op)) + if (QCC_OPCodeValidForTarget(targfmt, qcc_targetversion, op)) op->flags |= OPF_VALID; else op->flags &= ~OPF_VALID; @@ -1528,7 +1712,7 @@ static struct { {QCF_STANDARD, "quakec", 0}, {QCF_STANDARD, "qs", 0}, - {QCF_QSS, "qss", 0}, + {QCF_QSS, "qss", QCTARGVER_QSS_MAX}, {QCF_HEXEN2, "hexen2", 0}, {QCF_HEXEN2, "h2", 0}, @@ -1538,15 +1722,15 @@ static struct { {QCF_KK7, "kk7", 0}, {QCF_KK7, "version7", 0}, - {QCF_FTE, "fte", 5529}, //'latest' stable revision. - {QCF_FTEH2, "fteh2", 5529}, - {QCF_FTEDEBUG, "ftedebug", 5529}, - {QCF_FTEDEBUG, "debug", 5529}, + {QCF_FTE, "fte", QCTARGVER_FTE_DEF}, //'latest' stable revision. + {QCF_FTEH2, "fteh2", QCTARGVER_FTE_DEF}, + {QCF_FTEDEBUG, "ftedebug", QCTARGVER_FTE_DEF}, + {QCF_FTEDEBUG, "debug", QCTARGVER_FTE_DEF}, {QCF_FTE, "quake2c", 5744}, //an alias for Paril's project, which does various pointer stuff. the revision should be high enough for str[int] ops. - {QCF_DARKPLACES,"darkplaces", 0}, - {QCF_DARKPLACES,"dp", 0}, + {QCF_DARKPLACES,"darkplaces", QCTARGVER_DP_MAX}, + {QCF_DARKPLACES,"dp", QCTARGVER_DP_MAX}, {QCF_QTEST, "qtest", 0}, {0, NULL} @@ -1572,9 +1756,6 @@ pbool QCC_OPCodeSetTargetName(const char *targ) { qcc_targetformat_t newtype = targets[i].target; - if (newtype == QCF_DARKPLACES) - QCC_PR_ParseWarning(WARN_BADTARGET, "#pragma target \"%s\". Requires an unofficial patch to DP. Without that patch there is no support for any opcodes beyond vanilla.", targ); - if (numstatements > 1) { #define ish2(fmt) ((fmt) == QCF_HEXEN2 || (fmt) == QCF_UHEXEN2 || (fmt) == QCF_FTEH2) @@ -1628,7 +1809,7 @@ static const QCC_eval_t *QCC_SRef_EvalConst(QCC_sref_t ref) if (ref.sym && ref.sym->initialized && ref.sym->constant) { ref.sym->referenced = true; - return &ref.sym->symboldata[ref.ofs]; + return (const QCC_eval_t*)&ref.sym->symboldata[ref.ofs]; } return NULL; } @@ -1645,7 +1826,11 @@ static pbool QCC_Eval_Truth(const QCC_eval_t *eval, QCC_type_t *type, pbool assu case ev_float: istrue = (eval->_float != 0); break; + case ev_double: + istrue = (eval->_double != 0); + break; case ev_integer: + case ev_uint: case ev_function: case ev_entity: case ev_field: @@ -1653,6 +1838,10 @@ static pbool QCC_Eval_Truth(const QCC_eval_t *eval, QCC_type_t *type, pbool assu case ev_boolean: istrue = (eval->_int != 0); break; + case ev_int64: + case ev_uint64: + istrue = (eval->_int64 != 0); + break; case ev_string: if (flag_ifstring) istrue = !!strings[eval->_int]; //value compare. @@ -1746,11 +1935,16 @@ static int QCC_ShouldConvert(QCC_type_t *from, etype_t wanted) /*impossible*/ return -1; } +static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit); static QCC_sref_t QCC_SupplyConversionForAssignment(QCC_ref_t *to, QCC_sref_t from, QCC_type_t *wanted, pbool fatal) { int o; QCC_sref_t rhs; + rhs = QCC_TryEvaluateCast(from, to->cast, !fatal); + if (rhs.cast) + return rhs; + if (wanted->type == ev_accessor && wanted->parentclass && from.cast->type != ev_accessor) wanted = wanted->parentclass; if (from.cast->type == ev_accessor && from.cast->parentclass && wanted->type != ev_accessor) @@ -1880,6 +2074,8 @@ static void QCC_ClobberDef(QCC_def_t *def) tmp.sym = a; if (a->type->type==ev_variant || a->type->type == ev_vector) QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_V], from, tmp, NULL, STFL_PRESERVEB)); + else if (a->type->type==ev_int64 || a->type->type == ev_uint64 || a->type->type == ev_double) + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I64], from, tmp, NULL, STFL_PRESERVEB)); else QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], from, tmp, NULL, STFL_PRESERVEB)); } @@ -1938,6 +2134,8 @@ static QCC_sref_t QCC_GetTemp(QCC_type_t *type) gofs_t ofs = tempsused; unsigned int i; unsigned int size = type->size; + if (type->type == ev_accessor) + size = type->parentclass->size; tempsused += size; if (tempsused > tempsmax) @@ -2330,7 +2528,18 @@ const char *QCC_VarAtOffset(QCC_sref_t ref) return message; case ev_field: case ev_integer: - QC_snprintfz(message, sizeof(message), "%"pPRIi"i", val->_int); + QC_snprintfz(message, sizeof(message), "%#"pPRIx"i", val->_int); + return message; + case ev_uint: + QC_snprintfz(message, sizeof(message), "%#"pPRIx"u", val->_uint); + return message; + case ev_int64: + //QC_snprintfz(message, sizeof(message), "%"pPRIu64"ill", val->_int64); + QC_snprintfz(message, sizeof(message), "%#"pPRIx64"ill", val->_int64); + return message; + case ev_uint64: + //QC_snprintfz(message, sizeof(message), "%"pPRIu64"ull", val->_uint64); + QC_snprintfz(message, sizeof(message), "%#"pPRIx64"ull", val->_uint64); return message; case ev_entity: QC_snprintfz(message, sizeof(message), "%"pPRIi"e", val->_int); @@ -2341,6 +2550,9 @@ const char *QCC_VarAtOffset(QCC_sref_t ref) else QC_snprintfz(message, sizeof(message), "%%%"pPRIi, val->_int); return message; + case ev_double: + QC_snprintfz(message, sizeof(message), "%gd", val->_double); + return message; case ev_vector: QC_snprintfz(message, sizeof(message), "'%g %g %g'", val->vector[0], val->vector[1], val->vector[2]); return message; @@ -2483,6 +2695,8 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ const QCC_eval_t *eval_b = QCC_SRef_EvalConst(var_b); if (eval_a) { + if (outstatement) + *outstatement = NULL; if (eval_b) { //both are constants @@ -2870,6 +3084,115 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ case OP_NE_FI: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); return QCC_MakeIntConst(eval_a->_float != eval_b->_int); + + + case OP_LT_U: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUIntConst(eval_a->_uint < eval_b->_uint); + case OP_LE_U: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUIntConst(eval_a->_uint <= eval_b->_uint); + case OP_DIV_U: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUIntConst(eval_a->_uint / eval_b->_uint); + case OP_RSHIFT_U: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUIntConst(eval_a->_uint >> eval_b->_int); + + case OP_ADD_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 + eval_b->_int64); + case OP_SUB_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 - eval_b->_int64); + case OP_MUL_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 * eval_b->_int64); + case OP_DIV_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 / eval_b->_int64); + case OP_LSHIFT_I64I: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 << eval_b->_int); + case OP_RSHIFT_I64I: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 >> eval_b->_int); + case OP_BITAND_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 & eval_b->_int64); + case OP_BITOR_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 | eval_b->_int64); + case OP_BITXOR_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeInt64Const(eval_a->_int64 ^ eval_b->_int64); + case OP_LE_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_int64 <= eval_b->_int64); + case OP_LT_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_int64 < eval_b->_int64); + case OP_EQ_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_int64 == eval_b->_int64); + case OP_NE_I64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_int64 != eval_b->_int64); + case OP_LT_U64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_uint64 < eval_b->_uint64); + case OP_LE_U64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_uint64 <= eval_b->_uint64); + case OP_DIV_U64: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUInt64Const(eval_a->_uint64 / eval_b->_uint64); + case OP_RSHIFT_U64I: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeUInt64Const(eval_a->_uint64 >> eval_b->_int); + + case OP_ADD_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst(eval_a->_double + eval_b->_double); + case OP_SUB_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst(eval_a->_double - eval_b->_double); + case OP_MUL_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst(eval_a->_double * eval_b->_double); + case OP_DIV_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst(eval_a->_double / eval_b->_double); + + case OP_LE_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_double <= eval_b->_double); + case OP_LT_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_double < eval_b->_double); + case OP_EQ_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_double == eval_b->_double); + case OP_NE_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeIntConst(eval_a->_double != eval_b->_double); + + + case OP_LSHIFT_DI: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst((pint64_t)eval_a->_double << eval_b->_int); + case OP_RSHIFT_DI: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst((pint64_t)eval_a->_double >> eval_b->_int); + case OP_BITAND_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst((pint64_t)eval_a->_double & (pint64_t)eval_b->_double); + case OP_BITOR_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst((pint64_t)eval_a->_double | (pint64_t)eval_b->_double); + case OP_BITXOR_D: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + return QCC_MakeDoubleConst((pint64_t)eval_a->_double ^ (pint64_t)eval_b->_double); } } else @@ -2925,6 +3248,78 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } return QCC_MakeFloatConst(eval_a->_int); + case OP_CONV_FD: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + return QCC_MakeDoubleConst(eval_a->_float); + case OP_CONV_DF: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + float fl = eval_a->_double; +// if ((double)fl != eval_a->_double) +// QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %g to %g.", eval_a->_double, (float)fl); + return QCC_MakeFloatConst(fl); + } + + case OP_CONV_DI64: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + if ((pint64_t)eval_a->_double != eval_a->_double) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical overflow. %f will be rounded to %"pPRIi64"", eval_a->_double, (pint64_t)eval_a->_double); + return QCC_MakeInt64Const(eval_a->_double); + case OP_CONV_I64D: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + double d = eval_a->_int64; + if ((pint64_t)d != eval_a->_int64) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %#"pPRIx64" to %#"pPRIx64".", eval_a->_int64, (pint64_t)d); + return QCC_MakeDoubleConst(d); + } + case OP_CONV_FI64: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + if ((pint64_t)eval_a->_float != eval_a->_float) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical overflow. %f will be rounded to %"pPRIi64"", eval_a->_float, (pint64_t)eval_a->_float); + return QCC_MakeInt64Const(eval_a->_float); + case OP_CONV_I64F: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + float d = eval_a->_int64; + if ((pint64_t)d != eval_a->_int64) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %#"pPRIx64" to %#"pPRIx64".", eval_a->_int64, (pint64_t)d); + return QCC_MakeFloatConst(d); + } + case OP_CONV_II64: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + pint64_t d = eval_a->_int; + if ((pint_t)d != eval_a->_int) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %#"pPRIi" to %#"pPRIx64".", eval_a->_int, (pint64_t)d); + return QCC_MakeInt64Const(d); + } + case OP_CONV_UI64: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + puint64_t d = eval_a->_uint; + if ((puint_t)d != eval_a->_uint) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %#"pPRIu" to %#"pPRIx64".", eval_a->_uint, (pint64_t)d); + return QCC_MakeUInt64Const(d); + } + case OP_CONV_I64I: + QCC_FreeTemp(var_a); + optres_constantarithmatic++; + { + pint_t d = eval_a->_int64; + if ((pint64_t)d != eval_a->_int64) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Numerical truncation of %#"pPRIx64" to %#"pPRIx".", eval_a->_int64, (pint_t)d); + return QCC_MakeIntConst(d); + } + case OP_BITOR_F: case OP_ADD_F: if (eval_a->_float == 0) @@ -3035,6 +3430,8 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } else if (eval_b) { + if (outstatement) + *outstatement = NULL; //b is const, a is not switch (op - pr_opcodes) { @@ -3185,6 +3582,8 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ case OP_STORE_I: case OP_STORE_ENT: case OP_STORE_FNC: + case OP_STORE_I64: +// case OP_STORE_D: { const QCC_eval_t *idxeval = QCC_SRef_EvalConst(var_a); if (idxeval && (var_a.cast->type == ev_integer || var_a.cast->type == ev_float) && !idxeval->_int) @@ -3195,6 +3594,11 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ QCC_FreeTemp(var_a); var_a = QCC_MakeVectorConst(0, 0, 0); } + if (op - pr_opcodes == OP_STORE_I64) //make sure vectors get set properly. + { + QCC_FreeTemp(var_a); + var_a = QCC_MakeInt64Const(0); + } } /*else { @@ -3940,6 +4344,14 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_b, var_a, NULL, STFL_PRESERVEB); return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_V], var_c, var_a, NULL, 0); + case OP_BITXOR_D: +// r = (a & ~b) | (b & ~a); + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_D], var_b, nullsref, NULL, STFL_PRESERVEA); + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_D], var_a, var_c, NULL, STFL_PRESERVEA); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_D], var_a, nullsref, NULL, STFL_PRESERVEA); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_D], var_b, var_a, NULL, STFL_PRESERVEB); + return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_D], var_c, var_a, NULL, 0); + case OP_IF_S: tmp = QCC_MakeFloatConst(0); tmp.cast = type_string; @@ -4164,6 +4576,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ op = &pr_opcodes[OP_LT_I]; break; + case OP_BITCLR_I64: + //b = var, a = bit field. + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_I64], var_a, var_b, NULL, STFL_PRESERVEA); + var_c = nullsref; + op = &pr_opcodes[OP_SUB_I64]; + break; + case OP_BITCLR_I: if (QCC_OPCodeValid(&pr_opcodes[OP_BITCLRSTORE_I])) { @@ -4178,17 +4597,21 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ //b = var, a = bit field. var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_I], var_b, var_a, NULL, STFL_PRESERVEA); - op = &pr_opcodes[OP_SUB_I]; var_a = var_b; var_b = var_c; var_c = ((op - pr_opcodes)==OP_BITCLRSTORE_I)?var_a:nullsref; + op = &pr_opcodes[OP_SUB_I]; break; case OP_BITCLR_V: var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_a, var_b, NULL, STFL_PRESERVEA); op = &pr_opcodes[OP_SUB_V]; var_c = nullsref; break; - + case OP_BITCLR_D: + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_D], var_a, var_b, NULL, STFL_PRESERVEA); + op = &pr_opcodes[OP_SUB_D]; + var_c = nullsref; + break; case OP_BITCLR_F: var_c = var_b; @@ -4207,10 +4630,10 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_b, var_a, NULL, STFL_PRESERVEA); - op = &pr_opcodes[OP_SUB_F]; var_a = var_b; var_b = var_c; var_c = ((op - pr_opcodes)==OP_BITCLRSTORE_F)?var_a:nullsref; + op = &pr_opcodes[OP_SUB_F]; break; #if IAMNOTLAZY case OP_SUBSTOREP_FI: @@ -4433,6 +4856,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } break; + case OP_LSHIFT_DI: + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_a, nullsref, NULL, flags&STFL_PRESERVEA); + return QCC_PR_StatementFlags(&pr_opcodes[OP_LSHIFT_I64I], var_a, var_b, NULL, 0); + case OP_RSHIFT_DI: + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_a, nullsref, NULL, flags&STFL_PRESERVEA); + return QCC_PR_StatementFlags(&pr_opcodes[OP_RSHIFT_I64I], var_a, var_b, NULL, 0); + //convert both to ints case OP_LSHIFT_F: if (QCC_OPCodeValid(&pr_opcodes[OP_LSHIFT_I])) @@ -4500,6 +4930,74 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ break; } + case OP_BITAND_D: + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_a, nullsref, NULL, flags&STFL_PRESERVEA); + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_b, nullsref, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0); + return QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_I64], var_a, var_b, NULL, 0); + case OP_BITOR_D: + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_a, nullsref, NULL, flags&STFL_PRESERVEA); + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_DI64], var_b, nullsref, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0); + return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_I64], var_a, var_b, NULL, 0); + + case OP_LOAD_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_GetTemp(type_int64); + QCC_PR_SimpleStatement(&pr_opcodes[OP_LOAD_FLD], var_a, var_b, var_c, false); + var_b.ofs++; + var_c.ofs++; + QCC_PR_SimpleStatement(&pr_opcodes[OP_LOAD_FLD], var_a, var_b, var_c, false); + var_c.ofs--; + return var_c; + case OP_BITAND_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_GetTemp(type_int64); + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITAND_I], var_a, var_b, var_c, false); + var_a.ofs++; + var_b.ofs++; + var_c.ofs++; + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITAND_I], var_a, var_b, var_c, false); + var_c.ofs--; + return var_c; + case OP_BITOR_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_GetTemp(type_int64); + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITOR_I], var_a, var_b, var_c, false); + var_a.ofs++; + var_b.ofs++; + var_c.ofs++; + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITOR_I], var_a, var_b, var_c, false); + var_c.ofs--; + return var_c; + case OP_BITXOR_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_GetTemp(type_int64); + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITXOR_I], var_a, var_b, var_c, false); + var_a.ofs++; + var_b.ofs++; + var_c.ofs++; + QCC_PR_SimpleStatement(&pr_opcodes[OP_BITXOR_I], var_a, var_b, var_c, false); + var_c.ofs--; + return var_c; + case OP_EQ_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_EQ_I], var_a, var_b, NULL, STFL_PRESERVEA|STFL_PRESERVEB); + var_a.ofs++; + var_b.ofs++; + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_EQ_I], var_a, var_b, NULL, 0); + return QCC_PR_StatementFlags(&pr_opcodes[OP_AND_I], var_c, var_a, NULL, 0); + case OP_NE_I64: + var_a.cast = type_integer; + var_b.cast = type_integer; + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_NE_I], var_a, var_b, NULL, STFL_PRESERVEA|STFL_PRESERVEB); + var_a.ofs++; + var_b.ofs++; + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_NE_I], var_a, var_b, NULL, 0); + return QCC_PR_StatementFlags(&pr_opcodes[OP_OR_I], var_c, var_a, NULL, 0); //statements where the rhs is an input int and can be swapped with a float case OP_ADD_FI: @@ -4697,11 +5195,49 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ var_c.cast = var_a.cast; return var_c; - default: - if (QCC_OPCodeValidForTarget(QCF_FTE, op)) - QCC_PR_ParseError(ERR_BADEXTENSION, "Opcode \"%s|%s\" not valid for target. Consider the use of: #pragma target fte", op->name, op->opname); + case OP_LT_U: + case OP_LE_U: + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_a, QCC_MakeIntConst((int)0x80000000), NULL, flags&STFL_PRESERVEA); + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_b, QCC_MakeIntConst((int)0x80000000), NULL, (flags&STFL_PRESERVEB?STFL_PRESERVEA:0)); + if (op == &pr_opcodes[OP_LT_U]) + return QCC_PR_StatementFlags(&pr_opcodes[OP_LT_I], var_a, var_b, NULL, flags&~(STFL_PRESERVEA|STFL_PRESERVEB)); else - QCC_PR_ParseError(ERR_BADEXTENSION, "Opcode \"%s|%s\" is not supported.", op->name, op->opname); + return QCC_PR_StatementFlags(&pr_opcodes[OP_LE_I], var_a, var_b, NULL, flags&~(STFL_PRESERVEA|STFL_PRESERVEB)); + break; + case OP_DIV_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + + //other uint ops have the same bit pattern + case OP_ADD_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_SUB_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_MUL_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; +// case OP_MOD_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_MOD_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_BITAND_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_BITOR_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_BITXOR_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITXOR_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_BITNOT_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_BITCLR_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITCLR_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_LSHIFT_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_LSHIFT_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_GE_U: var_a.cast = type_integer; var_b.cast = type_integer; return QCC_PR_StatementFlags(&pr_opcodes[OP_LT_U], var_b, var_a, NULL, flags); + case OP_GT_U: var_a.cast = type_integer; var_b.cast = type_integer; return QCC_PR_StatementFlags(&pr_opcodes[OP_LE_U], var_b, var_a, NULL, flags); + case OP_EQ_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_EQ_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + case OP_NE_U: var_a.cast = type_integer; var_b.cast = type_integer; var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_NE_I], var_a, var_b, NULL, flags); var_c.cast = type_uint; return var_c; + + case OP_STORE_I64: + var_c = var_b; + var_c.cast = type_integer; + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FLD], var_a, var_c, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); + var_a.ofs++; + var_c.ofs++; + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FLD], var_a, var_c, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); + return var_b; + + default: + if (QCC_OPCodeValidForTarget(QCF_FTE, QCTARGVER_FTE_DEF, op)) + QCC_PR_ParseWarning(ERR_BADEXTENSION, "Opcode \"%s|%s\" not valid for target. Consider the use of: #pragma target fte", op->name, op->opname); + else if (QCC_OPCodeValidForTarget(QCF_FTE, QCTARGVER_FTE_MAX, op)) + QCC_PR_ParseWarning(ERR_BADEXTENSION, "Opcode \"%s|%s\" not valid for target. Consider the use of: #pragma target fte_%u", op->name, op->opname, QCTARGVER_FTE_MAX); + else + QCC_PR_ParseWarning(ERR_BADEXTENSION, "Opcode \"%s|%s\" is not supported.", op->name, op->opname); break; } } @@ -4910,6 +5446,23 @@ static QCC_sref_t QCC_PR_ParseImmediate (void) cn = QCC_MakeIntConst(pr_immediate._int); QCC_PR_Lex (); return cn; + case ev_uint: + cn = QCC_MakeUIntConst(pr_immediate._uint); + QCC_PR_Lex (); + return cn; + + case ev_double: + cn = QCC_MakeDoubleConst(pr_immediate._double); + QCC_PR_Lex (); + return cn; + case ev_int64: + cn = QCC_MakeInt64Const(pr_immediate._int64); + QCC_PR_Lex (); + return cn; + case ev_uint64: + cn = QCC_MakeUInt64Const(pr_immediate._uint64); + QCC_PR_Lex (); + return cn; case ev_vector: cn = QCC_MakeVectorConst(pr_immediate.vector[0], pr_immediate.vector[1], pr_immediate.vector[2]); @@ -5461,6 +6014,48 @@ nolength: } } +static void QCC_VerifyArgs_sendevent (const char *funcname, QCC_ref_t **arglist, unsigned int argcount) +{ + //arg0 is the event name, and not meaningful + //arg1 denotes the arg types passed and defines the types used for all other args. + const QCC_eval_t *eval = (argcount >= 2 && arglist[1]->type == REF_GLOBAL)?QCC_SRef_EvalConst(arglist[1]->base):NULL; + const char *argtypes = eval?strings + eval->string:NULL; + size_t arg = 2; + QCC_type_t *t; + char temp[256]; + if (!argtypes) + return; + + for (; *argtypes; argtypes++, arg++) + { + switch(*argtypes) + { + case 's': t = type_string; break; + case 'f': t = type_float; break; + case 'F': t = type_double; break; + case 'i': t = type_integer; break; + case 'I': t = type_int64; break; + case 'u': t = type_uint; break; + case 'U': t = type_uint64; break; + case 'v': t = type_vector; break; + case 'e': t = type_entity; break; + default: t = NULL; break; + } + if (arg >= argcount) + { + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: arg type list", funcname, col_name, *argtypes, col_none); + break; + } + else if (!t) + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: '%s%c%s' is not a recognised arg type", funcname, col_name, *argtypes, col_none); + else if (typecmp_lax(arglist[arg]->cast, t)) + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: '%s%c%s' specified, but was passed %s%s%s", funcname, col_name, *argtypes, col_none, col_type, TypeName(arglist[arg]->cast, temp, sizeof(temp)), col_none); + } + + if (arg > 8) + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: cannot pass more than 8 args to a builtin.", funcname); +} + static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglist, unsigned int argcount) { static struct @@ -5565,6 +6160,46 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: unknown argument %i", funcname, vf); } +void QCC_VerifyArgs_cvar(const char *funcname, QCC_ref_t *cvarname) +{ + if (cvarname->type == REF_GLOBAL && cvarname->cast->type == ev_string) + { + const QCC_eval_t *a = QCC_SRef_EvalConst(cvarname->base); + const char *str; + if (!a) + return; + str = strings + a->string; + if (!strcmp(str, "vid_conwidth") || !strcmp(str, "vid_conheight")) + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: cvar(\"%s\") is deprecated and is likely to give some hacky value to work around old API usage which does not necessarily reflect the actual cvar value. Use getviewprop(VF_SCREENVSIZE) for the screen's virtual use, or use ftos+cvar_string to read the actual value of the cvar, or cast to variant to mute this warning.", funcname, str); + } +} + +void QCC_VerifyArgs_MatchingFieldType(const char *funcname, QCC_ref_t *type, QCC_ref_t *fldref) +{ + if (type->type == REF_GLOBAL && fldref->cast->type == ev_field) + { + char temp[256]; + const QCC_eval_t *a = QCC_SRef_EvalConst(type->base); + if (a) + { + int i; + if (type->cast->type == ev_integer || type->cast->type == ev_uint) + i = a->_int; + else if (type->cast->type == ev_float) + i = a->_float; + else + return; + if (i != fldref->cast->aux_type->type && fldref->cast->aux_type->type != ev_variant) + { + if (i >= 0 && i < ev_variant) + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: indicated type ev_%s does not match passed field type .%s", funcname, basictypenames[i], TypeName(fldref->cast->aux_type, temp, sizeof(temp))); + else + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: indicated type %i is not a basic type", funcname, i); + } + } + } +} + #ifdef SUPPORTINLINE struct inlinectx_s { @@ -6161,8 +6796,14 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (!strcmp(funcname, "sprintf")) QCC_VerifyFormatString(funcname, arglist, argcount); + if (!strcmp(funcname, "cvar") && argcount == 1) + QCC_VerifyArgs_cvar(funcname, arglist[0]); + if ((!strcmp(funcname, "clientstat")||!strcmp(funcname, "addstat")) && argcount == 3) + QCC_VerifyArgs_MatchingFieldType(funcname, arglist[1], arglist[2]); if (!strcmp(funcname, "setviewprop") || !strcmp(funcname, "setproperty")) QCC_VerifyArgs_setviewprop(funcname, arglist, argcount); + if (!strcmp(funcname, "sendevent")) //void(string eventname, string argtypes, ...) + QCC_VerifyArgs_sendevent(funcname, arglist, argcount); func.sym->timescalled++; @@ -6251,9 +6892,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, { int firststatement; QCC_sref_t sref = nullsref, copyop_index = nullsref; - int copyop_v = 0, copyop_i = 0, copyop_idx=0; - copyop_v = 0; - copyop_i = 0; + int copyop[3] = {0,0,0}, copyop_idx=0; if (arglist[i]->postinc) { arglist[i]->base = QCC_RefToDef(arglist[i], true); @@ -6271,8 +6910,9 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, break; //no problem if (QCC_OPCodeValid(&pr_opcodes[OP_LOADA_V])) { - copyop_v = OP_LOADA_V; - copyop_i = OP_LOADA_F; + copyop[2] = OP_LOADA_V; +// copyop[1] = OP_LOADA_L; + copyop[0] = OP_LOADA_F; copyop_idx = -1; copyop_index = arglist[i]->index; copyop_index = QCC_SupplyConversion(copyop_index, ev_integer, true); @@ -6280,23 +6920,26 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, } else if (arglist[i]->base.sym->arraylengthprefix && QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F])) { - copyop_v = 0; - copyop_i = OP_FETCH_GBL_F; + copyop[2] = 0; + copyop[1] = 0; + copyop[0] = OP_FETCH_GBL_F; copyop_idx = OP_ADD_F; copyop_index = arglist[i]->index; sref = arglist[i]->base; } break; case REF_FIELD: - copyop_v = OP_LOAD_V; - copyop_i = OP_LOAD_F; + copyop[2] = OP_LOAD_V; + copyop[1] = OP_LOAD_I64; + copyop[0] = OP_LOAD_F; copyop_index = arglist[i]->index; copyop_idx = -1; sref = arglist[i]->base; break; case REF_POINTER: - copyop_v = OP_LOADP_V; - copyop_i = OP_LOADP_F; + copyop[2] = OP_LOADP_V; + copyop[1] = OP_LOADP_I64; + copyop[0] = OP_LOADP_F; copyop_idx = OP_ADD_I; copyop_index = arglist[i]->index; sref = arglist[i]->base; @@ -6311,8 +6954,9 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (!sref.cast) { sref = QCC_RefToDef(arglist[i], func.cast->type != ev_function || !func.cast->params || i >= func.cast->num_parms || !func.cast->params[i].out); - copyop_v = OP_STORE_V; - copyop_i = OP_STORE_F; + copyop[2] = OP_STORE_V; + copyop[1] = OP_STORE_I64; + copyop[0] = OP_STORE_F; copyop_idx = 0; } else if (!(func.cast->type != ev_function || !func.cast->params || i >= func.cast->num_parms || !func.cast->params[i].out)) @@ -6325,6 +6969,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, { unsigned int ofs; QCC_sref_t src, fparm, newindex; + int asz; src = sref; if (copyop_idx == OP_ADD_I && copyop_index.cast) copyop_index = QCC_SupplyConversion(copyop_index, ev_integer, true); @@ -6332,9 +6977,6 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, copyop_index = QCC_SupplyConversion(copyop_index, ev_float, true); for (ofs = 0; ofs < arglist[i]->cast->size; ) { - if (ofs+3 > arglist[i]->cast->size) - copyop_v = 0; //don't over-read it - if (copyop_idx == -1) { //with this mode, the base reference can just be updated. no mess with the index. newindex = copyop_index; @@ -6380,27 +7022,35 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, else newindex = nullsref; - if (copyop_i == OP_STORE_F) + asz = 3-(ofs%3); + if (ofs+asz > arglist[i]->cast->size) + asz = arglist[i]->cast->size-ofs; + while (!copyop[asz-1] || !QCC_OPCodeValid(&pr_opcodes[copyop[asz-1]])) + asz--; //can't do that size... + + if (copyop[0] == OP_STORE_F) { - if (ofs+(copyop_v?3:1) != arglist[i]->cast->size) + if (ofs+asz != arglist[i]->cast->size) QCC_UnFreeTemp(src); if (!(ofs%3)) { args[parm].firststatement = numstatements; args[parm].ref = QCC_GetTemp(type_vector); - QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[copyop_v?copyop_v:copyop_i], src, args[parm].ref, NULL, STFL_PRESERVEB)); + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[copyop[asz-1]], src, args[parm].ref, NULL, STFL_PRESERVEB)); parm++; } else { QCC_sref_t t = args[parm-1].ref; t.ofs += ofs%3; - QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[copyop_v?copyop_v:copyop_i], src, t, NULL, STFL_PRESERVEB)); + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[copyop[asz-1]], src, t, NULL, STFL_PRESERVEB)); } } else { + if (ofs%3) + parm--; if (parm+ofs/3>=MAX_PARMS) { fparm = extra_parms[parm+ofs/3 - MAX_PARMS]; @@ -6419,27 +7069,27 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, fparm.cast = type_vector; QCC_ForceUnFreeDef(fparm.sym); } - fparm.ofs = ofs - (ofs%3); + fparm.ofs = ofs; if (!fparm.ofs) { args[parm].firststatement = numstatements; args[parm].ref = fparm; - parm++; } + parm++; - if (ofs+(copyop_v?3:1) == arglist[i]->cast->size) + if (ofs+asz == arglist[i]->cast->size) { QCC_FreeTemp(src); QCC_FreeTemp(copyop_index); } QCC_FreeTemp(newindex); - QCC_PR_SimpleStatement(&pr_opcodes[copyop_v?copyop_v:copyop_i], src, newindex, fparm, false); + QCC_PR_SimpleStatement(&pr_opcodes[copyop[asz-1]], src, newindex, fparm, false); } - ofs += copyop_v?3:1; + ofs += asz; if (copyop_idx == 0) - src.ofs += copyop_v?3:1; + src.ofs += asz; } } else @@ -6493,8 +7143,12 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, #else if (args[i].ref.cast->size == 3) QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_V], args[i].ref, d, NULL, 0)); - else + else if (args[i].ref.cast->size == 2) + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[QCC_OPCodeValid(&pr_opcodes[OP_STORE_I64])?OP_STORE_I64:OP_STORE_V], args[i].ref, d, NULL, 0)); + else if (args[i].ref.cast->size == 1) QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], args[i].ref, d, NULL, 0)); + else + QCC_PR_ParseErrorPrintSRef (ERR_BADEXTENSION, func, "arg storage not 1, 2, or 3."); #endif } else @@ -7353,45 +8007,27 @@ QCC_sref_t QCC_MakeSRef(QCC_def_t *def, unsigned int ofs, QCC_type_t *type) //int varchecks; //int typechecks; extern hashtable_t floatconstdefstable; -QCC_sref_t QCC_MakeIntConst(longlong llvalue) +static QCC_sref_t QCC_Make32bitConst(QCC_type_t *type, puint_t value) //none of these types may be mutilated by the engine (allowing 0s to merge) { QCC_def_t *cn; - int value = llvalue; + unsigned int key = value; - if (value != llvalue) - QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %lld will be truncated to %i", llvalue, value); - - cn = Hash_GetKey(&floatconstdefstable, value); - if (cn) - return QCC_MakeSRefForce(cn, 0, type_integer); - -//FIXME: union with float consts? -// check for a constant with the same value - /*for (cn=pr.def_head.next ; cn ; cn=cn->next) + cn = Hash_GetKey(&floatconstdefstable, key); + while (cn) { - varchecks++; - if (!cn->initialized) - continue; - if (!cn->constant) - continue; - constchecks++; - if (cn->type != type_integer) - continue; - typechecks++; - - if ( cn->symboldata[0]._int == value ) - { - return QCC_MakeSRefForce(cn, 0, type_integer); - } - }*/ + if (cn->type->size == type->size) + if (((QCC_eval_t*)cn->symboldata)->_uint == value) + return QCC_MakeSRefForce(cn, 0, type); + cn = Hash_GetNextKey(&floatconstdefstable, key, cn); + } // allocate a new one - cn = (void *)qccHunkAlloc (sizeof(QCC_def_t) + sizeof(pint_t)); + cn = (void *)qccHunkAlloc (sizeof(QCC_def_t) + sizeof(value)); cn->next = NULL; pr.def_tail->next = cn; pr.def_tail = cn; - cn->type = type_integer; + cn->type = type; cn->name = "IMMEDIATE"; cn->constant = true; cn->initialized = 1; @@ -7401,13 +8037,140 @@ QCC_sref_t QCC_MakeIntConst(longlong llvalue) cn->ofs = 0; cn->symbolheader = cn; cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); + cn->symboldata = (QCC_eval_basic_t*)(cn+1); - cn->symboldata[0]._int = value; + ((QCC_eval_t*)cn->symboldata)->_uint = value; - Hash_AddKey(&floatconstdefstable, value, cn, qccHunkAlloc(sizeof(bucket_t))); + Hash_AddKey(&floatconstdefstable, key, cn, qccHunkAlloc(sizeof(bucket_t))); - return QCC_MakeSRefForce(cn, 0, type_integer); + return QCC_MakeSRefForce(cn, 0, type); +} +static QCC_sref_t QCC_Make64bitConst(QCC_type_t *type, puint64_t value) //all values MUST be word-swapped, for big-endian machines to byteswap their 64bit immediates, or something. +{ + QCC_def_t *cn; + unsigned int key = value ^ (value>>32); + + cn = Hash_GetKey(&floatconstdefstable, key); + while (cn) + { + if (cn->type->size == type->size) + if (((QCC_eval_t*)cn->symboldata)->_uint64 == value) + return QCC_MakeSRefForce(cn, 0, type); + cn = Hash_GetNextKey(&floatconstdefstable, key, cn); + } + +// allocate a new one + cn = (void *)qccHunkAlloc (sizeof(QCC_def_t) + sizeof(value)); + cn->next = NULL; + pr.def_tail->next = cn; + pr.def_tail = cn; + + cn->type = type; + cn->name = "IMMEDIATE"; + cn->constant = true; + cn->initialized = 1; + cn->scope = NULL; // always share immediates + cn->arraysize = 0; + + cn->ofs = 0; + cn->symbolheader = cn; + cn->symbolsize = cn->type->size; + cn->symboldata = (QCC_eval_basic_t*)(cn+1); + + ((QCC_eval_t*)cn->symboldata)->_uint64 = value; + + Hash_AddKey(&floatconstdefstable, key, cn, qccHunkAlloc(sizeof(bucket_t))); + + return QCC_MakeSRefForce(cn, 0, type); +} +static QCC_sref_t QCC_Make96bitConst(QCC_type_t *type, puint_t *value) //basically just vectors... +{ + QCC_def_t *cn; + unsigned int key = value[0] ^ value[1] ^ value[2]; + + cn = Hash_GetKey(&floatconstdefstable, key); + while (cn) + { + if (cn->type->size == type->size) + if (((puint_t*)cn->symboldata)[0] == value[0] && + ((puint_t*)cn->symboldata)[1] == value[1] && + ((puint_t*)cn->symboldata)[2] == value[2]) + return QCC_MakeSRefForce(cn, 0, type); + cn = Hash_GetNextKey(&floatconstdefstable, key, cn); + } + +// allocate a new one + cn = (void *)qccHunkAlloc (sizeof(QCC_def_t) + sizeof(*value)*3); + cn->next = NULL; + pr.def_tail->next = cn; + pr.def_tail = cn; + + cn->type = type; + cn->name = "IMMEDIATE"; + cn->constant = true; + cn->initialized = 1; + cn->scope = NULL; // always share immediates + cn->arraysize = 0; + + cn->ofs = 0; + cn->symbolheader = cn; + cn->symbolsize = cn->type->size; + cn->symboldata = (QCC_eval_basic_t*)(cn+1); + + ((puint_t*)cn->symboldata)[0] = value[0]; + ((puint_t*)cn->symboldata)[1] = value[1]; + ((puint_t*)cn->symboldata)[2] = value[2]; + + Hash_AddKey(&floatconstdefstable, key, cn, qccHunkAlloc(sizeof(bucket_t))); + + return QCC_MakeSRefForce(cn, 0, type); +} + +QCC_sref_t QCC_MakeFloatConst(float value) +{ + union + { + float d; + puint_t i; + } u = {value}; + return QCC_Make32bitConst(type_float, u.i); +} +QCC_sref_t QCC_MakeIntConst(longlong llvalue) +{ + pint_t value = llvalue; + if (value != llvalue) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %llu will be truncated to %i", llvalue, value); + return QCC_Make32bitConst(type_integer, value); +} +QCC_sref_t QCC_MakeUIntConst(unsigned longlong llvalue) +{ + puint_t value = llvalue; + if (value != llvalue) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %llu will be truncated to %i", llvalue, value); + return QCC_Make32bitConst(type_uint, value); +} +QCC_sref_t QCC_MakeInt64Const(longlong llvalue) +{ + pint64_t value = llvalue; + if (value != llvalue) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %llu will be truncated to %"PRIi64, llvalue, value); + return QCC_Make64bitConst(type_int64, value); +} +QCC_sref_t QCC_MakeUInt64Const(unsigned longlong llvalue) +{ + puint64_t value = llvalue; + if (value != llvalue) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %llu will be truncated to %"PRIu64, llvalue, value); + return QCC_Make64bitConst(type_uint64, value); +} +QCC_sref_t QCC_MakeDoubleConst(double value) +{ + union + { + double d; + puint64_t i; + } u = {value}; + return QCC_Make64bitConst(type_double, u.i); } //immediates with no overlapping. this means aliases can be set up to mark them as strings/fields/functions and the engine can safely remap them as needed @@ -7431,7 +8194,7 @@ static QCC_sref_t QCC_MakeUniqueConst(QCC_type_t *type, void *data) cn->ofs = 0; cn->symbolheader = cn; cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); + cn->symboldata = (QCC_eval_basic_t*)(cn+1); memcpy(cn->symboldata, data, sizeof(pint_t) * type->size); @@ -7461,7 +8224,7 @@ static QCC_sref_t QCC_MakeGAddress(QCC_type_t *type, QCC_def_t *relocof) cn->ofs = 0; cn->symbolheader = cn; cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); + cn->symboldata = (QCC_eval_basic_t*)(cn+1); cn->reloc = relocof; relocof->gaddress = cn; @@ -7476,7 +8239,7 @@ static QCC_sref_t QCC_MakeGAddress(QCC_type_t *type, QCC_def_t *relocof) QCC_sref_t QCC_PR_GenerateVector(QCC_sref_t x, QCC_sref_t y, QCC_sref_t z); QCC_sref_t QCC_MakeVectorConst(pvec_t a, pvec_t b, pvec_t c) { - QCC_def_t *cn; +/* QCC_def_t *cn; // check for a constant with the same value for (cn=pr.def_head.next ; cn ; cn=cn->next) @@ -7496,91 +8259,16 @@ QCC_sref_t QCC_MakeVectorConst(pvec_t a, pvec_t b, pvec_t c) { return QCC_MakeSRefForce(cn, 0, type_vector); } + }*/ + + { + union + { + pvec_t f[3]; + pint_t i[3]; + } u = {{a,b,c}}; + return QCC_Make96bitConst(type_vector, u.i); } - -/* if (pr_scope) - { //crappy-but-globals-efficient version - QCC_sref_t d = QCC_GetTemp(type_vector); - d.cast = type_float; - QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, QCC_MakeFloatConst(a), d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT); - d.ofs++; - QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, QCC_MakeFloatConst(b), d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT); - d.ofs++; - QCC_PR_StatementFlags(pr_opcodes + OP_STORE_F, QCC_MakeFloatConst(c), d, NULL, STFL_PRESERVEB|STFL_DISCARDRESULT); - d.ofs++; - d.ofs -= 3; - d.cast = type_vector; - return d; - } -*/ - -// allocate a new one - cn = (void *)qccHunkAlloc (sizeof(QCC_def_t)+sizeof(pvec_t)*3); - cn->next = NULL; - pr.def_tail->next = cn; - pr.def_tail = cn; - - cn->type = type_vector; - cn->name = "IMMEDIATE"; - cn->constant = true; - cn->initialized = 1; - cn->scope = NULL; // always share immediates - cn->arraysize = 0; - -// copy the immediate to the global area - cn->ofs = 0; - cn->symbolheader = cn; - cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); - - cn->symboldata[0].vector[0] = a; - cn->symboldata[0].vector[1] = b; - cn->symboldata[0].vector[2] = c; - - return QCC_MakeSRefForce(cn, 0, type_vector); -} - -extern hashtable_t floatconstdefstable; -QCC_sref_t QCC_MakeFloatConst(pvec_t value) -{ - QCC_def_t *cn; - - union { - pvec_t f; - pint_t i; - } fi; - - fi.f = value; - - cn = Hash_GetKey(&floatconstdefstable, fi.i); - if (cn) - return QCC_MakeSRefForce(cn, 0, type_float); - -// allocate a new one - cn = (void *)qccHunkAlloc (sizeof(QCC_def_t) + sizeof(pvec_t)); - cn->next = NULL; - pr.def_tail->next = cn; - pr.def_tail = cn; - -// cn->s_file = s_file; -// cn->s_line = pr_source_line; - cn->type = type_float; - cn->name = "IMMEDIATE"; - cn->constant = true; - cn->initialized = 1; - cn->scope = NULL; // always share immediates - cn->arraysize = 0; - - cn->ofs = 0; - cn->symbolheader = cn; - cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); - - Hash_AddKey(&floatconstdefstable, fi.i, cn, qccHunkAlloc(sizeof(bucket_t))); - - cn->symboldata[0]._float = value; - - return QCC_MakeSRefForce(cn, 0, type_float); } extern hashtable_t stringconstdefstable, stringconstdefstable_trans; @@ -7632,7 +8320,7 @@ static QCC_sref_t QCC_MakeStringConstInternal(const char *value, size_t length, cn->ofs = 0; cn->symbolheader = cn; cn->symbolsize = cn->type->size; - cn->symboldata = (QCC_eval_t*)(cn+1); + cn->symboldata = (QCC_eval_basic_t*)(cn+1); if (usehash) { @@ -7679,9 +8367,16 @@ QCC_type_t **basictypes[] = &type_function, &type_pointer, &type_integer, + &type_uint, + &type_int64, + &type_uint64, + &type_double, &type_variant, NULL, //type_struct NULL, //type_union + NULL, //type_accessor + NULL, //type_enum + NULL, //type_boolean }; /*static QCC_def_t *QCC_MemberInParentClass(char *name, QCC_type_t *clas) @@ -7902,6 +8597,23 @@ static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_ case ev_integer: r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_I], ent, field, NULL, preserveflags); break; + case ev_uint: + r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_I], ent, field, NULL, preserveflags); + r.cast = type_uint; + break; + case ev_double: + r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_I64], ent, field, NULL, preserveflags); + r.cast = type_double; + break; + case ev_int64: + r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_I64], ent, field, NULL, preserveflags); + r.cast = type_int64; + break; + case ev_uint64: + r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_I64], ent, field, NULL, preserveflags); + r.cast = type_uint64; + break; + case ev_pointer: r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_P], ent, field, NULL, preserveflags); break; @@ -8897,7 +9609,7 @@ QCC_sref_t QCC_PR_GenerateLogicalNot(QCC_sref_t e, const char *errormessage) { etype_t t; QCC_type_t *type = e.cast; - while(type->type == ev_accessor) + while(type->type == ev_accessor || type->type == ev_boolean) type = type->parentclass; t = type->type; if (t == ev_float) @@ -8914,6 +9626,12 @@ QCC_sref_t QCC_PR_GenerateLogicalNot(QCC_sref_t e, const char *errormessage) return QCC_PR_Statement (&pr_opcodes[OP_NOT_I], e, nullsref, NULL); //functions are integer values too. else if (t == ev_pointer) return QCC_PR_Statement (&pr_opcodes[OP_NOT_I], e, nullsref, NULL); //Pointers are too. + else if (t == ev_double) + return QCC_PR_Statement (&pr_opcodes[OP_EQ_D], e, QCC_MakeDoubleConst(0), NULL); + else if (t == ev_int64) + return QCC_PR_Statement (&pr_opcodes[OP_EQ_I64], e, QCC_MakeInt64Const(0), NULL); + else if (t == ev_uint64) + return QCC_PR_Statement (&pr_opcodes[OP_EQ_U64], e, QCC_MakeUInt64Const(0), NULL); else if (t == ev_void && flag_laxcasts) { QCC_PR_ParseWarning(WARN_LAXCAST, errormessage, "void"); @@ -8935,7 +9653,9 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im QCC_type_t *tmp; int totype; - for (tmp = cast; tmp->type == ev_accessor; tmp = tmp->parentclass) + while (src.cast->type == ev_boolean) + src.cast = src.cast->parentclass; + for (tmp = cast; tmp->type == ev_accessor || tmp->type == ev_boolean; tmp = tmp->parentclass) ; totype = tmp->type; @@ -8955,11 +9675,76 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im src.cast = cast; } /*cast from int->float will convert*/ - else if (totype == ev_float && (src.cast->type == ev_integer || (src.cast->type == ev_entity && !implicit))) + else if (totype == ev_float && (src.cast->type == ev_uint || src.cast->type == ev_integer || (src.cast->type == ev_entity && !implicit))) + { src = QCC_PR_Statement (&pr_opcodes[OP_CONV_ITOF], src, nullsref, NULL); + src.cast = cast; + } /*cast from float->int will convert*/ - else if ((totype == ev_integer || (totype == ev_entity && !implicit)) && src.cast->type == ev_float) + else if (((totype == ev_integer || totype == ev_uint) || (totype == ev_entity && !implicit)) && src.cast->type == ev_float) + { src = QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], src, nullsref, NULL); + src.cast = cast; + } + else if ((totype == ev_integer || totype == ev_uint) && (src.cast->type == ev_integer || src.cast->type == ev_uint)) + src.cast = cast; //fine, just treat it as-is + else if ((totype == ev_int64 || totype == ev_uint64) && (src.cast->type == ev_int64 || src.cast->type == ev_uint64)) + src.cast = cast; //fine, just treat it as-is + + else if (totype == ev_float && src.cast->type == ev_double) + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_DF], src, nullsref, NULL); + else if (totype == ev_double && src.cast->type == ev_float) + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_FD], src, nullsref, NULL); + + else if (totype == ev_float && src.cast->type == ev_int64) + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_I64F], src, nullsref, NULL); + else if (totype == ev_int64 && src.cast->type == ev_float) + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_FI64], src, nullsref, NULL); + + else if ((totype == ev_int64||totype == ev_uint64) && src.cast->type == ev_double) + { + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_DI64], src, nullsref, NULL); + src.cast = cast; + } + else if (totype == ev_double && (src.cast->type == ev_int64 || src.cast->type == ev_uint64)) + { + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_I64D], src, nullsref, NULL); + src.cast = cast; + } + + else if ((totype == ev_integer||totype == ev_uint) && src.cast->type == ev_double) + { + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_DI64], src, nullsref, NULL); + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_I64I], src, nullsref, NULL); + src.cast = cast; + } + else if (totype == ev_double && (src.cast->type == ev_integer || src.cast->type == ev_uint)) + { + if (src.cast->type == ev_uint) + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_UI64], src, nullsref, NULL); + else + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_II64], src, nullsref, NULL); + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_I64D], src, nullsref, NULL); + src.cast = cast; + } + + + else if ((totype == ev_int64||totype == ev_uint64) && src.cast->type == ev_uint) + { //zero extends. we could emulate this but that means endian issues. + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_UI64], src, nullsref, NULL); + src.cast = cast; + } + else if ((totype == ev_int64||totype == ev_uint64) && src.cast->type == ev_integer) + { //sign extends + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_II64], src, nullsref, NULL); + src.cast = cast; + } + else if ((totype == ev_integer||totype == ev_uint) && (src.cast->type == ev_integer||src.cast->type == ev_uint)) + { //truncates. we could emulate this but that means endian issues. + src = QCC_PR_Statement (&pr_opcodes[OP_CONV_I64I], src, nullsref, NULL); + src.cast = cast; + } + else if (totype == ev_vector && src.cast->type == ev_float) { if (implicit) @@ -8968,10 +9753,22 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(WARN_IMPLICITVARIANTCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } src = QCC_PR_Statement (&pr_opcodes[OP_MUL_FV], src, QCC_MakeVectorConst(1,1,1), NULL); } + else if (totype == ev_vector && src.cast->type == ev_integer) + { + if (implicit) + { + char typea[256]; + char typeb[256]; + TypeName(src.cast, typea, sizeof(typea)); + TypeName(cast, typeb, sizeof(typeb)); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + } + src = QCC_PR_Statement (&pr_opcodes[OP_MUL_IV], src, QCC_MakeVectorConst(1,1,1), NULL); + } else if (totype == ev_entity && src.cast->type == ev_entity) { if (implicit) @@ -8990,7 +9787,7 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(0, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } } src.cast = cast; @@ -9013,7 +9810,7 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(0, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } } src.cast = cast; @@ -9030,7 +9827,7 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(WARN_IMPLICITVARIANTCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } } /*these casts are acceptable but probably an error (so warn when implicit)*/ @@ -9055,7 +9852,7 @@ static QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool im char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(0, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); + QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } src.cast = cast; } @@ -9103,7 +9900,7 @@ QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit) char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseWarning(0, "Implicit lax cast from %s to %s", typea, typeb); + QCC_PR_ParseWarning(0, "Implicit lax cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type,typeb,col_none); } r = src; r.cast = cast; //decompilers suck @@ -9115,7 +9912,7 @@ QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit) char typeb[256]; TypeName(src.cast, typea, sizeof(typea)); TypeName(cast, typeb, sizeof(typeb)); - QCC_PR_ParseError(0, "Cannot cast from %s to %s", typea, typeb); + QCC_PR_ParseError(0, "Cannot cast from %s%s%s to %s%s%s", col_type,typea,col_none, col_type, typeb,col_none); } } } @@ -9160,12 +9957,24 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) case ev_integer: e = QCC_PR_Statement(&pr_opcodes[OP_ADD_I], e, QCC_MakeIntConst(preinc), NULL); break; + case ev_uint: + e = QCC_PR_Statement(&pr_opcodes[OP_ADD_U], e, QCC_MakeIntConst(preinc), NULL); + break; case ev_pointer: e = QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], e, QCC_MakeIntConst(preinc * e.cast->aux_type->size), NULL); break; case ev_float: e = QCC_PR_Statement(&pr_opcodes[OP_ADD_F], e, QCC_MakeFloatConst(preinc), NULL); break; + case ev_double: + e = QCC_PR_Statement(&pr_opcodes[OP_ADD_D], e, QCC_MakeDoubleConst(preinc), NULL); + break; + case ev_int64: + e = QCC_PR_Statement(&pr_opcodes[OP_ADD_I64], e, QCC_MakeInt64Const(preinc), NULL); + break; + case ev_uint64: + e = QCC_PR_Statement(&pr_opcodes[OP_ADD_U64], e, QCC_MakeInt64Const(preinc), NULL); + break; default: QCC_PR_ParseError(ERR_BADPLUSPLUSOPERATOR, "++ operator on unsupported type"); break; @@ -9188,8 +9997,16 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) t = e.cast->parentclass->type; if (t == ev_float) e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_F], e, nullsref, NULL); +// else if (t == ev_double) +// e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_D], e, nullsref, NULL); else if (t == ev_integer) e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_I], e, nullsref, NULL); + else if (t == ev_uint) + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_U], e, nullsref, NULL); + else if (t == ev_int64) + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_I64], e, nullsref, NULL); + else if (t == ev_uint64) + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_U64], e, nullsref, NULL); else if (t == ev_vector) e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_V], e, nullsref, NULL); else @@ -9244,19 +10061,35 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) } if (QCC_PR_CheckToken ("-")) { + QCC_type_t *type; e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA); - switch(e.cast->type) + type = e.cast; + while (type->type == ev_boolean) + type = type->parentclass; + switch(type->type) { case ev_float: e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_F], QCC_MakeFloatConst(0), e, NULL); break; + case ev_double: + e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_D], QCC_MakeDoubleConst(0), e, NULL); + break; case ev_vector: e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_V], QCC_MakeVectorConst(0, 0, 0), e, NULL); break; case ev_integer: e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_I], QCC_MakeIntConst(0), e, NULL); break; + case ev_uint: + e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_U], QCC_MakeIntConst(0), e, NULL); + break; + case ev_int64: + e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_I64], QCC_MakeInt64Const(0), e, NULL); + break; + case ev_uint64: + e2 = QCC_PR_Statement (&pr_opcodes[OP_SUB_U64], QCC_MakeInt64Const(0), e, NULL); + break; default: QCC_PR_ParseError (ERR_BADNOTTYPE, "type mismatch for -"); e2 = nullsref; @@ -9271,8 +10104,12 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) switch(e.cast->type) { case ev_float: + case ev_double: case ev_vector: case ev_integer: + case ev_uint: + case ev_int64: + case ev_uint64: e2 = e; break; default: @@ -9425,21 +10262,32 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) return QCC_PR_ParseRefValue (retbuf, pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN), true, true); } - +static int QCC_NumericTypeRanking(etype_t t) +{ + switch(t) + { + case ev_double: return 15; + case ev_float: return 10; + //large gap, to try to de-prioritize the opcodes that mix float and int types. + case ev_uint64: return 6; + case ev_int64: return 3; + case ev_uint: return 1; + case ev_integer:return 0; + default: return -1; //unranked + } +} +//type promotions: +//identity=0 > inheritance=1 > null=2 > double=3 > float=4 > uint64=5 > int64=6 > uint=7 > int=8 > short=9 > char=10 > variant=11 > vector=12 > failure static int QCC_canConv(QCC_sref_t from, etype_t to) { - while(from.cast->type == ev_accessor) + int frompri; + int topri; + + while(from.cast->type == ev_accessor || from.cast->type == ev_boolean) //no opcodes use accessors. convert to their real type. from.cast = from.cast->parentclass; if (from.cast->type == to) - return 0; - - //triggers a warning. conversion works by using _x - if (from.cast->type == ev_vector && to == ev_float) - return 8; - //triggers a warning. - if (from.cast->type == ev_float && to == ev_vector) - return 7; + return 0; //identity if (pr_classtype) { @@ -9450,26 +10298,33 @@ static int QCC_canConv(QCC_sref_t from, etype_t to) } } - //somewhat high penalty, ensures the other side is correct - if (from.cast->type == ev_variant) - return 3; - if (to == ev_variant) - return 3; - -/* if (from->type->type == ev_pointer && from->type->aux_type->type == to) - return 1; - - if (QCC_ShouldConvert(from.cast, to)>=0) - return 1; -*/ -// if (from->type->type == ev_integer && to == ev_function) -// return 1; - - //silently convert 0 to whatever as required. if (QCC_SRef_IsNull(from)) return 2; - return -100; + frompri = QCC_NumericTypeRanking(from.cast->type); + topri = QCC_NumericTypeRanking(to); + if (frompri >= 0 && topri >= 0) + { //3...12 + if (topri >= frompri) + return 3+(topri-frompri); + else + return 150+(frompri-topri); + } + + //somewhat high penalty, ensures the other side is correct + if (to == ev_variant) + return 9; + if (from.cast->type == ev_variant) + return 10; + + //triggers a warning. + if (from.cast->type == ev_float && to == ev_vector) + return 200; + //triggers a warning. conversion works by using _x + if (from.cast->type == ev_vector && to == ev_float) + return 201; + + return -1; } /* ============== @@ -9552,6 +10407,7 @@ static void QCC_StoreToSRef(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type //fixme: we should probably handle entire structs or something switch(type->type) { + default: case ev_struct: case ev_union: case ev_enum: @@ -9560,6 +10416,9 @@ static void QCC_StoreToSRef(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type { for (i = 0; i+2 < type->size; i+=3, dest.ofs += 3) QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_V], QCC_MakeVectorConst(0,0,0), dest, nullsref, false); + if (QCC_OPCodeValid(&pr_opcodes[OP_STORE_I64])) + for (; i+1 < type->size; i+=2, dest.ofs+=2) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_I64], QCC_MakeInt64Const(0), dest, nullsref, false); for (; i < type->size; i++, dest.ofs++) QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_F], QCC_MakeIntConst(0), dest, nullsref, false); } @@ -9567,6 +10426,9 @@ static void QCC_StoreToSRef(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type { for (i = 0; i+2 < type->size; i+=3, dest.ofs += 3, source.ofs += 3) QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_V], source, dest, nullsref, false); + if (QCC_OPCodeValid(&pr_opcodes[OP_STORE_I64])) + for (; i+1 < type->size; i+=2, dest.ofs+=2, source.ofs+=2) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_I64], source, dest, nullsref, false); for (; i < type->size; i++, dest.ofs++, source.ofs++) QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_F], source, dest, nullsref, false); source.ofs -= type->size; @@ -9577,7 +10439,6 @@ static void QCC_StoreToSRef(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type if (!preservedest) QCC_FreeTemp(dest); break; - default: case ev_float: QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], source, dest, NULL, flags)); break; @@ -9597,8 +10458,13 @@ static void QCC_StoreToSRef(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FLD], source, dest, NULL, flags)); break; case ev_integer: + case ev_uint: QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I], source, dest, NULL, flags)); break; + case ev_int64: + case ev_uint64: + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I64], source, dest, NULL, flags)); + break; case ev_pointer: QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_P], source, dest, NULL, flags)); break; @@ -9650,7 +10516,6 @@ static void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t idx, QCC_sref_t sourc switch(type->type) { default: - QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, dest, "QCC_StoreToPointer doesn't know how to store to that type"); case ev_struct: case ev_union: { @@ -9669,6 +10534,19 @@ static void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t idx, QCC_sref_t sourc } QCC_FreeTemp(newidx); } + if (QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I64])) + for (; i+1 < type->size; i+=2) + { + QCC_sref_t newidx = idx.sym?QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], idx, QCC_MakeIntConst(i), NULL, STFL_PRESERVEA):QCC_MakeIntConst(i); + if (QCC_SRef_IsNull(source)) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I64], QCC_MakeVectorConst(0,0,0), dest, newidx, false); + else + { + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I64], source, dest, newidx, false); + source.ofs += 2; + } + QCC_FreeTemp(newidx); + } for (; i < type->size; i++) { QCC_sref_t newidx = idx.sym?QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], idx, QCC_MakeIntConst(i), NULL, STFL_PRESERVEA):QCC_MakeIntConst(i); @@ -9691,6 +10569,19 @@ static void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t idx, QCC_sref_t sourc } QCC_FreeTemp(newptr); } + if (QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I64])) + for (; i+1 < type->size; i+=2) + { + QCC_sref_t newptr = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], dest, QCC_MakeIntConst(i), NULL, STFL_PRESERVEA); + if (QCC_SRef_IsNull(source)) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I64], QCC_MakeVectorConst(0,0,0), newptr, idx, false); + else + { + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I64], source, newptr, idx, false); + source.ofs += 2; + } + QCC_FreeTemp(newptr); + } for (; i < type->size; i++) { QCC_sref_t newptr = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], dest, QCC_MakeIntConst(i), NULL, STFL_PRESERVEA); @@ -9725,11 +10616,28 @@ static void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t idx, QCC_sref_t sourc QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, idx, false); break; case ev_integer: + case ev_uint: if (!QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I])) QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, idx, false); else QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I], source, dest, idx, false); break; + case ev_double: + case ev_int64: + case ev_uint64: + if (!QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I64])) + { + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, idx, false); + if (QCC_OPCode_StorePOffset()) + idx = idx.sym?QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], idx, QCC_MakeIntConst(1), NULL, STFL_PRESERVEA):QCC_MakeIntConst(1); + else + dest = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], dest, QCC_MakeIntConst(1), NULL, STFL_PRESERVEA); + source.ofs+=1; + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, idx, false); + } + else + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I64], source, dest, idx, false); + break; case ev_pointer: if (!QCC_OPCodeValid(&pr_opcodes[OP_STOREP_P])) QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, idx, false); @@ -9756,6 +10664,9 @@ static void QCC_StoreToGPointer(QCC_sref_t dest, QCC_sref_t source, QCC_type_t * QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, dest, "QCC_StoreToPointer doesn't know how to store to that type"); case ev_struct: case ev_union: + case ev_double: + case ev_int64: + case ev_uint64: { unsigned int i; for (i = 0; i+2 < type->size; i+=3) @@ -9803,6 +10714,7 @@ static void QCC_StoreToGPointer(QCC_sref_t dest, QCC_sref_t source, QCC_type_t * QCC_PR_SimpleStatement(&pr_opcodes[OP_GSTOREP_FLD], source, dest, nullsref, false); break; case ev_integer: + case ev_uint: case ev_pointer: QCC_PR_SimpleStatement(&pr_opcodes[OP_GSTOREP_I], source, dest, nullsref, false); break; @@ -9844,6 +10756,9 @@ static QCC_sref_t QCC_LoadFromPointer(QCC_sref_t source, QCC_sref_t idx, QCC_typ return ret; } break; +// case ev_double: op = OP_LOADP_D; break; + case ev_int64: op = OP_LOADP_I64; break; + case ev_uint64: op = OP_LOADP_I64; break; case ev_float: op = OP_LOADP_F; break; case ev_string: op = OP_LOADP_S; break; case ev_vector: op = OP_LOADP_V; break; @@ -9851,6 +10766,7 @@ static QCC_sref_t QCC_LoadFromPointer(QCC_sref_t source, QCC_sref_t idx, QCC_typ case ev_field: op = OP_LOADP_FLD; break; case ev_function: op = OP_LOADP_FNC; break; case ev_integer: op = OP_LOADP_I; break; + case ev_uint: op = OP_LOADP_I; break; case ev_void: case ev_variant: QCC_PR_ParseError(ERR_TYPEMISMATCH, "ptr-to-variants must be cast to a different type before being read"); @@ -10000,6 +10916,9 @@ QCC_sref_t QCC_LoadFromArray(QCC_sref_t base, QCC_sref_t index, QCC_type_t *t, p case ev_variant: case ev_struct: case ev_union: + case ev_int64: + case ev_uint64: + case ev_double: { QCC_sref_t r; unsigned int i; @@ -10072,8 +10991,14 @@ QCC_sref_t QCC_LoadFromArray(QCC_sref_t base, QCC_sref_t index, QCC_type_t *t, p break; case ev_pointer: //no OP_LOADA_P case ev_integer: + case ev_uint: base = QCC_PR_StatementFlags(&pr_opcodes[OP_LOADA_I], base, index, NULL, flags); //get pointer to precise def. break; + case ev_int64: + case ev_uint64: + case ev_double: + base = QCC_PR_StatementFlags(&pr_opcodes[OP_LOADA_I64], base, index, NULL, flags); //get pointer to precise def. + break; case ev_variant: case ev_struct: case ev_union: @@ -10343,9 +11268,21 @@ QCC_sref_t QCC_RefToDef(QCC_ref_t *ref, pbool freetemps) case ev_float: QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], ret, QCC_MakeFloatConst(inc), NULL, STFL_PRESERVEA), false, !freetemps); break; + case ev_double: + QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_D], ret, QCC_MakeDoubleConst(inc), NULL, STFL_PRESERVEA), false, !freetemps); + break; case ev_integer: QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], ret, QCC_MakeIntConst(inc), NULL, STFL_PRESERVEA), false, !freetemps); break; + case ev_uint: + QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_U], ret, QCC_MakeIntConst(inc), NULL, STFL_PRESERVEA), false, !freetemps); + break; + case ev_int64: + QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I64], ret, QCC_MakeInt64Const(inc), NULL, STFL_PRESERVEA), false, !freetemps); + break; + case ev_uint64: + QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_U64], ret, QCC_MakeInt64Const(inc), NULL, STFL_PRESERVEA), false, !freetemps); + break; case ev_pointer: inc *= ref->cast->aux_type->size; QCC_StoreSRefToRef(ref, QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], ret, QCC_MakeIntConst(inc), NULL, STFL_PRESERVEA), false, !freetemps); @@ -10661,9 +11598,13 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable dest->cast->type == ev_function || dest->cast->type == ev_pointer || dest->cast->type == ev_integer || + dest->cast->type == ev_uint || dest->cast->type == ev_struct || dest->cast->type == ev_union || - dest->cast->type == ev_enum) + dest->cast->type == ev_enum || + dest->cast->type == ev_int64 || + dest->cast->type == ev_uint64 || + dest->cast->type == ev_double) storef_opcode = OP_STOREF_I; else storef_opcode = OP_DONE; @@ -10676,6 +11617,9 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable { for (i = 0; i+2 < sz; i+=3, dest->index.ofs += 3) QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREF_V], dest->base, dest->index, QCC_MakeVectorConst(0,0,0), true); + if (QCC_OPCodeValid(&pr_opcodes[OP_STOREF_I64])) + for (; i+1 < sz; i+=2, dest->index.ofs += 2) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREF_V], dest->base, dest->index, QCC_MakeVectorConst(0,0,0), true); for (; i < sz; i++, dest->index.ofs++) QCC_PR_SimpleStatement(&pr_opcodes[storef_opcode], dest->base, dest->index, QCC_MakeIntConst(0), true); } @@ -10683,6 +11627,9 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable { for (i = 0; i+2 < sz; i+=3, dest->index.ofs += 3, source.ofs += 3) QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREF_V], dest->base, dest->index, source, true); + if (QCC_OPCodeValid(&pr_opcodes[OP_STOREF_I64])) + for (; i+1 < sz; i+=2, dest->index.ofs += 2, source.ofs += 2) + QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREF_I64], dest->base, dest->index, source, true); for (; i < sz; i++, dest->index.ofs++, source.ofs++) QCC_PR_SimpleStatement(&pr_opcodes[storef_opcode], dest->base, dest->index, source, true); source.ofs -= i; @@ -10710,6 +11657,13 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable QCC_StoreToPointer(t, nullsref, nullsrc?QCC_MakeVectorConst(0,0,0):source, type_vector); QCC_FreeTemp(t); } + if (QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I64])) + for (; i+1 < sz; i+=2, dest->index.ofs += 2, source.ofs+=2) + { + t = QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, STFL_PRESERVEA|STFL_PRESERVEB); + QCC_StoreToPointer(t, nullsref, nullsrc?QCC_MakeInt64Const(0):source, type_int64); + QCC_FreeTemp(t); + } for (; i < sz; i++, dest->index.ofs++, source.ofs++) { t = QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, STFL_PRESERVEA|STFL_PRESERVEB); @@ -10783,9 +11737,21 @@ void QCC_PR_DiscardRef(QCC_ref_t *ref) case ev_float: oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], oval, QCC_MakeFloatConst(inc), NULL, 0); break; + case ev_double: + oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_D], oval, QCC_MakeDoubleConst(inc), NULL, 0); + break; case ev_integer: oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], oval, QCC_MakeIntConst(inc), NULL, 0); break; + case ev_uint: + oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_U], oval, QCC_MakeIntConst(inc), NULL, 0); + break; + case ev_int64: + oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I64], oval, QCC_MakeInt64Const(inc), NULL, 0); + break; + case ev_uint64: + oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_U64], oval, QCC_MakeInt64Const(inc), NULL, 0); + break; case ev_pointer: inc *= ref->cast->aux_type->size; oval = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], oval, QCC_MakeIntConst(inc), NULL, 0); @@ -10883,17 +11849,16 @@ static QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opc } else { - /*if (op->type_a == &type_pointer) //ent var + int l = QCC_canConv(lhs, (*op->type_a)->type); + int r = QCC_canConv(rhs, (*op->type_b)->type); + c = min(l,r); + if (c >= 0) { - if (e2->type->type != ev_pointer || e2->type->aux_type->type != (*op->type_b)->type) //if e isn't a pointer to a type_b - c = -200; //don't let the conversion work - else - c = 0; - } - else*/ - { - c=QCC_canConv(lhs, (*op->type_a)->type); - c+=QCC_canConv(rhs, (*op->type_b)->type); + c = max(l,r); + /*QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "%s (%i): Possible conversion from %s to %s (%i), %s to %s (%i)", + op->opname, c, + lhs.cast->name, (*op->type_a)->name, l, + rhs.cast->name, (*op->type_b)->name, r);*/ } } @@ -10916,8 +11881,10 @@ static QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opc // op = oldop; // else { + char temp1[256]; + char temp2[256]; op = oldop; - QCC_PR_ParseWarning(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, "type mismatch for %s (%s and %s)", oldop->name, lhs.cast->name, rhs.cast->name); + QCC_PR_ParseWarning(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, "type mismatch for %s (%s%s%s and %s%s%s)", oldop->name, col_type,TypeName(lhs.cast,temp1,sizeof(temp1)),col_none, col_type,TypeName(rhs.cast,temp2,sizeof(temp2)),col_none); QCC_PR_ParsePrintSRef(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, lhs); QCC_PR_ParsePrintSRef(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, rhs); } @@ -10932,7 +11899,7 @@ static QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opc QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", lhs.cast->name, (*op->type_a)->name); c=QCC_canConv(rhs, (*op->type_b)->type); if (c>3) - QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhs.cast->name, (*op->type_a)->name); + QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhs.cast->name, (*op->type_b)->name); }*/ } return op; @@ -11104,7 +12071,14 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) if (typecmp(val.cast, r.cast) != 0) { - if (QCC_SRef_IsNull(val) && r.cast->size == val.cast->size) + while (val.cast->type == ev_boolean) + val.cast = val.cast->parentclass; + while (r.cast->type == ev_boolean) + r.cast = r.cast->parentclass; + + if (typecmp(val.cast, r.cast) == 0) + ; + else if (QCC_SRef_IsNull(val) && r.cast->size == val.cast->size) val.cast = r.cast; //null is null... unless its a vector... else if (lvalisnull && r.cast->size == val.cast->size) r.cast = val.cast; //null is null... unless its a vector... @@ -11129,15 +12103,18 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) opnum=0; - if (pr_token_type == tt_immediate) + if (pr_token_type == tt_immediate && *pr_token=='-') { - if ((pr_immediate_type->type == ev_float && pr_immediate._float < 0) || - (pr_immediate_type->type == ev_integer && pr_immediate._int < 0)) //hehehe... was a minus all along... - { - QCC_PR_IncludeChunk(pr_token, true, NULL); - strcpy(pr_token, "+");//two negatives would make a positive. - pr_token_type = tt_punct; - } + //work around (4-3) being parsed as 4 -3 with no operator between + //(don't get confused by "-foo" strings though + if (pr_immediate_type->type == ev_float || pr_immediate_type->type == ev_double || + pr_immediate_type->type == ev_integer || pr_immediate_type->type == ev_uint || + pr_immediate_type->type == ev_int64 || pr_immediate_type->type == ev_uint64) + { + QCC_PR_IncludeChunk(pr_token, true, NULL); + strcpy(pr_token, "+");//two negatives would make a positive. + pr_token_type = tt_punct; + } } if (pr_token_type != tt_punct) @@ -11290,7 +12267,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) } if (!ops[i]) { - rhsd = QCC_SupplyConversion(rhsd, lhsr->cast->type, true); + rhsd = QCC_EvaluateCast(rhsd, lhsr->cast, true); for (i = 0; ops[i]; i++) { op = ops[i]; @@ -11315,6 +12292,9 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) } else { +#if 1 + rhsd = QCC_EvaluateCast(rhsd, lhsr->cast, true); +#else /*if (flag_qccx && lhsr->cast->type == ev_pointer && rhsd.cast->type == ev_float) { //&%555 = 4.0; char destname[256]; @@ -11342,6 +12322,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) } else rhsd = QCC_SupplyConversionForAssignment(lhsr, rhsd, lhsr->cast, true); +#endif } rhsd = QCC_StoreSRefToRef(lhsr, rhsd, true, false); //FIXME: this should not always be true, but we don't know if the caller actually needs it qcc_usefulstatement = true; @@ -11374,6 +12355,10 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_MUL_V], lhsd, lhsd, NULL, STFL_PRESERVEA); if (lhsd.cast->type == ev_string && flag_ifstring) lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_S], lhsd, QCC_MakeStringConst(""), NULL, 0); + if (lhsd.cast->type == ev_double) + lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_D], lhsd, QCC_MakeDoubleConst(0), NULL, 0); + if (lhsd.cast->type == ev_int64 || lhsd.cast->type == ev_uint64) + lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_I64], lhsd, QCC_MakeInt64Const(0), NULL, 0); if (!QCC_Eval_Truth(QCC_SRef_EvalConst(lhsd), lhsd.cast, false)) { QCC_ClobberDef(NULL); //FIXME... @@ -11386,6 +12371,10 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_MUL_V], lhsd, lhsd, NULL, STFL_PRESERVEA); if (lhsd.cast->type == ev_string && flag_ifstring) lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_S], lhsd, QCC_MakeStringConst(""), NULL, 0); + if (lhsd.cast->type == ev_double) + lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_D], lhsd, QCC_MakeDoubleConst(0), NULL, 0); + if (lhsd.cast->type == ev_int64 || lhsd.cast->type == ev_uint64) + lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_I64], lhsd, QCC_MakeInt64Const(0), NULL, 0); if (!QCC_Eval_Truth(QCC_SRef_EvalConst(lhsd), lhsd.cast, false)) { QCC_ClobberDef(NULL); //FIXME... @@ -11407,13 +12396,13 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) if ((*op->type_a)->type != lhsd.cast->type && (*op->type_a)->type != ev_variant) { - if (QCC_canConv(lhsd, (*op->type_a)->type) > 3) + if (QCC_canConv(lhsd, (*op->type_a)->type) >= 100) QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", lhsd.cast->name, (*op->type_a)->name); lhsd = QCC_EvaluateCast(lhsd, (*op->type_a), true); } if ((*op->type_b)->type != rhsd.cast->type && (*op->type_b)->type != ev_variant) { - if (QCC_canConv(rhsd, (*op->type_b)->type) > 3) + if (QCC_canConv(rhsd, (*op->type_b)->type) >= 100) QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhsd.cast->name, (*op->type_b)->name); rhsd = QCC_EvaluateCast(rhsd, (*op->type_b), true); } @@ -11504,17 +12493,37 @@ int QCC_PR_IntConstExpr(void) { //fixme: should make sure that no actual statements are generated QCC_sref_t def = QCC_PR_Expression(TOP_PRIORITY, 0); - if (def.sym->constant) + const QCC_eval_t *ev = QCC_SRef_EvalConst(def); + if (ev) { QCC_FreeTemp(def); def.sym->referenced = true; - if (def.cast->type == ev_integer) - return def.sym->symboldata[def.ofs]._int; - if (def.cast->type == ev_float) + switch(def.cast->type) { - int i = def.sym->symboldata[def.ofs]._float; - if ((float)i == def.sym->symboldata[def.ofs]._float) - return i; + case ev_integer: + return ev->_int; + case ev_float: + { + int i = ev->_float; + if ((float)i == ev->_float) + return i; + } + break; + case ev_double: + { + int i = ev->_double; + if ((double)i == ev->_double) + return i; + } + break; + case ev_uint: + return ev->_uint; + case ev_int64: + return ev->_int64; + case ev_uint64: + return ev->_uint64; + default: + QCC_PR_ParseError(ERR_NOTACONSTANT, "Value is not an integer constant"); } } QCC_PR_ParseError(ERR_NOTACONSTANT, "Value is not an integer constant"); @@ -11578,6 +12587,8 @@ QCC_statement_t *QCC_Generate_OP_IF(QCC_sref_t e, pbool preserve) case ev_function: case ev_pointer: case ev_integer: + case ev_uint: + case ev_boolean: //should be 0, 1i, or 1.0f, either way -0 isn't a problem so we can use the vanilla OP_IF_I for this op = OP_IF_I; break; @@ -11605,6 +12616,16 @@ QCC_statement_t *QCC_Generate_OP_IF(QCC_sref_t e, pbool preserve) op = OP_IF_I; break; + case ev_double: + e = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_D], e, QCC_MakeDoubleConst(0), NULL, flags); + op = OP_IF_I; + break; + case ev_int64: + case ev_uint64: + e = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_I64], e, QCC_MakeInt64Const(0), NULL, flags); + op = OP_IF_I; + break; + case ev_variant: case ev_struct: case ev_union: @@ -11636,6 +12657,8 @@ QCC_statement_t *QCC_Generate_OP_IFNOT(QCC_sref_t e, pbool preserve) case ev_function: case ev_pointer: case ev_integer: + case ev_uint: + case ev_boolean: //should be 0, 1i, or 1.0f, either way -0 isn't a problem so we can use the vanilla OP_IFNOT_I for this op = OP_IFNOT_I; break; @@ -11666,6 +12689,16 @@ QCC_statement_t *QCC_Generate_OP_IFNOT(QCC_sref_t e, pbool preserve) } break; + case ev_double: + e = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_D], e, QCC_MakeDoubleConst(0), NULL, flags); + op = OP_IFNOT_I; + break; + case ev_int64: + case ev_uint64: + e = QCC_PR_StatementFlags (&pr_opcodes[OP_NE_I64], e, QCC_MakeInt64Const(0), NULL, flags); + op = OP_IFNOT_I; + break; + case ev_variant: case ev_struct: case ev_union: @@ -11948,6 +12981,7 @@ void QCC_PR_ParseStatement (void) if (QCC_PR_CheckToken ("{")) { + int startingtypes = numtypeinfos; d = pr.local_tail; while (!QCC_PR_CheckToken("}")) QCC_PR_ParseStatement (); @@ -11963,6 +12997,14 @@ void QCC_PR_ParseStatement (void) } } } + for (; startingtypes < numtypeinfos; startingtypes++) + { + if (qcc_typeinfo[startingtypes].typedefed) + { + qcc_typeinfo[startingtypes].typedefed = false; + pHash_RemoveData(&typedeftable, qcc_typeinfo[startingtypes].name, &qcc_typeinfo[startingtypes]); + } + } return; } @@ -12223,6 +13265,11 @@ void QCC_PR_ParseStatement (void) QCC_PR_ParseDefs (NULL, true); return; } + if (QCC_PR_CheckKeyword(keyword_typedef, "typedef")) + { + QCC_PR_ParseTypedef(); + return; + } if (pr_token_type == tt_name) { @@ -12240,10 +13287,16 @@ void QCC_PR_ParseStatement (void) (keyword_noref && !STRCMP ("noref", pr_token)) || (keyword_string && !STRCMP ("string", pr_token)) || (keyword_float && !STRCMP ("float", pr_token)) || + (keyword_double && !STRCMP ("double", pr_token)) || (keyword_entity && !STRCMP ("entity", pr_token)) || (keyword_vector && !STRCMP ("vector", pr_token)) || (keyword_integer && !STRCMP ("integer", pr_token)) || + (keyword_unsigned && !STRCMP ("unsigned", pr_token)) || + (keyword_signed && !STRCMP ("signed", pr_token)) || + (keyword_long && !STRCMP ("long", pr_token)) || (keyword_int && !STRCMP ("int", pr_token)) || + (keyword_short && !STRCMP ("short", pr_token)) || + (keyword_char && !STRCMP ("char", pr_token)) || (keyword_static && !STRCMP ("static", pr_token)) || (keyword_class && !STRCMP ("class", pr_token)) || (keyword_const && !STRCMP ("const", pr_token))) @@ -14193,6 +15246,8 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ QCC_def_t *prior = NULL, *d, *lastparm; pbool mergeargs; + int startingtypes = numtypeinfos; + conditional = 0; expandedemptymacro = false; @@ -14572,6 +15627,15 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ } #endif + for (; startingtypes < numtypeinfos; startingtypes++) + { + if (qcc_typeinfo[startingtypes].typedefed) + { + qcc_typeinfo[startingtypes].typedefed = false; + pHash_RemoveData(&typedeftable, qcc_typeinfo[startingtypes].name, &qcc_typeinfo[startingtypes]); + } + } + QCC_PR_Lex(); return f; @@ -15139,12 +16203,16 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *s case ev_accessor: //shouldn't happen. case ev_enum: case ev_float: + case ev_double: case ev_boolean: case ev_string: case ev_entity: case ev_field: case ev_pointer: case ev_integer: + case ev_uint: + case ev_int64: + case ev_uint64: case ev_struct: case ev_union: case ev_variant: //for lack of any better alternative @@ -15568,6 +16636,7 @@ static QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, QCC_function_t *scope, case ev_enum: case ev_accessor: case ev_float: + case ev_double: case ev_boolean: case ev_string: case ev_vector: @@ -15575,6 +16644,9 @@ static QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, QCC_function_t *scope, case ev_field: case ev_pointer: case ev_integer: + case ev_uint: + case ev_int64: + case ev_uint64: case ev_variant: case ev_function: if (!*type->params[partnum].paramname) @@ -15764,7 +16836,7 @@ finalnotconst: else QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_FLD], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); } - else if (def.cast->type == ev_integer) + else if (def.cast->type == ev_integer || def.cast->type == ev_uint) { rhs.cast = def.cast = type_integer; if (type->size - i == 1) @@ -15775,6 +16847,17 @@ finalnotconst: else QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); } + else if (def.cast->type == ev_int64 || def.cast->type == ev_uint64 || def.cast->type == ev_double) + { + rhs.cast = def.cast = type_int64; + if (type->size - i == 2) + { + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I64], rhs, def, NULL, STFL_PRESERVEB)); + return ret; + } + else + QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I64], rhs, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB)); + } else { rhs.cast = def.cast = type_float; @@ -16355,8 +17438,10 @@ QCC_type_t *QCC_PR_ParseEnum(pbool flags) QCC_PR_ParseWarning(WARN_ENUMFLAGS_NOTINTEGER, "enumflags - %#x(%i) has multiple bits set", next_i, next_i); } } + if (enumtype) { + //generate enumname::valname symbol info for (acc = enumtype->accessors; acc; acc = acc->next) if (!strcmp(acc->fieldname, name)) { @@ -16369,12 +17454,11 @@ QCC_type_t *QCC_PR_ParseEnum(pbool flags) acc->type = enumtype;//sref.cast; acc->indexertype = NULL; enumtype->accessors = acc; - acc->staticval = sref; acc->staticval.cast = enumtype; } - else - { //value gets added to global pool + if (!strictenum) + { //value gets added to global pool too (whenever not strict) pHash_Add(&globalstable, name, sref.sym, qccHunkAlloc(sizeof(bucket_t))); } QCC_FreeTemp(sref); @@ -16401,6 +17485,65 @@ QCC_type_t *QCC_PR_ParseEnum(pbool flags) } return enumtype?enumtype:basetype; } + +void QCC_PR_ParseTypedef(void) +{ + QCC_type_t *type = QCC_PR_ParseType(false, false); + if (!type) + { + QCC_PR_ParseError(ERR_NOTATYPE, "typedef found unexpected tokens"); + } + do + { + char *name; + if (QCC_PR_CheckToken(";")) + return; + + while (QCC_PR_CheckToken("*")) + type = QCC_PointerTypeTo(type); + + if (QCC_PR_CheckToken("(")) + { //c-style function pointers are annoying. + int levels = 0; + while (QCC_PR_CheckToken("*")) + levels++; + name = QCC_PR_ParseName(); + QCC_PR_Expect(")"); + + //now parse its args + QCC_PR_Expect("("); + type = QCC_PR_ParseFunctionType(false, type); + + //and bring it to the intended indirection level... + while (levels --> 1) + type = QCC_PointerTypeTo(type); + } + else + name = QCC_PR_ParseName(); + + if (QCC_PR_CheckToken("[")) + { + struct QCC_typeparam_s *param = qccHunkAlloc(sizeof(*param)); + param->type = type; + param->arraysize = QCC_PR_IntConstExpr(); + type = QCC_PR_NewType(name, ev_union, true); + type->params = param; + type->num_parms = 1; + type->size = param->type->size * param->arraysize; + QCC_PR_Expect("]"); + } + else + { + type = QCC_PR_DuplicateType(type, false); + type->name = name; + type->typedefed = true; + pHash_Add(&typedeftable, name, type, qccHunkAlloc(sizeof(bucket_t))); + } + } while(QCC_PR_CheckToken(",")); + QCC_PR_Expect(";"); + return; +} + /* ================ PR_ParseDefs @@ -16408,7 +17551,7 @@ PR_ParseDefs Called at the outer layer and when a local statement is hit ================ */ -void QCC_PR_ParseDefs (char *classname, pbool fatal) +void QCC_PR_ParseDefs (char *classname, pbool fatal_unused) { char *name; QCC_type_t *basetype, *type, *defclass; @@ -16440,46 +17583,11 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) pr_ignoredeprecation = false; while (QCC_PR_CheckToken(";")) - fatal = false; + ; if (QCC_PR_CheckKeyword (keyword_typedef, "typedef")) { - type = QCC_PR_ParseType(false, false); - if (!type) - { - QCC_PR_ParseError(ERR_NOTATYPE, "typedef found unexpected tokens"); - } - do - { - char *name; - if (QCC_PR_CheckToken(";")) - return; - - if (QCC_PR_CheckToken("*")) - type = QCC_PointerTypeTo(type); - - name = QCC_PR_ParseName(); - - if (QCC_PR_CheckToken("[")) - { - struct QCC_typeparam_s *param = qccHunkAlloc(sizeof(*param)); - param->type = type; - param->arraysize = QCC_PR_IntConstExpr(); - type = QCC_PR_NewType(name, ev_union, true); - type->params = param; - type->num_parms = 1; - type->size = param->type->size * param->arraysize; - QCC_PR_Expect("]"); - } - else - { - type = QCC_PR_DuplicateType(type, false); - type->name = name; - type->typedefed = true; - pHash_Add(&typedeftable, name, type, qccHunkAlloc(sizeof(bucket_t))); - } - } while(QCC_PR_CheckToken(",")); - QCC_PR_Expect(";"); + QCC_PR_ParseTypedef(); return; } @@ -16862,8 +17970,8 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) // { // return; // } - QCC_PR_ParseError (ERR_TYPEWITHNONAME, "type (%s) with no name", type->name); - name = NULL; +// QCC_PR_ParseError (WARN_TYPEWITHNONAME, "type (%s) with no name", type->name); + return; } else { @@ -17196,7 +18304,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) if (!def->nofold && def->constant && def->initialized && def->symbolheader == def && def->ofs == 0 && !def->arraysize) { QCC_def_t *base = NULL; - QCC_eval_t *val = &def->symboldata[0]; + const QCC_eval_t *val = (const QCC_eval_t *)&def->symboldata[0]; if (type->type == ev_float) base = QCC_MakeFloatConst(val->_float).sym; else if (type->type == ev_integer) diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index f196c4210..6ebf88033 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -41,7 +41,7 @@ token_type_t pr_token_type; int pr_token_line; int pr_token_line_last; QCC_type_t *pr_immediate_type; -QCC_evalstorage_t pr_immediate; +QCC_eval_t pr_immediate; char pr_immediate_string[8192]; size_t pr_immediate_strlen; @@ -84,16 +84,22 @@ char *pr_punctuationremap[] = //a nice bit of evilness. QCC_type_t *type_void; //void QCC_type_t *type_string; //string QCC_type_t *type_float; //float +QCC_type_t *type_double; //double QCC_type_t *type_vector; //vector QCC_type_t *type_entity; //entity QCC_type_t *type_field; //.void QCC_type_t *type_function; //void() QCC_type_t *type_floatfunction; //float() QCC_type_t *type_pointer; //??? * - careful with this one -QCC_type_t *type_integer; //int +QCC_type_t *type_integer; //int32 +QCC_type_t *type_uint; //uint32 +QCC_type_t *type_int64; //int64 +QCC_type_t *type_uint64; //uint64 QCC_type_t *type_variant; //__variant QCC_type_t *type_floatpointer; //float * QCC_type_t *type_intpointer; //int * +QCC_type_t *type_bint; //int (0 or 1) +QCC_type_t *type_bfloat; //float (0.0 or 1.0, and never -0.0) QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float}; @@ -1306,8 +1312,9 @@ static pbool QCC_PR_Precompiler(void) } else if (!QC_strcasecmp(qcc_token, "sourcefile")) { - QCC_COM_Parse(msg); - QCC_RegisterSourceFile(qcc_token); + char *s = msg; + while ((s = QCC_COM_Parse(s))) + QCC_RegisterSourceFile(qcc_token); } else if (!QC_strcasecmp(qcc_token, "TARGET")) { @@ -1330,6 +1337,41 @@ static pbool QCC_PR_Precompiler(void) if (strcmp(destfile, olddest)) externs->Printf("Outputfile: %s\n", destfile); } + else if (!QC_strcasecmp(qcc_token, "opcode")) + { + int st; + char *s = QCC_COM_Parse(msg); + if (!QC_strcasecmp(qcc_token, "enable") || !QC_strcasecmp(qcc_token, "on")) + st = 1; + else if (!QC_strcasecmp(qcc_token, "disable") || !QC_strcasecmp(qcc_token, "off")) + st = 0; + else + { + QCC_PR_ParseWarning(WARN_BADPRAGMA, "opcode state not recognised"); + st = -1; + } + + if (st >= 0) + { + int f; + while ((s = QCC_COM_Parse(s))) + { + for (f = 0; pr_opcodes[f].opname; f++) + { + if (!QC_strcasecmp(pr_opcodes[f].opname, qcc_token)) + { + if (st) + pr_opcodes[f].flags |= OPF_VALID; + else + pr_opcodes[f].flags &= ~OPF_VALID; + break; + } + } + if (!pr_opcodes[f].opname) + QCC_PR_ParseWarning(WARN_BADPRAGMA, "opcode %s not recognised", qcc_token); + } + } + } else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag")) { char *s; @@ -1344,31 +1386,29 @@ static pbool QCC_PR_Precompiler(void) QCC_PR_ParseWarning(WARN_BADPRAGMA, "compiler flag state not recognised"); st = -1; } - if (st < 0) - QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised"); - else + if (st >= 0) { int f; - s = QCC_COM_Parse(s); - - for (f = 0; compiler_flag[f].enabled; f++) + while ((s = QCC_COM_Parse(s))) { - if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token)) + for (f = 0; compiler_flag[f].enabled; f++) { - if (compiler_flag[f].flags & FLAG_MIDCOMPILE) + if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token)) { - *compiler_flag[f].enabled = st; - if (compiler_flag[f].enabled == &flag_cpriority) - QCC_PrioritiseOpcodes(); + if (compiler_flag[f].flags & FLAG_MIDCOMPILE) + { + *compiler_flag[f].enabled = st; + if (compiler_flag[f].enabled == &flag_cpriority) + QCC_PrioritiseOpcodes(); + } + else + QCC_PR_ParseWarning(WARN_BADPRAGMA, "Cannot enable/disable keyword/flag via a pragma"); + break; } - else - QCC_PR_ParseWarning(WARN_BADPRAGMA, "Cannot enable/disable keyword/flag via a pragma"); - break; } + if (!compiler_flag[f].enabled) + QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag %s not recognised", qcc_token); } - if (!compiler_flag[f].enabled) - QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag %s not recognised", qcc_token); - } } else if (!QC_strcasecmp(qcc_token, "warning")) @@ -1392,21 +1432,28 @@ static pbool QCC_PR_Precompiler(void) if (st>=0) { int wn; - s = QCC_COM_Parse(s); - wn = QCC_WarningForName(qcc_token); - if (wn < 0) - QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised"); - else + while ((s = QCC_COM_Parse(s))) { - if (st == 3) //toggle - qccwarningaction[wn] = !!qccwarningaction[wn]; + wn = QCC_WarningForName(qcc_token); + if (wn < 0) + QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised"); else - qccwarningaction[wn] = st; + { + if (st == 3) //toggle + qccwarningaction[wn] = !!qccwarningaction[wn]; + else + qccwarningaction[wn] = st; + } } } } else + { + QCC_PR_SkipToEndOfLine(false); QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token); + } + + QCC_PR_SkipToEndOfLine(true); } return true; } @@ -1445,98 +1492,6 @@ PR_LexString Parses a quoted string ============== */ -#if 0 -void QCC_PR_LexString (void) -{ - int c; - int len; - char tmpbuf[2048]; - - char *text; - char *oldf; - int oldline; - - bool fromfile = true; - - len = 0; - - text = pr_file_p; - do - { - QCC_COM_Parse(text); -// print("Next token is \"%s\"\n", com_token); - if (*text == '\"') - { - text++; - if (fromfile) pr_file_p++; - } - do - { - c = *text++; - if (fromfile) pr_file_p++; - if (!c) - QCC_PR_ParseError ("EOF inside quote"); - if (c=='\n') - QCC_PR_ParseError ("newline inside quote"); - if (c=='\\') - { // escape char - c = *text++; - if (fromfile) pr_file_p++; - if (!c) - QCC_PR_ParseError ("EOF inside quote"); - if (c == 'n') - c = '\n'; - else if (c == '"') - c = '"'; - else if (c == '\\') - c = '\\'; - else - QCC_PR_ParseError ("Unknown escape char"); - } - else if (c=='\"') - { - if (fromfile) pr_file_p++; - break; - } - tmpbuf[len] = c; - len++; - } while (1); - tmpbuf[len] = 0; -// if (fromfile) pr_file_p++; - - pr_immediate_type=NULL; - oldline=pr_source_line; - oldf=pr_file_p; - QCC_PR_Lex(); - if (pr_immediate_type == &type_string) - { -// print("Appending \"%s\" to \"%s\"\n", pr_immediate_string, tmpbuf); - strcat(tmpbuf, pr_immediate_string); - len+=strlen(pr_immediate_string); - } - else - { - pr_source_line = oldline; - pr_file_p = oldf-1; - QCC_PR_LexWhitespace(); - if (*pr_file_p != '\"') //annother string - break; - } - - QCC_PR_LexWhitespace(); - text = pr_file_p; - - } while (1); - - strcpy(pr_token, tmpbuf); - pr_token_type = tt_immediate; - pr_immediate_type = &type_string; - strcpy (pr_immediate_string, pr_token); - pr_immediate_strlen = strlen(pr_immediate_string); - -// print("Found \"%s\"\n", pr_immediate_string); -} -#else int QCC_PR_LexEscapedCodepoint(void) { //for "\foo" or '\foo' handling. //caller will have read the \ already. @@ -1759,7 +1714,7 @@ void QCC_PR_LexString (void) } else if ((*pr_file_p == 'U' || *pr_file_p == 'u' || *pr_file_p == 'L') && pr_file_p[1] == '\"') { //unicode string, char32_t, char16_t, wchar_t respectively. we spit out utf-8 regardless. - QCC_PR_ParseWarning(WARN_NOTUTF8, "interpretting char32_t/char16_t/wchar_t as utf-8"); + QCC_PR_ParseWarning(WARN_NOTUTF8, "char32_t/char16_t/wchar_t strings are not supported, treating as u8 prefix (as utf-8)"); stringtype = 2; pr_file_p+=2; } @@ -1823,22 +1778,22 @@ void QCC_PR_LexString (void) c = 0xe01c | texttype; } else if (c == 'u' || c == 'U') - { + { //special hack, \u is a utf-8 code regardless of output encoding... c = QCC_PR_LexEscapedCodepoint(); goto forceutf8; } else if (c == 'x' || c == 'X') - { + { //special hack, \xXX in a string is an explicit byte regardless of encoding. c = QCC_PR_LexEscapedCodepoint(); - if (c > 0xff) - QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code - codepoint %u is above 0xFF", c); +// if (c > 0xff) +// QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code - codepoint %#x is above 0xFF", c); goto forcebyte; } else { c = QCC_PR_LexEscapedCodepoint(); - if (stringtype != 2 && c > 0xff) - QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad legacy character code - codepoint %u is above 0xFF", c); +// if (stringtype != 2 && c > 0xff) +// QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad legacy character code - codepoint %#x is above 0xFF", c); } } else if (c=='\"') @@ -2019,7 +1974,6 @@ forcebyte: } }*/ } -#endif /* ============== @@ -2120,7 +2074,7 @@ static void QCC_PR_LexNumber (void) { pr_token[tokenlen++] = c; pr_file_p++; - pr_immediate_type = type_float; + pr_immediate_type = flag_assume_double?type_double:type_float; while(1) { c = *pr_file_p; @@ -2128,11 +2082,17 @@ static void QCC_PR_LexNumber (void) { pr_token[tokenlen++] = c; } - else if (c == 'f') + else if (c == 'f' || c == 'F') { pr_file_p++; break; } + else if (c == 'd' || c == 'D') + { + pr_immediate_type = type_double; + pr_file_p++; + break; + } else { break; @@ -2140,10 +2100,13 @@ static void QCC_PR_LexNumber (void) pr_file_p++; } pr_token[tokenlen++] = 0; - pr_immediate._float = (float)atof(pr_token); - return; + if (pr_immediate_type == type_double) + pr_immediate._double = atof(pr_token); + else + pr_immediate._float = (float)atof(pr_token); + goto checkjunk; } - else if (c == 'f') + else if (c == 'f' || c == 'F') { pr_token[tokenlen++] = c; pr_token[tokenlen++] = 0; @@ -2154,23 +2117,71 @@ static void QCC_PR_LexNumber (void) num*=sign; if ((longlong)pr_immediate._float != (longlong)num) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); - return; + goto checkjunk; } - else if (c == 'i' || c == 'u') - { + else if (c == 'd' || c == 'D') + { //note: conflicts with hex. add a dot before it or something. pr_token[tokenlen++] = c; pr_token[tokenlen++] = 0; pr_file_p++; - pr_immediate_type = type_integer; - pr_immediate._int = num*sign; + pr_immediate_type = type_double; + pr_immediate._double = num*sign; num*=sign; - if ((longlong)pr_immediate._int != (longlong)num) - { - if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) - QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); + if ((longlong)pr_immediate._double != (longlong)num) + QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); + goto checkjunk; + } + else if (c == 'i' || c == 'u' || c == 'l' || c == 'I' || c == 'U' || c == 'L') + { //length and sign flags can be any order. LL suffix must have the same case (but not necessarily match the sign suffix) + int isunsigned; + int islong = (c == 'l')||(c == 'L'); + pr_token[tokenlen++] = c; + pr_file_p++; + if (islong) + { //length suffix was first. + //long-long? + if (*pr_file_p == c) + pr_token[tokenlen++] = *pr_file_p++; + //check for signed suffix... + c = *pr_file_p; + isunsigned = (c == 'u')||(c=='U'); + if (c == 'i' || c == 'I' || isunsigned) //ignore an explicit redundant 'i' char, for not-a-float. + pr_token[tokenlen++] = *pr_file_p++; } - return; + else + { + isunsigned = (c == 'u')||(c=='U'); + //we already made sure it u or i, and its not an l + c = *pr_file_p; + if (c == 'l' || c == 'L') + { + pr_token[tokenlen++] = *pr_file_p++; + islong = true; + //long-long? + if (*pr_file_p == c) + pr_token[tokenlen++] = *pr_file_p++; + } + } + pr_token[tokenlen++] = 0; + num *= sign; + if (islong) + { + pr_immediate_type = (isunsigned)?type_uint64:type_int64; + pr_immediate._int64 = num; + } + else + { + pr_immediate_type = (isunsigned)?type_uint:type_integer; + pr_immediate._int = num; + + if ((longlong)pr_immediate._int != (longlong)num) + { + if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) + QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); + } + } + goto checkjunk; } else break; @@ -2217,6 +2228,11 @@ qccxhex: if ((longlong)pr_immediate._float != (longlong)num && base == 16) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow %lld will be rounded to %f", num, pr_immediate._float); } + +checkjunk: + c = *pr_file_p; + if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || (c & 0x80)) + QCC_PR_ParseWarning(ERR_NOTANUMBER, "bad suffix on number %s", pr_token); } @@ -3960,7 +3976,7 @@ Aborts the current file load void editbadfile(const char *file, int line); #endif //will abort. -void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) +NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) { va_list argptr; char string[1024]; @@ -3982,7 +3998,7 @@ void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) longjmp (pr_parse_abort, 1); } //will abort. -void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...) +NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...) { va_list argptr; char string[1024]; @@ -4005,7 +4021,7 @@ void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char longjmp (pr_parse_abort, 1); } -void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t def, const char *error, ...) +NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t def, const char *error, ...) { va_list argptr; char string[1024]; @@ -4632,6 +4648,35 @@ char *TypeName(QCC_type_t *type, char *buffer, int buffersize) Q_strlcat(buffer, "void", buffersize); return buffer; } + if (type->type == ev_enum) + { + if (buffersize < 0) + return buffer; + *buffer = 0; + Q_strlcat(buffer, "enum ", buffersize); + Q_strlcat(buffer, type->name, buffersize); + Q_strlcat(buffer, ":", buffersize); + TypeName(type->aux_type, buffer+strlen(buffer), buffersize-strlen(buffer)); + return buffer; + } + if (type->type == ev_struct) + { + if (buffersize < 0) + return buffer; + *buffer = 0; + Q_strlcat(buffer, "struct ", buffersize); + Q_strlcat(buffer, type->name, buffersize); + return buffer; + } + if (type->type == ev_union) + { + if (buffersize < 0) + return buffer; + *buffer = 0; + Q_strlcat(buffer, "union ", buffersize); + Q_strlcat(buffer, type->name, buffersize); + return buffer; + } if (type->type == ev_pointer) { @@ -4953,8 +4998,18 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) if (QCC_PR_CheckToken("[")) { - QCC_PR_ParseError(0, "Array arguments are not supported\n"); - QCC_PR_Expect("]"); + if (QCC_PR_CheckToken("]")) //length omitted. just treat it as a pointer...? + { + QCC_PR_ParseError(0, "unsized array argument\n"); + paramlist[numparms].type = QCC_PointerTypeTo(paramlist[numparms].type); + } + else + { //proper array + paramlist[numparms].arraysize = QCC_PR_IntConstExpr(); + if (!paramlist[numparms].arraysize) + QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays"); + QCC_PR_Expect("]"); + } } } else if (definenames) @@ -5153,6 +5208,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) // int ofs; + if (QCC_PR_CheckKeyword(keyword_const, "const")) + { + QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword"); + silentfail = false; //FIXME + } + if (QCC_PR_PeekToken ("...") ) //this is getting stupid { QCC_PR_LexWhitespace (false); @@ -5875,20 +5936,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) return NULL; } - //FIXME: these should be moved into parsetype if (QCC_PR_CheckKeyword(keyword_enum, "enum")) { - newt = QCC_PR_ParseEnum(false); - if (QCC_PR_CheckToken(";")) - return NULL; - return newt; + return QCC_PR_ParseEnum(false); } if (QCC_PR_CheckKeyword(keyword_enumflags, "enumflags")) { - newt = QCC_PR_ParseEnum(true); - if (QCC_PR_CheckToken(";")) - return NULL; - return newt; + return QCC_PR_ParseEnum(true); } structtype = ev_void; @@ -6039,6 +6093,15 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays"); QCC_PR_Expect("]"); } + while (QCC_PR_CheckToken("[")) + { + int nsize=QCC_PR_IntConstExpr(); + if (!nsize) + QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays"); + QCC_PR_Expect("]"); + arraysize *= nsize; + QCC_PR_ParseWarning(WARN_IGNOREDKEYWORD, "multi-dimensional arrays are not supported. flattening to single array."); + } if (QCC_PR_CheckToken("(")) type = QCC_PR_ParseFunctionType(false, type); @@ -6050,6 +6113,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) continue; } + if (QCC_PR_CheckToken(":")) + { + QCC_PR_IntConstExpr(); + QCC_PR_ParseWarning(WARN_IGNOREDKEYWORD, "bitfields are not supported"); + } + if ((isnonvirt || isvirt) && type->type != ev_function) QCC_PR_ParseWarning(ERR_INTERNAL, "[non]virtual members must be functions", type->name); @@ -6175,6 +6244,78 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) type = type_function; else { + //try and handle C's types, which have weird and obtuse combinations (like long long, long int, short int). + pbool isokay = false; + pbool issigned = false; + pbool isunsigned = false; + pbool islong = false; + pbool isfloat = false; + int bits = 0; + + while(true) + { + if (!isunsigned && !issigned && QCC_PR_CheckKeyword(keyword_signed, "signed")) + issigned = isokay = true; + else if (!issigned && !isunsigned && QCC_PR_CheckKeyword(keyword_unsigned, "unsigned")) + isunsigned = isokay = true; + else if (!bits && QCC_PR_CheckKeyword(keyword_long, "long")) + { + if (islong) + bits = 128; + islong = isokay = true; + } + else if ((!bits || bits==16) && (QCC_PR_CheckKeyword(keyword_int, "int") || QCC_PR_CheckKeyword(keyword_integer, "integer"))) + { //long int, short int, etc are allowed + if (!bits) + bits = 32; + isokay = true; + } + else if (!bits && QCC_PR_CheckKeyword(keyword_short, "short")) + bits = 16, isokay = true; + else if (!bits && QCC_PR_CheckKeyword(keyword_char, "char")) + bits = 8, isokay = true; + else if (!bits && QCC_PR_CheckKeyword(keyword_int, "_Bool")) //c99 + bits = 1, isokay = true; + + else if (!bits && !islong && QCC_PR_CheckKeyword(keyword_float, "float")) + bits = 32, isfloat = isokay = true; + else if ((!bits||islong) && QCC_PR_CheckKeyword(keyword_double, "double")) + bits = islong?128:64, islong=false, isfloat = isokay = true; + else + break; + } + if (isokay) + { + if (!bits) + bits = islong?64:32; // [int] + if (isfloat) + { + if (isunsigned) + QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported unsigned keyword, type will be signed"); + if (bits > 64) + type = type_double, QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "long doubles are not supported, using double"); //permitted + else if (bits == 64) + type = type_double; + else + type = type_float; + } + else + { + if (bits > 64) + type = (isunsigned?type_uint64:type_int64), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "long longs are not supported, using long"); //permitted + else if (bits == 64) + type = (isunsigned?type_uint64:type_int64); + else if (bits == 16) + type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "shorts are not supported, using int"); //permitted + else if (bits == 8) + type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "chars are not supported, using int"); //permitted + else + type = (isunsigned?type_uint:type_integer); + } + goto wasctype; + } + + if (silentfail) return NULL; @@ -6183,11 +6324,16 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) } } QCC_PR_Lex (); +wasctype: while (QCC_PR_CheckToken("*")) + { + if (QCC_PR_CheckKeyword(keyword_const, "const")) + QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword"); type = QCC_PointerTypeTo(type); + } - if (QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function. + if (flag_qcfuncs && QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function. { type_inlinefunction = true; type = QCC_PR_ParseFunctionType(newtype, type); diff --git a/engine/qclib/qccguiqt.cpp b/engine/qclib/qccguiqt.cpp index fc1290fb1..e6d82a901 100644 --- a/engine/qclib/qccguiqt.cpp +++ b/engine/qclib/qccguiqt.cpp @@ -1701,6 +1701,7 @@ private: connect(fileopen, &QAction::triggered, [=]() { GUIprintf("Ctrl+O hit\n"); + QMessageBox::critical(nullptr, "Error", QString::asprintf("Not yet implemented")); }); auto filesave = new QAction(tr("Save"), this); fileMenu->addAction(filesave); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 7be568aba..8de1ae3ef 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -77,7 +77,7 @@ pbool newstylesource; char destfile[1024]; //the file we're going to output to pbool destfile_explicit; //destfile was override on the commandline, don't let qc change it. -QCC_eval_t *qcc_pr_globals; +QCC_eval_basic_t *qcc_pr_globals; unsigned int numpr_globals; char *strings; @@ -235,6 +235,7 @@ struct { {" F330", WARN_MUTEDEPRECATEDVARIABLE}, {" F331", WARN_SELFNOTTHIS}, {" F332", WARN_DIVISIONBY0}, + {" F333", WARN_ARGUMENTCHECK}, {" F207", WARN_NOTREFERENCEDFIELD}, {" F208", WARN_NOTREFERENCEDCONST}, @@ -342,6 +343,12 @@ compiler_flag_t compiler_flag[] = { {&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."}, {&keyword_int, typekeyword, "int", "Keyword: int", "Disables the 'int' keyword."}, {&keyword_integer, typekeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."}, + {&keyword_double, defaultkeyword, "double", "Keyword: double", "Disables the 'double' keyword."}, + {&keyword_long, defaultkeyword, "long", "Keyword: long", "Disables the 'long' keyword."}, + {&keyword_short, defaultkeyword, "short", "Keyword: short", "Disables the 'short' keyword."}, + {&keyword_char, defaultkeyword, "char", "Keyword: char", "Disables the 'char' keyword."}, + {&keyword_signed, defaultkeyword, "signed", "Keyword: signed", "Disables the 'signed' keyword."}, + {&keyword_unsigned, defaultkeyword, "unsigned", "Keyword: unsigned", "Disables the 'unsigned' keyword."}, {&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't warn about it. {&keyword_unused, nondefaultkeyword, "unused", "Keyword: unused", "Disables the 'unused' keyword. 'unused' means that the variable is unused, you're aware that its unused, and you'd rather not know about all the warnings this results in."}, {&keyword_used, nondefaultkeyword, "used", "Keyword: used", "Disables the 'used' keyword. 'used' means that the variable is used even if the qcc can't see how - thus preventing it from ever being stripped."}, @@ -374,7 +381,7 @@ compiler_flag_t compiler_flag[] = { //options {&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows | for linebreaks. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files. {&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."}, - {&keywords_coexist, FLAG_ASDEFAULT, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."}, + {&keywords_coexist, defaultflag, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."}, // {&flag_lno, defaultflag, "lno", "Write Line Numbers", "Writes line number information. This is required for any real kind of debugging. Will be ignored if filenames were stripped."}, {&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers) {&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance. @@ -404,6 +411,8 @@ compiler_flag_t compiler_flag[] = { {&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."}, {&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."}, {&flag_cpriority, hideflag, "cpriority", "C Operator Priority", "QC treats !a&&b as equivelent to !(a&&b). When this is set, behaviour will be (!a)&&b as in C. Other operators are also affected in similar ways."}, + {&flag_assume_double, hideflag, "assumedouble", "Assume Doubles", "Floating point immediates will be treated as doubles, for C compat."}, + {&flag_qcfuncs, hidedefaultflag,"qcfuncs", "Parse QC-style funcs", "Recognise void() as a function type. Required for QC compat."}, {&flag_allowuninit, hideflag, "allowuninit", "Uninitialised Locals", "Permit optimisations that may result in locals being uninitialised. This may allow for greater reductions in temps."}, {&flag_nopragmafileline,FLAG_MIDCOMPILE,"nofileline", "Ignore #pragma file", "Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols reflect the actual lines, instead of the original source."}, // {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."}, @@ -711,7 +720,7 @@ static void QCC_DumpAutoCvars (const char *outputname) if (!strncmp(n, "autocvar_", 9)) { char *desc; - QCC_eval_t *val = &qcc_pr_globals[d->ofs]; + const QCC_eval_t *val = (const QCC_eval_t*)&qcc_pr_globals[d->ofs]; QCC_def_t *def = QCC_PR_GetDef(NULL, n, NULL, false, 0, 0); n += 9; @@ -725,17 +734,29 @@ static void QCC_DumpAutoCvars (const char *outputname) case ev_float: snprintf(line, sizeof(line), "set %s\t%g%s%s\n", n, val->_float, desc?"\t//":"", desc?desc:""); break; + case ev_double: + snprintf(line, sizeof(line), "set %s\t%g%s%s\n", n, val->_double, desc?"\t//":"", desc?desc:""); + break; case ev_vector: - snprintf(line, sizeof(line), "set %s\t\"%g %g %g\"%s%s\n", n, val->vector[0], val->vector[1], val->vector[2], desc?"\t//":"", desc?desc:""); + snprintf(line, sizeof(line), "set %s\t\"%g %g %g\"%s%s\n", n, val->vector[0], val->vector[1], val->vector[2], desc?"\t//":"", desc?desc:""); break; case ev_integer: - snprintf(line, sizeof(line), "set %s\t%"pPRIi"%s%s\n", n, val->_int, desc?"\t//":"", desc?desc:""); + snprintf(line, sizeof(line), "set %s\t%"pPRIi"%s%s\n", n, val->_int, desc?"\t//":"", desc?desc:""); + break; + case ev_uint: + snprintf(line, sizeof(line), "set %s\t%"pPRIu"%s%s\n", n, val->_uint, desc?"\t//":"", desc?desc:""); + break; + case ev_int64: + snprintf(line, sizeof(line), "set %s\t%"pPRIi64"%s%s\n", n, val->_int64, desc?"\t//":"", desc?desc:""); + break; + case ev_uint64: + snprintf(line, sizeof(line), "set %s\t%"pPRIu64"%s%s\n", n, val->_uint64, desc?"\t//":"", desc?desc:""); break; case ev_string: snprintf(line, sizeof(line), "set %s\t\"%s\"%s%s\n", n, strings + val->_int, desc?"\t//":"", desc?desc:""); break; default: - snprintf(line, sizeof(line), "//set %s\t ?%s%s\n", n, desc?"\t//":"", desc?desc:""); + snprintf(line, sizeof(line), "//set %s\t ?%s%s\n", n, desc?"\t//":"", desc?desc:""); break; } SafeWrite(h, line, strlen(line)); @@ -2640,7 +2661,7 @@ strofs = (strofs+3)&~3; externs->Printf("Compile finished: %s (uhexen2 format)\n", destfile); break; case QCF_DARKPLACES: - externs->Printf("Compile finished: %s (patched-dp format)\n", destfile); + externs->Printf("Compile finished: %s (fte+dp format)\n", destfile); break; case QCF_QSS: externs->Printf("Compile finished: %s (fte+qss format)\n", destfile); @@ -3273,6 +3294,7 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize) type_void = QCC_PR_NewType("void", ev_void, true); type_string = QCC_PR_NewType("string", ev_string, true); type_float = QCC_PR_NewType("float", ev_float, true); + type_double = QCC_PR_NewType("__double", ev_double, true); type_vector = QCC_PR_NewType("vector", ev_vector, true); type_entity = QCC_PR_NewType("entity", ev_entity, true); type_field = QCC_PR_NewType("__field", ev_field, false); @@ -3280,6 +3302,9 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize) type_function->aux_type = type_void; type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false); type_integer = QCC_PR_NewType("__int", ev_integer, true); + type_uint = QCC_PR_NewType("__uint", ev_uint, true); + type_int64 = QCC_PR_NewType("__int64", ev_int64, true); + type_uint64 = QCC_PR_NewType("__uint64", ev_int64, true); type_variant = QCC_PR_NewType("__variant", ev_variant, true); type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false); @@ -3293,6 +3318,11 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize) type_floatfunction = QCC_PR_NewType("__floatfunction", ev_function, false); type_floatfunction->aux_type = type_float; + type_bfloat = QCC_PR_NewType("__bfloat", ev_boolean, false); + type_bfloat->parentclass = type_float; + type_bint = QCC_PR_NewType("__bint", ev_boolean, false); + type_bint->parentclass = type_integer; + //type_field->aux_type = type_float; // QCC_PR_NewType("_Bool", ev_boolean, true); @@ -3300,8 +3330,6 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize) // QCC_PR_NewType("__int", ev_integer, keyword_integer?true:false); QCC_PR_NewType("variant", ev_variant, true); - QCC_PR_NewType("integer", ev_integer, keyword_integer?true:false); - QCC_PR_NewType("int", ev_integer, keyword_int?true:false); @@ -4297,7 +4325,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) else *compiler_flag[p].enabled = false; } - if (!stricmp(myargv[i]+5, "C")) + if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17")) { //set up for greatest C compatibility... variations from C are bugs, not features. keyword_asm = false; keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true; @@ -4315,13 +4343,32 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) flag_assumevar = true; //const only if explicitly const. pr_subscopedlocals = true; //locals shadow other locals rather than being the same one. flag_cpriority = true; //fiddle with operator precedence. - flag_assume_integer = true; + flag_assume_integer = true; //unqualified numeric constants are assumed to be ints, consistent with C. + flag_assume_double = true; //and any immediates with a decimal points are assumed to be doubles, consistent with C. + flag_qcfuncs = false; qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too. qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird. qccwarningaction[WARN_TOOFEWPARAMS] = WA_ERROR; //missing args should be fatal. qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default. qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals. + + if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90")) + val = "199409L"; //it was ammended, apparently. + else if (!stricmp(myargv[i]+5, "c99")) + val = "199901L"; + else if (!stricmp(myargv[i]+5, "c11")) + val = "201112L"; + else if (!stricmp(myargv[i]+5, "c17")) + val = "201710L"; + else + val = NULL; + cnst = QCC_PR_DefineName("__STDC_VERSION__"); + if (val) + { + cnst->value = qccHunkAlloc(strlen(val)+1); + memcpy(cnst->value, val, strlen(val)+1); + } } else if (!strcmp(myargv[i]+5, "qccx")) { @@ -4647,6 +4694,7 @@ static void QCC_SetDefaultProperties (void) QCC_PR_CloseProcessor(); QCC_PR_DefineName("FTEQCC"); + QCC_PR_DefineName("__FTEQCC__"); if ((FWDSLASHARGS && QCC_CheckParm("/O0")) || QCC_CheckParm("-O0")) level = 0; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index fda5b91b1..d4abd49b1 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -5395,6 +5395,59 @@ void QCBUILTIN PF_WriteInt (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } } +void QCBUILTIN PF_WriteInt64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int dest = G_FLOAT(OFS_PARM0); + pint64_t val = G_INT64(OFS_PARM1); + if (dest == MSG_CSQC) + { //csqc buffers are always written. + MSG_WriteInt64(&csqcmsgbuffer, val); + return; + } + + if (pr_nonetaccess.value) + return; +#ifdef SERVER_DEMO_PLAYBACK + if (sv.demofile) + return; +#endif + +#ifdef NETPREPARSE + if (dpcompat_nopreparse.ival) + ; + else if (progstype != PROG_QW) + { + NPP_NQWriteLong(dest, val&0xffffffff); + NPP_NQWriteLong(dest, (val>>32)&0xffffffff); + return; + } +#ifdef NQPROT + else + { + NPP_QWWriteLong(dest, val&0xffffffff); + NPP_QWWriteLong(dest, (val>>32)&0xffffffff); + return; + } +#endif +#endif + + if (dest == MSG_ONE) + { + client_t *cl = Write_GetClient(); + if (!cl) + return; + ClientReliableCheckBlock(cl, 8); + ClientReliableWrite_Int64(cl, val); + } + else + { + if (progstype != PROG_QW) + MSG_WriteInt64 (NQWriteDest(dest), val); + else + MSG_WriteInt64 (QWWriteDest(dest), val); + } +} + void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int dest = G_FLOAT(OFS_PARM0); @@ -5559,6 +5612,63 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl } } +void QCBUILTIN PF_WriteDouble (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int dest = G_FLOAT(OFS_PARM0); + double val = G_DOUBLE(OFS_PARM1); + union { + double val; + quint64_t ival; + } u = {val}; + if (dest == MSG_CSQC) + { //csqc buffers are always written. + MSG_WriteDouble(&csqcmsgbuffer, val); + return; + } + + if (pr_nonetaccess.value) + return; +#ifdef SERVER_DEMO_PLAYBACK + if (sv.demofile) + return; +#endif + +#ifdef NETPREPARSE + if (dpcompat_nopreparse.ival) + ; + else if (progstype != PROG_QW) + { + NPP_NQWriteLong(dest, u.ival&0xffffffff); + NPP_NQWriteLong(dest, (u.ival>>32)&0xffffffff); + return; + } +#ifdef NQPROT + else + { + NPP_QWWriteLong(dest, u.ival&0xffffffff); + NPP_QWWriteLong(dest, (u.ival>>32)&0xffffffff); + return; + } +#endif +#endif + + if (dest == MSG_ONE) + { + client_t *cl = Write_GetClient(); + if (!cl) + return; + ClientReliableCheckBlock(cl, 8); + ClientReliableWrite_Double(cl, val); + } + else + { + if (progstype != PROG_QW) + MSG_WriteDouble (NQWriteDest(dest), val); + else + MSG_WriteDouble (QWWriteDest(dest), val); + } +} + void PF_WriteString_Internal (int target, const char *str) { if (target == MSG_CSQC) @@ -11006,7 +11116,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void(optional entity ent, optional vector neworigin)", "Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity.")},// {"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, D("void(float buf, float fl)", "Writes a full 32bit float without any data conversions at all, for full precision.")},// - {"WriteInt", PF_WriteInt, 0, 0, 0, 0, D("void(float buf, int fl)", "Equivelent to WriteLong, but doesn't truncate to a float first before converting back to an int.")},// + {"WriteDouble", PF_WriteDouble, 0, 0, 0, 0, D("void(float buf, __double dbl)", "Writes a full 64bit double-precision float without any data conversions at all, for excessive precision.")},// + {"WriteInt", PF_WriteInt, 0, 0, 0, 0, D("void(float buf, int fl)", "Writes all 4 bytes of a 32bit integer without truncating to a float first before converting back to an int (unlike WriteLong does, but otherwise equivelent).")},// + {"WriteInt64", PF_WriteInt64, 0, 0, 0, 0, D("void(float buf, __int64 fl)", "Writes all 8 bytes of a 64bit integer.")},// {"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL) {"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, D("void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)", "Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use.")}, @@ -11147,7 +11259,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"readangle", PF_Fixme, 0, 0, 0, 365, D("float()", "Reads a value matching the unspecified precision written ONLY by WriteAngle.")},// (EXT_CSQC) {"readstring", PF_Fixme, 0, 0, 0, 366, D("string()", "Reads a null-terminated string.")},// (EXT_CSQC) {"readfloat", PF_Fixme, 0, 0, 0, 367, D("float()", "Reads a float without any truncation nor conversions. Data MUST have originally been written with WriteFloat.")},// (EXT_CSQC) + {"readdouble", PF_Fixme, 0, 0, 0, 0, D("__double()", "Reads a double-precision float without any truncation nor conversions. Data MUST have originally been written with WriteDouble.")},// (EXT_CSQC) {"readint", PF_Fixme, 0, 0, 0, 0, D("int()", "Reads a 32bit int without any conversions to float, otherwise interchangable with readlong.")},// (EXT_CSQC) + {"readint64", PF_Fixme, 0, 0, 0, 0, D("__int64()", "Reads a 64bit int. Paired with WriteInt64.")},// (EXT_CSQC) {"readentitynum", PF_Fixme, 0, 0, 0, 368, D("float()", "Reads the serverside index of an entity, paired with WriteEntity. There may be nothing else known about the entity yet, so the result typically needs to be saved as-is and re-looked up each frame. This can be done via getentity(NUM, GE_*) for non-csqc ents, or findentity(world,entnum,NUM) - both of which can fail due to latency.")},// (EXT_CSQC) // {"readserverentitystate",PF_Fixme,0, 0, 0, 369, "void(float flags, float simtime)"},// (EXT_CSQC_1) @@ -11330,7 +11444,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"strlennocol", PF_strlennocol, 0, 0, 0, 476, D("float(string s)", "Returns the number of characters in the string after any colour codes or other markup has been parsed.")},//DP_QC_STRINGCOLORFUNCTIONS {"strdecolorize", PF_strdecolorize, 0, 0, 0, 477, D("string(string s)", "Flattens any markup/colours, removing them from the string.")},//DP_QC_STRINGCOLORFUNCTIONS {"strftime", PF_strftime, 0, 0, 0, 478, "string(float uselocaltime, string format, ...)"}, //DP_QC_STRFTIME - {"tokenizebyseparator",PF_tokenizebyseparator,0,0, 0, 479, "float(string s, string separator1, ...)"}, //DP_QC_TOKENIZEBYSEPARATOR + {"tokenizebyseparator",PF_tokenizebyseparator,0,0, 0, 479, D("float(string s, string separator1, ...)", "Splits up the string using only the specified delimiters/separators. Multiple delimiters can be given, they are each considered equivelent (though should start with the longest if you want to do weird subseparator stuff).\nThe resulting tokens can be queried via argv (and argv_start|end_index builtins, if you want to determine which of the separators was present between two tokens).\nNote that while an input string containing JUST a separator will return 2, a string with no delimiter will return 1, while (in FTE) an empty string will ALWAYS return 0.")}, //DP_QC_TOKENIZEBYSEPARATOR {"strtolower", PF_strtolower, 0, 0, 0, 480, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS {"strtoupper", PF_strtoupper, 0, 0, 0, 481, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS {"cvar_defstring", PF_cvar_defstring, 0, 0, 0, 482, "string(string s)"}, //DP_QC_CVAR_DEFSTRING @@ -12954,7 +13068,7 @@ void PR_DumpPlatform_f(void) {"PFLAGS_FULLDYNAMIC", "const float", QW|NQ, D("When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used."), PFLAGS_FULLDYNAMIC}, //including these for csqc stat types, hash tables, etc. -// {"EV_VOID", "const float", QW|NQ|CS, NULL, ev_void}, +// {"EV_VOID", "const float", ALL, NULL, ev_void}, {"EV_STRING", "const float", ALL, NULL, ev_string}, {"EV_FLOAT", "const float", ALL, NULL, ev_float}, {"EV_VECTOR", "const float", ALL, NULL, ev_vector}, @@ -12963,11 +13077,12 @@ void PR_DumpPlatform_f(void) {"EV_FUNCTION", "const float", ALL, NULL, ev_function}, {"EV_POINTER", "const float", ALL, NULL, ev_pointer}, {"EV_INTEGER", "const float", ALL, NULL, ev_integer}, - {"EV_VARIANT", "const float", ALL, NULL, ev_variant}, -// {"EV_STRUCT", "const float", QW|NQ|CS, NULL, ev_struct}, -// {"EV_UNION", "const float", QW|NQ|CS, NULL, ev_union}, + {"EV_UINT", "const float", ALL, NULL, ev_uint}, + {"EV_INT64", "const float", ALL, NULL, ev_int64}, + {"EV_UINT64", "const float", ALL, NULL, ev_uint64}, + {"EV_DOUBLE", "const float", ALL, NULL, ev_double}, - {"gamestate", "hashtable", ALL, D("Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted)."), 0}, + {"gamestate", "hashtable", ALL, D("Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted)."), 0}, {"HASH_REPLACE", "const float", ALL, D("Used with hash_add. Attempts to remove the old value instead of adding two values for a single key."), 256}, {"HASH_ADD", "const float", ALL, D("Used with hash_add. The new entry will be inserted in addition to the existing entry."), 512}, diff --git a/engine/server/server.h b/engine/server/server.h index 5229e7898..7529cd6f0 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1432,7 +1432,9 @@ void ClientReliableWrite_Angle16(client_t *cl, float f); void ClientReliableWrite_Byte(client_t *cl, int c); void ClientReliableWrite_Char(client_t *cl, int c); void ClientReliableWrite_Float(client_t *cl, float f); +void ClientReliableWrite_Double(client_t *cl, double f); void ClientReliableWrite_Coord(client_t *cl, float f); +void ClientReliableWrite_Int64(client_t *cl, qint64_t c); void ClientReliableWrite_Long(client_t *cl, int c); void ClientReliableWrite_Short(client_t *cl, int c); void ClientReliableWrite_Entity(client_t *cl, int c); diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index be7a6c3c9..4d30f298d 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -37,7 +37,7 @@ qboolean SV_MayCheat(void) } #ifdef SUBSERVERS -cvar_t sv_autooffload = CVARD("sv_autooffload", "0", "Automatically start the server in a separate process, so that sporadic or persistent gamecode slowdowns do not affect visual framerates. Note: Offloaded servers have separate cvar states which may complicate usage."); +cvar_t sv_autooffload = CVARD("sv_autooffload", "0", "Automatically start the server in a separate process, so that sporadic or persistent gamecode slowdowns do not affect visual framerates (equivelent to the mapcluster command). Note: Offloaded servers have separate cvar+command states which may complicate usage."); #endif extern cvar_t cl_warncmd; cvar_t sv_cheats = CVARF("sv_cheats", "0", CVAR_LATCH); diff --git a/engine/server/sv_nchan.c b/engine/server/sv_nchan.c index ae1babc5f..18789c401 100644 --- a/engine/server/sv_nchan.c +++ b/engine/server/sv_nchan.c @@ -187,6 +187,17 @@ void ClientReliableWrite_Char(client_t *cl, int c) MSG_WriteChar(&cl->netchan.message, c); } +void ClientReliableWrite_Double(client_t *cl, double f) +{ + if (cl->num_backbuf) + { + MSG_WriteDouble(&cl->backbuf, f); + ClientReliable_FinishWrite(cl); + } + else + MSG_WriteDouble(&cl->netchan.message, f); +} + void ClientReliableWrite_Float(client_t *cl, float f) { if (cl->num_backbuf) @@ -209,6 +220,16 @@ void ClientReliableWrite_Coord(client_t *cl, float f) MSG_WriteCoord(&cl->netchan.message, f); } +void ClientReliableWrite_Int64(client_t *cl, qint64_t c) +{ + if (cl->num_backbuf) + { + MSG_WriteInt64(&cl->backbuf, c); + ClientReliable_FinishWrite(cl); + } + else + MSG_WriteInt64(&cl->netchan.message, c); +} void ClientReliableWrite_Long(client_t *cl, int c) { if (cl->num_backbuf) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 564cdfa7e..0d57f024e 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -7785,6 +7785,10 @@ void SV_ReadQCRequest(void) args[i] = 'f'; G_FLOAT(OFS_PARM0+i*3) = MSG_ReadFloat(); break; + case ev_double: + args[i] = 'F'; + G_FLOAT(OFS_PARM0+i*3) = MSG_ReadDouble(); + break; case ev_vector: args[i] = 'v'; G_FLOAT(OFS_PARM0+i*3+0) = MSG_ReadFloat(); @@ -7795,6 +7799,18 @@ void SV_ReadQCRequest(void) args[i] = 'i'; G_INT(OFS_PARM0+i*3) = MSG_ReadLong(); break; + case ev_uint: + args[i] = 'u'; + G_UINT(OFS_PARM0+i*3) = MSG_ReadLong(); + break; + case ev_int64: + args[i] = 'I'; + G_INT64(OFS_PARM0+i*3) = MSG_ReadInt64(); + break; + case ev_uint64: + args[i] = 'U'; + G_UINT64(OFS_PARM0+i*3) = MSG_ReadInt64(); + break; case ev_string: args[i] = 's'; G_INT(OFS_PARM0+i*3) = PR_TempString(svprogfuncs, MSG_ReadString());