From e18699c7027ee28c61266ff6f30c01a831bfbb84 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 7 Nov 2006 09:50:09 +0000 Subject: [PATCH] added experimental new String tag. this tag will revert array usage to "char" sizing and packed strings --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40156 --- sourcepawn/compiler/sc.h | 5 +++ sourcepawn/compiler/sc1.c | 31 ++++++++++++--- sourcepawn/compiler/sc2.c | 15 +++++--- sourcepawn/compiler/sc3.c | 80 ++++++++++++++++++++++++++++++--------- sourcepawn/compiler/sc4.c | 4 ++ 5 files changed, 106 insertions(+), 29 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index ecd01dd0..ffac5b94 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -567,9 +567,13 @@ SC_FUNC char *itoh(ucell val); SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam, value *lval,int *resulttag); SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce); +SC_FUNC int checktag(int tags[],int numtags,int exprtag); SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult); SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state); SC_FUNC cell array_totalsize(symbol *sym); +SC_FUNC int matchtag_string(int ident, int tag); +SC_FUNC int checktag_string(value *sym1, value *sym2); +SC_FUNC int checktags_string(int tags[], int numtags, value *sym1); /* function prototypes in SC4.C */ SC_FUNC void writeleader(symbol *root); @@ -809,6 +813,7 @@ SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ SC_VDECL int pc_functag; /* global function tag */ +SC_VDECL int pc_tag_string; /* global string tag */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ SC_VDECL constvalue sc_state_tab; /* state table */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 0188be0f..58d657b1 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -71,6 +71,7 @@ #define VERSION_INT 0x0302 int pc_functag = 0; +int pc_tag_string = 0; static void resetglobals(void); static void initglobals(void); @@ -683,7 +684,7 @@ static void initglobals(void) verbosity=1; /* verbosity level, no copyright banner */ sc_debug=sCHKBOUNDS|sSYMBOLIC; /* sourcemod: full debug stuff */ pc_optimize=sOPTIMIZE_DEFAULT; /* sourcemod: full optimization */ - sc_packstr=FALSE; /* strings are unpacked by default */ + sc_packstr=TRUE; /* strings are packed by default */ sc_compress=FALSE; /* always disable compact encoding! */ sc_needsemicolon=FALSE;/* semicolon required to terminate expressions? */ sc_dataalign=sizeof(cell); @@ -1248,6 +1249,7 @@ static void setconstants(void) append_constval(&tagname_tab,"_",0,0);/* "untagged" */ append_constval(&tagname_tab,"bool",1,0); pc_functag = pc_addfunctag("Function"); + pc_tag_string = pc_addtag("String"); add_constant("true",1,sGLOBAL,1); /* boolean flags */ add_constant("false",0,sGLOBAL,1); @@ -1731,6 +1733,8 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst #endif dim[numdim++]=(int)size; } /* while */ + if (ident == iARRAY && tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); assert(sc_curstates==0); sc_curstates=getstates(name); if (sc_curstates<0) { @@ -1989,6 +1993,9 @@ static int declloc(int fstatic) #endif dim[numdim++]=(int)size; } while (matchtoken('[')); + /* Change the last dimension to be based on chars instead if we have a string */ + if (tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); } else if (matchtoken('(')) { int dim_ident; symbol *dim_sym; @@ -2072,10 +2079,11 @@ static int declloc(int fstatic) /* simple variable, also supports initialization */ int ctag = tag; /* set to "tag" by default */ int explicit_init=FALSE;/* is the variable explicitly initialized? */ + int cident=ident; if (matchtoken('=')) { if (!autozero) error(10); - doexpr(FALSE,FALSE,FALSE,FALSE,&ctag,NULL,TRUE); + cident=doexpr(FALSE,FALSE,FALSE,FALSE,&ctag,NULL,TRUE); explicit_init=TRUE; } else { if (autozero) @@ -2094,7 +2102,7 @@ static int declloc(int fstatic) assert(staging); /* end staging phase (optimize expression) */ stgout(staging_start); stgset(FALSE); - if (!matchtag(tag,ctag,TRUE)) + if (!matchtag_string(cident, ctag) && !matchtag(tag,ctag,TRUE)) error(213); /* tag mismatch */ /* if the variable was not explicitly initialized, reset the * "uWRITTEN" flag that store() set */ @@ -2501,7 +2509,7 @@ static cell init(int ident,int *tag,int *errorfound) error(6); /* must be assigned to an array */ litidx=1; /* reset literal queue */ } /* if */ - *tag=0; + *tag=pc_tag_string; } else if (constexpr(&i,tag,NULL)){ litadd(i); /* store expression result in literal table */ } else { @@ -2702,6 +2710,7 @@ static void dofuncenum(void) } if (matchtoken('[')) { + cell size; if (arg->ident == iREFERENCE) { error(67, str); @@ -2709,7 +2718,6 @@ static void dofuncenum(void) do { constvalue *enumroot; - cell size; int ignore_tag; if (arg->dimcount == sDIMEN_MAX) { @@ -2720,6 +2728,11 @@ static void dofuncenum(void) arg->dims[arg->dimcount] = size; arg->dimcount += 1; } while (matchtoken('[')); + /* Handle strings */ + if (arg->tagcount == 1 && arg->tags[0] == pc_tag_string) + { + arg->dims[arg->dimcount-1] = (size + sizeof(cell)-1) / sizeof(cell); + } arg->ident=iREFARRAY; } else if (arg->ident == 0) { arg->ident = iVARIABLE; @@ -2850,6 +2863,7 @@ static void decl_enum(int vclass) constexpr(&size,&fieldtag,NULL); /* get size */ needtoken(']'); } /* if */ + /* :TODO: do we need a size modifier here for pc_tag_string? */ if (matchtoken('=')) constexpr(&value,NULL,NULL); /* get value */ /* add_constant() checks whether a variable (global or local) or @@ -3355,6 +3369,9 @@ static void funcstub(int fnative) dim[numdim++]=(int)size; } /* while */ + if (tag == pc_tag_string) + dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell); + tok=lex(&val,&str); fpublic=(tok==tPUBLIC) || (tok==tSYMBOL && str[0]==PUBLIC_CHAR); if (fnative) { @@ -3933,6 +3950,8 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, arg->numdim+=1; } while (matchtoken('[')); ident=iREFARRAY; /* "reference to array" (is a pointer) */ + if (checktag(tags, numtags, pc_tag_string)) + arg->dim[arg->numdim - 1] = (size + sizeof(cell) - 1) / sizeof(cell); if (matchtoken('=')) { lexpush(); /* initials() needs the "=" token again */ assert(litidx==0); /* at the start of a function, this is reset */ @@ -5682,7 +5701,7 @@ static void doreturn(void) rettype|=uRETVALUE; /* function returns a value */ /* check tagname with function tagname */ assert(curfunc!=NULL); - if (!matchtag(curfunc->tag,tag,TRUE)) + if (!matchtag_string(ident, tag) && !matchtag(curfunc->tag,tag,TRUE)) error(213); /* tagname mismatch */ if (ident==iARRAY || ident==iREFARRAY) { int dim[sDIMEN_MAX],numdim; diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 93576701..a65e684f 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -1795,7 +1795,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) int i; ucell val,c; - i=sizeof(ucell)-(sCHARBITS/8); /* start at most significant byte */ + i=0; /* start at least significant byte */ val=0; while (*lptr!='\"' && *lptr!='\0') { if (*lptr=='\a') { /* ignore '\a' (which was inserted at a line concatenation) */ @@ -1806,14 +1806,16 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags) if (c>=(ucell)(1 << sCHARBITS)) error(43); /* character constant exceeds range */ val |= (c << 8*i); - if (i==0) { + if (i==sizeof(ucell)-(sCHARBITS/8)) { litadd(val); val=0; - } /* if */ - i=(i+sizeof(ucell)-(sCHARBITS/8)) % sizeof(ucell); + i=0; + } else { + i=i+1; + } } /* if */ /* save last code; make sure there is at least one terminating zero character */ - if (i!=(int)(sizeof(ucell)-(sCHARBITS/8))) + if (i!=0) litadd(val); /* at least one zero character in "val" */ else litadd(0); /* add full cell of zeros */ @@ -1875,7 +1877,7 @@ char *sc_tokens[] = { "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=", "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", - "assert", "*begin", "break", "case", "char", "const", "continue", "default", + "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", @@ -2008,6 +2010,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym) lptr+=1; /* skip double quote */ if ((stringflags & RAWMODE)!=0) lptr+=1; /* skip "escape" character too */ + /* Note that this should always be packedstring() for SourcePawn */ lptr=sc_packstr ? packedstring(lptr,stringflags) : unpackedstring(lptr,stringflags); if (*lptr=='\"') lptr+=1; /* skip final quote */ diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 4e7e47a6..a0a37657 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -282,6 +282,44 @@ static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec }; return TRUE; } +SC_FUNC int checktags_string(int tags[], int numtags, value *sym1) +{ + int i; + if (sym1->ident == iARRAY || sym1->ident == iREFARRAY) + { + return FALSE; + } + for (i=0; itag == pc_tag_string && tags[i] == 0) || + (sym1->tag == 0 && tags[i] == pc_tag_string)) + return TRUE; + } + return FALSE; +} + +SC_FUNC int checktag_string(value *sym1, value *sym2) +{ + if (sym1->ident == iARRAY || sym2->ident == iARRAY + || sym1->ident == iREFARRAY || sym2->ident == iREFARRAY) + { + return FALSE; + } + if ((sym1->tag == pc_tag_string && sym2->tag == 0) + || (sym1->tag == 0 && sym2->tag == pc_tag_string)) + { + return TRUE; + } + + return FALSE; +} + +SC_FUNC int matchtag_string(int ident, int tag) +{ + if (ident == iARRAY || ident == iREFARRAY) + return FALSE; + return (tag == pc_tag_string) ? TRUE : FALSE; +} + SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) { if (formaltag!=actualtag) { @@ -781,7 +819,7 @@ static void plnge2(void (*oper)(void), error(213); /* tagname mismatch */ lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult); } else { - if (!matchtag(lval1->tag,lval2->tag,FALSE)) + if (!checktag_string(lval1, lval2) && !matchtag(lval1->tag,lval2->tag,FALSE)) error(213); /* tagname mismatch */ (*oper)(); /* do the (signed) operation */ lval1->ident=iEXPRESSION; @@ -1205,7 +1243,7 @@ static int hier14(value *lval1) check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag); store(&lval3); /* now, store the expression result */ } /* if */ - if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE)) + if (!oper && !checktag_string(&lval3, &lval2) && !matchtag(lval3.tag,lval2.tag,TRUE)) error(213); /* tagname mismatch (if "oper", warning already given in plunge2()) */ if (lval3.sym) markusage(lval3.sym,uWRITTEN); @@ -1658,6 +1696,10 @@ static int hier2(value *lval) popreg(sPRI); /* restore PRI (result of rvalue()) */ sideeffect=TRUE; return FALSE; +/* This is temporarily disabled because we detect it automatically. + * Thus, it could be weird if both were used at once + */ +#if 0 case tCHAR: /* char (compute required # of cells */ if (lval->ident==iCONSTEXPR) { lval->constval *= sCHARBITS/8; /* from char to bytes */ @@ -1670,6 +1712,7 @@ static int hier2(value *lval) addr2cell(); /* truncate to number of cells */ } /* if */ return FALSE; +#endif default: lexpush(); return lvalue; @@ -1745,7 +1788,7 @@ restart: assert(sym->dim.array.level>=0 && sym->dim.array.levelarrayidx[sym->dim.array.level]=lval2.constval; } /* if */ - if (close==']') { + if (close==']' && !(sym->tag == pc_tag_string && sym->dim.array.level == 0)) { /* normal array index */ if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval) error(32,sym->name); /* array index out of bounds */ @@ -1826,7 +1869,11 @@ restart: } /* if */ assert(sym->dim.array.level==0); /* set type to fetch... INDIRECTLY */ - lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR); + if (sym->tag == pc_tag_string) { + lval1->ident = iARRAYCHAR; + } else { + lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR); + } /* if the array index is a field from an enumeration, get the tag name * from the field and save the size of the field too. Otherwise, the * tag is the one from the array symbol. @@ -2105,7 +2152,7 @@ static int findnamedarg(arginfo *arg,char *name) return -1; } -static int checktag(int tags[],int numtags,int exprtag) +int checktag(int tags[],int numtags,int exprtag) { int i; @@ -2281,12 +2328,8 @@ static int nesting=0; heapalloc+=markheap(MEMUSE_STATIC, 1); nest_stkusage++; } /* if */ - } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION - || lval.ident==iARRAYCHAR) + } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION) { - /* fetch value if needed */ - if (lval.ident==iARRAYCHAR) - rvalue(&lval); /* allocate a cell on the heap and store the * value (already in PRI) there */ setheap_pri(); /* address of the value on the heap in PRI */ @@ -2297,7 +2340,8 @@ static int nesting=0; /* otherwise, the address is already in PRI */ if (lval.sym!=NULL) markusage(lval.sym,uWRITTEN); - if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) + if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) + && !checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) error(213); if (lval.tag!=0) append_constval(&taglst,arg[argidx].name,lval.tag,0); @@ -2311,14 +2355,15 @@ static int nesting=0; /* otherwise, the expression result is already in PRI */ assert(arg[argidx].numtags>0); check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag); - if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) + if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) + && !checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) error(213); if (lval.tag!=0) append_constval(&taglst,arg[argidx].name,lval.tag,0); argidx++; /* argument done */ break; case iREFERENCE: - if (!lvalue || lval.ident==iARRAYCHAR) + if (!lvalue) error(35,argidx+1); /* argument type mismatch */ if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) error(35,argidx+1); /* argument type mismatch */ @@ -2343,7 +2388,7 @@ static int nesting=0; break; case iREFARRAY: if (lval.ident!=iARRAY && lval.ident!=iREFARRAY - && lval.ident!=iARRAYCELL) + && lval.ident!=iARRAYCELL && lval.ident!=iARRAYCHAR) { error(35,argidx+1); /* argument type mismatch */ break; @@ -2354,7 +2399,7 @@ static int nesting=0; * A literal array always has a single dimension. * An iARRAYCELL parameter is also assumed to have a single dimension. */ - if (lval.sym==NULL || lval.ident==iARRAYCELL) { + if (lval.sym==NULL || lval.ident==iARRAYCELL || lval.ident==iARRAYCHAR) { if (arg[argidx].numdim!=1) { error(48); /* array dimensions must match */ } else if (arg[argidx].dim[0]!=0) { @@ -2372,14 +2417,14 @@ static int nesting=0; error(47); /* array sizes must match */ } /* if */ } /* if */ - if (lval.ident!=iARRAYCELL) { + if (lval.ident!=iARRAYCELL && lval.ident!=iARRAYCHAR) { /* save array size, for default values with uSIZEOF flag */ cell array_sz=lval.constval; assert(array_sz!=0);/* literal array must have a size */ if (array_sz<0) array_sz= -array_sz; append_constval(&arrayszlst,arg[argidx].name,array_sz,0); - } /* if */ + }/* if */ } else { symbol *sym=lval.sym; short level=0; @@ -2669,6 +2714,7 @@ static int constant(value *lval) * value distinguishes between literal arrays * and literal strings (this was done for * array assignment). */ + lval->tag=pc_tag_string; } else if (tok=='{') { int tag,lasttag=-1; val=litidx; diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index ff8045c3..509b4e06 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -961,12 +961,16 @@ SC_FUNC void char2addr(void) * The ALIGN.pri/alt instructions must solve this machine dependence; * that is, on Big Endian computers, ALIGN.pri/alt shuold do nothing * and on Little Endian computers they should toggle the address. + * + * NOTE: For Source Pawn, this is fliped. It will do nothing on Little-Endian. */ SC_FUNC void charalign(void) { +#if 0 /* TEMPORARILY DISABLED BECAUSE WE DON'T USE BIG ENDIAN */ stgwrite("\talign.pri "); outval(sCHARBITS/8,TRUE); code_idx+=opcodes(1)+opargs(1); +#endif } /*