compiler improvments

New pragmas: option, warning.
New simplified zero division detector.
Fixed const scopes.
Fixed 'assigned to itself' warning on multidimensional array's cell's (invertion operators).
This commit is contained in:
shel 2020-11-26 03:38:06 +04:00
parent 7cb045c688
commit c0844ccfaf
7 changed files with 240 additions and 77 deletions

View File

@ -439,6 +439,11 @@ typedef enum s_optmark {
#endif #endif
#define TAGMASK (~PUBLICTAG) #define TAGMASK (~PUBLICTAG)
typedef enum s_warnmode {
warnDISABLE,
warnENABLE,
warnTOGGLE
} warnmode;
/* interface functions */ /* interface functions */
#if defined __cplusplus #if defined __cplusplus
@ -451,7 +456,9 @@ typedef enum s_optmark {
int pc_compile(int argc, char **argv); int pc_compile(int argc, char **argv);
int pc_addconstant(char *name,cell value,int tag); int pc_addconstant(char *name,cell value,int tag);
int pc_addtag(char *name); int pc_addtag(char *name);
int pc_enablewarning(int number,int enable); int pc_enablewarning(int number,warnmode enable);
void pc_pushwarnings(void);
void pc_popwarnings(void);
/* /*
* Functions called from the compiler (to be implemented by you) * Functions called from the compiler (to be implemented by you)
@ -664,6 +671,8 @@ SC_FUNC void outval(cell val,int newline);
/* function prototypes in SC5.C */ /* function prototypes in SC5.C */
SC_FUNC int error(int number,...) INVISIBLE; SC_FUNC int error(int number,...) INVISIBLE;
SC_FUNC void errorset(int code, int line); SC_FUNC void errorset(int code, int line);
SC_FUNC void warnstack_init(void);
SC_FUNC void warnstack_cleanup(void);
/* function prototypes in SC6.C */ /* function prototypes in SC6.C */
SC_FUNC int assemble(FILE *fout,FILE *fin); SC_FUNC int assemble(FILE *fout,FILE *fin);

View File

@ -656,9 +656,11 @@ int pc_compile(int argc, char *argv[])
error(100,incfname); /* cannot read from ... (fatal error) */ error(100,incfname); /* cannot read from ... (fatal error) */
} /* if */ } /* if */
} /* if */ } /* if */
warnstack_init();
preprocess(); /* fetch first line */ preprocess(); /* fetch first line */
parse(); /* process all input */ parse(); /* process all input */
sc_parsenum++; sc_parsenum++;
warnstack_cleanup();
} while (sc_reparse); } while (sc_reparse);
/* second (or third) pass */ /* second (or third) pass */
@ -723,8 +725,10 @@ int pc_compile(int argc, char *argv[])
else else
plungequalifiedfile(incfname); /* parse implicit include file (again) */ plungequalifiedfile(incfname); /* parse implicit include file (again) */
} /* if */ } /* if */
warnstack_init();
preprocess(); /* fetch first line */ preprocess(); /* fetch first line */
parse(); /* process all input */ parse(); /* process all input */
warnstack_cleanup();
/* inpf is already closed when readline() attempts to pop of a file */ /* inpf is already closed when readline() attempts to pop of a file */
writetrailer(); /* write remaining stuff */ writetrailer(); /* write remaining stuff */
@ -1129,8 +1133,10 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
} /* switch */ } /* switch */
break; break;
case 'e': case 'e':
strncpy(ename,option_value(ptr),_MAX_PATH); /* set name of error file */ if (ename) {
ename[_MAX_PATH-1]='\0'; strncpy(ename,option_value(ptr),_MAX_PATH); /* set name of error file */
ename[_MAX_PATH-1]='\0';
}
break; break;
case 'E': case 'E':
sc_warnings_are_errors = 1; sc_warnings_are_errors = 1;
@ -1163,15 +1169,21 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
sc_listing=TRUE; /* skip second pass & code generation */ sc_listing=TRUE; /* skip second pass & code generation */
break; break;
case 'o': case 'o':
strncpy(oname,option_value(ptr),_MAX_PATH); /* set name of (binary) output file */ if(oname) {
oname[_MAX_PATH-1]='\0'; strncpy(oname,option_value(ptr),_MAX_PATH); /* set name of (binary) output file */
oname[_MAX_PATH-1]='\0';
}
break; break;
case 'p': case 'p':
strncpy(pname,option_value(ptr),_MAX_PATH); /* set name of implicit include file */ if(pname) {
pname[_MAX_PATH-1]='\0'; strncpy(pname,option_value(ptr),_MAX_PATH); /* set name of implicit include file */
pname[_MAX_PATH-1]='\0';
}
break; break;
#if !defined SC_LIGHT #if !defined SC_LIGHT
case 'r': case 'r':
if (!rname)
break;
strncpy(rname,option_value(ptr),_MAX_PATH); /* set name of report file */ strncpy(rname,option_value(ptr),_MAX_PATH); /* set name of report file */
rname[_MAX_PATH-1]='\0'; rname[_MAX_PATH-1]='\0';
sc_makereport=TRUE; sc_makereport=TRUE;
@ -1222,11 +1234,11 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
case 'w': case 'w':
i=(int)strtol(option_value(ptr),(char **)&ptr,10); i=(int)strtol(option_value(ptr),(char **)&ptr,10);
if (*ptr=='-') if (*ptr=='-')
pc_enablewarning(i,0); pc_enablewarning(i,warnDISABLE);
else if (*ptr=='+') else if (*ptr=='+')
pc_enablewarning(i,1); pc_enablewarning(i,warnENABLE);
else if (*ptr=='\0') else if (*ptr=='\0') /* Note: returned by strtol especially */
pc_enablewarning(i,2); pc_enablewarning(i,warnTOGGLE);
break; break;
case 'X': case 'X':
i=atoi(option_value(ptr)); i=atoi(option_value(ptr));
@ -1264,10 +1276,10 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
str[i]='\0'; /* str holds symbol name */ str[i]='\0'; /* str holds symbol name */
i=atoi(ptr+1); i=atoi(ptr+1);
add_constant(str,i,sGLOBAL,0); add_constant(str,i,sGLOBAL,0);
} else { } else if (oname) {
strncpy(str,argv[arg],sizeof(str)-5); /* -5 because default extension is 4 characters */ strncpy(str,argv[arg],sizeof(str)-5); /* -5 because default extension is 4 characters */
str[sizeof(str)-5]='\0'; str[sizeof(str)-5]='\0';
set_extension(str,".p",FALSE); set_extension(str,".sma",FALSE); /* add default extension if it doesn't exist */
insert_sourcefile(str); insert_sourcefile(str);
/* The output name is the first input name with a different extension, /* The output name is the first input name with a different extension,
* but it is stored in a different directory * but it is stored in a different directory
@ -1296,6 +1308,18 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
} /* for */ } /* for */
} }
void parsesingleoption(char *argv)
{
/* argv[0] is the program, which we don't need here */
char *args[2] = { 0, argv };
char codepage[MAXCODEPAGE + 1] = { 0 };
codepage[0] = '\0';
parseoptions(2, args, NULL, NULL, NULL, NULL, codepage);
/* need explicit support for codepages */
if (codepage[0] && !cp_set(codepage))
error(108); /* codepage mapping file not found */
}
#if !defined SC_LIGHT #if !defined SC_LIGHT
static void parserespf(char *filename,char *oname,char *ename,char *pname, static void parserespf(char *filename,char *oname,char *ename,char *pname,
char *rname,char *codepage) char *rname,char *codepage)
@ -1462,44 +1486,44 @@ static void about(void)
setcaption(); setcaption();
pc_printf("Usage: pawncc <filename> [filename...] [options]\n\n"); pc_printf("Usage: pawncc <filename> [filename...] [options]\n\n");
pc_printf("Options:\n"); pc_printf("Options:\n");
pc_printf(" -A<num> alignment in bytes of the data segment and the stack\n"); pc_printf(" -A<num> alignment in bytes of the data segment and the stack\n");
pc_printf(" -a output assembler code\n"); pc_printf(" -a output assembler code\n");
#if AMX_COMPACTMARGIN > 2 #if AMX_COMPACTMARGIN > 2
pc_printf(" -C[+/-] compact encoding for output file (default=%c)\n", sc_compress ? '+' : '-'); pc_printf(" -C[+/-] compact encoding for output file (default=%c)\n", sc_compress ? '+' : '-');
#endif #endif
pc_printf(" -c<name> codepage name or number; e.g. 1252 for Windows Latin-1\n"); pc_printf(" -c<name> codepage name or number; e.g. 1252 for Windows Latin-1\n");
#if defined dos_setdrive #if defined dos_setdrive
pc_printf(" -Dpath active directory path\n"); pc_printf(" -Dpath active directory path\n");
#endif #endif
pc_printf(" -d0 no symbolic information, no run-time checks\n"); pc_printf(" -d0 no symbolic information, no run-time checks\n");
pc_printf(" -d1 [default] run-time checks, no symbolic information\n"); pc_printf(" -d1 [default] run-time checks, no symbolic information\n");
pc_printf(" -d2 full debug information and dynamic checking\n"); pc_printf(" -d2 full debug information and dynamic checking\n");
pc_printf(" -d3 full debug information, dynamic checking, no optimization\n"); pc_printf(" -d3 full debug information, dynamic checking, no optimization\n");
pc_printf(" -e<name> set name of error file (quiet compile)\n"); pc_printf(" -e<name> set name of error file (quiet compile)\n");
#if defined __WIN32__ || defined _WIN32 || defined _Windows #if defined __WIN32__ || defined _WIN32 || defined _Windows
pc_printf(" -H<hwnd> window handle to send a notification message on finish\n"); pc_printf(" -H<hwnd> window handle to send a notification message on finish\n");
#endif #endif
pc_printf(" -i<name> path for include files\n"); pc_printf(" -i<name> path for include files\n");
pc_printf(" -l create list file (preprocess only)\n"); pc_printf(" -l create list file (preprocess only)\n");
pc_printf(" -o<name> set base name of (P-code) output file\n"); pc_printf(" -o<name> set base name of (P-code) output file\n");
pc_printf(" -p<name> set name of \"prefix\" file\n"); pc_printf(" -p<name> set name of \"prefix\" file\n");
#if !defined SC_LIGHT #if !defined SC_LIGHT
pc_printf(" -r[name] write cross reference report to console or to specified file\n"); pc_printf(" -r[name] write cross reference report to console or to specified file\n");
#endif #endif
pc_printf(" -S<num> stack/heap size in cells (default=%d)\n",(int)sc_stksize); pc_printf(" -S<num> stack/heap size in cells (default=%d)\n",(int)sc_stksize);
pc_printf(" -s<num> skip lines from the input file\n"); pc_printf(" -s<num> skip lines from the input file\n");
pc_printf(" -sui[+/-] show stack usage info\n"); pc_printf(" -sui[+/-] show stack usage info\n");
pc_printf(" -t<num> TAB indent size (in character positions, default=%d)\n",sc_tabsize); pc_printf(" -t<num> TAB indent size (in character positions, default=%d)\n",sc_tabsize);
pc_printf(" -v<num> verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity); pc_printf(" -v<num> verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity);
pc_printf(" -w<num> disable a specific warning by its number\n"); pc_printf(" -w<num>[+/-] disable a specific warning by its number\n");
pc_printf(" -E treat warnings as errors\n"); pc_printf(" -E treat warnings as errors\n");
pc_printf(" -X<num> abstract machine size limit in bytes\n"); pc_printf(" -X<num> abstract machine size limit in bytes\n");
pc_printf(" -\\ use '\\' for escape characters\n"); pc_printf(" -\\ use '\\' for escape characters\n");
pc_printf(" -^ use '^' for escape characters\n"); pc_printf(" -^ use '^' for escape characters\n");
pc_printf(" -;[+/-] require a semicolon to end each statement (default=%c)\n", sc_needsemicolon ? '+' : '-'); pc_printf(" -;[+/-] require a semicolon to end each statement (default=%c)\n", sc_needsemicolon ? '+' : '-');
pc_printf(" -([+/-] require parantheses for function invocation (default=%c)\n", optproccall ? '-' : '+'); pc_printf(" -([+/-] require parantheses for function invocation (default=%c)\n", optproccall ? '-' : '+');
pc_printf(" sym=val define constant \"sym\" with value \"val\"\n"); pc_printf(" sym=val define constant \"sym\" with value \"val\"\n");
pc_printf(" sym= define constant \"sym\" with value 0\n"); pc_printf(" sym= define constant \"sym\" with value 0\n");
#if defined __WIN32__ || defined _WIN32 || defined _Windows || defined __MSDOS__ #if defined __WIN32__ || defined _WIN32 || defined _Windows || defined __MSDOS__
pc_printf("\nOptions may start with a dash or a slash; the options \"-d0\" and \"/d0\" are\n"); pc_printf("\nOptions may start with a dash or a slash; the options \"-d0\" and \"/d0\" are\n");
pc_printf("equivalent.\n"); pc_printf("equivalent.\n");
@ -1549,7 +1573,7 @@ static void setconstants(void)
#endif #endif
add_constant("charbits",sCHARBITS,sGLOBAL,0); add_constant("charbits",sCHARBITS,sGLOBAL,0);
add_constant("charmin",0,sGLOBAL,0); add_constant("charmin",0,sGLOBAL,0);
add_constant("charmax",~(-1UL << sCHARBITS) - 1,sGLOBAL,0); add_constant("charmax",~((~(ucell)0) << sCHARBITS) - 1,sGLOBAL,0);
add_constant("ucharmax",(1 << (sizeof(cell)-1)*8)-1,sGLOBAL,0); add_constant("ucharmax",(1 << (sizeof(cell)-1)*8)-1,sGLOBAL,0);
add_constant("__Pawn",VERSION_INT,sGLOBAL,0); add_constant("__Pawn",VERSION_INT,sGLOBAL,0);
@ -1944,7 +1968,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst
int numdim; int numdim;
short filenum; short filenum;
symbol *sym; symbol *sym;
constvalue *enumroot; constvalue *enumroot=NULL;
#if !defined NDEBUG #if !defined NDEBUG
cell glbdecl=0; cell glbdecl=0;
#endif #endif
@ -2066,7 +2090,7 @@ static int declloc(int fstatic)
int idxtag[sDIMEN_MAX]; int idxtag[sDIMEN_MAX];
char name[sNAMEMAX+1]; char name[sNAMEMAX+1];
symbol *sym; symbol *sym;
constvalue *enumroot; constvalue *enumroot=NULL;
cell val,size; cell val,size;
char *str; char *str;
value lval = {0}; value lval = {0};
@ -2736,7 +2760,7 @@ static void decl_enum(int vclass)
/* go through all constants */ /* go through all constants */
value=0; /* default starting value */ value=0; /* default starting value */
do { do {
int idxtag,fieldtag; int idxtag,fieldtag=0;
symbol *sym; symbol *sym;
if (matchtoken('}')) { /* quick exit if '}' follows ',' */ if (matchtoken('}')) { /* quick exit if '}' follows ',' */
lexpush(); lexpush();
@ -2812,7 +2836,7 @@ static int getstates(const char *funcname)
fsa=-1; fsa=-1;
do { do {
if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL)) if ((islabel=matchtoken(tLABEL))==0 && !needtoken(tSYMBOL))
break; break;
tokeninfo(&val,&str); tokeninfo(&val,&str);
assert(strlen(str)<sizeof fsaname); assert(strlen(str)<sizeof fsaname);
@ -4458,7 +4482,7 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
errorset(sSETFILE,sym->fnumber); errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber); errorset(sSETLINE,sym->lnumber);
error(204,sym->name); /* value assigned to symbol is never used */ error(204,sym->name); /* value assigned to symbol is never used */
#if 0 // ??? not sure whether it is a good idea to force people use "const" #if 0 // ??? not sure whether it is a good idea to force people use "const" | I guess we should start using this due pawn specification about arrays
} else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY) { } else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY) {
errorset(sSETFILE,sym->fnumber); errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber); errorset(sSETLINE,sym->lnumber);
@ -4664,6 +4688,8 @@ SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag)
/* constant doesn't exist yet, an entry must be created */ /* constant doesn't exist yet, an entry must be created */
sym=addsym(name,val,iCONSTEXPR,vclass,tag,uDEFINE); sym=addsym(name,val,iCONSTEXPR,vclass,tag,uDEFINE);
assert(sym!=NULL); /* fatal error 103 must be given on error */ assert(sym!=NULL); /* fatal error 103 must be given on error */
if (vclass == sLOCAL)
sym->compound = nestlevel;
if (sc_status == statIDLE) if (sc_status == statIDLE)
sym->usage |= uPREDEF; sym->usage |= uPREDEF;
return sym; return sym;
@ -5124,13 +5150,13 @@ static void dofor(void)
assert(stgidx==0); assert(stgidx==0);
index=stgidx; index=stgidx;
stgmark(sSTARTREORDER); stgmark(sSTARTREORDER);
stgmark((char)(sEXPRSTART+0)); /* mark start of 2nd expression in stage */ stgmark((unsigned char)(sEXPRSTART+0)); /* mark start of 2nd expression in stage */
setlabel(skiplab); /* jump to this point after 1st expression */ setlabel(skiplab); /* jump to this point after 1st expression */
if (matchtoken(';')==0) { if (matchtoken(';')==0) {
test(wq[wqEXIT],FALSE,FALSE); /* expression 2 (jump to wq[wqEXIT] if false) */ test(wq[wqEXIT],FALSE,FALSE); /* expression 2 (jump to wq[wqEXIT] if false) */
needtoken(';'); needtoken(';');
} /* if */ } /* if */
stgmark((char)(sEXPRSTART+1)); /* mark start of 3th expression in stage */ stgmark((unsigned char)(sEXPRSTART+1)); /* mark start of 3th expression in stage */
if (matchtoken(')')==0) { if (matchtoken(')')==0) {
doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE); /* expression 3 */ doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE); /* expression 3 */
needtoken(')'); needtoken(')');
@ -5649,7 +5675,7 @@ static void dostate(void)
fsa=0; fsa=0;
if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL)) { if ((islabel=matchtoken(tLABEL))==0 && !needtoken(tSYMBOL)) {
delete_autolisttable(); delete_autolisttable();
return; return;
} /* if */ } /* if */

View File

@ -846,6 +846,8 @@ enum {
* Global variables: iflevel, ifstack (altered) * Global variables: iflevel, ifstack (altered)
* lptr (altered) * lptr (altered)
*/ */
void parsesingleoption(char *argv);
static int command(void) static int command(void)
{ {
int tok,ret; int tok,ret;
@ -1051,10 +1053,11 @@ static int command(void)
!strcmp(str, "explib") || !strcmp(str, "explib") ||
!strcmp(str, "expclass") || !strcmp(str, "expclass") ||
!strcmp(str, "defclasslib") ) { !strcmp(str, "defclasslib") ) {
char name[sNAMEMAX+1],sname[sNAMEMAX+1]; char name[sNAMEMAX+1] = { 0 }, sname[sNAMEMAX + 1];
const char *prefix = ""; const char *prefix = ""; /* it's empty on library only */
sname[0] = '\0'; sname[0] = '\0';
sname[1] = '\0'; sname[1] = '\0';
if (!strcmp(str, "reqlib")) if (!strcmp(str, "reqlib"))
prefix = "?rl_"; prefix = "?rl_";
else if (!strcmp(str, "reqclass")) else if (!strcmp(str, "reqclass"))
@ -1097,7 +1100,7 @@ static int command(void)
pc_addlibtable=FALSE; pc_addlibtable=FALSE;
} else { } else {
/* add the name if it does not yet exist in the table */ /* add the name if it does not yet exist in the table */
char newname[sNAMEMAX+1]; char newname[sNAMEMAX+1] = { 0 };
if (strlen(name) + strlen(prefix) + strlen(sname) <= sNAMEMAX) if (strlen(name) + strlen(prefix) + strlen(sname) <= sNAMEMAX)
{ {
strcpy(newname, prefix); strcpy(newname, prefix);
@ -1190,8 +1193,42 @@ static int command(void)
if (comma) if (comma)
lptr++; lptr++;
} while (comma); } while (comma);
} else if (strcmp(str, "showstackusageinfo")==0) { } else if (strcmp(str,"showstackusageinfo")==0) {
sc_stkusageinfo=TRUE; sc_stkusageinfo=TRUE;
} else if (strcmp(str,"warning")==0) {
int ok=lex(&val,&str) == tSYMBOL;
if (ok) {
if (strcmp(str,"enable")==0 || strcmp(str,"disable")==0) {
cell val;
enum s_warnmode enable=(str[0]=='e') ? warnENABLE : warnDISABLE;
do {
preproc_expr(&val,NULL);
pc_enablewarning(val,enable);
} while (*lptr != '\0');
}
else if (strcmp(str,"push")==0) {
pc_pushwarnings();
}
else if (strcmp(str,"pop")==0) {
pc_popwarnings();
}
else {
ok=FALSE;
} /* if */
}
if (!ok) {
error(207); /* unknown #pragma */
} /* if */
} else if (strcmp(str,"option")==0) {
char name[sNAMEMAX + 1] = { 0 };
int i;
/* first gather all information, start with the tag name */
while (*lptr <= ' ' && *lptr != '\0')
lptr++;
for (i=0; i<sNAMEMAX && *lptr && *lptr>' '; i++,lptr++)
name[i]=*lptr;
name[i] = '\0';
parsesingleoption(name);
} else { } else {
error(207); /* unknown #pragma */ error(207); /* unknown #pragma */
} /* if */ } /* if */

View File

@ -603,6 +603,10 @@ static void plnge2(void (*oper)(void),
} /* if */ } /* if */
/* ??? ^^^ should do same kind of error checking with functions */ /* ??? ^^^ should do same kind of error checking with functions */
/* If we're handling a division operation, make sure the divisor is not zero. */
if ((oper == os_div || oper == os_mod) && lval2->ident == iCONSTEXPR && lval2->constval == 0)
error(89); /* division by zero */
/* check whether an "operator" function is defined for the tag names /* check whether an "operator" function is defined for the tag names
* (a constant expression cannot be optimized in that case) * (a constant expression cannot be optimized in that case)
*/ */
@ -629,6 +633,28 @@ static cell truemodulus(cell a,cell b)
return (a % b + b) % b; return (a % b + b) % b;
} }
static cell flooreddiv(cell a,cell b,int return_remainder)
{
cell q,r;
if (b==0) {
// error(89); /* division by zero */ /* never called on const values, so, moved to plnge2 */
return 0;
} /* if */
/* first implement truncated division in a portable way */
#define IABS(a) ((a)>=0 ? (a) : (-a))
q=IABS(a)/IABS(b);
if ((cell)(a ^ b)<0)
q=-q; /* swap sign if either "a" or "b" is negative (but not both) */
r=a-q*b; /* calculate the matching remainder */
/* now "fiddle" with the values to get floored division */
if (r!=0 && (cell)(r ^ b)<0) {
q--;
r+=b;
} /* if */
return return_remainder ? r : q;
}
static cell calc(cell left,void (*oper)(),cell right,char *boolresult) static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
{ {
if (oper==ob_or) if (oper==ob_or)
@ -662,9 +688,9 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
else if (oper==os_mult) else if (oper==os_mult)
return (left * right); return (left * right);
else if (oper==os_div) else if (oper==os_div)
return (left - truemodulus(left,right)) / right; return flooreddiv(left,right,FALSE);
else if (oper==os_mod) else if (oper==os_mod)
return truemodulus(left,right); return flooreddiv(left,right,TRUE);
else else
error(29); /* invalid expression, assumed 0 (this should never occur) */ error(29); /* invalid expression, assumed 0 (this should never occur) */
return 0; return 0;
@ -749,7 +775,7 @@ static int hier14(value *lval1)
* negative value would do). * negative value would do).
*/ */
for (i=0; i<sDIMEN_MAX; i++) for (i=0; i<sDIMEN_MAX; i++)
arrayidx1[i]=arrayidx2[i]=(cell)(-1UL << (sizeof(cell)*8-1)); arrayidx1[i]=arrayidx2[i]=(cell)((~(ucell)0) << (sizeof(cell)*8-1));
org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */ org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */
if (lval1->arrayidx==NULL) if (lval1->arrayidx==NULL)
lval1->arrayidx=arrayidx1; lval1->arrayidx=arrayidx1;
@ -850,22 +876,23 @@ static int hier14(value *lval1)
{ {
int same=TRUE; int same=TRUE;
assert(lval2.arrayidx==arrayidx2); assert(lval2.arrayidx==arrayidx2);
for (i=0; i<sDIMEN_MAX; i++) for (i=0; i<sDIMEN_MAX; i++) {
same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]); same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]);
}
if (same) if (same)
error(226,lval3.sym->name); /* self-assignment */ error(226,lval3.sym->name); /* self-assignment */
} /* if */ } /* if */
} else { } else {
if (oper){ if (oper) {
rvalue(lval1); rvalue(lval1);
plnge2(oper,hier14,lval1,&lval2); plnge2(oper,hier14,lval1,&lval2);
} else { } else {
/* if direct fetch and simple assignment: no "push" /* if direct fetch and simple assignment: no "push"
* and "pop" needed -> call hier14() directly, */ * and "pop" needed -> call hier14() directly, */
if (hier14(&lval2)) if (hier14(&lval2))
rvalue(&lval2); /* instead of plnge2(). */ rvalue(&lval2); /* instead of plnge2(). */
else if (lval2.ident==iVARIABLE) else if (lval2.ident==iVARIABLE)
lval2.ident=iEXPRESSION;/* mark as "rvalue" if it is not an "lvalue" */ lval2.ident=iEXPRESSION; /* mark as "rvalue" if it is not an "lvalue" */
checkfunction(&lval2); checkfunction(&lval2);
/* check whether lval2 and lval3 (old lval1) refer to the same variable */ /* check whether lval2 and lval3 (old lval1) refer to the same variable */
if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) { if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) {
@ -1011,8 +1038,8 @@ static int hier13(value *lval)
int lvalue=plnge1(hier12,lval); int lvalue=plnge1(hier12,lval);
if (matchtoken('?')) { if (matchtoken('?')) {
int locheap=decl_heap; /* save current heap delta */ int locheap=decl_heap; /* save current heap delta */
long heap1,heap2; /* max. heap delta either branch */ long heap1=0,heap2=0; /* max. heap delta either branch */
valuepair *heaplist_node; valuepair *heaplist_node=NULL;
int flab1=getlabel(); int flab1=getlabel();
int flab2=getlabel(); int flab2=getlabel();
value lval2 = {0}; value lval2 = {0};
@ -1209,6 +1236,8 @@ static int hier2(value *lval)
rvalue(lval); rvalue(lval);
invert(); /* bitwise NOT */ invert(); /* bitwise NOT */
lval->constval=~lval->constval; lval->constval=~lval->constval;
if (lval->ident==iVARIABLE || lval->ident==iARRAYCELL)
lval->ident=iEXPRESSION;
return FALSE; return FALSE;
case '!': /* ! (logical negate) */ case '!': /* ! (logical negate) */
if (hier2(lval)) if (hier2(lval))
@ -1220,6 +1249,8 @@ static int hier2(value *lval)
lneg(); /* 0 -> 1, !0 -> 0 */ lneg(); /* 0 -> 1, !0 -> 0 */
lval->constval=!lval->constval; lval->constval=!lval->constval;
lval->tag=pc_addtag("bool"); lval->tag=pc_addtag("bool");
if (lval->ident==iVARIABLE || lval->ident==iARRAYCELL)
lval->ident=iEXPRESSION;
} /* if */ } /* if */
return FALSE; return FALSE;
case '-': /* unary - (two's complement) */ case '-': /* unary - (two's complement) */
@ -1248,6 +1279,8 @@ static int hier2(value *lval)
} else { } else {
neg(); /* arithmic negation */ neg(); /* arithmic negation */
lval->constval=-lval->constval; lval->constval=-lval->constval;
if (lval->ident==iVARIABLE || lval->ident==iARRAYCELL)
lval->ident=iEXPRESSION;
} /* if */ } /* if */
return FALSE; return FALSE;
case tLABEL: /* tagname override */ case tLABEL: /* tagname override */

View File

@ -1224,6 +1224,10 @@ SC_FUNC void inc(value *lval)
symbol *sym; symbol *sym;
sym=lval->sym; sym=lval->sym;
#if 0 // useless due forcing const usage is disable in sc1.c
if (sym != NULL)
markusage(sym,uWRITTEN);
#endif
if (lval->ident==iARRAYCELL) { if (lval->ident==iARRAYCELL) {
/* indirect increment, address already in PRI */ /* indirect increment, address already in PRI */
stgwrite("\tinc.i\n"); stgwrite("\tinc.i\n");
@ -1282,6 +1286,10 @@ SC_FUNC void dec(value *lval)
symbol *sym; symbol *sym;
sym=lval->sym; sym=lval->sym;
#if 0 // useless due forcing const usage is disable in sc1.c
if (sym != NULL)
markusage(sym,uWRITTEN);
#endif
if (lval->ident==iARRAYCELL) { if (lval->ident==iARRAYCELL) {
/* indirect decrement, address already in PRI */ /* indirect decrement, address already in PRI */
stgwrite("\tdec.i\n"); stgwrite("\tdec.i\n");

View File

@ -107,7 +107,8 @@ static char *errmsg[] = {
/*085*/ "no states are defined for function \"%s\"\n", /*085*/ "no states are defined for function \"%s\"\n",
/*086*/ "unknown automaton \"%s\"\n", /*086*/ "unknown automaton \"%s\"\n",
/*087*/ "unknown state \"%s\" for automaton \"%s\"\n", /*087*/ "unknown state \"%s\" for automaton \"%s\"\n",
/*088*/ "number of arguments does not match definition\n" /*088*/ "number of arguments does not match definition\n",
/*089*/ "division by zero\n"
}; };
static char *fatalmsg[] = { static char *fatalmsg[] = {
@ -168,4 +169,5 @@ static char *warnmsg[] = {
/*232*/ "output file is written, but with compact encoding disabled\n", /*232*/ "output file is written, but with compact encoding disabled\n",
/*233*/ "symbol \"%s\" is marked as deprecated: %s\n", /*233*/ "symbol \"%s\" is marked as deprecated: %s\n",
/*234*/ "recursive function \"%s\"\n", /*234*/ "recursive function \"%s\"\n",
/*235*/ "detected %s with no corresponding %s\n"
}; };

View File

@ -48,7 +48,10 @@
#endif #endif
#define NUM_WARNINGS (sizeof warnmsg / sizeof warnmsg[0]) #define NUM_WARNINGS (sizeof warnmsg / sizeof warnmsg[0])
static unsigned char warndisable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */ static struct s_warnstack {
unsigned char disable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */
struct s_warnstack *next;
} warnstack;
static int errflag; static int errflag;
static int errfile; static int errfile;
@ -90,7 +93,7 @@ static short lastfile;
if (number>=200) { if (number>=200) {
int index=(number-200)/8; int index=(number-200)/8;
int mask=1 << ((number-200)%8); int mask=1 << ((number-200)%8);
if ((warndisable[index] & mask)!=0) if ((warnstack.disable[index] & mask)!=0)
return 0; return 0;
} /* if */ } /* if */
@ -214,32 +217,77 @@ SC_FUNC void errorset(int code,int line)
* o 1 for enable * o 1 for enable
* o 2 for toggle * o 2 for toggle
*/ */
int pc_enablewarning(int number,int enable) int pc_enablewarning(int number,warnmode enable)
{ {
int index; int index;
unsigned char mask; unsigned char mask;
if (number<200) if (number<200)
return FALSE; /* errors and fatal errors cannot be disabled */ return FALSE; /* errors and fatal errors cannot be disabled */
number -= 200; number-=200;
if (number>=NUM_WARNINGS) if (number>=NUM_WARNINGS)
return FALSE; return FALSE;
index=number/8; index=number/8;
mask=(unsigned char)(1 << (number%8)); mask=(unsigned char)(1 << (number%8));
switch (enable) { switch (enable) {
case 0: case warnDISABLE:
warndisable[index] |= mask; warnstack.disable[index] |= mask;
break; break;
case 1: case warnENABLE:
warndisable[index] &= (unsigned char)~mask; warnstack.disable[index] &= (unsigned char)~mask;
break; break;
case 2: case warnTOGGLE:
warndisable[index] ^= mask; warnstack.disable[index] ^= mask;
break; break;
} /* switch */ } /* switch */
return TRUE; return TRUE;
} }
/* pc_pushwarnings()
* Saves currently disabled warnings, used to implement #pragma warning push
*/
void pc_pushwarnings(void)
{
void *p;
p=calloc(sizeof(struct s_warnstack),1);
if (p==NULL)
error(103); /* insufficient memory */
memmove(p,&warnstack,sizeof(struct s_warnstack));
warnstack.next=p;
}
/* pc_popwarnings()
* This function is the reverse of pc_pushwarnings()
*/
void pc_popwarnings(void)
{
void *p=warnstack.next;
if (p==NULL) { /* nothing to do */
error(235,"#pragma warning pop","#pragma warning push");
return;
} /* if */
memmove(&warnstack,p,sizeof(struct s_warnstack));
free(p);
}
SC_FUNC void warnstack_init(void)
{
memset(&warnstack,0,sizeof(warnstack));
}
SC_FUNC void warnstack_cleanup(void)
{
struct s_warnstack *cur=warnstack.next,*next;
if (cur!=NULL)
error(1,"#pragma warning pop","-end of file-");
for (;cur!=NULL;cur=next) {
next=cur->next;
free(cur);
} /* for */
warnstack.next=NULL;
}
#undef SCPACK_TABLE #undef SCPACK_TABLE