//------------------------------------------------------------------------- /* Copyright (C) 1996, 2003 - 3D Realms Entertainment Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements) Copyright (C) 2004, 2007 - EDuke32 developers This file is part of EDuke32 EDuke32 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //------------------------------------------------------------------------- #include "m32script.h" #include "m32def.h" #include "cache1d.h" //#include "osd.h" #include "keys.h" char g_szScriptFileName[BMAX_PATH] = "(none)"; // file we're currently compiling static char g_szCurrentBlockName[256] = "(none)", g_szLastBlockName[256] = "NULL"; ////// compiler state vvv static const char *textptr; int32_t g_totalLines, g_lineNumber; int32_t g_numCompilerErrors, g_numCompilerWarnings; int32_t g_didDefineSomething; typedef struct { int32_t currentStateIdx; ofstype currentStateOfs; // the offset to the start of the currently parsed states' code int32_t currentEvent; ofstype parsingEventOfs; int32_t checkingSwitch; int32_t numCases; instype *caseScriptPtr; // the pointer to the start of the case table in a switch statement // first entry is 'default' code. instype *caseCodePtr; // the pointer to the start of the different cases' code int32_t labelsOnly; int32_t numBraces; int32_t checkingIfElse, ifElseAborted; } compilerstate_t; static compilerstate_t cs; static compilerstate_t cs_default = {-1, -1, -1, -1, 0, 0, NULL, NULL, 0, 0, 0, 0}; ////// ------------------- instype *script = NULL; instype *g_scriptPtr; int32_t g_scriptSize = 65536; int32_t *constants, constants_allocsize=1024; int32_t g_numSavedConstants=0; static int32_t g_tooBigConstant=0; char *label; int32_t *labelval; uint8_t *labeltype; int32_t g_numLabels=0, g_numDefaultLabels=0; static int32_t label_allocsize = 512; int32_t g_stateCount = 0; statesinfo_t *statesinfo = NULL; static int32_t statesinfo_allocsize = 512; static char tempbuf[2048]; static char tlabel[MAXLABELLEN]; int32_t g_iReturnVar=0; int32_t m32_sortvar1, m32_sortvar2; int32_t g_iReturnVarID=-1; // var ID of "RETURN" int32_t g_iLoTagID=-1; // var ID of "LOTAG" int32_t g_iHiTagID=-1; // var ID of "HITAG" int32_t g_iTextureID=-1; // var ID of "TEXTURE" int32_t g_iThisActorID=-1; // var ID of "I" ///"THISACTOR" int32_t g_iSpriteVarID=-1; int32_t g_iSectorVarID=-1; int32_t g_iWallVarID=-1; char *ScriptQuotes[MAXQUOTES+1], *ScriptQuoteRedefinitions[MAXQUOTES+1]; int32_t g_numQuoteRedefinitions = 0; ofstype aEventOffsets[MAXEVENTS]; static int32_t aEventSizes[MAXEVENTS]; gamevar_t aGameVars[MAXGAMEVARS]; gamearray_t aGameArrays[MAXGAMEARRAYS]; int32_t g_gameVarCount=0, g_systemVarCount=0; int32_t g_gameArrayCount=0, g_systemArrayCount=0; // "magic" number for { and }, overrides line number in compiled code for later detection #define IFELSE_MAGIC 31337 void C_ReportError(int32_t iError); enum ScriptLabel_t { LABEL_ANY = -1, LABEL_DEFINE = 1, LABEL_EVENT = 2, }; static const char *LabelTypeText[] = { "define", "event", }; static const char *C_GetLabelType(int32_t type) { uint32_t i; char x[64]; x[0] = 0; for (i=0; i" }; const memberlabel_t SectorLabels[]= { { "wallptr", SECTOR_WALLPTR, 1, 0, 0 }, { "wallnum", SECTOR_WALLNUM, 1, 0, 0 }, { "ceilingz", SECTOR_CEILINGZ, 0, 0, 0 }, { "floorz", SECTOR_FLOORZ, 0, 0, 0 }, { "ceilingstat", SECTOR_CEILINGSTAT, 0, 0, 0 }, { "floorstat", SECTOR_FLOORSTAT, 0, 0, 0 }, { "ceilingpicnum", SECTOR_CEILINGPICNUM, 0, 0, MAXTILES-1 }, { "ceilingslope", SECTOR_CEILINGSLOPE, 0, 0, 0}, { "ceilingshade", SECTOR_CEILINGSHADE, 0, 0, 0 }, { "ceilingpal", SECTOR_CEILINGPAL, 0, 0, 0 }, { "ceilingxpanning", SECTOR_CEILINGXPANNING, 0, 0, 0 }, { "ceilingypanning", SECTOR_CEILINGYPANNING, 0, 0, 0 }, { "floorpicnum", SECTOR_FLOORPICNUM, 0, 0, MAXTILES-1 }, { "floorslope", SECTOR_FLOORSLOPE, 0, 0, 0 }, { "floorshade", SECTOR_FLOORSHADE, 0, 0, 0 }, { "floorpal", SECTOR_FLOORPAL, 0, 0, 0 }, { "floorxpanning", SECTOR_FLOORXPANNING, 0, 0, 0 }, { "floorypanning", SECTOR_FLOORYPANNING, 0, 0, 0 }, { "visibility", SECTOR_VISIBILITY, 0, 0, 0 }, { "alignto", SECTOR_ALIGNTO, 0, 0, 0 }, // aka filler, not used { "lotag", SECTOR_LOTAG, 0, 0, 0 }, { "hitag", SECTOR_HITAG, 0, 0, 0 }, { "extra", SECTOR_EXTRA, 0, 0, 0 }, { "", -1, 0, 0, 0 } // END OF LIST }; const memberlabel_t WallLabels[]= { { "x", WALL_X, 0, -524288, 524288 }, { "y", WALL_Y, 0, -524288, 524288 }, { "point2", WALL_POINT2, 1, 0, 0 }, { "nextwall", WALL_NEXTWALL, 1, 0, 0 }, { "nextsector", WALL_NEXTSECTOR, 1, 0, 0 }, { "cstat", WALL_CSTAT, 0, 0, 0 }, { "picnum", WALL_PICNUM, 0, 0, MAXTILES-1 }, { "overpicnum", WALL_OVERPICNUM, 0, 0, MAXTILES-1 }, { "shade", WALL_SHADE, 0, 0, 0 }, { "pal", WALL_PAL, 0, 0, 0 }, { "xrepeat", WALL_XREPEAT, 0, 0, 0 }, { "yrepeat", WALL_YREPEAT, 0, 0, 0 }, { "xpanning", WALL_XPANNING, 0, 0, 0 }, { "ypanning", WALL_YPANNING, 0, 0, 0 }, { "lotag", WALL_LOTAG, 0, 0, 0 }, { "hitag", WALL_HITAG, 0, 0, 0 }, { "extra", WALL_EXTRA, 0, 0, 0 }, { "", -1, 0, 0, 0 } // END OF LIST }; const memberlabel_t SpriteLabels[]= { { "x", SPRITE_X, 0, -524288, 524288 }, { "y", SPRITE_Y, 0, -524288, 524288 }, { "z", SPRITE_Z, 0, 0, 0 }, { "cstat", SPRITE_CSTAT, 0, 0, 0 }, { "picnum", SPRITE_PICNUM, 0, 0, MAXTILES-1 }, { "shade", SPRITE_SHADE, 0, 0, 0 }, { "pal", SPRITE_PAL, 0, 0, 0 }, { "clipdist", SPRITE_CLIPDIST, 0, 0, 0 }, { "detail", SPRITE_DETAIL, 1, 0, 0 }, // aka filler, not used { "xrepeat", SPRITE_XREPEAT, 0, 0, 0 }, { "yrepeat", SPRITE_YREPEAT, 0, 0, 0 }, { "xoffset", SPRITE_XOFFSET, 0, 0, 0 }, { "yoffset", SPRITE_YOFFSET, 0, 0, 0 }, { "sectnum", SPRITE_SECTNUM, 1, 0, 0 }, { "statnum", SPRITE_STATNUM, 1, 0, 0 }, { "ang", SPRITE_ANG, 0, 0, 0 }, { "owner", SPRITE_OWNER, 0, 0, 0 }, { "xvel", SPRITE_XVEL, 0, 0, 0 }, { "yvel", SPRITE_YVEL, 0, 0, 0 }, { "zvel", SPRITE_ZVEL, 0, 0, 0 }, { "lotag", SPRITE_LOTAG, 0, 0, 0 }, { "hitag", SPRITE_HITAG, 0, 0, 0 }, { "extra", SPRITE_EXTRA, 0, 0, 0 }, { "", -1, 0, 0, 0 } // END OF LIST }; const tokenmap_t iter_tokens[] = { { "allsprites", ITER_ALLSPRITES }, { "allsectors", ITER_ALLSECTORS }, { "allwalls", ITER_ALLWALLS }, { "selsprites", ITER_SELSPRITES }, { "selsectors", ITER_SELSECTORS }, { "selwalls", ITER_SELWALLS }, { "drawnsprites", ITER_DRAWNSPRITES }, { "spritesofsector", ITER_SPRITESOFSECTOR }, { "wallsofsector", ITER_WALLSOFSECTOR }, { "range", ITER_RANGE }, // vvv alternatives go here vvv { "selspr", ITER_SELSPRITES }, { "selsec", ITER_SELSECTORS }, { "sprofsec", ITER_SPRITESOFSECTOR }, { "walofsec", ITER_WALLSOFSECTOR }, { "", -1 } // END OF LIST }; hashtable_t gamevarH = { MAXGAMEVARS>>1, NULL }; hashtable_t arrayH = { MAXGAMEARRAYS>>1, NULL }; hashtable_t labelH = { 11262>>1, NULL }; hashtable_t stateH = { 1264>>1, NULL }; hashtable_t keywH = { CON_END>>1, NULL }; hashtable_t iterH = { ITER_END, NULL }; hashtable_t sectorH = { SECTOR_END>>1, NULL }; hashtable_t wallH = { WALL_END>>1, NULL }; hashtable_t spriteH = { SPRITE_END>>1, NULL }; static void C_InitHashes() { int32_t i; hash_init(&gamevarH); hash_init(&arrayH); hash_init(&labelH); hash_init(&stateH); hash_init(&keywH); for (i=NUMKEYWORDS-1; i>=0; i--) hash_add(&keywH, keyw[i], i); for (i=0; i=0; i++) hash_add(§orH,SectorLabels[i].name,i); hash_add(§orH,"filler",SECTOR_ALIGNTO); hash_init(&wallH); for (i=0; WallLabels[i].lId >=0; i++) hash_add(&wallH,WallLabels[i].name,i); hash_init(&spriteH); for (i=0; SpriteLabels[i].lId >=0; i++) hash_add(&spriteH,SpriteLabels[i].name,i); hash_add(&spriteH,"filler",SPRITE_DETAIL); hash_init(&iterH); for (i=0; iter_tokens[i].val >=0; i++) hash_add(&iterH, iter_tokens[i].token, iter_tokens[i].val); } static int32_t C_SetScriptSize(int32_t size) { ofstype oscriptOfs = (unsigned)(g_scriptPtr-script); ofstype ocaseScriptOfs = (unsigned)(cs.caseScriptPtr-script); ofstype ocaseCodeOfs = (unsigned)(cs.caseCodePtr-script); instype *newscript; int32_t osize = g_scriptSize; if (g_scriptSize >= size) return 0; //initprintf("offset: %d\n",(unsigned)(g_scriptPtr-script)); g_scriptSize = size; initprintf("Resizing code buffer to %d*%d bytes\n",g_scriptSize, sizeof(instype)); newscript = (instype *)Brealloc(script, g_scriptSize * sizeof(instype)); if (newscript == NULL) { C_ReportError(-1); initprintf("%s:%d: out of memory: Aborted (%ud)\n",g_szScriptFileName,g_lineNumber,(unsigned)(g_scriptPtr-script)); initprintf(tempbuf); g_numCompilerErrors++; return 1; } if (size >= osize) Bmemset(&newscript[osize], 0, (size-osize) * sizeof(instype)); if (script != newscript) { initprintf("Relocating compiled code from to 0x%x to 0x%x\n", script, newscript); script = newscript; } g_scriptPtr = (instype *)(script+oscriptOfs); // initprintf("script: %d, \n",script); initprintf("offset: %d\n",(unsigned)(g_scriptPtr-script)); if (cs.caseScriptPtr != NULL) cs.caseScriptPtr = (instype *)(script+ocaseScriptOfs); if (cs.caseCodePtr != NULL) cs.caseCodePtr = (instype *)(script+ocaseCodeOfs); return 0; } static int32_t C_SkipComments(void) { char c = *textptr; do { if (c == ' ' || c == '\t' || c == '\r') textptr++; else if (c == '\n') { g_lineNumber++; textptr++; } else if (c == '/' && textptr[1] == '/') { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: got comment.\n",g_szScriptFileName,g_lineNumber); while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++; } else if (c == '/' && textptr[1] == '*') { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: got start of comment block.\n",g_szScriptFileName,g_lineNumber); while (*textptr && !(textptr[0] == '*' && textptr[1] == '/')) { if (*textptr == '\n') g_lineNumber++; textptr++; } // if ((!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) && (textptr[0] == '*' && textptr[1] == '/')) // initprintf("%s:%d: debug: got end of comment block.\n",g_szScriptFileName,g_lineNumber); if (!*textptr) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug) // initprintf("%s:%d: debug: EOF in comment!\n",g_szScriptFileName,g_lineNumber); C_ReportError(-1); initprintf("%s:%d: error: found `/*' with no `*/'.\n",g_szScriptFileName,g_lineNumber); cs.numBraces = 0; cs.currentStateIdx = -1; g_numCompilerErrors++; break; } else textptr += 2; } else break; } while ((c = *textptr)); if ((unsigned)(g_scriptPtr-script) > (unsigned)(g_scriptSize-32)) return C_SetScriptSize(g_scriptSize<<1); return 0; } static inline int32_t ispecial(const char c) { if (c == ' ' || c == 0x0d || c == '(' || c == ')' || c == ',' || c == ';' || (c == 0x0a /*&& ++g_lineNumber*/)) return 1; return 0; } static inline int32_t isaltok(const char c) { return (isalnum(c) || c == '#' || c == '{' || c == '}' || c == '/' || c == '\\' || c == '*' || c == '-' || c == '_' || c == '.'); } static inline int32_t C_GetLabelNameID(const memberlabel_t *pLabel, hashtable_t *tH, const char *psz) { // find the label psz in the table pLabel. // returns the ID for the label, or -1 int32_t l=-1; l = hash_findcase(tH,psz); if (l>=0) l=pLabel[l].lId; return l; } static void C_GetNextLabelName(void) { int32_t i; C_SkipComments(); while (isalnum(*textptr) == 0) { if (*textptr == 0x0a) g_lineNumber++; textptr++; if (*textptr == 0) return; } i = 0; while (!ispecial(*textptr) && *textptr!='['&& *textptr!=']' && *textptr!='\t' && *textptr!='\n' && *textptr!='\r') { if (i < MAXLABELLEN-1) tlabel[i++] = *(textptr++); else textptr++; } tlabel[i] = 0; // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: got label `%s'.\n",g_szScriptFileName,g_lineNumber,tlabel); } static int32_t C_CopyLabel(void) { if (g_numLabels >= label_allocsize) { label = Brealloc(label, 2*label_allocsize*MAXLABELLEN*sizeof(char)); labelval = Brealloc(labelval, 2*label_allocsize*sizeof(labelval[0])); labeltype = Brealloc(labeltype, 2*label_allocsize*sizeof(labeltype[0])); if (label==NULL || labelval==NULL || labeltype==NULL) { label_allocsize = 0; initprintf("Out of memory!"); return 1; } label_allocsize *= 2; } Bmemcpy(label+(g_numLabels*MAXLABELLEN), tlabel, MAXLABELLEN); return 0; } static int32_t C_GetKeyword(void) { int32_t i; const char *temptextptr; C_SkipComments(); temptextptr = textptr; while (isaltok(*temptextptr) == 0) { temptextptr++; if (*temptextptr == 0) return 0; } i = 0; while (isaltok(*temptextptr)) tempbuf[i++] = *(temptextptr++); tempbuf[i] = 0; return hash_find(&keywH, tempbuf); } static int32_t C_GetNextKeyword(void) //Returns its code # { int32_t i, l; C_SkipComments(); while (isaltok(*textptr) == 0) { if (*textptr == 0x0a) g_lineNumber++; if (*textptr == 0) return -1; textptr++; } l = 0; while (isaltok(*(textptr+l)) && !(*(textptr + l) == '.')) { tempbuf[l] = textptr[l]; l++; } while (isaltok(*(textptr+l))) { tempbuf[l] = textptr[l]; l++; } tempbuf[l] = 0; i = hash_find(&keywH, tempbuf); if (i>=0) { if (i == CON_LEFTBRACE || i == CON_RIGHTBRACE || i == CON_NULLOP) *g_scriptPtr = i + (IFELSE_MAGIC<<12); else *g_scriptPtr = i + (g_lineNumber<<12); textptr += l; g_scriptPtr++; // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug) // initprintf("%s:%d: debug: translating keyword `%s'.\n",g_szScriptFileName,g_lineNumber,keyw[i]); return i; } textptr += l; if (tempbuf[0] == '{' && tempbuf[1] != 0) { C_ReportError(-1); initprintf("%s:%d: error: expected whitespace between `{' and `%s'.\n",g_szScriptFileName,g_lineNumber,tempbuf+1); } else if (tempbuf[0] == '}' && tempbuf[1] != 0) { C_ReportError(-1); initprintf("%s:%d: error: expected whitespace between `}' and `%s'.\n",g_szScriptFileName,g_lineNumber,tempbuf+1); } else C_ReportError(ERROR_EXPECTEDKEYWORD); g_numCompilerErrors++; return -1; } #define GetGamevarID(szGameLabel) hash_find(&gamevarH, szGameLabel) #define GetGamearrayID(szGameLabel) hash_find(&arrayH, szGameLabel) static void C_GetNextVarType(int32_t type) { int32_t i, id=0, flags=0, num, indirect=0; C_SkipComments(); // constant where gamevar expected if ((type==0 || type==GAMEVAR_SPECIAL) && !cs.labelsOnly && (isdigit(*textptr) || ((*textptr == '-') && isdigit(*(textptr+1))))) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug) // initprintf("%s:%d: debug: accepted constant %d in place of gamevar.\n",g_szScriptFileName,g_lineNumber,atol(textptr)); if (tolower(textptr[1])=='x') sscanf(textptr+2, "%" SCNx32, &num); else num = atoi(textptr); if (type==GAMEVAR_SPECIAL && (num<0 || num>=65536)) { C_ReportError(-1); initprintf("%s:%d: error: array index %d out of bounds. (max: 65535)\n",g_szScriptFileName,g_lineNumber, num); g_numCompilerErrors++; } if (g_numCompilerErrors==0 && type!=GAMEVAR_SPECIAL && num != (int16_t)num) { g_tooBigConstant = 1; indirect = 1; for (i=g_numSavedConstants-1; i>=0; i--) if (constants[i] == num) break; if (i<0) { i = g_numSavedConstants; if (i>=constants_allocsize) { constants_allocsize *= 2; constants = Brealloc(constants, constants_allocsize * sizeof(constants[0])); if (!constants) { initprintf("C_GetNextVarType(): ERROR: out of memory!\n"); g_numCompilerErrors++; return; } } constants[i] = num; num = i; g_numSavedConstants++; } } *g_scriptPtr++ = MAXGAMEVARS | (num<<16) | indirect; while (!ispecial(*textptr) && *textptr != ']') textptr++; return; } else if (*textptr == '-' /* && !isdigit(*(textptr+1))*/) { if (type==0) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug) // initprintf("%s:%d: debug: flagging gamevar as negative.\n",g_szScriptFileName,g_lineNumber,atol(textptr)); flags = (MAXGAMEVARS<<1); } else { g_numCompilerErrors++; C_ReportError(ERROR_SYNTAXERROR); C_GetNextLabelName(); return; } } C_GetNextLabelName(); if (hash_find(&keywH, tlabel)>=0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return; } C_SkipComments(); //skip comments and whitespace if (*textptr == '[') //read of array as a gamevar { int32_t lLabelID = -1, aridx; textptr++; flags |= (MAXGAMEVARS<<2); if (type & GAMEVAR_SPECIAL) { g_numCompilerErrors++; C_ReportError(ERROR_EXPECTEDSIMPLEVAR); return; } id = GetGamearrayID(tlabel); if (id < 0) { id = GetGamevarID(tlabel); if (id >= 4) id = -1; if (id < 0) { g_numCompilerErrors++; C_ReportError(ERROR_NOTAGAMEARRAY); return; } flags &= ~(MAXGAMEVARS<<2); // not an array flags |= (MAXGAMEVARS<<3); } else { if ((aGameArrays[id].dwFlags & GAMEARRAY_READONLY) && type&GAMEVAR_READONLY) { C_ReportError(ERROR_ARRAYREADONLY); g_numCompilerErrors++; } } C_GetNextVarType(GAMEVAR_SPECIAL); // _SPECIAL signifies that we want only simple vars or a constant g_scriptPtr--; aridx = *g_scriptPtr; C_SkipComments(); if (*textptr != ']') { g_numCompilerErrors++; C_ReportError(ERROR_GAMEARRAYBNC); return; } textptr++; // writing arrays in this way is not supported because it would // require too many changes to other code // if (type) // { // g_numCompilerErrors++; // C_ReportError(ERROR_INVALIDARRAYWRITE); // return; // } if (flags & (MAXGAMEVARS<<3)) { while (*textptr && *textptr != 0x0a && *textptr != '.') textptr++; if (*textptr != '.') { g_numCompilerErrors++; C_ReportError(ERROR_SYNTAXERROR); return; } textptr++; /// now pointing at 'xxx' C_GetNextLabelName(); /*initprintf("found xxx label of '%s'\n", label+(g_numLabels*MAXLABELLEN));*/ if (id == g_iSpriteVarID || id==3) lLabelID = C_GetLabelNameID(SpriteLabels, &spriteH, strtolower(tlabel,Bstrlen(tlabel))); else if (id == g_iSectorVarID) lLabelID = C_GetLabelNameID(SectorLabels, §orH, strtolower(tlabel,Bstrlen(tlabel))); else if (id == g_iWallVarID) lLabelID = C_GetLabelNameID(WallLabels, &wallH, strtolower(tlabel,Bstrlen(tlabel))); //printf("LabelID is %d\n",lLabelID); if (lLabelID == -1) { g_numCompilerErrors++; C_ReportError(ERROR_SYMBOLNOTRECOGNIZED); return; } if ((aridx & 0x0000FFFF) == MAXGAMEVARS) // constant *g_scriptPtr++ = (aridx | id | (lLabelID<<2) | flags); else // simple gamevar *g_scriptPtr++ = (aridx<<16 | id | (lLabelID<<2) | flags); } else // if (flags & (MAXGAMEVARS<<2)) { if ((aridx & 0x0000FFFF) == MAXGAMEVARS) // constant *g_scriptPtr++ = (aridx | id | flags); else // simple gamevar *g_scriptPtr++ = (aridx<<16 | id | flags); } return; } // initprintf("not an array"); id = GetGamevarID(tlabel); if (id < 0) //gamevar not found { if (!type && !cs.labelsOnly) { //try looking for a define instead id = hash_find(&labelH, tlabel); if (id>=0 && labeltype[id]==LABEL_DEFINE) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug) // initprintf("%s:%d: debug: accepted defined label `%s' instead of gamevar.\n",g_szScriptFileName,g_lineNumber,label+(id*MAXLABELLEN)); num = labelval[id]; if (type==GAMEVAR_SPECIAL && (num<0 || num>=65536)) { C_ReportError(-1); initprintf("%s:%d: error: label %s=%d not suitable as array index. (max: 65535)\n",g_szScriptFileName,g_lineNumber, label+(id*MAXLABELLEN), num); g_numCompilerErrors++; } else if (num != (int16_t)num) { g_tooBigConstant = 1; indirect = 2; num = id; } *g_scriptPtr++ = MAXGAMEVARS | (num<<16) | indirect; return; } } g_numCompilerErrors++; C_ReportError(ERROR_NOTAGAMEVAR); textptr++; return; } if (type == GAMEVAR_READONLY && aGameVars[id].dwFlags & GAMEVAR_READONLY) { g_numCompilerErrors++; C_ReportError(ERROR_VARREADONLY); return; } else if (aGameVars[id].dwFlags & type) { g_numCompilerErrors++; C_ReportError(ERROR_VARTYPEMISMATCH); return; } // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: accepted gamevar `%s'.\n",g_szScriptFileName,g_lineNumber,tlabel); *g_scriptPtr++ = (id|flags); } #define C_GetNextVar() C_GetNextVarType(0) static inline void C_GetManyVarsType(int32_t type, int32_t num) { int32_t i; for (i=num-1; i>=0; i--) C_GetNextVarType(type); } #define C_GetManyVars(num) C_GetManyVarsType(0,num) static int32_t C_GetNextValue(int32_t type) { int32_t i, l; C_SkipComments(); while (isaltok(*textptr) == 0) { if (*textptr == 0x0a) g_lineNumber++; textptr++; if (*textptr == 0) return -1; // eof } l = 0; while (isaltok(*(textptr+l))) { tempbuf[l] = textptr[l]; l++; } tempbuf[l] = 0; if (hash_find(&keywH, tempbuf)>=0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); textptr+=l; } i = hash_find(&labelH, tempbuf); if (i >= 0) { char *el,*gl; if (labeltype[i] & type) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // { // gl = (char *)C_GetLabelType(labeltype[i]); // initprintf("%s:%d: debug: accepted %s label `%s'.\n",g_szScriptFileName,g_lineNumber,gl,label+(i*MAXLABELLEN)); // Bfree(gl); // } *(g_scriptPtr++) = labelval[i]; textptr += l; return labeltype[i]; } *(g_scriptPtr++) = 0; textptr += l; el = (char *)C_GetLabelType(type); gl = (char *)C_GetLabelType(labeltype[i]); C_ReportError(-1); initprintf("%s:%d: error: expected %s, found %s.\n",g_szScriptFileName,g_lineNumber,el,gl); // initprintf("i=%d, %s!!! lt:%d t:%d\n", i, label+(i*MAXLABELLEN), labeltype[i], type); g_numCompilerErrors++; Bfree(el); Bfree(gl); return -1; // valid label name, but wrong type } if (isdigit(*textptr) == 0 && *textptr != '-') { C_ReportError(ERROR_PARAMUNDEFINED); g_numCompilerErrors++; *g_scriptPtr = 0; g_scriptPtr++; textptr += l; return -1; // error! } if (isdigit(*textptr) && cs.labelsOnly) { C_ReportError(WARNING_LABELSONLY); g_numCompilerWarnings++; } i = l-1; do { // FIXME: check for 0-9 A-F for hex if (textptr[0] == '0' && textptr[1] == 'x') break; // kill the warning for hex if (!isdigit(textptr[i--])) { C_ReportError(-1); initprintf("%s:%d: warning: invalid character `%c' in definition!\n",g_szScriptFileName,g_lineNumber,textptr[i+1]); g_numCompilerWarnings++; break; } } while (i > 0); // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: accepted constant %d.\n",g_szScriptFileName,g_lineNumber,atol(textptr)); if (tolower(textptr[1])=='x') sscanf(textptr+2,"%" SCNx32 "",g_scriptPtr); else *g_scriptPtr = atol(textptr); g_scriptPtr++; textptr += l; return 0; // literal value } static inline int32_t C_IntPow2(int32_t v) { return ((v!=0) && (v&(v-1))==0); } static inline uint32_t C_Pow2IntLogBase2(int32_t v) { static const uint32_t b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; register uint32_t r = (v & b[0]) != 0; int32_t i = 4; for (; i > 0; i--) r |= ((v & b[i]) != 0) << i; return r; } static int32_t C_CheckMalformedBranch(ofstype lastScriptOfs) { switch (C_GetKeyword()) { case CON_RIGHTBRACE: case CON_ENDEVENT: case CON_ENDS: case CON_ELSE: g_scriptPtr = script + lastScriptOfs; cs.ifElseAborted = 1; C_ReportError(-1); g_numCompilerWarnings++; initprintf("%s:%d: warning: malformed `%s' branch\n", g_szScriptFileName, g_lineNumber, keyw[*(g_scriptPtr) & 0xFFF]); return 1; } return 0; } static int32_t C_CheckEmptyBranch(int32_t tw, ofstype lastScriptOfs) { // ifrnd actually does something when the condition is executed if ((Bstrncmp(keyw[tw], "if", 2) && tw != CON_ELSE) || tw == CON_IFRND) { cs.ifElseAborted = 0; return 0; } if ((*(g_scriptPtr) & 0xFFF) != CON_NULLOP || *(g_scriptPtr)>>12 != IFELSE_MAGIC) cs.ifElseAborted = 0; if (cs.ifElseAborted) { C_ReportError(-1); g_numCompilerWarnings++; g_scriptPtr = script + lastScriptOfs; initprintf("%s:%d: warning: empty `%s' branch\n",g_szScriptFileName,g_lineNumber, keyw[*(g_scriptPtr) & 0xFFF]); *(g_scriptPtr) = (CON_NULLOP + (IFELSE_MAGIC<<12)); return 1; } return 0; } static int32_t C_ParseCommand(void); static int32_t C_CountCaseStatements() { int32_t lCount; const char *temptextptr = textptr; int32_t temp_ScriptLineNumber = g_lineNumber; ofstype scriptoffset = (unsigned)(g_scriptPtr-script); ofstype caseoffset = (unsigned)(cs.caseScriptPtr-script); cs.numCases=0; cs.caseScriptPtr=NULL; //Bsprintf(g_szBuf,"CSS: %.12s",textptr); AddLog(g_szBuf); while (C_ParseCommand() == 0) { //Bsprintf(g_szBuf,"CSSL: %.20s",textptr); AddLog(g_szBuf); ; } // since we processed the endswitch, we need to re-increment cs.checkingSwitch cs.checkingSwitch++; textptr = temptextptr; g_scriptPtr = (instype *)(script+scriptoffset); g_lineNumber = temp_ScriptLineNumber; lCount = cs.numCases; cs.numCases = 0; cs.caseScriptPtr = (instype *)(script+caseoffset); return lCount; } static int32_t C_ParseCommand(void) { int32_t i, j=0, k=0, done, tw; const char *temptextptr; instype *tempscrptr = NULL; if (quitevent) { /// initprintf("Aborted.\n"); /// return 1; } if (g_numCompilerErrors >= ABORTERRCNT || (*textptr == '\0') || (*(textptr+1) == '\0')) return 1; // if (g_scriptDebug) // C_ReportError(-1); /// if (cs.checkingSwitch > 0) /// Bsprintf(g_szBuf,"PC(): '%.25s'",textptr); AddLog(g_szBuf); tw = C_GetNextKeyword(); // Bsprintf(tempbuf,"%s",keyw[tw]); AddLog(tempbuf); if (C_SkipComments()) return 1; switch (tw) { default: case -1: return 0; //End // *** basic commands case CON_NULLOP: if (C_GetKeyword() != CON_ELSE) { C_ReportError(-1); g_numCompilerWarnings++; initprintf("%s:%d: warning: `nullop' found without `else'\n",g_szScriptFileName,g_lineNumber); g_scriptPtr--; cs.ifElseAborted = 1; } return 0; case CON_DEFINE: { C_GetNextLabelName(); if (hash_find(&keywH, tlabel) >= 0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return 0; } // Check to see it's already defined i = hash_find(&gamevarH, tlabel); if (i>=0) { g_numCompilerWarnings++; C_ReportError(WARNING_NAMEMATCHESVAR); } if (hash_find(&stateH, tlabel) >= 0) { g_numCompilerErrors++; C_ReportError(ERROR_LABELINUSE); return 1; } C_GetNextValue(LABEL_DEFINE); i = hash_find(&labelH, tlabel); if (i == -1) { // printf("Defining Definition '%s' to be '%d'\n",label+(g_numLabels*MAXLABELLEN),*(g_scriptPtr-1)); // Bmemcpy(label+(g_numLabels*MAXLABELLEN), tlabel, MAXLABELLEN); C_CopyLabel(); hash_add(&labelH, label+(g_numLabels*MAXLABELLEN), g_numLabels); labeltype[g_numLabels] = LABEL_DEFINE; labelval[g_numLabels++] = *(g_scriptPtr-1); } // else if (i>=g_numDefaultLabels) // { // if (labeltype[i] == LABEL_DEFINE) // labelval[i] = *(g_scriptPtr-1); // } g_scriptPtr -= 2; return 0; } case CON_INCLUDE: g_scriptPtr--; while (!isaltok(*textptr)) { if (*textptr == 0x0a) g_lineNumber++; textptr++; if (*textptr == 0) break; } j = 0; while (isaltok(*textptr)) { tempbuf[j] = *(textptr++); j++; } tempbuf[j] = '\0'; { int32_t temp_ScriptLineNumber; int32_t temp_ifelse_check; const char *origtptr; char *mptr; char parentScriptFileName[255]; int32_t fp; fp = kopen4load(tempbuf, 0 /*g_loadFromGroupOnly*/); if (fp < 0) { g_numCompilerErrors++; initprintf("%s:%d: error: could not find file `%s'.\n",g_szScriptFileName,g_lineNumber,tempbuf); return 1; } j = kfilelength(fp); mptr = (char *)Bmalloc(j+1); if (!mptr) { kclose(fp); g_numCompilerErrors++; initprintf("%s:%d: error: could not allocate %d bytes to include `%s'.\n", g_lineNumber,g_szScriptFileName,j,tempbuf); return 1; } initprintf(" Including: %s (%d bytes)\n", tempbuf, j); kread(fp, mptr, j); kclose(fp); mptr[j] = 0; if (*textptr == '"') // skip past the closing quote if it's there so we don't screw up the next line textptr++; origtptr = textptr; Bstrcpy(parentScriptFileName, g_szScriptFileName); Bstrcpy(g_szScriptFileName, tempbuf); temp_ScriptLineNumber = g_lineNumber; g_lineNumber = 1; temp_ifelse_check = cs.checkingIfElse; cs.checkingIfElse = 0; textptr = mptr; do done = C_ParseCommand(); while (!done); Bstrcpy(g_szScriptFileName, parentScriptFileName); g_totalLines += g_lineNumber; g_lineNumber = temp_ScriptLineNumber; cs.checkingIfElse = temp_ifelse_check; textptr = origtptr; Bfree(mptr); } return 0; case CON_DEFSTATE: g_scriptPtr--; if (cs.parsingEventOfs < 0 && cs.currentStateIdx < 0) { C_GetNextLabelName(); if (hash_find(&keywH, tlabel)>=0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return 1; } if (hash_find(&gamevarH, tlabel)>=0) { g_numCompilerWarnings++; C_ReportError(WARNING_NAMEMATCHESVAR); } j = hash_find(&labelH, tlabel); if (j>=0) { g_numCompilerErrors++; C_ReportError(ERROR_LABELINUSE); return 1; } j = hash_find(&stateH, tlabel); if (j>=0) // only redefining { cs.currentStateIdx = j; cs.currentStateOfs = (g_scriptPtr-script); Bsprintf(g_szCurrentBlockName, "%s", statesinfo[j].name); } else // new state definition { cs.currentStateIdx = j = g_stateCount; cs.currentStateOfs = (g_scriptPtr-script); if (g_stateCount >= statesinfo_allocsize) { statesinfo_allocsize *= 2; statesinfo = Brealloc(statesinfo, statesinfo_allocsize * sizeof(statesinfo[0])); if (!statesinfo) { initprintf("C_ParseCommand(): ERROR: out of memory!\n"); g_numCompilerErrors++; return 1; } } Bmemcpy(statesinfo[j].name, tlabel, MAXLABELLEN); Bsprintf(g_szCurrentBlockName, "%s", tlabel); hash_add(&stateH, tlabel, j); } return 0; } g_numCompilerErrors++; C_ReportError(ERROR_FOUNDWITHIN); return 1; case CON_ENDS: if (cs.currentStateIdx < 0) { C_ReportError(-1); initprintf("%s:%d: error: found `ends' without open `state'.\n",g_szScriptFileName,g_lineNumber); g_numCompilerErrors++; return 1; //+ } else { if (cs.numBraces > 0) { C_ReportError(ERROR_OPENBRACKET); g_numCompilerErrors++; } if (cs.numBraces < 0) { C_ReportError(ERROR_CLOSEBRACKET); g_numCompilerErrors++; } if (cs.checkingSwitch > 0) { C_ReportError(ERROR_NOENDSWITCH); g_numCompilerErrors++; cs.checkingSwitch = 0; // can't be checking anymore... } if (g_numCompilerErrors) { g_scriptPtr = script+cs.currentStateOfs; cs.currentStateOfs = -1; cs.currentStateIdx = -1; Bsprintf(g_szCurrentBlockName,"(none)"); return 0; } j = cs.currentStateIdx; if (cs.currentStateIdx == g_stateCount) // we were defining a new state { statesinfo[j].ofs = cs.currentStateOfs; statesinfo[j].codesize = (g_scriptPtr-script) - cs.currentStateOfs; g_stateCount++; initprintf(" Defined state `%s' (index %d).\n", g_szCurrentBlockName, j); } else // we were redefining a state { int32_t oofs = statesinfo[j].ofs; int32_t nofs = cs.currentStateOfs; int32_t osize = statesinfo[j].codesize; int32_t nsize = (g_scriptPtr-script) - nofs; if (nsize == osize) { int ii, equal=1; for (ii=0; ii oofs) statesinfo[ii].ofs -= osize; } for (ii=0; ii oofs) aEventOffsets[ii] -= osize; statesinfo[j].ofs = nofs-osize; statesinfo[j].codesize = nsize; initprintf(" Redefined state `%s' (index %d).\n", g_szCurrentBlockName, j); } g_scriptPtr -= osize; } g_didDefineSomething = 1; cs.currentStateOfs = -1; cs.currentStateIdx = -1; Bsprintf(g_szCurrentBlockName,"(none)"); } return 0; case CON_SORT: C_GetNextLabelName(); i = GetGamearrayID(tlabel); if (i >= 0) { *g_scriptPtr++ = i; if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) { C_ReportError(ERROR_ARRAYREADONLY); g_numCompilerErrors++; } } else { C_ReportError(ERROR_NOTAGAMEARRAY); g_numCompilerErrors++; } C_SkipComments(); C_GetNextVar(); // element count to sort if (C_GetKeyword() >= 0) { *g_scriptPtr++ = -1; return 0; } // fall-through case CON_STATE: C_GetNextLabelName(); if (hash_find(&keywH, tlabel)>=0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return 1; } if (hash_find(&gamevarH, tlabel)>=0) { g_numCompilerWarnings++; C_ReportError(WARNING_NAMEMATCHESVAR); } j = hash_find(&stateH, tlabel); if (j>=0) { // if (!(g_numCompilerErrors || g_numCompilerWarnings) && g_scriptDebug > 1) // initprintf("%s:%d: debug: accepted state label `%s'.\n",g_szScriptFileName,g_lineNumber,label+(k*MAXLABELLEN)); *g_scriptPtr++ = j; return 0; } C_ReportError(-1); initprintf("%s:%d: error: state `%s' not found.\n",g_szScriptFileName,g_lineNumber,tlabel); g_numCompilerErrors++; g_scriptPtr++; return 0; case CON_ONEVENT: if (cs.currentStateIdx >= 0 || cs.parsingEventOfs >= 0) { C_ReportError(ERROR_FOUNDWITHIN); g_numCompilerErrors++; } g_scriptPtr--; cs.numBraces = 0; C_SkipComments(); j = 0; while (isaltok(*(textptr+j))) { g_szCurrentBlockName[j] = textptr[j]; j++; } g_szCurrentBlockName[j] = 0; cs.labelsOnly = 1; C_GetNextValue(LABEL_EVENT); cs.labelsOnly = 0; g_scriptPtr--; j = *g_scriptPtr; // event number cs.currentEvent = j; cs.parsingEventOfs = g_scriptPtr-script; //Bsprintf(g_szBuf,"Adding Event for %d at %lX",j, g_parsingEventPtr); AddLog(g_szBuf); if (j<0 || j >= MAXEVENTS) { initprintf("%s:%d: error: invalid event ID.\n",g_szScriptFileName,g_lineNumber); g_numCompilerErrors++; return 0; } cs.checkingIfElse = 0; return 0; case CON_ENDEVENT: if (cs.parsingEventOfs < 0) { C_ReportError(-1); initprintf("%s:%d: error: found `endevent' without open `onevent'.\n",g_szScriptFileName,g_lineNumber); g_numCompilerErrors++; return 1; } if (cs.numBraces > 0) { C_ReportError(ERROR_OPENBRACKET); g_numCompilerErrors++; } if (cs.numBraces < 0) { C_ReportError(ERROR_CLOSEBRACKET); g_numCompilerErrors++; } if (g_numCompilerErrors) { g_scriptPtr = script+cs.parsingEventOfs; cs.parsingEventOfs = -1; cs.currentEvent = -1; Bsprintf(g_szCurrentBlockName,"(none)"); return 0; } j = cs.currentEvent; if (aEventOffsets[j] >= 0) // if event was previously declared, overwrite it { int32_t oofs = aEventOffsets[j], nofs = cs.parsingEventOfs; int32_t osize = aEventSizes[j], nsize = (g_scriptPtr-script) - nofs; if (osize == nsize) { int ii, equal=1; for (ii=0; ii oofs) statesinfo[ii].ofs -= osize; } for (ii=0; ii oofs) aEventOffsets[ii] -= osize; aEventOffsets[j] = nofs - osize; aEventSizes[j] = nsize; initprintf(" Redefined event `%s' (index %d).\n", g_szCurrentBlockName, j); } g_scriptPtr -= osize; } else // event defined for the first time { aEventOffsets[j] = cs.parsingEventOfs; aEventSizes[j] = (g_scriptPtr-script) - cs.parsingEventOfs; initprintf(" Defined event `%s' (index %d).\n", g_szCurrentBlockName, j); } g_didDefineSomething = 1; cs.parsingEventOfs = -1; cs.currentEvent = -1; Bsprintf(g_szCurrentBlockName,"(none)"); return 0; // *** control flow case CON_ELSE: if (cs.checkingIfElse) { ofstype offset; ofstype lastScriptOfs = (g_scriptPtr-script) - 1; instype *tscrptr; cs.ifElseAborted = 0; cs.checkingIfElse--; if (C_CheckMalformedBranch(lastScriptOfs)) return 0; offset = (unsigned)(g_scriptPtr-script); g_scriptPtr++; //Leave a spot for the fail location C_ParseCommand(); if (C_CheckEmptyBranch(tw, lastScriptOfs)) return 0; tscrptr = (instype *)script+offset; *tscrptr = (ofstype) (g_scriptPtr-script)-offset; // relative offset } else { instype *tscrptr; g_scriptPtr--; tscrptr = g_scriptPtr; g_numCompilerWarnings++; C_ReportError(-1); initprintf("%s:%d: warning: found `else' with no `if'.\n",g_szScriptFileName,g_lineNumber); if (C_GetKeyword() == CON_LEFTBRACE) { C_GetNextKeyword(); cs.numBraces++; do done = C_ParseCommand(); while (done == 0); } else C_ParseCommand(); g_scriptPtr = tscrptr; } return 0; case CON_RETURN: case CON_BREAK: if (cs.checkingSwitch) { //Bsprintf(g_szBuf," * (L%d) case Break statement.\n",g_lineNumber); AddLog(g_szBuf); return 1; } return 0; case CON_SWITCH: { ofstype tempoffset; //AddLog("Got Switch statement"); // if (cs.checkingSwitch) Bsprintf(g_szBuf,"ERROR::%s %d: cs.checkingSwitch=",__FILE__,__LINE__, cs.checkingSwitch); AddLog(g_szBuf); cs.checkingSwitch++; // allow nesting (if other things work) C_GetNextVar(); // Get The ID of the DEF tempoffset = (unsigned)(g_scriptPtr-script); *g_scriptPtr++ = 0; // leave spot for end location (for after processing) *g_scriptPtr++ = 0; // count of case statements cs.caseScriptPtr = g_scriptPtr; // the first case's pointer. *g_scriptPtr++ = -1; // leave spot for 'default' offset to cases' code (-1 if none) temptextptr = textptr; // probably does not allow nesting... //AddLog("Counting Case Statements..."); j = C_CountCaseStatements(); // initprintf("Done Counting Case Statements for switch %d: found %d.\n", cs.checkingSwitch,j); g_scriptPtr += j*2; cs.caseCodePtr = g_scriptPtr; C_SkipComments(); g_scriptPtr -= j*2; // allocate buffer for the table tempscrptr = (instype *)(script+tempoffset); // if (cs.checkingSwitch>1) Bsprintf(g_szBuf,"ERROR::%s %d: cs.checkingSwitch=",__FILE__,__LINE__, cs.checkingSwitch); AddLog(g_szBuf); if (j<0) return 1; if (tempscrptr) tempscrptr[1] = j; // save count of cases // else // Bsprintf(g_szBuf,"ERROR::%s %d",__FILE__,__LINE__); AddLog(g_szBuf); while (j--) { // leave room for statements *g_scriptPtr++ = 0; // value check *g_scriptPtr++ = -1; // code offset C_SkipComments(); } //Bsprintf(g_szBuf,"SWITCH1: '%.22s'",textptr); AddLog(g_szBuf); cs.numCases = 0; while (C_ParseCommand() == 0) { //Bsprintf(g_szBuf,"SWITCH2: '%.22s'",textptr); AddLog(g_szBuf); } tempscrptr = (instype *)(script+tempoffset); //Bsprintf(g_szBuf,"SWITCHXX: '%.22s'",textptr); AddLog(g_szBuf); // done processing switch. clean up. // if (cs.checkingSwitch < 1) Bsprintf(g_szBuf,"ERROR::%s %d: cs.checkingSwitch=%d",__FILE__,__LINE__, cs.checkingSwitch); AddLog(g_szBuf); if (tempscrptr) { int32_t t,n; // !!! for (i=3; i<3+tempscrptr[1]*2-2; i+=2) // sort them { t = tempscrptr[i]; n=i; for (j=i+2; j<3+tempscrptr[1]*2; j+=2) if (tempscrptr[j] < t) t = tempscrptr[j], n=j; if (n != i) { t = tempscrptr[i]; tempscrptr[i] = tempscrptr[n]; tempscrptr[n] = t; t = tempscrptr[i+1]; tempscrptr[i+1] = tempscrptr[n+1]; tempscrptr[n+1] = t; } } // for (j=3;j<3+tempscrptr[1]*2;j+=2)initprintf("%5d %8x\n",tempscrptr[j],tempscrptr[j+1]); tempscrptr[0] = (ofstype)(g_scriptPtr-cs.caseCodePtr); // save 'end' location as offset from code-place } // else Bsprintf(g_szBuf,"ERROR::%s %d",__FILE__,__LINE__); AddLog(g_szBuf); cs.numCases = 0; cs.caseScriptPtr = NULL; cs.caseCodePtr = NULL; // decremented in endswitch. Don't decrement here... // cs.checkingSwitch--; // allow nesting (maybe if other things work) tempscrptr = NULL; // if (cs.checkingSwitch) Bsprintf(g_szBuf,"ERROR::%s %d: cs.checkingSwitch=%d",__FILE__,__LINE__, cs.checkingSwitch); AddLog(g_szBuf); //AddLog("End of Switch statement"); } break; case CON_CASE: { ofstype tempoffset = 0; //AddLog("Found Case"); repeatcase: g_scriptPtr--; // don't save in code if (cs.checkingSwitch < 1) { g_numCompilerErrors++; C_ReportError(-1); initprintf("%s:%d: error: found `case' statement when not in switch\n", g_szScriptFileName, g_lineNumber); return 1; } cs.numCases++; //Bsprintf(g_szBuf,"case1: %.12s",textptr); AddLog(g_szBuf); C_GetNextValue(LABEL_DEFINE); if (*textptr == ':') textptr++; //Bsprintf(g_szBuf,"case2: %.12s",textptr); AddLog(g_szBuf); j = *(--g_scriptPtr); // get value //Bsprintf(g_szBuf,"case: Value of case %d is %d",(int32_t)cs.numCases,(int32_t)j); AddLog(g_szBuf); if (cs.caseScriptPtr) { for (i=(cs.numCases/2)-1; i>=0; i--) if (cs.caseScriptPtr[i*2+1] == j) { g_numCompilerWarnings++; C_ReportError(WARNING_DUPLICATECASE); break; } //AddLog("Adding value to script"); cs.caseScriptPtr[cs.numCases++] = j; // save value cs.caseScriptPtr[cs.numCases] = (ofstype)(g_scriptPtr - cs.caseCodePtr); // offset from beginning of cases' code } //Bsprintf(g_szBuf,"case3: %.12s",textptr); AddLog(g_szBuf); j = C_GetKeyword(); if (j == CON_CASE) { //AddLog("Found Repeat Case"); C_GetNextKeyword(); // eat 'case' goto repeatcase; } //Bsprintf(g_szBuf,"case4: '%.12s'",textptr); AddLog(g_szBuf); tempoffset = (unsigned)(tempscrptr-script); while (C_ParseCommand() == 0) { //Bsprintf(g_szBuf,"case5 '%.25s'",textptr); AddLog(g_szBuf); j = C_GetKeyword(); if (j == CON_CASE) { //AddLog("Found Repeat Case"); C_GetNextKeyword(); // eat 'case' tempscrptr = (instype *)(script+tempoffset); goto repeatcase; } } tempscrptr = (instype *)(script+tempoffset); //AddLog("End Case"); return 0; // break; } case CON_DEFAULT: g_scriptPtr--; // don't save if (cs.checkingSwitch < 1) { g_numCompilerErrors++; C_ReportError(-1); initprintf("%s:%d: error: found `default' statement when not in switch\n",g_szScriptFileName,g_lineNumber); return 1; } if (cs.caseScriptPtr && cs.caseScriptPtr[0]!=0) { // duplicate default statement g_numCompilerErrors++; C_ReportError(-1); initprintf("%s:%d: error: multiple `default' statements found in switch\n",g_szScriptFileName,g_lineNumber); } if (cs.caseScriptPtr) cs.caseScriptPtr[0] = (ofstype)(g_scriptPtr-cs.caseCodePtr); // save offset from cases' code //Bsprintf(g_szBuf,"default: '%.22s'",textptr); AddLog(g_szBuf); while (C_ParseCommand() == 0) { //Bsprintf(g_szBuf,"defaultParse: '%.22s'",textptr); AddLog(g_szBuf); ; } break; case CON_ENDSWITCH: //AddLog("End Switch"); cs.checkingSwitch--; if (cs.checkingSwitch < 0) { g_numCompilerErrors++; C_ReportError(-1); initprintf("%s:%d: error: found `endswitch' without matching `switch'\n",g_szScriptFileName,g_lineNumber); } return 1; // end of block // break; case CON_GETCURRADDRESS: C_GetNextVarType(GAMEVAR_READONLY); return 0; case CON_JUMP: C_GetNextVar(); return 0; case CON_LEFTBRACE: // if (!(cs.currentStateIdx >= 0 || cs.parsingEventOfs >= 0)) // { // g_numCompilerErrors++; // C_ReportError(ERROR_SYNTAXERROR); // } cs.numBraces++; do done = C_ParseCommand(); while (done == 0); return 0; case CON_RIGHTBRACE: cs.numBraces--; // rewrite "{ }" into "nullop" if (*(g_scriptPtr-2) == CON_LEFTBRACE + (IFELSE_MAGIC<<12)) { // initprintf("%s:%d: rewriting empty braces '{ }' as 'nullop' from right\n",g_szScriptFileName,g_lineNumber); *(g_scriptPtr-2) = CON_NULLOP + (IFELSE_MAGIC<<12); g_scriptPtr -= 2; if (C_GetKeyword() != CON_ELSE && (*(g_scriptPtr-2)&0xFFF) != CON_ELSE) cs.ifElseAborted = 1; else cs.ifElseAborted = 0; j = C_GetKeyword(); if (cs.checkingIfElse && j != CON_ELSE) cs.checkingIfElse--; return 1; } if (cs.numBraces < 0) { if (cs.checkingSwitch) C_ReportError(ERROR_NOENDSWITCH); C_ReportError(-1); initprintf("%s:%d: error: found more `}' than `{'.\n",g_szScriptFileName,g_lineNumber); g_numCompilerErrors++; } if (cs.checkingIfElse && j != CON_ELSE) cs.checkingIfElse--; return 1; // *** more basic commands case CON_SETSECTOR: case CON_GETSECTOR: case CON_SETWALL: case CON_GETWALL: case CON_SETSPRITE: case CON_GETSPRITE: case CON_SETTSPR: case CON_GETTSPR: { int32_t lLabelID; // syntax getsector[].x // gets the value of sector[].xxx into if ((tw==CON_GETTSPR || tw==CON_SETTSPR) && cs.currentEvent != EVENT_ANALYZESPRITES) { C_ReportError(-1); initprintf("%s:%d: warning: found `%s' outside of EVENT_ANALYZESPRITES\n",g_szScriptFileName,g_lineNumber,tempbuf); g_numCompilerWarnings++; } // now get name of .xxx while ((*textptr != '[')) { textptr++; } if (*textptr == '[') textptr++; // get the ID of the DEF cs.labelsOnly = 1; C_GetNextVar(); cs.labelsOnly = 0; // now get name of .xxx while (*textptr != '.') { if (*textptr == 0xa) break; if (!*textptr) break; textptr++; } if (*textptr!='.') { g_numCompilerErrors++; C_ReportError(ERROR_SYNTAXERROR); return 0; } textptr++; /// now pointing at 'xxx' C_GetNextLabelName(); //printf("found xxx label of '%s'\n", label+(g_numLabels*MAXLABELLEN)); if (tw==CON_GETSECTOR || tw==CON_SETSECTOR) lLabelID = C_GetLabelNameID(SectorLabels, §orH, strtolower(tlabel,Bstrlen(tlabel))); else if (tw==CON_GETWALL || tw==CON_SETWALL) lLabelID = C_GetLabelNameID(WallLabels, &wallH, strtolower(tlabel,Bstrlen(tlabel))); else // if (tw==CON_GETSPRITE || tw==CON_SETSPRITE || tw==CON_GETTSPR || tw==CON_SETTSPR) lLabelID = C_GetLabelNameID(SpriteLabels, &spriteH, strtolower(tlabel,Bstrlen(tlabel))); if (lLabelID == -1) { g_numCompilerErrors++; C_ReportError(ERROR_SYMBOLNOTRECOGNIZED); return 0; } *g_scriptPtr++ = lLabelID; // now at target VAR... // get the ID of the DEF if (tw==CON_GETSECTOR || tw==CON_GETWALL || tw==CON_GETSPRITE || tw==CON_GETTSPR) C_GetNextVarType(GAMEVAR_READONLY); else C_GetNextVar(); break; } case CON_GAMEVAR: // syntax: gamevar // defines var1 and sets initial value. // flags are used to define usage // (see top of this files for flags) //printf("Got gamedef. Getting Label. '%.20s'\n",textptr); if (isdigit(*textptr) || (*textptr == '-')) { C_GetNextLabelName(); g_numCompilerErrors++; C_ReportError(ERROR_SYNTAXERROR); C_GetNextValue(LABEL_DEFINE); C_GetNextValue(LABEL_DEFINE); g_scriptPtr -= 3; // we complete the process anyways just to skip past the fucked up section return 0; } C_GetNextLabelName(); //printf("Got Label '%.20s'\n",textptr); // Check to see it's already defined if (hash_find(&keywH, tlabel)>=0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return 0; } C_GetNextValue(LABEL_DEFINE); // get initial value C_GetNextValue(LABEL_DEFINE); // get flags //Bsprintf(g_szBuf,"Adding GameVar='%s', val=%l, flags=%lX",label+(g_numLabels*MAXLABELLEN), *(g_scriptPtr-2), *(g_scriptPtr-1)); AddLog(g_szBuf); /// if ((*(g_scriptPtr-1)&GAMEVAR_USER_MASK)==3) /// { /// g_numCompilerWarnings++; /// *(g_scriptPtr-1) ^= GAMEVAR_PERBLOCK; /// C_ReportError(WARNING_BADGAMEVAR); /// } Gv_NewVar(tlabel, *(g_scriptPtr-2), /* can't define default or secret */ *(g_scriptPtr-1) & ~(GAMEVAR_DEFAULT|GAMEVAR_SECRET)); //AddLog("Added gamevar"); g_scriptPtr -= 3; // no need to save in script... return 0; // *** arrays case CON_GAMEARRAY: if (isdigit(*textptr) || (*textptr == '-')) { C_GetNextLabelName(); g_numCompilerErrors++; C_ReportError(ERROR_SYNTAXERROR); C_GetNextValue(LABEL_DEFINE); C_GetNextValue(LABEL_DEFINE); g_scriptPtr -= 2; // we complete the process anyways just to skip past the fucked up section return 0; } C_GetNextLabelName(); //printf("Got Label '%.20s'\n",textptr); // Check to see it's already defined if (hash_find(&keywH, tlabel) >= 0) { g_numCompilerErrors++; C_ReportError(ERROR_ISAKEYWORD); return 0; } if (hash_find(&gamevarH, tlabel) >= 0) { g_numCompilerWarnings++; C_ReportError(WARNING_NAMEMATCHESVAR); } C_GetNextValue(LABEL_DEFINE); Gv_NewArray(tlabel, 0, *(g_scriptPtr-1), GAMEARRAY_NORMAL); g_scriptPtr -= 2; // no need to save in script... return 0; case CON_COPY: C_GetNextLabelName(); i = GetGamearrayID(tlabel); if (i >= 0) *g_scriptPtr++ = i; else { C_ReportError(ERROR_NOTAGAMEARRAY); g_numCompilerErrors++; } C_SkipComments();// skip comments and whitespace if (*textptr != '[') { g_numCompilerErrors++; C_ReportError(ERROR_GAMEARRAYBNO); return 1; } textptr++; C_GetNextVar(); C_SkipComments();// skip comments and whitespace if (*textptr != ']') { g_numCompilerErrors++; C_ReportError(ERROR_GAMEARRAYBNC); return 1; } textptr++; case CON_SETARRAY: C_GetNextLabelName(); i = GetGamearrayID(tlabel); if (i >= 0) { *g_scriptPtr++ = i; if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) { C_ReportError(ERROR_ARRAYREADONLY); g_numCompilerErrors++; } } else { C_ReportError(ERROR_NOTAGAMEARRAY); g_numCompilerErrors++; } C_SkipComments();// skip comments and whitespace if (*textptr != '[') { g_numCompilerErrors++; C_ReportError(ERROR_GAMEARRAYBNO); return 1; } textptr++; C_GetNextVar(); C_SkipComments();// skip comments and whitespace if (*textptr != ']') { g_numCompilerErrors++; C_ReportError(ERROR_GAMEARRAYBNC); return 1; } textptr++; C_GetNextVar(); return 0; case CON_GETARRAYSIZE: case CON_RESIZEARRAY: C_GetNextLabelName(); i = GetGamearrayID(tlabel); if (i >= 0) { *g_scriptPtr++ = i; if (tw==CON_RESIZEARRAY && (aGameArrays[i].dwFlags&(GAMEARRAY_TYPEMASK))) { C_ReportError(-1); initprintf("%s:%d: error: can't resize system array `%s'.\n",g_szScriptFileName,g_lineNumber,tlabel); g_numCompilerErrors++; } } else { C_ReportError(ERROR_NOTAGAMEARRAY); g_numCompilerErrors++; } C_SkipComments(); C_GetNextVar(); return 0; #if 0 case CON_WRITEARRAYTOFILE: case CON_READARRAYFROMFILE: C_GetNextLabelName(); i = GetGamearrayID(tlabel); if (i > (-1)) { *g_scriptPtr++ = i; } else { C_ReportError(ERROR_NOTAGAMEARRAY); g_numCompilerErrors++; } C_GetNextValue(LABEL_DEFINE); return 0; #endif // *** var ops case CON_RANDVAR: case CON_DISPLAYRANDVAR: case CON_SETVAR: case CON_ADDVAR: case CON_SUBVAR: case CON_MULVAR: case CON_DIVVAR: case CON_MODVAR: case CON_ANDVAR: case CON_ORVAR: case CON_XORVAR: case CON_SHIFTVARL: case CON_SHIFTVARR: { instype *inst = g_scriptPtr-1; const char *tptr = textptr; // syntax: [rand|add|set]var // sets var1 to const1 // adds const1 to var1 (const1 can be negative...) //printf("Found [add|set]var at line= %d\n",g_lineNumber); // get the ID of the DEF C_GetNextVarType(GAMEVAR_READONLY); C_GetNextValue(LABEL_DEFINE); // the number to check against... if (tw == CON_MULVAR && *(g_scriptPtr-1) == -1) { *inst = CON_INV; g_scriptPtr--; return 0; } if (tw == CON_DIVVAR || (tw == CON_MULVAR && *(g_scriptPtr-1) > 0)) { int32_t i = *(g_scriptPtr-1); j = klabs(i); if (C_IntPow2(j)) { *inst = ((tw == CON_DIVVAR) ? CON_SHIFTVARR : CON_SHIFTVARL); *(g_scriptPtr-1) = C_Pow2IntLogBase2(j); // initprintf("%s:%d: replacing multiply/divide with shift\n",g_szScriptFileName,g_lineNumber); if (i == j) return 0; *g_scriptPtr++ = CON_INV + (g_lineNumber<<12); textptr = tptr; C_GetNextVarType(GAMEVAR_READONLY); C_GetNextValue(LABEL_DEFINE); g_scriptPtr--; // initprintf("%s:%d: adding inversion\n",g_szScriptFileName,g_lineNumber); } } } return 0; // *** varvar ops case CON_RANDVARVAR: case CON_DISPLAYRANDVARVAR: case CON_SETVARVAR: case CON_ADDVARVAR: case CON_SUBVARVAR: case CON_MULVARVAR: case CON_DIVVARVAR: case CON_MODVARVAR: case CON_ANDVARVAR: case CON_ORVARVAR: case CON_XORVARVAR: { instype *inst = (g_scriptPtr-1); const char *otextptr; C_GetNextVarType(GAMEVAR_READONLY); otextptr = textptr; g_tooBigConstant = 0; C_GetNextVar(); if (!g_numCompilerErrors && g_tooBigConstant) { textptr = otextptr; g_scriptPtr--; *inst -= (CON_SETVARVAR - CON_SETVAR); C_GetNextValue(LABEL_DEFINE); } return 0; } case CON_SIN: case CON_COS: C_GetNextVarType(GAMEVAR_READONLY); C_GetNextVar(); return 0; // *** random case CON_DISPLAYRAND: // syntax: displayrand // gets rand (not game rand) into C_GetNextVarType(GAMEVAR_READONLY); break; // *** other math case CON_INV: C_GetNextVarType(GAMEVAR_READONLY); return 0; case CON_SQRT: { // syntax sqrt // gets the sqrt of invar into outvar C_GetNextVar(); // target var C_GetNextVarType(GAMEVAR_READONLY); break; } case CON_MULSCALE: C_GetManyVars(4); return 0; case CON_DIST: case CON_LDIST: case CON_GETANGLE: case CON_GETINCANGLE: C_GetNextVarType(GAMEVAR_READONLY); C_GetNextVar(); C_GetNextVar(); return 0; case CON_FOR: // special-purpose iteration { ofstype offset; instype *tscrptr; int32_t how; C_GetNextVarType(GAMEVAR_READONLY|GAMEVAR_SPECIAL); // only simple vars allowed C_GetNextLabelName(); how = hash_find(&iterH, tlabel); if (how < 0) { C_ReportError(-1); initprintf("%s:%d: error: unknown iteration type `%s'.\n",g_szScriptFileName,g_lineNumber,tlabel); g_numCompilerErrors++; return 1; } *g_scriptPtr++ = how; if (how <= ITER_DRAWNSPRITES) {} else C_GetNextVarType(0); offset = g_scriptPtr-script; g_scriptPtr++; //Leave a spot for the location to jump to after completion C_ParseCommand(); tscrptr = (instype *)script+offset; *tscrptr = (g_scriptPtr-script)-offset; // relative offset return 0; } // *** if&while var&varvar case CON_IFVARL: case CON_IFVARLE: case CON_IFVARG: case CON_IFVARGE: case CON_IFVARE: case CON_IFVARN: case CON_IFVARAND: case CON_IFVAROR: case CON_IFVARXOR: case CON_IFVAREITHER: case CON_IFVARBOTH: case CON_WHILEVARN: case CON_WHILEVARL: // --- case CON_IFVARVARL: case CON_IFVARVARLE: case CON_IFVARVARG: case CON_IFVARVARGE: case CON_IFVARVARE: case CON_IFVARVARN: case CON_IFVARVARAND: case CON_IFVARVAROR: case CON_IFVARVARXOR: case CON_IFVARVAREITHER: case CON_IFVARVARBOTH: case CON_WHILEVARVARN: case CON_WHILEVARVARL: // --- case CON_IFHITKEY: case CON_IFHOLDKEY: case CON_IFRND: // vvv if* using current sprite case CON_IFANGDIFFL: case CON_IFSPRITEPAL: case CON_IFACTOR: case CON_IFPDISTL: case CON_IFPDISTG: /// case CON_IFGAPZL: /// case CON_IFFLOORDISTL: /// case CON_IFCEILINGDISTL: /// case CON_IFSOUND: // --- case CON_IFINSIDE: // --- case CON_IFEITHERALT: case CON_IFEITHERCTRL: case CON_IFEITHERSHIFT: case CON_IFAWAYFROMWALL: case CON_IFCANSEE: case CON_IFONWATER: case CON_IFINWATER: case CON_IFOUTSIDE: /// case CON_IFHITSPACE: /// case CON_IFINSPACE: /// case CON_IFINOUTERSPACE: /// case CON_IFCANSEETARGET: /// case CON_IFNOSOUNDS: { ofstype offset; ofstype lastScriptOfs = (g_scriptPtr-script-1); instype *tscrptr; cs.ifElseAborted = 0; if (tw<=CON_WHILEVARL) // careful! check this against order in m32def.h! { C_GetNextVar(); C_GetNextValue(LABEL_DEFINE); // the number to check against... } else if (tw<=CON_WHILEVARVARL) { instype *inst = (g_scriptPtr-1); const char *otextptr; C_GetNextVar(); otextptr = textptr; g_tooBigConstant = 0; C_GetNextVar(); if (!g_numCompilerErrors && g_tooBigConstant) { textptr = otextptr; g_scriptPtr--; *inst -= (CON_IFVARVARL - CON_IFVARL); C_GetNextValue(LABEL_DEFINE); } } else if (tw<=CON_IFPDISTG) /// C_GetNextValue(LABEL_DEFINE); C_GetNextVar(); else if (tw<=CON_IFINSIDE) C_GetManyVars(3); // else {} if (C_CheckMalformedBranch(lastScriptOfs)) return 0; offset = (g_scriptPtr-script); g_scriptPtr++; //Leave a spot for the fail location C_ParseCommand(); if (C_CheckEmptyBranch(tw, lastScriptOfs)) return 0; tscrptr = (instype *)script+offset; *tscrptr = (g_scriptPtr-script)-offset; // relative offset if (tw != CON_WHILEVARN && tw != CON_WHILEVARVARN) { j = C_GetKeyword(); if (j == CON_ELSE || j == CON_LEFTBRACE) cs.checkingIfElse++; } return 0; } // *** BUILD functions case CON_INSERTSPRITE: case CON_DUPSPRITE: case CON_DELETESPRITE: C_GetNextVar(); break; case CON_LASTWALL: C_GetNextVar(); C_GetNextVarType(GAMEVAR_READONLY); break; case CON_UPDATECURSECTNUM: return 0; case CON_UPDATESECTOR: case CON_UPDATESECTORZ: C_GetManyVars(2); if (tw==CON_UPDATESECTORZ) C_GetNextVar(); C_GetNextVarType(GAMEVAR_READONLY); break; case CON_GETZRANGE: C_GetManyVars(4); C_GetManyVarsType(GAMEVAR_READONLY,4); C_GetManyVars(2); break; case CON_HITSCAN: case CON_CANSEE: // get the ID of the DEF C_GetManyVars(tw==CON_CANSEE?8:7); C_GetManyVarsType(GAMEVAR_READONLY,tw==CON_CANSEE?1:6); if (tw==CON_HITSCAN) C_GetNextVar(); break; case CON_CANSEESPR: C_GetManyVars(2); C_GetNextVarType(GAMEVAR_READONLY); break; case CON_NEARTAG: case CON_ROTATEPOINT: C_GetManyVars(5); C_GetManyVarsType(GAMEVAR_READONLY,2); if (tw == CON_NEARTAG) { C_GetManyVarsType(GAMEVAR_READONLY,2); C_GetManyVars(2); } break; case CON_DRAGPOINT: C_GetManyVars(3); return 0; case CON_GETFLORZOFSLOPE: case CON_GETCEILZOFSLOPE: C_GetManyVars(3); C_GetNextVarType(GAMEVAR_READONLY); return 0; case CON_BSETSPRITE: // was CON_SETSPRITE C_GetManyVars(4); break; case CON_SETFIRSTWALL: case CON_CHANGESPRITESTAT: case CON_CHANGESPRITESECT: case CON_HEADSPRITESTAT: case CON_PREVSPRITESTAT: case CON_NEXTSPRITESTAT: case CON_HEADSPRITESECT: case CON_PREVSPRITESECT: case CON_NEXTSPRITESECT: C_GetManyVars(2); return 0; case CON_SECTOROFWALL: C_GetNextVarType(GAMEVAR_READONLY); C_GetNextVar(); return 0; // *** stuff case CON_ADDLOGVAR: // syntax: addlogvar // prints the line number in the log file. C_GetNextVar(); return 0; case CON_ADDLOG: // syntax: addlog // prints the line number in the log file. return 0; case CON_DEBUG: C_GetNextValue(LABEL_DEFINE); return 0; // *** strings case CON_DEFINEQUOTE: case CON_REDEFINEQUOTE: if (tw == CON_DEFINEQUOTE) g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); k = *(g_scriptPtr-1); if (k<0 || k >= MAXQUOTES) { initprintf("%s:%d: error: quote number out of range (0 to %d).\n",g_szScriptFileName,g_lineNumber,MAXQUOTES-1); g_numCompilerErrors++; k = MAXQUOTES; } if (ScriptQuotes[k] == NULL) ScriptQuotes[k] = Bcalloc(MAXQUOTELEN,sizeof(uint8_t)); if (!ScriptQuotes[k]) { Bsprintf(tempbuf,"Failed allocating %" PRIdPTR " byte quote text buffer.",sizeof(uint8_t) * MAXQUOTELEN); g_numCompilerErrors++; return 1; } if (tw == CON_DEFINEQUOTE) g_scriptPtr--; while (*textptr == ' ' || *textptr == '\t') textptr++; if (tw == CON_REDEFINEQUOTE) { if (ScriptQuoteRedefinitions[g_numQuoteRedefinitions] == NULL) ScriptQuoteRedefinitions[g_numQuoteRedefinitions] = Bcalloc(MAXQUOTELEN,sizeof(uint8_t)); if (!ScriptQuoteRedefinitions[g_numQuoteRedefinitions]) { Bsprintf(tempbuf,"Failed allocating %" PRIdPTR " byte quote text buffer.",sizeof(uint8_t) * MAXQUOTELEN); g_numCompilerErrors++; return 1; } } i = 0; while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) { // if (*textptr == '%' && *(textptr+1) == 's') // { // initprintf("%s:%d: error: quote text contains string identifier.\n",g_szScriptFileName,g_lineNumber); // g_numCompilerErrors++; // while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++; // break; // } if (tw == CON_DEFINEQUOTE) *(ScriptQuotes[k]+i) = *textptr; else *(ScriptQuoteRedefinitions[g_numQuoteRedefinitions]+i) = *textptr; textptr++,i++; if (i >= MAXQUOTELEN-1) { initprintf("%s:%d: warning: truncating quote text to %d characters.\n",g_szScriptFileName,g_lineNumber,MAXQUOTELEN-1); g_numCompilerWarnings++; while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++; break; } } if (tw == CON_DEFINEQUOTE) *(ScriptQuotes[k]+i) = '\0'; else { *(ScriptQuoteRedefinitions[g_numQuoteRedefinitions]+i) = '\0'; *g_scriptPtr++ = g_numQuoteRedefinitions; g_numQuoteRedefinitions++; } return 0; case CON_QUOTE: case CON_ERRORINS: case CON_PRINTMESSAGE16: C_GetNextVar(); return 0; case CON_PRINTMESSAGE256: C_GetManyVars(3); return 0; case CON_PRINTEXT256: case CON_PRINTEXT16: C_GetManyVars(6); return 0; case CON_GETNUMBER16: case CON_GETNUMBER256: C_GetNextVarType(GAMEVAR_READONLY); C_GetManyVars(2); return 0; case CON_QSPRINTF: C_GetManyVars(2); j = 0; while (C_GetKeyword() == -1 && j < 32) C_GetNextVar(), j++; *g_scriptPtr++ = CON_NULLOP + (g_lineNumber<<12); return 0; case CON_QSTRCAT: case CON_QSTRCPY: case CON_QSTRLEN: #if 0 case CON_QGETSYSSTR: C_GetManyVars(2); return 0; #endif case CON_QSTRNCAT: C_GetManyVars(3); return 0; case CON_QSUBSTR: C_GetManyVars(4); return 0; // *** findnear* case CON_FINDNEARSPRITE: case CON_FINDNEARSPRITE3D: case CON_FINDNEARSPRITEZ: { // syntax findnearactor // gets the sprite ID of the nearest actor within max dist // that is of into // -1 for none found C_GetNextValue(LABEL_DEFINE); // get C_GetNextValue(LABEL_DEFINE); // get maxdist if (tw==CON_FINDNEARSPRITEZ) C_GetNextValue(LABEL_DEFINE); // target var // get the ID of the DEF C_GetNextVarType(GAMEVAR_READONLY); break; } case CON_FINDNEARSPRITEVAR: case CON_FINDNEARSPRITE3DVAR: case CON_FINDNEARSPRITEZVAR: { C_GetNextValue(LABEL_DEFINE); // get // get the ID of the DEF C_GetNextVar(); if (tw==CON_FINDNEARSPRITEZVAR) C_GetNextVar(); // target var // get the ID of the DEF C_GetNextVarType(GAMEVAR_READONLY); break; } case CON_GETTICKS: C_GetNextVarType(GAMEVAR_READONLY); return 0; case CON_GETTIMEDATE: C_GetManyVarsType(GAMEVAR_READONLY,8); break; case CON_SETASPECT: C_GetNextVar(); // get the ID of the DEF C_GetNextVar(); // get the ID of the DEF return 0; case CON_SPGETLOTAG: case CON_SPGETHITAG: case CON_SECTGETLOTAG: case CON_SECTGETHITAG: case CON_GETTEXTUREFLOOR: case CON_GETTEXTURECEILING: // no paramaters... return 0; case CON_SETI: C_GetNextVar(); return 0; case CON_SIZEAT: C_GetManyVars(2); // C_GetNextValue(LABEL_DEFINE); // C_GetNextValue(LABEL_DEFINE); break; /// case CON_ANGOFF: /// case CON_SOUND: /// case CON_GLOBALSOUND: /// case CON_SOUNDONCE: /// case CON_STOPSOUND: case CON_CSTATOR: case CON_SPRITEPAL: case CON_CACTOR: case CON_CLIPDIST: C_GetNextVar(); return 0; case CON_CSTAT: C_GetNextValue(LABEL_DEFINE); if (*(g_scriptPtr-1) == 32767) { *(g_scriptPtr-1) = 32768; C_ReportError(-1); initprintf("%s:%d: warning: tried to set cstat 32767, using 32768 instead.\n",g_szScriptFileName,g_lineNumber); g_numCompilerWarnings++; } else if ((*(g_scriptPtr-1) & 32) && (*(g_scriptPtr-1) & 16)) { i = *(g_scriptPtr-1); *(g_scriptPtr-1) ^= 48; C_ReportError(-1); initprintf("%s:%d: warning: tried to set cstat %d, using %d instead.\n",g_szScriptFileName,g_lineNumber,i,*(g_scriptPtr-1)); g_numCompilerWarnings++; } return 0; case CON_DRAWLINE16: case CON_DRAWLINE16B: case CON_DRAWCIRCLE16: case CON_DRAWCIRCLE16B: if (cs.parsingEventOfs < 0 && cs.currentStateIdx < 0) { C_ReportError(ERROR_EVENTONLY); g_numCompilerErrors++; } C_GetManyVars((tw==CON_DRAWLINE16||tw==CON_DRAWLINE16B) ? 5 : 4); break; case CON_ROTATESPRITE16: case CON_ROTATESPRITE: if (cs.parsingEventOfs < 0 && cs.currentStateIdx < 0) { C_ReportError(ERROR_EVENTONLY); g_numCompilerErrors++; } // syntax: // int32_t x, int32_t y, int32_t z, short a, short tilenum, int8_t shade, char orientation, x1, y1, x2, y2 // myospal adds char pal C_GetManyVars(12); // get the ID of the DEFs break; case CON_SETGAMEPALETTE: C_GetNextVar(); return 0; } return 0; } /* Anything added with C_AddDefinition() cannot be overwritten in the CONs */ static void C_AddDefinition(const char *lLabel,int32_t lValue, uint8_t lType) { Bstrcpy(label+(g_numLabels*MAXLABELLEN), lLabel); hash_add(&labelH, label+(g_numLabels*MAXLABELLEN), g_numLabels); labeltype[g_numLabels] = lType; labelval[g_numLabels++] = lValue; g_numDefaultLabels++; } static void C_AddDefaultDefinitions(void) { // events must come first and in correct order C_AddDefinition("EVENT_ENTER3DMODE", EVENT_ENTER3DMODE, LABEL_EVENT); C_AddDefinition("EVENT_ANALYZESPRITES", EVENT_ANALYZESPRITES, LABEL_EVENT); C_AddDefinition("EVENT_INSERTSPRITE2D", EVENT_INSERTSPRITE2D, LABEL_EVENT); C_AddDefinition("EVENT_INSERTSPRITE3D", EVENT_INSERTSPRITE3D, LABEL_EVENT); C_AddDefinition("EVENT_DRAW2DSCREEN", EVENT_DRAW2DSCREEN, LABEL_EVENT); C_AddDefinition("EVENT_KEYS2D", EVENT_KEYS2D, LABEL_EVENT); C_AddDefinition("EVENT_KEYS3D", EVENT_KEYS3D, LABEL_EVENT); C_AddDefinition("EVENT_OVERHEADEDITOR", EVENT_OVERHEADEDITOR, LABEL_EVENT); C_AddDefinition("CLIPMASK0", CLIPMASK0, LABEL_DEFINE); C_AddDefinition("CLIPMASK1", CLIPMASK1, LABEL_DEFINE); C_AddDefinition("MAXSPRITES", MAXSPRITES, LABEL_DEFINE); C_AddDefinition("MAXSECTORS", MAXSECTORS, LABEL_DEFINE); C_AddDefinition("MAXWALLS", MAXWALLS, LABEL_DEFINE); C_AddDefinition("MAXTILES", MAXTILES, LABEL_DEFINE); // keys C_AddDefinition("KEY_SPACE", KEYSC_SPACE, LABEL_DEFINE); C_AddDefinition("KEY_A", KEYSC_A, LABEL_DEFINE); C_AddDefinition("KEY_B", KEYSC_B, LABEL_DEFINE); C_AddDefinition("KEY_C", KEYSC_C, LABEL_DEFINE); C_AddDefinition("KEY_D", KEYSC_D, LABEL_DEFINE); C_AddDefinition("KEY_E", KEYSC_E, LABEL_DEFINE); C_AddDefinition("KEY_F", KEYSC_F, LABEL_DEFINE); C_AddDefinition("KEY_G", KEYSC_G, LABEL_DEFINE); C_AddDefinition("KEY_H", KEYSC_H, LABEL_DEFINE); C_AddDefinition("KEY_I", KEYSC_I, LABEL_DEFINE); C_AddDefinition("KEY_J", KEYSC_J, LABEL_DEFINE); C_AddDefinition("KEY_K", KEYSC_K, LABEL_DEFINE); C_AddDefinition("KEY_L", KEYSC_L, LABEL_DEFINE); C_AddDefinition("KEY_M", KEYSC_M, LABEL_DEFINE); C_AddDefinition("KEY_N", KEYSC_N, LABEL_DEFINE); C_AddDefinition("KEY_O", KEYSC_O, LABEL_DEFINE); C_AddDefinition("KEY_P", KEYSC_P, LABEL_DEFINE); C_AddDefinition("KEY_Q", KEYSC_Q, LABEL_DEFINE); C_AddDefinition("KEY_R", KEYSC_R, LABEL_DEFINE); C_AddDefinition("KEY_S", KEYSC_S, LABEL_DEFINE); C_AddDefinition("KEY_T", KEYSC_T, LABEL_DEFINE); C_AddDefinition("KEY_U", KEYSC_U, LABEL_DEFINE); C_AddDefinition("KEY_V", KEYSC_V, LABEL_DEFINE); C_AddDefinition("KEY_W", KEYSC_W, LABEL_DEFINE); C_AddDefinition("KEY_X", KEYSC_X, LABEL_DEFINE); C_AddDefinition("KEY_Y", KEYSC_Y, LABEL_DEFINE); C_AddDefinition("KEY_Z", KEYSC_Z, LABEL_DEFINE); C_AddDefinition("KEY_ENTER", KEYSC_ENTER, LABEL_DEFINE); C_AddDefinition("KEY_BS", KEYSC_BS, LABEL_DEFINE); C_AddDefinition("KEY_TAB", KEYSC_TAB, LABEL_DEFINE); C_AddDefinition("KEY_0", KEYSC_0, LABEL_DEFINE); C_AddDefinition("KEY_1", KEYSC_1, LABEL_DEFINE); C_AddDefinition("KEY_2", KEYSC_2, LABEL_DEFINE); C_AddDefinition("KEY_3", KEYSC_3, LABEL_DEFINE); C_AddDefinition("KEY_4", KEYSC_4, LABEL_DEFINE); C_AddDefinition("KEY_5", KEYSC_5, LABEL_DEFINE); C_AddDefinition("KEY_6", KEYSC_6, LABEL_DEFINE); C_AddDefinition("KEY_7", KEYSC_7, LABEL_DEFINE); C_AddDefinition("KEY_8", KEYSC_8, LABEL_DEFINE); C_AddDefinition("KEY_9", KEYSC_9, LABEL_DEFINE); C_AddDefinition("KEY_DASH", KEYSC_DASH, LABEL_DEFINE); C_AddDefinition("KEY_EQUAL", KEYSC_EQUAL, LABEL_DEFINE); C_AddDefinition("KEY_LBRACK", KEYSC_LBRACK, LABEL_DEFINE); C_AddDefinition("KEY_RBRACK", KEYSC_RBRACK, LABEL_DEFINE); C_AddDefinition("KEY_SEMI", KEYSC_SEMI, LABEL_DEFINE); C_AddDefinition("KEY_QUOTE", KEYSC_QUOTE, LABEL_DEFINE); C_AddDefinition("KEY_BQUOTE", KEYSC_BQUOTE, LABEL_DEFINE); C_AddDefinition("KEY_BSLASH", KEYSC_BSLASH, LABEL_DEFINE); C_AddDefinition("KEY_COMMA", KEYSC_COMMA, LABEL_DEFINE); C_AddDefinition("KEY_PERIOD", KEYSC_PERIOD, LABEL_DEFINE); C_AddDefinition("KEY_SLASH", KEYSC_SLASH, LABEL_DEFINE); C_AddDefinition("KEY_LALT", KEYSC_LALT, LABEL_DEFINE); C_AddDefinition("KEY_LCTRL", KEYSC_LCTRL, LABEL_DEFINE); C_AddDefinition("KEY_LSHIFT", KEYSC_LSHIFT, LABEL_DEFINE); C_AddDefinition("KEY_RALT", KEYSC_RALT, LABEL_DEFINE); C_AddDefinition("KEY_RCTRL", KEYSC_RCTRL, LABEL_DEFINE); C_AddDefinition("KEY_RSHIFT", KEYSC_RSHIFT, LABEL_DEFINE); C_AddDefinition("KEY_gDEL", KEYSC_gDEL, LABEL_DEFINE); C_AddDefinition("KEY_gDOWN", KEYSC_gDOWN, LABEL_DEFINE); C_AddDefinition("KEY_gEND", KEYSC_gEND, LABEL_DEFINE); C_AddDefinition("KEY_gHOME", KEYSC_gHOME, LABEL_DEFINE); C_AddDefinition("KEY_gINS", KEYSC_gINS, LABEL_DEFINE); C_AddDefinition("KEY_gKP5", KEYSC_gKP5, LABEL_DEFINE); C_AddDefinition("KEY_gLEFT", KEYSC_gLEFT, LABEL_DEFINE); C_AddDefinition("KEY_gMINUS", KEYSC_gMINUS, LABEL_DEFINE); C_AddDefinition("KEY_gPGDN", KEYSC_gPGDN, LABEL_DEFINE); C_AddDefinition("KEY_gPGUP", KEYSC_gPGUP, LABEL_DEFINE); C_AddDefinition("KEY_gPLUS", KEYSC_gPLUS, LABEL_DEFINE); C_AddDefinition("KEY_gRIGHT", KEYSC_gRIGHT, LABEL_DEFINE); C_AddDefinition("KEY_gSLASH", KEYSC_gSLASH, LABEL_DEFINE); C_AddDefinition("KEY_gSTAR", KEYSC_gSTAR, LABEL_DEFINE); C_AddDefinition("KEY_gUP", KEYSC_gUP, LABEL_DEFINE); C_AddDefinition("KEY_HOME", KEYSC_HOME, LABEL_DEFINE); C_AddDefinition("KEY_UP", KEYSC_UP, LABEL_DEFINE); C_AddDefinition("KEY_PGUP", KEYSC_PGUP, LABEL_DEFINE); C_AddDefinition("KEY_LEFT", KEYSC_LEFT, LABEL_DEFINE); C_AddDefinition("KEY_RIGHT", KEYSC_RIGHT, LABEL_DEFINE); C_AddDefinition("KEY_END", KEYSC_END, LABEL_DEFINE); C_AddDefinition("KEY_DOWN", KEYSC_DOWN, LABEL_DEFINE); C_AddDefinition("KEY_PGDN", KEYSC_PGDN, LABEL_DEFINE); C_AddDefinition("KEY_INSERT", KEYSC_INSERT, LABEL_DEFINE); C_AddDefinition("KEY_DELETE", KEYSC_DELETE, LABEL_DEFINE); // end keys // C_AddDefinition("STR_MAPFILENAME",STR_MAPFILENAME, LABEL_DEFINE); // C_AddDefinition("STR_VERSION",STR_VERSION, LABEL_DEFINE); C_AddDefinition("NO",0, LABEL_DEFINE); C_AddDefinition("COLOR_WHITE",31, LABEL_DEFINE); } void C_CompilationInfo(void) { int32_t j, k=0; initprintf("Compiled code info: (size=%ld*%d bytes)\n", (unsigned)(g_scriptPtr-script), sizeof(instype)); initprintf(" %d/%d user labels, %d/65536 indirect constants,\n", g_numLabels-g_numDefaultLabels, 65536-g_numDefaultLabels, g_numSavedConstants); initprintf(" %d/%d user variables, %d/%d user arrays\n", g_gameVarCount-g_systemVarCount, MAXGAMEVARS-g_systemVarCount, g_gameArrayCount-g_systemArrayCount, MAXGAMEARRAYS-g_systemArrayCount); for (j=0; j= 0) k++; initprintf(" %d states, %d/%d defined events\n", g_stateCount, k,MAXEVENTS); for (k=0, j=MAXQUOTES-1; j>=0; j--) if (ScriptQuotes[j]) k++; if (k || g_numQuoteRedefinitions) initprintf(" %d/%d quotes, %d/%d quote redefinitions\n", k,MAXQUOTES, g_numQuoteRedefinitions,MAXQUOTES); } void C_Compile(const char *filenameortext, int32_t isfilename) { char *mptr = NULL; static char firstime=1; int32_t i,j; int32_t fs,fp; int32_t startcompiletime; instype* oscriptPtr; int32_t ostateCount = g_stateCount; if (firstime) { label = Bmalloc(label_allocsize * MAXLABELLEN * sizeof(char)); labelval = Bmalloc(label_allocsize * sizeof(int32_t)); labeltype = Bmalloc(label_allocsize * sizeof(uint8_t)); constants = Bmalloc(constants_allocsize * sizeof(int32_t)); statesinfo = Bmalloc(statesinfo_allocsize * sizeof(statesinfo_t)); for (i=0; i= ABORTERRCNT) initprintf("fatal error: too many errors: Aborted\n"); //*script = g_scriptPtr-script; if (mptr) Bfree(mptr); if (g_stateCount > ostateCount) { for (i=0; i=0; i--) /// if (ScriptQuotes[i] == NULL) /// ScriptQuotes[i] = Bcalloc(MAXQUOTELEN,sizeof(uint8_t)); } if (g_numCompilerErrors) { initprintf("--- Found %d errors", g_numCompilerErrors); if (g_numCompilerWarnings) initprintf(", %d warnings.\n", g_numCompilerWarnings); else initprintf(".\n"); } else if (g_numCompilerWarnings) initprintf("--- Found %d warnings.\n", g_numCompilerWarnings); } void C_ReportError(int32_t iError) { if (Bstrcmp(g_szCurrentBlockName, g_szLastBlockName)) { if (cs.parsingEventOfs >= 0 || cs.currentStateIdx >= 0) initprintf("%s: In %s `%s':\n",g_szScriptFileName, cs.parsingEventOfs >= 0 ? "event":"state", g_szCurrentBlockName); else initprintf("%s: At top level:\n", g_szScriptFileName); Bstrcpy(g_szLastBlockName, g_szCurrentBlockName); } switch (iError) { case ERROR_CLOSEBRACKET: initprintf("%s:%d: error: found more `}' than `{' before `%s'.\n", g_szScriptFileName, g_lineNumber, tempbuf); break; case ERROR_EVENTONLY: initprintf("%s:%d: error: `%s' only valid during events.\n", g_szScriptFileName, g_lineNumber, tempbuf); break; case ERROR_EXCEEDSMAXTILES: initprintf("%s:%d: error: `%s' value exceeds MAXTILES. Maximum is %d.\n", g_szScriptFileName, g_lineNumber, tempbuf, MAXTILES-1); break; case ERROR_EXPECTEDKEYWORD: initprintf("%s:%d: error: expected a keyword but found `%s'.\n", g_szScriptFileName, g_lineNumber, tempbuf); break; case ERROR_FOUNDWITHIN: initprintf("%s:%d: error: found `%s' within %s.\n", g_szScriptFileName, g_lineNumber, tempbuf, (cs.parsingEventOfs >= 0)?"an event":"a state"); break; case ERROR_ISAKEYWORD: initprintf("%s:%d: error: symbol `%s' is a keyword.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_NOENDSWITCH: initprintf("%s:%d: error: did not find `endswitch' before `%s'.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_NOTAGAMEDEF: initprintf("%s:%d: error: symbol `%s' is not a game definition.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_NOTAGAMEVAR: initprintf("%s:%d: error: symbol `%s' is not a game variable.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_NOTAGAMEARRAY: initprintf("%s:%d: error: symbol `%s' is not a game array.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_GAMEARRAYBNC: initprintf("%s:%d: error: square brackets for index of game array not closed, expected ] found %c\n", g_szScriptFileName, g_lineNumber, *textptr); break; case ERROR_GAMEARRAYBNO: initprintf("%s:%d: error: square brackets for index of game array not opened, expected [ found %c\n", g_szScriptFileName, g_lineNumber, *textptr); break; case ERROR_INVALIDARRAYWRITE: initprintf("%s:%d: error: arrays can only be written to using `setarray'\n", g_szScriptFileName, g_lineNumber); break; case ERROR_EXPECTEDSIMPLEVAR: initprintf("%s:%d: error: expected a simple gamevar or a constant\n", g_szScriptFileName, g_lineNumber); break; case ERROR_OPENBRACKET: initprintf("%s:%d: error: found more `{' than `}' before `%s'.\n", g_szScriptFileName, g_lineNumber, tempbuf); break; case ERROR_PARAMUNDEFINED: initprintf("%s:%d: error: parameter `%s' is undefined.\n", g_szScriptFileName, g_lineNumber, tempbuf); break; case ERROR_SYMBOLNOTRECOGNIZED: initprintf("%s:%d: error: symbol `%s' is not recognized.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_SYNTAXERROR: initprintf("%s:%d: error: syntax error.\n", g_szScriptFileName, g_lineNumber); break; case ERROR_VARREADONLY: initprintf("%s:%d: error: variable `%s' is read-only.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_ARRAYREADONLY: initprintf("%s:%d: error: array `%s' is read-only.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_VARTYPEMISMATCH: initprintf("%s:%d: error: variable `%s' is of the wrong type.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case ERROR_LABELINUSE: initprintf("%s:%d: error: label `%s' is already in use by a %s.\n", g_szScriptFileName, g_lineNumber, tlabel, g_tw==CON_DEFSTATE?"define":"state"); break; // case WARNING_BADGAMEVAR: // initprintf("%s:%ld: warning: variable `%s' should be either per-player OR per-actor, not both.\n", // g_szScriptFileName, g_lineNumber, tlabel); // break; case WARNING_DUPLICATECASE: initprintf("%s:%ld: warning: duplicate case ignored.\n", g_szScriptFileName, g_lineNumber); break; case WARNING_DUPLICATEDEFINITION: initprintf("%s:%d: warning: duplicate game definition `%s' ignored.\n", g_szScriptFileName, g_lineNumber, tlabel); break; case WARNING_LABELSONLY: initprintf("%s:%d: warning: expected a label, found a constant.\n", g_szScriptFileName, g_lineNumber); break; case WARNING_NAMEMATCHESVAR: initprintf("%s:%d: warning: symbol `%s' already used for game variable.\n", g_szScriptFileName, g_lineNumber, tlabel); case WARNING_CONSTANTBITSIZE: initprintf("%s:%d: warning: constants where gamevars are expected save only 16 bits.\n", g_szScriptFileName,g_lineNumber); break; } }