diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index dd1b4e85..34f0e739 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -144,6 +144,7 @@ SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" + LinkTimeCodeGeneration="0" TargetMachine="1" /> argcount * sizeof(cell)); + found = (cell *)malloc(pstruct->argcount * sizeof(cell)); + + memset(found, 0, sizeof(cell) * pstruct->argcount); + + + /** + * Lastly, very lastly, we will insert a copy of this variable. + * This is soley to expose the pubvar. + */ + usage = uDEFINE|uREAD|uCONST; + if (fpublic) + { + usage |= uPUBLIC; + } + mysym=addsym(name, 0, iVARIABLE, sGLOBAL, pc_addtag(pstruct->name), usage); + + /* Maybe error with "public struct requires initialization?" */ + if (!needtoken('=')) + { + matchtoken(';'); + return; + } + needtoken('{'); + do + { + structarg_t *arg; + /* Detect early exit */ + if (matchtoken('}')) + { + lexpush(); + break; + } + tok=lex(&val,&str); + if (tok != tSYMBOL) + { + error(1, "-identifier-", str); + continue; + } + arg=pstructs_getarg(pstruct,str); + if (arg == NULL) + { + /* :TODO: change to "Could not find member %s in struct %s" */ + error(31); + } + needtoken('='); + cur_litidx = litidx; + tok=lex(&val,&str); + if (!arg) + { + continue; + } + if (tok == tSTRING) + { + assert(litidx != 0); + if (arg->dimcount != 1) + { + error(48); + } else if (arg->tag != pc_tag_string) { + error(213); + } + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += (litidx-cur_litidx); + found[arg->index] = 1; + } else if (tok == tNUMBER || tok == tRATIONAL) { + /* eat optional 'f' */ + matchtoken('f'); + if (arg->ident != iVARIABLE && arg->ident != iREFERENCE) + { + error(23); + } else { + if (arg->tag == pc_addtag("Float") && tok == tNUMBER || + arg->tag == 0 && tok == tRATIONAL) + { + error(213); + } + if (arg->ident == iVARIABLE) + { + values[arg->index] = val; + } else if (arg->ident == iREFERENCE) { + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += 1; + litadd(val); + cur_litidx = litidx; + } + found[arg->index] = 1; + } + } else if (tok == tSYMBOL) { + symbol *sym = NULL; + for (sym=glbtab.next; sym!=NULL; sym=sym->next) + { + if (sym->vclass != sGLOBAL) + { + continue; + } + if (strcmp(sym->name, str) == 0) + { + if (arg->ident == iREFERENCE && sym->ident != iVARIABLE) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } else if (arg->ident == iARRAY) { + if (sym->ident != iARRAY) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } else { + /* :TODO: We should check dimension sizes here... */ + } + } else if (arg->ident == iREFARRAY) { + if (sym->ident != iARRAY) + { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } + /* :TODO: Check dimension sizes! */ + } else { + /* :TODO: Change to "symbol \"%s\" does not have a matching type */ + error(20, str); + } + if (sym->tag != arg->tag) + { + error(213); + } + sym->usage |= uREAD; + values[arg->index] = sym->addr; + found[arg->index] = 1; + refer_symbol(sym, mysym); + break; + } + } + if (!sym) + { + error(17, str); + } + } else { + error(1, "-identifier-", str); + } + } while (matchtoken(',')); + needtoken('}'); + matchtoken(';'); /* eat up optional semicolon */ + + for (i=0; iargcount; i++) + { + if (!found[i]) + { + structarg_t *arg = pstruct->args[i]; + if (arg->ident == iREFARRAY) + { + values[arg->index] = glb_declared * sizeof(cell); + glb_declared += 1; + litadd(0); + cur_litidx = litidx; + } else if (arg->ident == iVARIABLE) { + values[arg->index] = 0; + } else { + /* :TODO: broken for iARRAY! (unused tho) */ + } + } + } + + mysym->addr = glb_declared * sizeof(cell); + glb_declared += pstruct->argcount; + + for (i=0; iargcount; i++) + { + litadd(values[i]); + } + + begdseg(); + dumplits(); + litidx=0; + + free(found); + free(values); +} + /* declglb - declare global symbols * * Declare a static (global) variable. Global variables are stored in @@ -2612,8 +2824,110 @@ static void decl_const(int vclass) needtoken(tTERM); } -/* dofuncenum - declare function enumerations - * +/* + * declstruct - declare a struct type + */ +static void declstruct(void) +{ + cell val; + char *str; + int tok; + pstruct_t *pstruct; + int size; + + /* get the explicit tag (required!) */ + tok = lex(&val,&str); + if (tok != tSYMBOL) + { + error(93); + } + + if (pstructs_find(str) != NULL) + { + /* :TODO: change to "struct requires unique struct name" */ + error(58); + } + + pstruct = pstructs_add(str); + + needtoken('{'); + do + { + structarg_t arg; + if (matchtoken('}')) + { + /* Quick exit */ + lexpush(); + break; + } + memset(&arg, 0, sizeof(structarg_t)); + tok = lex(&val,&str); + if (tok == tCONST) + { + arg.fconst = 1; + tok = lex(&val,&str); + } + arg.ident = 0; + if (tok == '&') + { + arg.ident = iREFERENCE; + tok = lex(&val,&str); + } + if (tok == tLABEL) + { + arg.tag = pc_addtag(str); + tok = lex(&val,&str); + } + if (tok != tSYMBOL) + { + error(1, "-identifier-", str); + continue; + } + strcpy(arg.name, str); + if (matchtoken('[')) + { + if (arg.ident == iREFERENCE) + { + error(67, arg.name); + } + arg.ident = iARRAY; + do + { + constvalue *enumroot; + int ignore_tag; + if (arg.dimcount == sDIMEN_MAX) + { + error(53); + break; + } + size = needsub(&ignore_tag, &enumroot); + arg.dims[arg.dimcount++] = size; + } while (matchtoken('[')); + /* Handle strings */ + if (arg.tag == pc_tag_string && arg.dims[arg.dimcount-1]) + { + arg.dims[arg.dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); + } + if (arg.dimcount == 1 && !arg.dims[arg.dimcount-1]) + { + arg.ident = iREFARRAY; + } + } else if (!arg.ident) { + arg.ident = iVARIABLE; + } + if (pstructs_addarg(pstruct, &arg) == NULL) + { + /* :TODO: change to "struct member name appears more than once" */ + error(58); + } + } while (matchtoken(',')); + needtoken('}'); + matchtoken(';'); /* eat up optional semicolon */ +} + + +/** + * dofuncenum - declare function enumerations */ static void dofuncenum(void) { @@ -2750,7 +3064,8 @@ static void dofuncenum(void) arg->dimcount += 1; } while (matchtoken('[')); /* Handle strings */ - if (arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + if ((arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + && arg->dims[arg->dimcount-1]) { arg->dims[arg->dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); } diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index a65e684f..a1efb2aa 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1880,7 +1880,7 @@ char *sc_tokens[] = { "assert", "*begin", "break", "case", "chars", "const", "continue", "default", "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto", "if", "native", "new", "decl", "operator", "public", "return", "sizeof", - "sleep", "state", "static", "stock", "switch", "tagof", "*then", "while", + "sleep", "state", "static", "stock", "struct", "switch", "tagof", "*then", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", "#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma", "#tryinclude", "#undef", diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index ec3cc398..e2988d75 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -86,7 +86,7 @@ static char *errmsg[] = { /*045*/ "too many function arguments\n", /*046*/ "unknown array size (variable \"%s\")\n", /*047*/ "array sizes do not match, or destination array is too small\n", -/*048*/ "array dimensions do not match\n", +/*048*/ "array (s do not match\n", /*049*/ "invalid line continuation\n", /*050*/ "invalid range\n", /*051*/ "invalid subscript, use \"[ ]\" operators on major dimensions\n", diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 308bd751..5c5693f6 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -8,6 +8,112 @@ memuse_list_t *heapusage = NULL; memuse_list_t *stackusage = NULL; funcenum_t *firstenum = NULL; funcenum_t *lastenum = NULL; +pstruct_t *firststruct = NULL; +pstruct_t *laststruct = NULL; + +structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member) +{ + int i; + + for (i=0; iargcount; i++) + { + if (strcmp(pstruct->args[i]->name, member) == 0) + { + return pstruct->args[i]; + } + } + + return NULL; +} + +pstruct_t *pstructs_add(const char *name) +{ + pstruct_t *p = (pstruct_t *)malloc(sizeof(pstruct_t)); + + memset(p, 0, sizeof(pstruct_t)); + strcpy(p->name, name); + + if (!firststruct) + { + firststruct = p; + laststruct = p; + } else { + laststruct->next = p; + laststruct = p; + } + + return p; +} + +void pstructs_free() +{ + pstruct_t *p, *next; + + p = firststruct; + while (p) + { + while (p->argcount--) + { + free(p->args[p->argcount]); + } + free(p->args); + next = p->next; + free(p); + p = next; + } + firststruct = NULL; + laststruct = NULL; +} + +pstruct_t *pstructs_find(const char *name) +{ + pstruct_t *p = firststruct; + + while (p) + { + if (strcmp(p->name, name) == 0) + { + return p; + } + p = p->next; + } + + return NULL; +} + +structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg) +{ + structarg_t *newarg; + int i; + + for (i=0; iargcount; i++) + { + if (strcmp(pstruct->args[i]->name, arg->name) == 0) + { + /* Don't allow dup names */ + return NULL; + } + } + + newarg = (structarg_t *)malloc(sizeof(structarg_t)); + + memcpy(newarg, arg, sizeof(structarg_t)); + + if (pstruct->argcount == 0) + { + pstruct->args = (structarg_t **)malloc(sizeof(structarg_t *) * 1); + } else { + pstruct->args = (structarg_t **)realloc( + pstruct->args, + sizeof(structarg_t *) * (pstruct->argcount + 1)); + } + + newarg->offs = pstruct->argcount * sizeof(cell); + newarg->index = pstruct->argcount; + pstruct->args[pstruct->argcount++] = newarg; + + return newarg; +} void funcenums_free() { diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 1e05a2c7..ed4576bf 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -46,6 +46,35 @@ typedef struct funcenum_s struct funcenum_s *next; } funcenum_t; +typedef struct structarg_s +{ + int tag; + int dimcount; + cell dims[sDIMEN_MAX]; + char name[sNAMEMAX+1]; + int fconst; + int ident; + unsigned int offs; + int index; +} structarg_t; + +typedef struct pstruct_s +{ + int argcount; + char name[sNAMEMAX+1]; + structarg_t **args; + struct pstruct_s *next; +} pstruct_t; + +/** + * Pawn Structs + */ +pstruct_t *pstructs_add(const char *name); +void pstructs_free(); +pstruct_t *pstructs_find(const char *name); +structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg); +structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member); + /** * Function enumeration tags */