diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 69a23640..c2104b18 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -1,3 +1,4 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: /* Pawn compiler * * Drafted after the Small-C compiler Version 2.01, originally created @@ -272,6 +273,7 @@ typedef struct { int numdim; int dim[sDIMEN_MAX]; int idxtag[sDIMEN_MAX]; + cell array_size; constvalue *enumroot; // Type information. diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 21613b8c..1377f47c 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -121,8 +121,7 @@ static void attachstatelist(symbol *sym, int state_id); static symbol *funcstub(int fnative, const funcstub_setup_t *setup); static int newfunc(const funcstub_setup_t *setup,int fpublic,int fstatic,int stock,symbol **symp); static int declargs(symbol *sym, int chkshadow, const int *thistag); -static void doarg(char *name,int ident,int offset,int tags[],int numtags, - int fpublic,int fconst,int chkshadow,arginfo *arg); +static void doarg(declinfo_t *decl, int offset, int fpublic, int chkshadow, arginfo *arg); static void make_report(symbol *root,FILE *log,char *sourcefile); static void reduce_referrers(symbol *root); static long max_stacksize(symbol *root,int *recursion); @@ -3271,14 +3270,16 @@ static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags) else lextok(&tok); - type->ident = iVARIABLE; - if (tok.id == tCONST) { + if (type->usage & uCONST) + error(138); type->usage |= uCONST; lextok(&tok); } - if (tok.id == '[') { + // Note: we could have already filled in the prefix array bits below, so we + // check that ident != iARRAY before looking for an open bracket. + if (type->ident != iARRAY && tok.id == '[') { // Not yet supported for return vals. This is allowed with old decls, but // it's a huge hack. For now we forbid it in new code until it works right. if (flags & TYPEFLAG_RETURN) @@ -3291,7 +3292,7 @@ static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags) } type->dim[type->numdim++] = 0; if (!needtoken(']')) - return FALSE; + goto err_out; lextok(&tok); } type->ident = iARRAY; @@ -3330,14 +3331,14 @@ static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags) break; default: error(122); - return FALSE; + goto err_out; } if (flags & TYPEFLAG_ARGUMENT) { if (matchtoken('&')) { if (type->ident == iARRAY) { error(137); - return FALSE; + goto err_out; } type->ident = iREFERENCE; } @@ -3346,6 +3347,11 @@ static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags) type->tags[0] = type->tag; type->numtags = 1; return TRUE; + +err_out: + type->tags[0] = type->tag; + type->numtags = 1; + return FALSE; } static void parse_old_array_dims(declinfo_t *decl, int flags) @@ -3370,11 +3376,11 @@ static void parse_old_array_dims(declinfo_t *decl, int flags) return; } - size = needsub(&type->idxtag[type->numdim], enumrootp); - if (size > INT_MAX) + type->array_size = needsub(&type->idxtag[type->numdim], enumrootp); + if (type->array_size > INT_MAX) error(165); - type->dim[type->numdim++] = (int)size; + type->dim[type->numdim++] = type->array_size; } while (matchtoken('[')); type->ident = iARRAY; @@ -3385,10 +3391,11 @@ static int parse_old_decl(declinfo_t *decl, int flags) token_t tok; typeinfo_t *type = &decl->type; - type->ident = iVARIABLE; - - if (matchtoken(tCONST)) + if (matchtoken(tCONST)) { + if (type->usage & uCONST) + error(138); type->usage |= uCONST; + } if (flags & TYPEFLAG_ARGUMENT) { if (matchtoken('&')) @@ -3413,9 +3420,22 @@ static int parse_old_decl(declinfo_t *decl, int flags) } needtoken(':'); } - } else { + } + + if (type->numtags == 0) { if (matchtoken2(tLABEL, &tok)) type->tags[type->numtags++] = pc_addtag(tok.str); + else + type->tags[type->numtags++] = 0; + } + + // All finished with tag stuff. + type->tag = type->tags[0]; + + // Look for varargs and end early. + if (matchtoken(tELLIPS)) { + type->ident = iVARARGS; + return TRUE; } if (flags & TYPEMASK_NAMED_DECL) { @@ -3430,15 +3450,14 @@ static int parse_old_decl(declinfo_t *decl, int flags) parse_old_array_dims(decl, flags); } - type->tag = type->tags[0]; return TRUE; } -static int parse_new_decl(declinfo_t *decl, int flags) +static int parse_new_decl(declinfo_t *decl, const token_t *first, int flags) { token_t tok; - if (!parse_new_typeexpr(&decl->type, NULL, flags)) + if (!parse_new_typeexpr(&decl->type, first, flags)) return FALSE; if (!expecttoken(tSYMBOL, &tok)) return FALSE; @@ -3465,9 +3484,16 @@ static int parse_new_decl(declinfo_t *decl, int flags) int parse_decl(declinfo_t *decl, int flags) { token_t tok; + token_ident_t ident; memset(decl, 0, sizeof(*decl)); + decl->type.ident = iVARIABLE; + + // Must attempt to match const first, since it's a common prefix. + if (matchtoken(tCONST)) + decl->type.usage |= uCONST; + // If parsing an argument, there are two simple checks for whether this is a // new or old-style declaration. if ((flags & TYPEFLAG_ARGUMENT) && (lexpeek('&') || lexpeek('{'))) @@ -3478,22 +3504,51 @@ int parse_decl(declinfo_t *decl, int flags) return parse_old_decl(decl, flags); // Otherwise, we have to eat a symbol to tell. - if (lextok(&tok) == tSYMBOL) { - if (lexpeek('[') || lexpeek(tSYMBOL)) { + if (matchsymbol(&ident)) { + if (lexpeek(tSYMBOL)) { // A new-style declaration only allows array dims or a symbol name, so // this is a new-style declaration. Make sure to push back the first // symbol. - lexpush(); - return parse_new_decl(decl, flags); + return parse_new_decl(decl, &ident.tok, flags); } - // Push the symbol back, we've got an old-style decl. + if ((flags & TYPEMASK_NAMED_DECL) && matchtoken('[')) { + // If we're not allowing postdims here, then it must be a newdecl. + if (flags & TYPEFLAG_NO_POSTDIMS) { + // Give the '[' and symbol back, since we're going to parse from the start. + lexpush(); + lexpush(); + return parse_new_decl(decl, NULL, flags); + } + + // Oh no - we have to parse array dims before we can tell what kind of + // declarator this is. It could be either: + // "x[] y" (new-style), or + // "y[]," (old-style) + parse_old_array_dims(decl, flags); + + if (matchtoken(tSYMBOL) || matchtoken('&')) { + // This must be a newdecl, "x[] y" or "x[] &y", the latter of which + // is illegal, but we flow it through the right path anyway. + lexpush(); + return parse_new_decl(decl, &ident.tok, flags); + } + + // The most basic - "x[]" and that's it. Well, we know it has no tag and + // we know its name. We might as well just complete the entire decl. + strcpy(decl->name, ident.name); + decl->type.tags[decl->type.numtags++] = 0; + decl->type.tag = decl->type.tags[0]; + return TRUE; + } + + // Give the symbol back to the lexer. This is an old decl. lexpush(); return parse_old_decl(decl, flags); } // All else has failed. Probably got a type keyword. New-style. - return parse_new_decl(decl, flags); + return parse_new_decl(decl, NULL, flags); } void define_constructor(methodmap_t *map, methodmap_method_t *method) @@ -5318,11 +5373,11 @@ static int argcompare(arginfo *a1,arginfo *a2) static int declargs(symbol *sym, int chkshadow, const int *thistag) { char *ptr; - int argcnt,oldargcnt,tok,tags[MAXTAGS],numtags; + int argcnt,oldargcnt,tok; cell val; arginfo arg, *arglist; char name[sNAMEMAX+1]; - int ident,fpublic,fconst; + int ident,fpublic; int idx; /* if the function is already defined earlier, get the number of arguments @@ -5333,9 +5388,6 @@ static int declargs(symbol *sym, int chkshadow, const int *thistag) while (sym->dim.arglist[oldargcnt].ident!=0) oldargcnt++; argcnt=0; /* zero aruments up to now */ - ident=iVARIABLE; - numtags=0; - fconst=FALSE; fpublic = (sym->usage & (uPUBLIC|uSTOCK))!=0; if (thistag && *thistag != -1) { @@ -5370,52 +5422,43 @@ static int declargs(symbol *sym, int chkshadow, const int *thistag) /* the '(' parantheses has already been parsed */ if (!matchtoken(')')){ do { /* there are arguments; process them */ - /* any legal name increases argument count (and stack offset) */ - tok=lex(&val,&ptr); - switch (tok) { - case 0: - /* nothing */ - break; - case '&': - if (ident!=iVARIABLE || numtags>0) - error(1,"-identifier-","&"); - ident=iREFERENCE; - break; - case tCONST: - if (ident!=iVARIABLE || numtags>0) - error(1,"-identifier-","const"); - fconst=TRUE; - break; - case tLABEL: - if (numtags>0) - error(1,"-identifier-","-tagname-"); - tags[0]=pc_addtag(ptr); - numtags=1; - break; - case '{': - if (numtags>0) - error(1,"-identifier-","-tagname-"); - numtags=0; - while (numtags=sMAXARGS) - error(45); /* too many function arguments */ - strcpy(name,ptr); /* save symbol name */ - if (name[0]==PUBLIC_CHAR) - error(56,name); /* function arguments cannot be public */ - if (numtags==0) - tags[numtags++]=0; /* default tag */ + declinfo_t decl; + parse_decl(&decl, TYPEFLAG_ARGUMENT|TYPEFLAG_ENUMROOT); + assert(decl.type.numtags > 0); + + if (decl.type.ident == iVARARGS) { + assert(decl.type.numtags > 0); + if ((sym->usage & uPROTOTYPED)==0) { + /* redimension the argument list, add the entry iVARARGS */ + sym->dim.arglist=(arginfo*)realloc(sym->dim.arglist,(argcnt+2)*sizeof(arginfo)); + if (sym->dim.arglist==0) + error(163); /* insufficient memory */ + memset(&sym->dim.arglist[argcnt+1],0,sizeof(arginfo)); /* keep the list terminated */ + sym->dim.arglist[argcnt].ident=iVARARGS; + sym->dim.arglist[argcnt].hasdefault=FALSE; + sym->dim.arglist[argcnt].defvalue.val=0; + sym->dim.arglist[argcnt].defvalue_tag=0; + sym->dim.arglist[argcnt].numtags=decl.type.numtags; + sym->dim.arglist[argcnt].tags=(int*)malloc(decl.type.numtags*sizeof decl.type.tags[0]); + if (sym->dim.arglist[argcnt].tags==NULL) + error(163); /* insufficient memory */ + memcpy(sym->dim.arglist[argcnt].tags,decl.type.tags,decl.type.numtags*sizeof decl.type.tags[0]); + } else { + if (argcnt>oldargcnt || sym->dim.arglist[argcnt].ident!=iVARARGS) + error(25); /* function definition does not match prototype */ + } /* if */ + argcnt++; + continue; + } + + if (argcnt>=sMAXARGS) + error(45); + if (decl.name[0] == PUBLIC_CHAR) + error(56,name); /* function arguments cannot be public */ + + if (1) { + if (decl.type.ident == iARRAY) + decl.type.ident = iREFARRAY; /* Stack layout: * base + 0*sizeof(cell) == previous "base" * base + 1*sizeof(cell) == function return address @@ -5423,10 +5466,11 @@ static int declargs(symbol *sym, int chkshadow, const int *thistag) * base + 3*sizeof(cell) == first argument of the function * So the offset of each argument is "(argcnt+3) * sizeof(cell)". */ - doarg(name,ident,(argcnt+3)*sizeof(cell),tags,numtags,fpublic,fconst,chkshadow,&arg); - /* :TODO: fix this so stocks that are func pointers can't have default arguments? */ + doarg(&decl,(argcnt+3)*sizeof(cell),fpublic,chkshadow,&arg); + if ((sym->usage & uPUBLIC) && arg.hasdefault) error(59,name); /* arguments of a public function may not have a default value */ + if ((sym->usage & uPROTOTYPED)==0) { /* redimension the argument list, add the entry */ sym->dim.arglist=(arginfo*)realloc(sym->dim.arglist,(argcnt+2)*sizeof(arginfo)); @@ -5447,41 +5491,8 @@ static int declargs(symbol *sym, int chkshadow, const int *thistag) free(arg.tags); } /* if */ argcnt++; - ident=iVARIABLE; - numtags=0; - fconst=FALSE; - break; - case tELLIPS: - if (ident!=iVARIABLE) - error(10); /* illegal function or declaration */ - if (numtags==0) - tags[numtags++]=0; /* default tag */ - if ((sym->usage & uPROTOTYPED)==0) { - /* redimension the argument list, add the entry iVARARGS */ - sym->dim.arglist=(arginfo*)realloc(sym->dim.arglist,(argcnt+2)*sizeof(arginfo)); - if (sym->dim.arglist==0) - error(163); /* insufficient memory */ - memset(&sym->dim.arglist[argcnt+1],0,sizeof(arginfo)); /* keep the list terminated */ - sym->dim.arglist[argcnt].ident=iVARARGS; - sym->dim.arglist[argcnt].hasdefault=FALSE; - sym->dim.arglist[argcnt].defvalue.val=0; - sym->dim.arglist[argcnt].defvalue_tag=0; - sym->dim.arglist[argcnt].numtags=numtags; - sym->dim.arglist[argcnt].tags=(int*)malloc(numtags*sizeof tags[0]); - if (sym->dim.arglist[argcnt].tags==NULL) - error(163); /* insufficient memory */ - memcpy(sym->dim.arglist[argcnt].tags,tags,numtags*sizeof tags[0]); - } else { - if (argcnt>oldargcnt || sym->dim.arglist[argcnt].ident!=iVARARGS) - error(25); /* function definition does not match prototype */ - } /* if */ - argcnt++; - break; - default: - error(10); /* illegal function or declaration */ - } /* switch */ - } while (tok=='&' || tok==tLABEL || tok==tCONST - || (tok!=tELLIPS && matchtoken(','))); /* more? */ + } + } while (matchtoken(',')); /* if the next token is not ",", it should be ")" */ needtoken(')'); } /* if */ @@ -5540,50 +5551,29 @@ static int declargs(symbol *sym, int chkshadow, const int *thistag) * "fpublic" indicates whether the function for this argument list is public. * The arguments themselves are never public. */ -static void doarg(char *name,int ident,int offset,int tags[],int numtags, - int fpublic,int fconst,int chkshadow,arginfo *arg) +static void doarg(declinfo_t *decl, int offset, int fpublic, int chkshadow, arginfo *arg) { symbol *argsym; constvalue *enumroot; - cell size; int slength=0; + typeinfo_t *type = &decl->type; - strcpy(arg->name,name); + strcpy(arg->name, decl->name); arg->hasdefault=FALSE; /* preset (most common case) */ arg->defvalue.val=0; /* clear */ arg->defvalue_tag=0; arg->numdim=0; - if (matchtoken('[')) { - if (ident==iREFERENCE) - error(67,name); /* illegal declaration ("&name[]" is unsupported) */ - do { - if (arg->numdim == sDIMEN_MAX) { - error(53); /* exceeding maximum number of dimensions */ - return; - } /* if */ - size=needsub(&arg->idxtag[arg->numdim],&enumroot);/* may be zero here, it is a pointer anyway */ - #if INT_MAX < LONG_MAX - if (size > INT_MAX) - error(165); /* overflow, exceeding capacity */ - #endif - arg->dim[arg->numdim]=(int)size; - arg->numdim+=1; - } while (matchtoken('[')); - ident=iREFARRAY; /* "reference to array" (is a pointer) */ -#if 0 /* For SM, multiple tags including string don't make sense, - so just check the first tag. Done manually so the string - tag isn't matched with the any tag. */ - if (checktag(tags, numtags, pc_tag_string)) { -#endif - assert(tags!=0); - assert(numtags>0); - if (tags[0] == pc_tag_string) { + if (type->ident == iREFARRAY) { + arg->numdim = type->numdim; + memcpy(arg->dim, type->dim, sizeof(int) * type->numdim); + memcpy(arg->idxtag, type->idxtag, sizeof(int) * type->numdim); + assert(type->numtags > 0); + if (type->tags[0] == pc_tag_string) { slength = arg->dim[arg->numdim - 1]; - arg->dim[arg->numdim - 1] = (size + sizeof(cell) - 1) / sizeof(cell); + arg->dim[arg->numdim - 1] = (type->array_size + sizeof(cell) - 1) / sizeof(cell); } if (matchtoken('=')) { assert(litidx==0); /* at the start of a function, this is reset */ - assert(numtags>0); /* Check if there is a symbol */ if (matchtoken(tSYMBOL)) { symbol *sym; @@ -5603,8 +5593,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, } } } else { - initials2(ident,tags[0],&size,arg->dim,arg->numdim,enumroot, 1, 0); - assert(size>=litidx); + initials2(type->ident, type->tags[0], &type->array_size, arg->dim, arg->numdim, type->enumroot, 1, 0); + assert(type->array_size >= litidx); /* allocate memory to hold the initial values */ arg->defvalue.array.data=(cell *)malloc(litidx*sizeof(cell)); if (arg->defvalue.array.data!=NULL) { @@ -5626,7 +5616,7 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, } else { if (matchtoken('=')) { unsigned char size_tag_token; - assert(ident==iVARIABLE || ident==iREFERENCE); + assert(type->ident==iVARIABLE || type->ident==iREFERENCE); arg->hasdefault=TRUE; /* argument has a default value */ size_tag_token=(unsigned char)(matchtoken(tSIZEOF) ? uSIZEOF : 0); if (size_tag_token==0) @@ -5635,8 +5625,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, size_tag_token=(unsigned char)(matchtoken(tCELLSOF) ? uCOUNTOF : 0); if (size_tag_token!=0) { int paranthese; - if (ident==iREFERENCE) - error(66,name); /* argument may not be a reference */ + if (type->ident==iREFERENCE) + error(66, decl->name); /* argument may not be a reference */ paranthese=0; while (matchtoken('(')) paranthese++; @@ -5654,41 +5644,41 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, needtoken(']'); } /* while */ } /* if */ - if (ident==iVARIABLE) /* make sure we set this only if not a reference */ + if (type->ident==iVARIABLE) /* make sure we set this only if not a reference */ arg->hasdefault |= size_tag_token; /* uSIZEOF or uTAGOF */ } /* if */ while (paranthese--) needtoken(')'); } else { constexpr(&arg->defvalue.val,&arg->defvalue_tag,NULL); - assert(numtags>0); - matchtag(tags[0],arg->defvalue_tag,TRUE); + assert(type->numtags > 0); + matchtag(type->tags[0], arg->defvalue_tag, TRUE); } /* if */ } /* if */ } /* if */ - arg->ident=(char)ident; - arg->usage=(char)(fconst ? uCONST : 0); - arg->numtags=numtags; - arg->tags=(int*)malloc(numtags*sizeof tags[0]); + arg->ident=(char)type->ident; + arg->usage=type->usage; + arg->numtags=type->numtags; + arg->tags=(int*)malloc(type->numtags * sizeof(type->tags[0])); if (arg->tags==NULL) error(163); /* insufficient memory */ - memcpy(arg->tags,tags,numtags*sizeof tags[0]); - argsym=findloc(name); + memcpy(arg->tags, type->tags, type->numtags * sizeof(type->tags[0])); + argsym=findloc(decl->name); if (argsym!=NULL) { - error(21,name); /* symbol already defined */ + error(21, decl->name); /* symbol already defined */ } else { - if (chkshadow && (argsym=findglb(name,sSTATEVAR))!=NULL && argsym->ident!=iFUNCTN) - error(219,name); /* variable shadows another symbol */ + if (chkshadow && (argsym=findglb(decl->name,sSTATEVAR))!=NULL && argsym->ident!=iFUNCTN) + error(219, decl->name); /* variable shadows another symbol */ /* add details of type and address */ - assert(numtags>0); - argsym=addvariable2(name,offset,ident,sLOCAL,tags[0], + assert(type->numtags > 0); + argsym=addvariable2(decl->name,offset,type->ident,sLOCAL,type->tags[0], arg->dim,arg->numdim,arg->idxtag,slength); argsym->compound=0; - if (ident==iREFERENCE) + if (type->ident==iREFERENCE) argsym->usage|=uREAD; /* because references are passed back */ if (fpublic) argsym->usage|=uREAD; /* arguments of public functions are always "used" */ - if (fconst) + if (type->usage & uCONST) argsym->usage|=uCONST; } /* if */ } diff --git a/sourcepawn/compiler/sc5.c b/sourcepawn/compiler/sc5.c index e5db4db0..064267c7 100644 --- a/sourcepawn/compiler/sc5.c +++ b/sourcepawn/compiler/sc5.c @@ -75,6 +75,10 @@ static short lastfile; char *msg,*pre; va_list argptr; + if (number == 47) { + printf("EGG\n"); + } + // sErrLine is used to temporarily change the line number of reported errors. // Pawn has an upstream bug where this is not reset on early-return, which // can lead to broken line numbers in error messages.