sourcepawn/compiler/sc3.c
author Scott Ehlert <ds@alliedmods.net>
Fri Aug 04 03:41:50 2006 +0000 (2006-08-04)
changeset 52 97bdc78041aa
parent 27 764c6dd3dc25
child 62 7c24f0801ae1
permissions -rw-r--r--
Corrected the most annoying spelling mistake ever: depricated -> deprecated
     1 /*  Pawn compiler - Recursive descend expresion parser
     2  *
     3  *  Copyright (c) ITB CompuPhase, 1997-2005
     4  *
     5  *  This software is provided "as-is", without any express or implied warranty.
     6  *  In no event will the authors be held liable for any damages arising from
     7  *  the use of this software.
     8  *
     9  *  Permission is granted to anyone to use this software for any purpose,
    10  *  including commercial applications, and to alter it and redistribute it
    11  *  freely, subject to the following restrictions:
    12  *
    13  *  1.  The origin of this software must not be misrepresented; you must not
    14  *      claim that you wrote the original software. If you use this software in
    15  *      a product, an acknowledgment in the product documentation would be
    16  *      appreciated but is not required.
    17  *  2.  Altered source versions must be plainly marked as such, and must not be
    18  *      misrepresented as being the original software.
    19  *  3.  This notice may not be removed or altered from any source distribution.
    20  *
    21  *  Version: $Id: sc3.c 3598 2006-07-04 13:44:04Z thiadmer $
    22  */
    23 #include <assert.h>
    24 #include <stdio.h>
    25 #include <stdlib.h>     /* for _MAX_PATH */
    26 #include <string.h>
    27 #if defined FORTIFY
    28   #include <alloc/fortify.h>
    29 #endif
    30 #include "sc.h"
    31 
    32 static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
    33                 int (*hier)(value*),value *lval);
    34 static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval);
    35 static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
    36                  char *forcetag,int chkbitwise);
    37 static int plnge1(int (*hier)(value *lval),value *lval);
    38 static void plnge2(void (*oper)(void),
    39                    int (*hier)(value *lval),
    40                    value *lval1,value *lval2);
    41 static cell calc(cell left,void (*oper)(),cell right,char *boolresult);
    42 static int hier14(value *lval);
    43 static int hier13(value *lval);
    44 static int hier12(value *lval);
    45 static int hier11(value *lval);
    46 static int hier10(value *lval);
    47 static int hier9(value *lval);
    48 static int hier8(value *lval);
    49 static int hier7(value *lval);
    50 static int hier6(value *lval);
    51 static int hier5(value *lval);
    52 static int hier4(value *lval);
    53 static int hier3(value *lval);
    54 static int hier2(value *lval);
    55 static int hier1(value *lval1);
    56 static int primary(value *lval);
    57 static void clear_value(value *lval);
    58 static void callfunction(symbol *sym,value *lval_result,int matchparanthesis);
    59 static int dbltest(void (*oper)(),value *lval1,value *lval2);
    60 static int commutative(void (*oper)());
    61 static int constant(value *lval);
    62 
    63 static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */
    64 static int bitwise_opercount;   /* count of bitwise operators in an expression */
    65 static int decl_heap=0;
    66 
    67 /* Function addresses of binary operators for signed operations */
    68 static void (*op1[17])(void) = {
    69   os_mult,os_div,os_mod,        /* hier3, index 0 */
    70   ob_add,ob_sub,                /* hier4, index 3 */
    71   ob_sal,os_sar,ou_sar,         /* hier5, index 5 */
    72   ob_and,                       /* hier6, index 8 */
    73   ob_xor,                       /* hier7, index 9 */
    74   ob_or,                        /* hier8, index 10 */
    75   os_le,os_ge,os_lt,os_gt,      /* hier9, index 11 */
    76   ob_eq,ob_ne,                  /* hier10, index 15 */
    77 };
    78 /* These two functions are defined because the functions inc() and dec() in
    79  * SC4.C have a different prototype than the other code generation functions.
    80  * The arrays for user-defined functions use the function pointers for
    81  * identifying what kind of operation is requested; these functions must all
    82  * have the same prototype. As inc() and dec() are special cases already, it
    83  * is simplest to add two "do-nothing" functions.
    84  */
    85 static void user_inc(void) {}
    86 static void user_dec(void) {}
    87 
    88 /*
    89  *  Searches for a binary operator a list of operators. The list is stored in
    90  *  the array "list". The last entry in the list should be set to 0.
    91  *
    92  *  The index of an operator in "list" (if found) is returned in "opidx". If
    93  *  no operator is found, nextop() returns 0.
    94  *
    95  *  If an operator is found in the expression, it cannot be used in a function
    96  *  call with omitted parantheses. Mark this...
    97  *
    98  *  Global references: sc_allowproccall   (modified)
    99  */
   100 static int nextop(int *opidx,int *list)
   101 {
   102   *opidx=0;
   103   while (*list){
   104     if (matchtoken(*list)){
   105       sc_allowproccall=FALSE;
   106       return TRUE;      /* found! */
   107     } else {
   108       list+=1;
   109       *opidx+=1;
   110     } /* if */
   111   } /* while */
   112   return FALSE;         /* entire list scanned, nothing found */
   113 }
   114 
   115 SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
   116                          value *lval,int *resulttag)
   117 {
   118 static char *binoperstr[] = { "*", "/", "%", "+", "-", "", "", "",
   119                               "", "", "", "<=", ">=", "<", ">", "==", "!=" };
   120 static int binoper_savepri[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   121                                  FALSE, FALSE, FALSE, FALSE, FALSE,
   122                                  TRUE, TRUE, TRUE, TRUE, FALSE, FALSE };
   123 static char *unoperstr[] = { "!", "-", "++", "--" };
   124 static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
   125   char opername[4] = "", symbolname[sNAMEMAX+1];
   126   int i,swapparams,savepri,savealt;
   127   int paramspassed;
   128   symbol *sym;
   129 
   130   /* since user-defined operators on untagged operands are forbidden, we have
   131    * a quick exit.
   132    */
   133   assert(numparam==1 || numparam==2);
   134   if (tag1==0 && (numparam==1 || tag2==0))
   135     return FALSE;
   136 
   137   savepri=savealt=FALSE;
   138   /* find the name with the operator */
   139   if (numparam==2) {
   140     if (oper==NULL) {
   141       /* assignment operator: a special case */
   142       strcpy(opername,"=");
   143       if (lval!=NULL && (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR))
   144         savealt=TRUE;
   145     } else {
   146       assert( (sizeof binoperstr / sizeof binoperstr[0]) == (sizeof op1 / sizeof op1[0]) );
   147       for (i=0; i<sizeof op1 / sizeof op1[0]; i++) {
   148         if (oper==op1[i]) {
   149           strcpy(opername,binoperstr[i]);
   150           savepri=binoper_savepri[i];
   151           break;
   152         } /* if */
   153       } /* for */
   154     } /* if */
   155   } else {
   156     assert(oper!=NULL);
   157     assert(numparam==1);
   158     /* try a select group of unary operators */
   159     assert( (sizeof unoperstr / sizeof unoperstr[0]) == (sizeof unopers / sizeof unopers[0]) );
   160     if (opername[0]=='\0') {
   161       for (i=0; i<sizeof unopers / sizeof unopers[0]; i++) {
   162         if (oper==unopers[i]) {
   163           strcpy(opername,unoperstr[i]);
   164           break;
   165         } /* if */
   166       } /* for */
   167     } /* if */
   168   } /* if */
   169   /* if not found, quit */
   170   if (opername[0]=='\0')
   171     return FALSE;
   172 
   173   /* create a symbol name from the tags and the operator name */
   174   assert(numparam==1 || numparam==2);
   175   operator_symname(symbolname,opername,tag1,tag2,numparam,tag2);
   176   swapparams=FALSE;
   177   sym=findglb(symbolname,sGLOBAL);
   178   if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/) {  /* ??? should not check uDEFINE; first pass clears these bits */
   179     /* check for commutative operators */
   180     if (tag1==tag2 || oper==NULL || !commutative(oper))
   181       return FALSE;             /* not commutative, cannot swap operands */
   182     /* if arrived here, the operator is commutative and the tags are different,
   183      * swap tags and try again
   184      */
   185     assert(numparam==2);        /* commutative operator must be a binary operator */
   186     operator_symname(symbolname,opername,tag2,tag1,numparam,tag1);
   187     swapparams=TRUE;
   188     sym=findglb(symbolname,sGLOBAL);
   189     if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/)
   190       return FALSE;
   191   } /* if */
   192 
   193   /* check existance and the proper declaration of this function */
   194   if ((sym->usage & uMISSING)!=0 || (sym->usage & uPROTOTYPED)==0) {
   195     char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
   196     funcdisplayname(symname,sym->name);
   197     if ((sym->usage & uMISSING)!=0)
   198       error(4,symname);           /* function not defined */
   199     if ((sym->usage & uPROTOTYPED)==0)
   200       error(71,symname);          /* operator must be declared before use */
   201   } /* if */
   202 
   203   /* we don't want to use the redefined operator in the function that
   204    * redefines the operator itself, otherwise the snippet below gives
   205    * an unexpected recursion:
   206    *    fixed:operator+(fixed:a, fixed:b)
   207    *        return a + b
   208    */
   209   if (sym==curfunc)
   210     return FALSE;
   211 
   212   /* for increment and decrement operators, the symbol must first be loaded
   213    * (and stored back afterwards)
   214    */
   215   if (oper==user_inc || oper==user_dec) {
   216     assert(!savepri);
   217     assert(lval!=NULL);
   218     if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
   219       pushreg(sPRI);            /* save current address in PRI */
   220     rvalue(lval);               /* get the symbol's value in PRI */
   221   } /* if */
   222 
   223   assert(!savepri || !savealt); /* either one MAY be set, but not both */
   224   if (savepri) {
   225     /* the chained comparison operators require that the ALT register is
   226      * unmodified, so we save it here; actually, we save PRI because the normal
   227      * instruction sequence (without user operator) swaps PRI and ALT
   228      */
   229     pushreg(sPRI);              /* right-hand operand is in PRI */
   230   } else if (savealt) {
   231     /* for the assignment operator, ALT may contain an address at which the
   232      * result must be stored; this address must be preserved accross the
   233      * call
   234      */
   235     assert(lval!=NULL);         /* this was checked earlier */
   236     assert(lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR); /* checked earlier */
   237     pushreg(sALT);
   238   } /* if */
   239 
   240   /* push parameters, call the function */
   241   paramspassed= (oper==NULL) ? 1 : numparam;
   242   switch (paramspassed) {
   243   case 1:
   244     pushreg(sPRI);
   245     break;
   246   case 2:
   247     /* note that 1) a function expects that the parameters are pushed
   248      * in reversed order, and 2) the left operand is in the secondary register
   249      * and the right operand is in the primary register */
   250     if (swapparams) {
   251       pushreg(sALT);
   252       pushreg(sPRI);
   253     } else {
   254       pushreg(sPRI);
   255       pushreg(sALT);
   256     } /* if */
   257     break;
   258   default:
   259     assert(0);
   260   } /* switch */
   261   markexpr(sPARM,NULL,0);       /* mark the end of a sub-expression */
   262   pushval((cell)paramspassed*sizeof(cell));
   263   assert(sym->ident==iFUNCTN);
   264   ffcall(sym,NULL,paramspassed);
   265   if (sc_status!=statSKIP)
   266     markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
   267   if ((sym->usage & uNATIVE)!=0 && sym->x.lib!=NULL)
   268     sym->x.lib->value += 1;     /* increment "usage count" of the library */
   269   sideeffect=TRUE;              /* assume functions carry out a side-effect */
   270   assert(resulttag!=NULL);
   271   *resulttag=sym->tag;          /* save tag of the called function */
   272 
   273   if (savepri || savealt)
   274     popreg(sALT);               /* restore the saved PRI/ALT that into ALT */
   275   if (oper==user_inc || oper==user_dec) {
   276     assert(lval!=NULL);
   277     if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
   278       popreg(sALT);             /* restore address (in ALT) */
   279     store(lval);                /* store PRI in the symbol */
   280     moveto1();                  /* make sure PRI is restored on exit */
   281   } /* if */
   282   return TRUE;
   283 }
   284 
   285 SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce)
   286 {
   287   if (formaltag!=actualtag) {
   288     /* if the formal tag is zero and the actual tag is not "fixed", the actual
   289      * tag is "coerced" to zero
   290      */
   291     if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0)
   292       return FALSE;
   293   } /* if */
   294   return TRUE;
   295 }
   296 
   297 /*
   298  *  The AMX pseudo-processor has no direct support for logical (boolean)
   299  *  operations. These have to be done via comparing and jumping. Since we are
   300  *  already jumping through the code, we might as well implement an "early
   301  *  drop-out" evaluation (also called "short-circuit"). This conforms to
   302  *  standard C:
   303  *
   304  *  expr1 || expr2           expr2 will only be evaluated if expr1 is false.
   305  *  expr1 && expr2           expr2 will only be evaluated if expr1 is true.
   306  *
   307  *  expr1 || expr2 && expr3  expr2 will only be evaluated if expr1 is false
   308  *                           and expr3 will only be evaluated if expr1 is
   309  *                           false and expr2 is true.
   310  *
   311  *  Code generation for the last example proceeds thus:
   312  *
   313  *      evaluate expr1
   314  *      operator || found
   315  *      jump to "l1" if result of expr1 not equal to 0
   316  *      evaluate expr2
   317  *      ->  operator && found; skip to higher level in hierarchy diagram
   318  *          jump to "l2" if result of expr2 equal to 0
   319  *          evaluate expr3
   320  *          jump to "l2" if result of expr3 equal to 0
   321  *          set expression result to 1 (true)
   322  *          jump to "l3"
   323  *      l2: set expression result to 0 (false)
   324  *      l3:
   325  *      <-  drop back to previous hierarchy level
   326  *      jump to "l1" if result of expr2 && expr3 not equal to 0
   327  *      set expression result to 0 (false)
   328  *      jump to "l4"
   329  *  l1: set expression result to 1 (true)
   330  *  l4:
   331  *
   332  */
   333 
   334 /*  Skim over terms adjoining || and && operators
   335  *  dropval   The value of the expression after "dropping out". An "or" drops
   336  *            out when the left hand is TRUE, so dropval must be 1 on "or"
   337  *            expressions.
   338  *  endval    The value of the expression when no expression drops out. In an
   339  *            "or" expression, this happens when both the left hand and the
   340  *            right hand are FALSE, so endval must be 0 for "or" expressions.
   341  */
   342 static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
   343                 int (*hier)(value*),value *lval)
   344 {
   345   int lvalue,hits,droplab,endlab,opidx;
   346   int allconst,foundop;
   347   cell constval;
   348   int index;
   349   cell cidx;
   350 
   351   stgget(&index,&cidx);         /* mark position in code generator */
   352   hits=FALSE;                   /* no logical operators "hit" yet */
   353   allconst=TRUE;                /* assume all values "const" */
   354   constval=0;
   355   droplab=0;                    /* to avoid a compiler warning */
   356   for ( ;; ) {
   357     lvalue=plnge1(hier,lval);   /* evaluate left expression */
   358 
   359     allconst= allconst && (lval->ident==iCONSTEXPR);
   360     if (allconst) {
   361       if (hits) {
   362         /* one operator was already found */
   363         if (testfunc==jmp_ne0)
   364           lval->constval= lval->constval || constval;
   365         else
   366           lval->constval= lval->constval && constval;
   367       } /* if */
   368       constval=lval->constval;  /* save result accumulated so far */
   369     } /* if */
   370 
   371     foundop=nextop(&opidx,opstr);
   372     if ((foundop || hits) && (lval->ident==iARRAY || lval->ident==iREFARRAY))
   373       error(33, lval->sym ? (lval->sym->name ? lval->sym->name : "-unknown") : "-unknown-");  /* array was not indexed in an expression */
   374     if (foundop) {
   375       if (!hits) {
   376         /* this is the first operator in the list */
   377         hits=TRUE;
   378         droplab=getlabel();
   379       } /* if */
   380       dropout(lvalue,testfunc,droplab,lval);
   381     } else if (hits) {                       /* no (more) identical operators */
   382       dropout(lvalue,testfunc,droplab,lval); /* found at least one operator! */
   383       ldconst(endval,sPRI);
   384       jumplabel(endlab=getlabel());
   385       setlabel(droplab);
   386       ldconst(dropval,sPRI);
   387       setlabel(endlab);
   388       lval->sym=NULL;
   389       lval->tag=pc_addtag("bool");  /* force tag to be "bool" */
   390       if (allconst) {
   391         lval->ident=iCONSTEXPR;
   392         lval->constval=constval;
   393         stgdel(index,cidx);         /* scratch generated code and calculate */
   394       } else {
   395         lval->ident=iEXPRESSION;
   396         lval->constval=0;
   397       } /* if */
   398       return FALSE;
   399     } else {
   400       return lvalue;            /* none of the operators in "opstr" were found */
   401     } /* if */
   402 
   403   } /* while */
   404 }
   405 
   406 /*
   407  *  Reads into the primary register the variable pointed to by lval if
   408  *  plunging through the hierarchy levels detected an lvalue. Otherwise
   409  *  if a constant was detected, it is loaded. If there is no constant and
   410  *  no lvalue, the primary register must already contain the expression
   411  *  result.
   412  *
   413  *  After that, the compare routines "jmp_ne0" or "jmp_eq0" are called, which
   414  *  compare the primary register against 0, and jump to the "early drop-out"
   415  *  label "exit1" if the condition is true.
   416  */
   417 static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval)
   418 {
   419   if (lvalue)
   420     rvalue(lval);
   421   else if (lval->ident==iCONSTEXPR)
   422     ldconst(lval->constval,sPRI);
   423   (*testfunc)(exit1);
   424 }
   425 
   426 static void checkfunction(value *lval)
   427 {
   428   symbol *sym=lval->sym;
   429 
   430   if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
   431     return;             /* no known symbol, or not a function result */
   432 
   433   if ((sym->usage & uDEFINE)!=0) {
   434     /* function is defined, can now check the return value (but make an
   435      * exception for directly recursive functions)
   436      */
   437     if (sym!=curfunc && (sym->usage & uRETVALUE)==0) {
   438       char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
   439       funcdisplayname(symname,sym->name);
   440       error(209,symname);       /* function should return a value */
   441     } /* if */
   442   } else {
   443     /* function not yet defined, set */
   444     sym->usage|=uRETVALUE;      /* make sure that a future implementation of
   445                                  * the function uses "return <value>" */
   446   } /* if */
   447 }
   448 
   449 /*
   450  *  Plunge to a lower level
   451  */
   452 static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
   453                  char *forcetag,int chkbitwise)
   454 {
   455   int lvalue,opidx;
   456   int count;
   457   value lval2 = {0};
   458 
   459   lvalue=plnge1(hier,lval);
   460   if (nextop(&opidx,opstr)==0)
   461     return lvalue;              /* no operator in "opstr" found */
   462   if (lvalue)
   463     rvalue(lval);
   464   count=0;
   465   do {
   466     if (chkbitwise && count++>0 && bitwise_opercount!=0)
   467       error(212);
   468     opidx+=opoff;               /* add offset to index returned by nextop() */
   469     plnge2(op1[opidx],hier,lval,&lval2);
   470     if (op1[opidx]==ob_and || op1[opidx]==ob_or)
   471       bitwise_opercount++;
   472     if (forcetag!=NULL)
   473       lval->tag=pc_addtag(forcetag);
   474   } while (nextop(&opidx,opstr)); /* do */
   475   return FALSE;         /* result of expression is not an lvalue */
   476 }
   477 
   478 /*  plnge_rel
   479  *
   480  *  Binary plunge to lower level; this is very simular to plnge, but
   481  *  it has special code generation sequences for chained operations.
   482  */
   483 static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
   484 {
   485   int lvalue,opidx;
   486   value lval2={0};
   487   int count;
   488 
   489   /* this function should only be called for relational operators */
   490   assert(op1[opoff]==os_le);
   491   lvalue=plnge1(hier,lval);
   492   if (nextop(&opidx,opstr)==0)
   493     return lvalue;              /* no operator in "opstr" found */
   494   if (lvalue)
   495     rvalue(lval);
   496   count=0;
   497   lval->boolresult=TRUE;
   498   do {
   499     /* same check as in plnge(), but "chkbitwise" is always TRUE */
   500     if (count>0 && bitwise_opercount!=0)
   501       error(212);
   502     if (count>0) {
   503       relop_prefix();
   504       *lval=lval2;      /* copy right hand expression of the previous iteration */
   505     } /* if */
   506     opidx+=opoff;
   507     plnge2(op1[opidx],hier,lval,&lval2);
   508     if (count++>0)
   509       relop_suffix();
   510   } while (nextop(&opidx,opstr)); /* enddo */
   511   lval->constval=lval->boolresult;
   512   lval->tag=pc_addtag("bool");    /* force tag to be "bool" */
   513   return FALSE;         /* result of expression is not an lvalue */
   514 }
   515 
   516 /*  plnge1
   517  *
   518  *  Unary plunge to lower level
   519  *  Called by: skim(), plnge(), plnge2(), plnge_rel(), hier14() and hier13()
   520  */
   521 static int plnge1(int (*hier)(value *lval),value *lval)
   522 {
   523   int lvalue,index;
   524   cell cidx;
   525 
   526   stgget(&index,&cidx); /* mark position in code generator */
   527   lvalue=(*hier)(lval);
   528   if (lval->ident==iCONSTEXPR)
   529     stgdel(index,cidx); /* load constant later */
   530   return lvalue;
   531 }
   532 
   533 /*  plnge2
   534  *
   535  *  Binary plunge to lower level
   536  *  Called by: plnge(), plnge_rel(), hier14() and hier1()
   537  */
   538 static void plnge2(void (*oper)(void),
   539                    int (*hier)(value *lval),
   540                    value *lval1,value *lval2)
   541 {
   542   int index;
   543   cell cidx;
   544 
   545   stgget(&index,&cidx);             /* mark position in code generator */
   546   if (lval1->ident==iCONSTEXPR) {   /* constant on left side; it is not yet loaded */
   547     if (plnge1(hier,lval2))
   548       rvalue(lval2);                /* load lvalue now */
   549     else if (lval2->ident==iCONSTEXPR)
   550       ldconst(lval2->constval<<dbltest(oper,lval2,lval1),sPRI);
   551     ldconst(lval1->constval<<dbltest(oper,lval2,lval1),sALT);
   552                    /* ^ doubling of constants operating on integer addresses */
   553                    /*   is restricted to "add" and "subtract" operators */
   554   } else {                          /* non-constant on left side */
   555     pushreg(sPRI);
   556     if (plnge1(hier,lval2))
   557       rvalue(lval2);
   558     if (lval2->ident==iCONSTEXPR) { /* constant on right side */
   559       if (commutative(oper)) {      /* test for commutative operators */
   560         value lvaltmp = {0};
   561         stgdel(index,cidx);         /* scratch pushreg() and constant fetch (then
   562                                      * fetch the constant again */
   563         ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sALT);
   564         /* now, the primary register has the left operand and the secondary
   565          * register the right operand; swap the "lval" variables so that lval1
   566          * is associated with the secondary register and lval2 with the
   567          * primary register, as is the "normal" case.
   568          */
   569         lvaltmp=*lval1;
   570         *lval1=*lval2;
   571         *lval2=lvaltmp;
   572       } else {
   573         ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sPRI);
   574         popreg(sALT);   /* pop result of left operand into secondary register */
   575       } /* if */
   576     } else {            /* non-constants on both sides */
   577       popreg(sALT);
   578       if (dbltest(oper,lval1,lval2))
   579         cell2addr();                    /* double primary register */
   580       if (dbltest(oper,lval2,lval1))
   581         cell2addr_alt();                /* double secondary register */
   582     } /* if */
   583   } /* if */
   584   if (oper) {
   585     /* If used in an expression, a function should return a value.
   586      * If the function has been defined, we can check this. If the
   587      * function was not defined, we can set this requirement (so that
   588      * a future function definition can check this bit.
   589      */
   590     checkfunction(lval1);
   591     checkfunction(lval2);
   592     if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
   593       char *ptr=(lval1->sym!=NULL) ? lval1->sym->name : "-unknown-";
   594       error(33,ptr);                    /* array must be indexed */
   595     } else if (lval2->ident==iARRAY || lval2->ident==iREFARRAY) {
   596       char *ptr=(lval2->sym!=NULL) ? lval2->sym->name : "-unknown-";
   597       error(33,ptr);                    /* array must be indexed */
   598     } /* if */
   599     /* ??? ^^^ should do same kind of error checking with functions */
   600 
   601     /* check whether an "operator" function is defined for the tag names
   602      * (a constant expression cannot be optimized in that case)
   603      */
   604     if (check_userop(oper,lval1->tag,lval2->tag,2,NULL,&lval1->tag)) {
   605       lval1->ident=iEXPRESSION;
   606       lval1->constval=0;
   607     } else if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
   608       /* only constant expression if both constant */
   609       stgdel(index,cidx);       /* scratch generated code and calculate */
   610       if (!matchtag(lval1->tag,lval2->tag,FALSE))
   611         error(213);             /* tagname mismatch */
   612       lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
   613     } else {
   614       if (!matchtag(lval1->tag,lval2->tag,FALSE))
   615         error(213);             /* tagname mismatch */
   616       (*oper)();                /* do the (signed) operation */
   617       lval1->ident=iEXPRESSION;
   618     } /* if */
   619   } /* if */
   620 }
   621 
   622 static cell truemodulus(cell a,cell b)
   623 {
   624   return (a % b + b) % b;
   625 }
   626 
   627 static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
   628 {
   629   if (oper==ob_or)
   630     return (left | right);
   631   else if (oper==ob_xor)
   632     return (left ^ right);
   633   else if (oper==ob_and)
   634     return (left & right);
   635   else if (oper==ob_eq)
   636     return (left == right);
   637   else if (oper==ob_ne)
   638     return (left != right);
   639   else if (oper==os_le)
   640     return *boolresult &= (char)(left <= right), right;
   641   else if (oper==os_ge)
   642     return *boolresult &= (char)(left >= right), right;
   643   else if (oper==os_lt)
   644     return *boolresult &= (char)(left < right), right;
   645   else if (oper==os_gt)
   646     return *boolresult &= (char)(left > right), right;
   647   else if (oper==os_sar)
   648     return (left >> (int)right);
   649   else if (oper==ou_sar)
   650     return ((ucell)left >> (ucell)right);
   651   else if (oper==ob_sal)
   652     return ((ucell)left << (int)right);
   653   else if (oper==ob_add)
   654     return (left + right);
   655   else if (oper==ob_sub)
   656     return (left - right);
   657   else if (oper==os_mult)
   658     return (left * right);
   659   else if (oper==os_div)
   660     return (left - truemodulus(left,right)) / right;
   661   else if (oper==os_mod)
   662     return truemodulus(left,right);
   663   else
   664     error(29);  /* invalid expression, assumed 0 (this should never occur) */
   665   return 0;
   666 }
   667 
   668 SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
   669 {
   670   int locheap=decl_heap;
   671   value lval={0};
   672 
   673   if (hier14(&lval))
   674     rvalue(&lval);
   675   /* scrap any arrays left on the heap */
   676   assert(decl_heap>=locheap);
   677   modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
   678   decl_heap=locheap;
   679 
   680   if (lval.ident==iCONSTEXPR && val!=NULL)    /* constant expression */
   681     *val=lval.constval;
   682   if (tag!=NULL)
   683     *tag=lval.tag;
   684   if (symptr!=NULL)
   685     *symptr=lval.sym;
   686   if (chkfuncresult)
   687     checkfunction(&lval);
   688   return lval.ident;
   689 }
   690 
   691 SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
   692 {
   693   char name[sNAMEMAX+1];
   694   cell val;
   695   char *str;
   696   int fsa,islabel;
   697 
   698   assert(automaton!=NULL);
   699   assert(state!=NULL);
   700   if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL))
   701     return 0;
   702 
   703   tokeninfo(&val,&str);
   704   assert(strlen(str)<sizeof name);
   705   strcpy(name,str);
   706   if (islabel || matchtoken(':')) {
   707     /* token is an automaton name, add the name and get a new token */
   708     *automaton=automaton_find(name);
   709     /* read in the state name before checking the automaton, to keep the parser
   710      * going (an "unknown automaton" error may occur when the "state" instruction
   711      * precedes any state definition)
   712      */
   713     if (!needtoken(tSYMBOL))
   714       return 0;
   715     tokeninfo(&val,&str);        /* do not copy the name yet, must check automaton first */
   716     if (*automaton==NULL) {
   717       error(86,name);            /* unknown automaton */
   718       return 0;
   719     } /* if */
   720     assert((*automaton)->index>0);
   721     assert(strlen(str)<sizeof name);
   722     strcpy(name,str);
   723   } else {
   724     *automaton=automaton_find("");
   725     assert(*automaton!=NULL);
   726     assert((*automaton)->index==0);
   727   } /* if */
   728   assert(*automaton!=NULL);
   729   fsa=(*automaton)->index;
   730 
   731   assert(*automaton!=NULL);
   732   *state=state_find(name,fsa);
   733   if (*state==NULL) {
   734     char *fsaname=(*automaton)->name;
   735     if (*fsaname=='\0')
   736       fsaname="<main>";
   737     error(87,name,fsaname);   /* unknown state for automaton */
   738     return 0;
   739   } /* if */
   740 
   741   return 1;
   742 }
   743 
   744 SC_FUNC cell array_totalsize(symbol *sym)
   745 {
   746   cell length;
   747 
   748   assert(sym!=NULL);
   749   assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   750   length=sym->dim.array.length;
   751   if (sym->dim.array.level > 0) {
   752     cell sublength=array_totalsize(finddepend(sym));
   753     if (sublength>0)
   754       length=length+length*sublength;
   755     else
   756       length=0;
   757   } /* if */
   758   return length;
   759 }
   760 
   761 static cell array_levelsize(symbol *sym,int level)
   762 {
   763   assert(sym!=NULL);
   764   assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   765   assert(level <= sym->dim.array.level);
   766   while (level-- > 0) {
   767     sym=finddepend(sym);
   768     assert(sym!=NULL);
   769   } /* if */
   770   return sym->dim.array.length;
   771 }
   772 
   773 /*  hier14
   774  *
   775  *  Lowest hierarchy level (except for the , operator).
   776  *
   777  *  Global references: sc_intest        (reffered to only)
   778  *                     sc_allowproccall (modified)
   779  */
   780 static int hier14(value *lval1)
   781 {
   782   int lvalue;
   783   value lval2={0},lval3={0};
   784   void (*oper)(void);
   785   int tok,level,i;
   786   cell val;
   787   char *st;
   788   int bwcount,leftarray;
   789   cell arrayidx1[sDIMEN_MAX],arrayidx2[sDIMEN_MAX];  /* last used array indices */
   790   cell *org_arrayidx;
   791 
   792   bwcount=bitwise_opercount;
   793   bitwise_opercount=0;
   794   /* initialize the index arrays with unlikely constant indices; note that
   795    * these indices will only be changed when the array is indexed with a
   796    * constant, and that negative array indices are invalid (so actually, any
   797    * negative value would do).
   798    */
   799   for (i=0; i<sDIMEN_MAX; i++)
   800     arrayidx1[i]=arrayidx2[i]=(cell)(-1L << (sizeof(cell)*8-1));
   801   org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */
   802   if (lval1->arrayidx==NULL)
   803     lval1->arrayidx=arrayidx1;
   804   lvalue=plnge1(hier13,lval1);
   805   if (lval1->ident!=iARRAYCELL && lval1->ident!=iARRAYCHAR)
   806     lval1->arrayidx=NULL;
   807   if (lval1->ident==iCONSTEXPR) /* load constant here */
   808     ldconst(lval1->constval,sPRI);
   809   tok=lex(&val,&st);
   810   switch (tok) {
   811     case taOR:
   812       oper=ob_or;
   813       break;
   814     case taXOR:
   815       oper=ob_xor;
   816       break;
   817     case taAND:
   818       oper=ob_and;
   819       break;
   820     case taADD:
   821       oper=ob_add;
   822       break;
   823     case taSUB:
   824       oper=ob_sub;
   825       break;
   826     case taMULT:
   827       oper=os_mult;
   828       break;
   829     case taDIV:
   830       oper=os_div;
   831       break;
   832     case taMOD:
   833       oper=os_mod;
   834       break;
   835     case taSHRU:
   836       oper=ou_sar;
   837       break;
   838     case taSHR:
   839       oper=os_sar;
   840       break;
   841     case taSHL:
   842       oper=ob_sal;
   843       break;
   844     case '=':           /* simple assignment */
   845       oper=NULL;
   846       if (sc_intest)
   847         error(211);     /* possibly unintended assignment */
   848       break;
   849     default:
   850       lexpush();
   851       bitwise_opercount=bwcount;
   852       lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   853       return lvalue;
   854   } /* switch */
   855 
   856   /* if we get here, it was an assignment; first check a few special cases
   857    * and then the general */
   858   if (lval1->ident==iARRAYCHAR) {
   859     /* special case, assignment to packed character in a cell is permitted */
   860     lvalue=TRUE;
   861   } else if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
   862     /* array assignment is permitted too (with restrictions) */
   863     if (oper)
   864       return error(23); /* array assignment must be simple assigment */
   865     assert(lval1->sym!=NULL);
   866     if (array_totalsize(lval1->sym)==0)
   867       return error(46,lval1->sym->name);        /* unknown array size */
   868     lvalue=TRUE;
   869   } /* if */
   870 
   871   /* operand on left side of assignment must be lvalue */
   872   if (!lvalue)
   873     return error(22);                   /* must be lvalue */
   874   /* may not change "constant" parameters */
   875   assert(lval1->sym!=NULL);
   876   if ((lval1->sym->usage & uCONST)!=0)
   877     return error(22);           /* assignment to const argument */
   878   sc_allowproccall=FALSE;       /* may no longer use "procedure call" syntax */
   879 
   880   lval3=*lval1;         /* save symbol to enable storage of expresion result */
   881   lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   882   if (lval1->ident==iARRAYCELL || lval1->ident==iARRAYCHAR
   883       || lval1->ident==iARRAY || lval1->ident==iREFARRAY)
   884   {
   885     /* if indirect fetch: save PRI (cell address) */
   886     if (oper) {
   887       pushreg(sPRI);
   888       rvalue(lval1);
   889     } /* if */
   890     lval2.arrayidx=arrayidx2;
   891     plnge2(oper,hier14,lval1,&lval2);
   892     if (lval2.ident!=iARRAYCELL && lval2.ident!=iARRAYCHAR)
   893       lval2.arrayidx=NULL;
   894     if (oper)
   895       popreg(sALT);
   896     if (!oper && lval3.arrayidx!=NULL && lval2.arrayidx!=NULL
   897         && lval3.ident==lval2.ident && lval3.sym==lval2.sym)
   898     {
   899       int same=TRUE;
   900       assert(lval2.arrayidx==arrayidx2);
   901       for (i=0; i<sDIMEN_MAX; i++)
   902         same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]);
   903         if (same)
   904           error(226,lval3.sym->name);   /* self-assignment */
   905     } /* if */
   906   } else {
   907     if (oper){
   908       rvalue(lval1);
   909       plnge2(oper,hier14,lval1,&lval2);
   910     } else {
   911       /* if direct fetch and simple assignment: no "push"
   912        * and "pop" needed -> call hier14() directly, */
   913       if (hier14(&lval2))
   914         rvalue(&lval2);         /* instead of plnge2(). */
   915       else if (lval2.ident==iVARIABLE)
   916         lval2.ident=iEXPRESSION;/* mark as "rvalue" if it is not an "lvalue" */
   917       checkfunction(&lval2);
   918       /* check whether lval2 and lval3 (old lval1) refer to the same variable */
   919       if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) {
   920         assert(lval3.sym!=NULL);
   921         error(226,lval3.sym->name);     /* self-assignment */
   922       } /* if */
   923     } /* if */
   924   } /* if */
   925   /* Array elements are sometimes considered as sub-arrays --when the
   926    * array index is an enumeration field and the enumeration size is greater
   927    * than 1. If the expression on the right side of the assignment is a cell,
   928    * or if an operation is in effect, this does not apply.
   929    */
   930   leftarray= lval3.ident==iARRAY || lval3.ident==iREFARRAY
   931              || ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   932                  && lval3.constval>1 && lval3.sym->dim.array.level==0
   933                  && !oper && (lval2.ident==iARRAY || lval2.ident==iREFARRAY));
   934   if (leftarray) {
   935     /* Left operand is an array, right operand should be an array variable
   936      * of the same size and the same dimension, an array literal (of the
   937      * same size) or a literal string. For single-dimensional arrays without
   938      * tag for the index, it is permitted to assign a smaller array into a
   939      * larger one (without warning). This is to make it easier to work with
   940      * strings.
   941      */
   942     int exactmatch=TRUE;
   943     int idxtag=0;
   944     int ltlength=(int)lval3.sym->dim.array.length;
   945     if ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   946         && lval3.constval>0 && lval3.sym->dim.array.level==0)
   947     {
   948       ltlength=(int)lval3.constval;
   949     } /* if */
   950     if (lval2.ident!=iARRAY && lval2.ident!=iREFARRAY
   951         && (lval2.sym==NULL || lval2.constval<=0))
   952       error(33,lval3.sym->name);        /* array must be indexed */
   953     if (lval2.sym!=NULL) {
   954       if (lval2.constval==0) {
   955         val=lval2.sym->dim.array.length;/* array variable */
   956       } else {
   957         val=lval2.constval;
   958         if (lval2.sym->dim.array.level!=0)
   959           error(28,lval2.sym->name);
   960       } /* if */
   961       level=lval2.sym->dim.array.level;
   962       idxtag=lval2.sym->x.tags.index;
   963       if (level==0 && idxtag==0 && lval3.sym->x.tags.index==0)
   964         exactmatch=FALSE;
   965     } else {
   966       val=lval2.constval;               /* literal array */
   967       level=0;
   968       /* If val is negative, it means that lval2 is a literal string.
   969        * The string array size may be smaller than the destination
   970        * array, provided that the destination array does not have an
   971        * index tag.
   972        */
   973       if (val<0) {
   974         val=-val;
   975         if (lval3.sym->x.tags.index==0)
   976           exactmatch=FALSE;
   977       } /* if */
   978     } /* if */
   979     if (lval3.sym->dim.array.level!=level)
   980       return error(48); /* array dimensions must match */
   981     else if (ltlength<val || exactmatch && ltlength>val || val==0)
   982       return error(47); /* array sizes must match */
   983     else if (lval3.ident!=iARRAYCELL && !matchtag(lval3.sym->x.tags.index,idxtag,TRUE))
   984       error(229,(lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name); /* index tag mismatch */
   985     if (level>0) {
   986       /* check the sizes of all sublevels too */
   987       symbol *sym1 = lval3.sym;
   988       symbol *sym2 = lval2.sym;
   989       int i;
   990       assert(sym1!=NULL && sym2!=NULL);
   991       /* ^^^ sym2 must be valid, because only variables can be
   992        *     multi-dimensional (there are no multi-dimensional literals),
   993        *     sym1 must be valid because it must be an lvalue
   994        */
   995       assert(exactmatch);
   996       for (i=0; i<level; i++) {
   997         sym1=finddepend(sym1);
   998         sym2=finddepend(sym2);
   999         assert(sym1!=NULL && sym2!=NULL);
  1000         /* ^^^ both arrays have the same dimensions (this was checked
  1001          *     earlier) so the dependend should always be found
  1002          */
  1003         if (sym1->dim.array.length!=sym2->dim.array.length)
  1004           error(47);    /* array sizes must match */
  1005         else if (!matchtag(sym1->x.tags.index,sym2->x.tags.index,TRUE))
  1006           error(229,sym2->name);  /* index tag mismatch */
  1007       } /* for */
  1008       /* get the total size in cells of the multi-dimensional array */
  1009       val=array_totalsize(lval3.sym);
  1010       assert(val>0);    /* already checked */
  1011     } /* if */
  1012   } else {
  1013     /* left operand is not an array, right operand should then not be either */
  1014     if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1015       error(6);         /* must be assigned to an array */
  1016   } /* if */
  1017   if (leftarray) {
  1018     memcopy(val*sizeof(cell));
  1019   } else {
  1020     check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag);
  1021     store(&lval3);      /* now, store the expression result */
  1022   } /* if */
  1023   if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE))
  1024     error(213);         /* tagname mismatch (if "oper", warning already given in plunge2()) */
  1025   if (lval3.sym)
  1026     markusage(lval3.sym,uWRITTEN);
  1027   sideeffect=TRUE;
  1028   bitwise_opercount=bwcount;
  1029   lval1->ident=iEXPRESSION;
  1030   return FALSE;         /* expression result is never an lvalue */
  1031 }
  1032 
  1033 static int hier13(value *lval)
  1034 {
  1035   int lvalue=plnge1(hier12,lval);
  1036   if (matchtoken('?')) {
  1037     int flab1=getlabel();
  1038     int flab2=getlabel();
  1039     value lval2={0};
  1040     int array1,array2;
  1041 
  1042     if (lvalue) {
  1043       rvalue(lval);
  1044     } else if (lval->ident==iCONSTEXPR) {
  1045       ldconst(lval->constval,sPRI);
  1046       error(lval->constval ? 206 : 205);        /* redundant test */
  1047     } /* if */
  1048     jmp_eq0(flab1);             /* go to second expression if primary register==0 */
  1049     PUSHSTK_I(sc_allowtags);
  1050     sc_allowtags=FALSE;         /* do not allow tagnames here (colon is a special token) */
  1051     if (hier13(lval))
  1052       rvalue(lval);
  1053     if (lval->ident==iCONSTEXPR)        /* load constant here */
  1054       ldconst(lval->constval,sPRI);
  1055     sc_allowtags=(short)POPSTK_I();     /* restore */
  1056     jumplabel(flab2);
  1057     setlabel(flab1);
  1058     needtoken(':');
  1059     if (hier13(&lval2))
  1060       rvalue(&lval2);
  1061     if (lval2.ident==iCONSTEXPR)        /* load constant here */
  1062       ldconst(lval2.constval,sPRI);
  1063     array1= (lval->ident==iARRAY || lval->ident==iREFARRAY);
  1064     array2= (lval2.ident==iARRAY || lval2.ident==iREFARRAY);
  1065     if (array1 && !array2) {
  1066       char *ptr=(lval->sym->name!=NULL) ? lval->sym->name : "-unknown-";
  1067       error(33,ptr);            /* array must be indexed */
  1068     } else if (!array1 && array2) {
  1069       char *ptr=(lval2.sym->name!=NULL) ? lval2.sym->name : "-unknown-";
  1070       error(33,ptr);            /* array must be indexed */
  1071     } /* if */
  1072     /* ??? if both are arrays, should check dimensions */
  1073     if (!matchtag(lval->tag,lval2.tag,FALSE))
  1074       error(213);               /* tagname mismatch ('true' and 'false' expressions) */
  1075     setlabel(flab2);
  1076     if (lval->ident==iARRAY)
  1077       lval->ident=iREFARRAY;    /* iARRAY becomes iREFARRAY */
  1078     else if (lval->ident!=iREFARRAY)
  1079       lval->ident=iEXPRESSION;  /* iREFARRAY stays iREFARRAY, rest becomes iEXPRESSION */
  1080     return FALSE;               /* conditional expression is no lvalue */
  1081   } else {
  1082     return lvalue;
  1083   } /* if */
  1084 }
  1085 
  1086 /* the order of the operators in these lists is important and must be
  1087  * the same as the order of the operators in the array "op1"
  1088  */
  1089 static int list3[]  = {'*','/','%',0};
  1090 static int list4[]  = {'+','-',0};
  1091 static int list5[]  = {tSHL,tSHR,tSHRU,0};
  1092 static int list6[]  = {'&',0};
  1093 static int list7[]  = {'^',0};
  1094 static int list8[]  = {'|',0};
  1095 static int list9[]  = {tlLE,tlGE,'<','>',0};
  1096 static int list10[] = {tlEQ,tlNE,0};
  1097 static int list11[] = {tlAND,0};
  1098 static int list12[] = {tlOR,0};
  1099 
  1100 static int hier12(value *lval)
  1101 {
  1102   return skim(list12,jmp_ne0,1,0,hier11,lval);
  1103 }
  1104 
  1105 static int hier11(value *lval)
  1106 {
  1107   return skim(list11,jmp_eq0,0,1,hier10,lval);
  1108 }
  1109 
  1110 static int hier10(value *lval)
  1111 { /* ==, != */
  1112   return plnge(list10,15,hier9,lval,"bool",TRUE);
  1113 }                  /* ^ this variable is the starting index in the op1[]
  1114                     *   array of the operators of this hierarchy level */
  1115 
  1116 static int hier9(value *lval)
  1117 { /* <=, >=, <, > */
  1118   return plnge_rel(list9,11,hier8,lval);
  1119 }
  1120 
  1121 static int hier8(value *lval)
  1122 { /* | */
  1123   return plnge(list8,10,hier7,lval,NULL,FALSE);
  1124 }
  1125 
  1126 static int hier7(value *lval)
  1127 { /* ^ */
  1128   return plnge(list7,9,hier6,lval,NULL,FALSE);
  1129 }
  1130 
  1131 static int hier6(value *lval)
  1132 { /* & */
  1133   return plnge(list6,8,hier5,lval,NULL,FALSE);
  1134 }
  1135 
  1136 static int hier5(value *lval)
  1137 { /* <<, >>, >>> */
  1138   return plnge(list5,5,hier4,lval,NULL,FALSE);
  1139 }
  1140 
  1141 static int hier4(value *lval)
  1142 { /* +, - */
  1143   return plnge(list4,3,hier3,lval,NULL,FALSE);
  1144 }
  1145 
  1146 static int hier3(value *lval)
  1147 { /* *, /, % */
  1148   return plnge(list3,0,hier2,lval,NULL,FALSE);
  1149 }
  1150 
  1151 static int hier2(value *lval)
  1152 {
  1153   int lvalue,tok;
  1154   int tag,paranthese;
  1155   cell val;
  1156   char *st;
  1157   symbol *sym;
  1158   int saveresult;
  1159 
  1160   tok=lex(&val,&st);
  1161   switch (tok) {
  1162   case tINC:                    /* ++lval */
  1163     if (!hier2(lval))
  1164       return error(22);         /* must be lvalue */
  1165     assert(lval->sym!=NULL);
  1166     if ((lval->sym->usage & uCONST)!=0)
  1167       return error(22);         /* assignment to const argument */
  1168     if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1169       inc(lval);                /* increase variable first */
  1170     rvalue(lval);               /* and read the result into PRI */
  1171     sideeffect=TRUE;
  1172     return FALSE;               /* result is no longer lvalue */
  1173   case tDEC:                    /* --lval */
  1174     if (!hier2(lval))
  1175       return error(22);         /* must be lvalue */
  1176     assert(lval->sym!=NULL);
  1177     if ((lval->sym->usage & uCONST)!=0)
  1178       return error(22);         /* assignment to const argument */
  1179     if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1180       dec(lval);                /* decrease variable first */
  1181     rvalue(lval);               /* and read the result into PRI */
  1182     sideeffect=TRUE;
  1183     return FALSE;               /* result is no longer lvalue */
  1184   case '~':                     /* ~ (one's complement) */
  1185     if (hier2(lval))
  1186       rvalue(lval);
  1187     invert();                   /* bitwise NOT */
  1188     lval->constval=~lval->constval;
  1189     return FALSE;
  1190   case '!':                     /* ! (logical negate) */
  1191     if (hier2(lval))
  1192       rvalue(lval);
  1193     if (check_userop(lneg,lval->tag,0,1,NULL,&lval->tag)) {
  1194       lval->ident=iEXPRESSION;
  1195       lval->constval=0;
  1196     } else {
  1197       lneg();                   /* 0 -> 1,  !0 -> 0 */
  1198       lval->constval=!lval->constval;
  1199       lval->tag=pc_addtag("bool");
  1200     } /* if */
  1201     return FALSE;
  1202   case '-':                     /* unary - (two's complement) */
  1203     if (hier2(lval))
  1204       rvalue(lval);
  1205     /* make a special check for a constant expression with the tag of a
  1206      * rational number, so that we can simple swap the sign of that constant.
  1207      */
  1208     if (lval->ident==iCONSTEXPR && lval->tag==sc_rationaltag && sc_rationaltag!=0) {
  1209       if (rational_digits==0) {
  1210         #if PAWN_CELL_SIZE==32
  1211           float *f = (float *)&lval->constval;
  1212         #elif PAWN_CELL_SIZE==64
  1213           double *f = (double *)&lval->constval;
  1214         #else
  1215           #error Unsupported cell size
  1216         #endif
  1217         *f= - *f; /* this modifies lval->constval */
  1218       } else {
  1219         /* the negation of a fixed point number is just an integer negation */
  1220         lval->constval=-lval->constval;
  1221       } /* if */
  1222     } else if (check_userop(neg,lval->tag,0,1,NULL,&lval->tag)) {
  1223       lval->ident=iEXPRESSION;
  1224       lval->constval=0;
  1225     } else {
  1226       neg();                    /* arithmic negation */
  1227       lval->constval=-lval->constval;
  1228     } /* if */
  1229     return FALSE;
  1230   case tLABEL:                  /* tagname override */
  1231     tag=pc_addtag(st);
  1232     lval->cmptag=tag;
  1233     lvalue=hier2(lval);
  1234     lval->tag=tag;
  1235     return lvalue;
  1236   case tDEFINED:
  1237     paranthese=0;
  1238     while (matchtoken('('))
  1239       paranthese++;
  1240     tok=lex(&val,&st);
  1241     if (tok!=tSYMBOL)
  1242       return error(20,st);      /* illegal symbol name */
  1243     sym=findloc(st);
  1244     if (sym==NULL)
  1245       sym=findglb(st,sSTATEVAR);
  1246     if (sym!=NULL && sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0)
  1247       sym=NULL;                 /* symbol is not a function, it is in the table, but not "defined" */
  1248     val= (sym!=NULL);
  1249     if (!val && find_subst(st,strlen(st))!=NULL)
  1250       val=1;
  1251     clear_value(lval);
  1252     lval->ident=iCONSTEXPR;
  1253     lval->constval= val;
  1254     lval->tag=pc_addtag("bool");
  1255     ldconst(lval->constval,sPRI);
  1256     while (paranthese--)
  1257       needtoken(')');
  1258     return FALSE;
  1259   case tSIZEOF:
  1260     paranthese=0;
  1261     while (matchtoken('('))
  1262       paranthese++;
  1263     tok=lex(&val,&st);
  1264     if (tok!=tSYMBOL)
  1265       return error(20,st);      /* illegal symbol name */
  1266     sym=findloc(st);
  1267     if (sym==NULL)
  1268       sym=findglb(st,sSTATEVAR);
  1269     if (sym==NULL)
  1270       return error(17,st);      /* undefined symbol */
  1271     if (sym->ident==iCONSTEXPR)
  1272       error(39);                /* constant symbol has no size */
  1273     else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC)
  1274       error(72);                /* "function" symbol has no size */
  1275     else if ((sym->usage & uDEFINE)==0)
  1276       return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1277     clear_value(lval);
  1278     lval->ident=iCONSTEXPR;
  1279     lval->constval=1;           /* preset */
  1280     if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1281       int level;
  1282       symbol *idxsym=NULL;
  1283       symbol *subsym=sym;
  1284       for (level=0; matchtoken('['); level++) {
  1285         idxsym=NULL;
  1286         if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1287           char *idxname;
  1288           int cmptag=subsym->x.tags.index;
  1289           tokeninfo(&val,&idxname);
  1290           if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1291             error(80,idxname);  /* unknown symbol, or non-constant */
  1292           else if (cmptag>1)
  1293             error(91,idxname);  /* ambiguous constant */
  1294         } /* if */
  1295         needtoken(']');
  1296         if (subsym!=NULL)
  1297           subsym=finddepend(subsym);
  1298       } /* for */
  1299       if (level>sym->dim.array.level+1)
  1300         error(28,sym->name);  /* invalid subscript */
  1301       else if (level==sym->dim.array.level+1)
  1302         lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1;
  1303       else
  1304         lval->constval=array_levelsize(sym,level);
  1305       if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL)
  1306         error(224,st);          /* indeterminate array size in "sizeof" expression */
  1307     } /* if */
  1308     ldconst(lval->constval,sPRI);
  1309     while (paranthese--)
  1310       needtoken(')');
  1311     return FALSE;
  1312   case tTAGOF:
  1313     paranthese=0;
  1314     while (matchtoken('('))
  1315       paranthese++;
  1316     tok=lex(&val,&st);
  1317     if (tok!=tSYMBOL && tok!=tLABEL)
  1318       return error(20,st);      /* illegal symbol name */
  1319     if (tok==tLABEL) {
  1320       constvalue *tagsym=find_constval(&tagname_tab,st,0);
  1321       tag=(int)((tagsym!=NULL) ? tagsym->value : 0);
  1322     } else {
  1323       sym=findloc(st);
  1324       if (sym==NULL)
  1325         sym=findglb(st,sSTATEVAR);
  1326       if (sym==NULL)
  1327         return error(17,st);      /* undefined symbol */
  1328       if ((sym->usage & uDEFINE)==0)
  1329         return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1330       tag=sym->tag;
  1331     } /* if */
  1332     if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1333       int level;
  1334       symbol *idxsym=NULL;
  1335       symbol *subsym=sym;
  1336       for (level=0; matchtoken('['); level++) {
  1337         idxsym=NULL;
  1338         if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1339           char *idxname;
  1340           int cmptag=subsym->x.tags.index;
  1341           tokeninfo(&val,&idxname);
  1342           if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1343             error(80,idxname);  /* unknown symbol, or non-constant */
  1344           else if (cmptag>1)
  1345             error(91,idxname);  /* ambiguous constant */
  1346         } /* if */
  1347         needtoken(']');
  1348         if (subsym!=NULL)
  1349           subsym=finddepend(subsym);
  1350       } /* for */
  1351       if (level>sym->dim.array.level+1)
  1352         error(28,sym->name);  /* invalid subscript */
  1353       else if (level==sym->dim.array.level+1 && idxsym!=NULL)
  1354         tag= idxsym->x.tags.index;
  1355     } /* if */
  1356     exporttag(tag);
  1357     clear_value(lval);
  1358     lval->ident=iCONSTEXPR;
  1359     lval->constval=tag | PUBLICTAG;
  1360     ldconst(lval->constval,sPRI);
  1361     while (paranthese--)
  1362       needtoken(')');
  1363     return FALSE;
  1364   case tSTATE: {
  1365     constvalue *automaton;
  1366     constvalue *state;
  1367     if (sc_getstateid(&automaton,&state)) {
  1368       assert(automaton!=NULL);
  1369       assert(automaton->index==0 && automaton->name[0]=='\0' || automaton->index>0);
  1370       loadreg(automaton->value,sALT);
  1371       assert(state!=NULL);
  1372       ldconst(state->value,sPRI);
  1373       ob_eq();
  1374       clear_value(lval);
  1375       lval->ident=iEXPRESSION;
  1376       lval->tag=pc_addtag("bool");
  1377     } /* if */
  1378     return FALSE;
  1379   } /* case */
  1380   default:
  1381     lexpush();
  1382     lvalue=hier1(lval);
  1383     /* check for postfix operators */
  1384     if (matchtoken(';')) {
  1385       /* Found a ';', do not look further for postfix operators */
  1386       lexpush();                /* push ';' back after successful match */
  1387       return lvalue;
  1388     } else if (matchtoken(tTERM)) {
  1389       /* Found a newline that ends a statement (this is the case when
  1390        * semicolons are optional). Note that an explicit semicolon was
  1391        * handled above. This case is similar, except that the token must
  1392        * not be pushed back.
  1393        */
  1394       return lvalue;
  1395     } else {
  1396       tok=lex(&val,&st);
  1397       switch (tok) {
  1398       case tINC:                /* lval++ */
  1399         if (!lvalue)
  1400           return error(22);     /* must be lvalue */
  1401         assert(lval->sym!=NULL);
  1402         if ((lval->sym->usage & uCONST)!=0)
  1403           return error(22);     /* assignment to const argument */
  1404         /* on incrementing array cells, the address in PRI must be saved for
  1405          * incremening the value, whereas the current value must be in PRI
  1406          * on exit.
  1407          */
  1408         saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1409         if (saveresult)
  1410           pushreg(sPRI);        /* save address in PRI */
  1411         rvalue(lval);           /* read current value into PRI */
  1412         if (saveresult)
  1413           swap1();              /* save PRI on the stack, restore address in PRI */
  1414         if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1415           inc(lval);            /* increase variable afterwards */
  1416         if (saveresult)
  1417           popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1418         sideeffect=TRUE;
  1419         return FALSE;           /* result is no longer lvalue */
  1420       case tDEC:                /* lval-- */
  1421         if (!lvalue)
  1422           return error(22);     /* must be lvalue */
  1423         assert(lval->sym!=NULL);
  1424         if ((lval->sym->usage & uCONST)!=0)
  1425           return error(22);     /* assignment to const argument */
  1426         saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1427         if (saveresult)
  1428           pushreg(sPRI);        /* save address in PRI */
  1429         rvalue(lval);           /* read current value into PRI */
  1430         if (saveresult)
  1431           swap1();              /* save PRI on the stack, restore address in PRI */
  1432         if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1433           dec(lval);            /* decrease variable afterwards */
  1434         if (saveresult)
  1435           popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1436         sideeffect=TRUE;
  1437         return FALSE;
  1438       case tCHAR:               /* char (compute required # of cells */
  1439         if (lval->ident==iCONSTEXPR) {
  1440           lval->constval *= sCHARBITS/8;  /* from char to bytes */
  1441           lval->constval = (lval->constval + sizeof(cell)-1) / sizeof(cell);
  1442         } else {
  1443           if (lvalue)
  1444             rvalue(lval);       /* fetch value if not already in PRI */
  1445           char2addr();          /* from characters to bytes */
  1446           addconst(sizeof(cell)-1);     /* make sure the value is rounded up */
  1447           addr2cell();          /* truncate to number of cells */
  1448         } /* if */
  1449         return FALSE;
  1450       default:
  1451         lexpush();
  1452         return lvalue;
  1453       } /* switch */
  1454     } /* if */
  1455   } /* switch */
  1456 }
  1457 
  1458 /*  hier1
  1459  *
  1460  *  The highest hierarchy level: it looks for pointer and array indices
  1461  *  and function calls.
  1462  *  Generates code to fetch a pointer value if it is indexed and code to
  1463  *  add to the pointer value or the array address (the address is already
  1464  *  read at primary()). It also generates code to fetch a function address
  1465  *  if that hasn't already been done at primary() (check lval[4]) and calls
  1466  *  callfunction() to call the function.
  1467  */
  1468 static int hier1(value *lval1)
  1469 {
  1470   int lvalue,index,tok,symtok;
  1471   cell val,cidx;
  1472   value lval2={0};
  1473   char *st;
  1474   char close;
  1475   symbol *sym;
  1476   symbol dummysymbol,*cursym;   /* for changing the index tags in case of enumerated pseudo-arrays */
  1477 
  1478   lvalue=primary(lval1);
  1479   symtok=tokeninfo(&val,&st);   /* get token read by primary() */
  1480   cursym=lval1->sym;
  1481 restart:
  1482   sym=cursym;
  1483   if (matchtoken('[') || matchtoken('{') || matchtoken('(')) {
  1484     tok=tokeninfo(&val,&st);    /* get token read by matchtoken() */
  1485     if (sym==NULL && symtok!=tSYMBOL) {
  1486       /* we do not have a valid symbol and we appear not to have read a valid
  1487        * symbol name (so it is unlikely that we would have read a name of an
  1488        * undefined symbol) */
  1489       error(29);                /* expression error, assumed 0 */
  1490       lexpush();                /* analyse '(', '{' or '[' again later */
  1491       return FALSE;
  1492     } /* if */
  1493     if (tok=='[' || tok=='{') { /* subscript */
  1494       close = (char)((tok=='[') ? ']' : '}');
  1495       if (sym==NULL) {  /* sym==NULL if lval is a constant or a literal */
  1496         error(28,"<no variable>");  /* cannot subscript */
  1497         needtoken(close);
  1498         return FALSE;
  1499       } else if (sym->ident!=iARRAY && sym->ident!=iREFARRAY){
  1500         error(28,sym->name);    /* cannot subscript, variable is not an array */
  1501         needtoken(close);
  1502         return FALSE;
  1503       } else if (sym->dim.array.level>0 && close!=']') {
  1504         error(51);      /* invalid subscript, must use [ ] */
  1505         needtoken(close);
  1506         return FALSE;
  1507       } /* if */
  1508       /* set the tag to match (enumeration fields as indices) */
  1509       lval2.cmptag=sym->x.tags.index;
  1510       stgget(&index,&cidx);     /* mark position in code generator */
  1511       pushreg(sPRI);            /* save base address of the array */
  1512       if (hier14(&lval2))       /* create expression for the array index */
  1513         rvalue(&lval2);
  1514       if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1515         error(33,lval2.sym->name);      /* array must be indexed */
  1516       needtoken(close);
  1517       if (!matchtag(sym->x.tags.index,lval2.tag,TRUE))
  1518         error(213);
  1519       if (lval2.ident==iCONSTEXPR) {    /* constant expression */
  1520         stgdel(index,cidx);             /* scratch generated code */
  1521         if (lval1->arrayidx!=NULL) {    /* keep constant index, for checking */
  1522           assert(sym->dim.array.level>=0 && sym->dim.array.level<sDIMEN_MAX);
  1523           lval1->arrayidx[sym->dim.array.level]=lval2.constval;
  1524         } /* if */
  1525         if (close==']') {
  1526           /* normal array index */
  1527           if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval)
  1528             error(32,sym->name);        /* array index out of bounds */
  1529           if (lval2.constval!=0) {
  1530             /* don't add offsets for zero subscripts */
  1531             #if PAWN_CELL_SIZE==16
  1532               ldconst(lval2.constval<<1,sALT);
  1533             #elif PAWN_CELL_SIZE==32
  1534               ldconst(lval2.constval<<2,sALT);
  1535             #elif PAWN_CELL_SIZE==64
  1536               ldconst(lval2.constval<<3,sALT);
  1537             #else
  1538               #error Unsupported cell size
  1539             #endif
  1540             ob_add();
  1541           } /* if */
  1542         } else {
  1543           /* character index */
  1544           if (lval2.constval<0 || sym->dim.array.length!=0
  1545               && sym->dim.array.length*((8*sizeof(cell))/sCHARBITS)<=(ucell)lval2.constval)
  1546             error(32,sym->name);        /* array index out of bounds */
  1547           if (lval2.constval!=0) {
  1548             /* don't add offsets for zero subscripts */
  1549             #if sCHARBITS==16
  1550               ldconst(lval2.constval<<1,sALT);/* 16-bit character */
  1551             #else
  1552               ldconst(lval2.constval,sALT);   /* 8-bit character */
  1553             #endif
  1554             ob_add();
  1555           } /* if */
  1556           charalign();                  /* align character index into array */
  1557         } /* if */
  1558         /* if the array index is a field from an enumeration, get the tag name
  1559          * from the field and save the size of the field too.
  1560          */
  1561         assert(lval2.sym==NULL || lval2.sym->dim.array.level==0);
  1562         if (lval2.sym!=NULL && lval2.sym->dim.array.length>0 && sym->dim.array.level==0) {
  1563           lval1->tag=lval2.sym->x.tags.index;
  1564           lval1->constval=lval2.sym->dim.array.length;
  1565         } /* if */
  1566       } else {
  1567         /* array index is not constant */
  1568         lval1->arrayidx=NULL;           /* reset, so won't be checked */
  1569         if (close==']') {
  1570           if (sym->dim.array.length!=0)
  1571             ffbounds(sym->dim.array.length-1);  /* run time check for array bounds */
  1572           cell2addr();  /* normal array index */
  1573         } else {
  1574           if (sym->dim.array.length!=0)
  1575             ffbounds(sym->dim.array.length*(32/sCHARBITS)-1);
  1576           char2addr();  /* character array index */
  1577         } /* if */
  1578         popreg(sALT);
  1579         ob_add();       /* base address was popped into secondary register */
  1580         if (close!=']')
  1581           charalign();  /* align character index into array */
  1582       } /* if */
  1583       /* the indexed item may be another array (multi-dimensional arrays) */
  1584       assert(cursym==sym && sym!=NULL); /* should still be set */
  1585       if (sym->dim.array.level>0) {
  1586         assert(close==']');     /* checked earlier */
  1587         assert(cursym==lval1->sym);
  1588         /* read the offset to the subarray and add it to the current address */
  1589         lval1->ident=iARRAYCELL;
  1590         pushreg(sPRI);          /* the optimizer makes this to a MOVE.alt */
  1591         rvalue(lval1);
  1592         popreg(sALT);
  1593         ob_add();
  1594         /* adjust the "value" structure and find the referenced array */
  1595         lval1->ident=iREFARRAY;
  1596         lval1->sym=finddepend(sym);
  1597         assert(lval1->sym!=NULL);
  1598         assert(lval1->sym->dim.array.level==sym->dim.array.level-1);
  1599         cursym=lval1->sym;
  1600         /* try to parse subsequent array indices */
  1601         lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1602         goto restart;
  1603       } /* if */
  1604       assert(sym->dim.array.level==0);
  1605       /* set type to fetch... INDIRECTLY */
  1606       lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR);
  1607       /* if the array index is a field from an enumeration, get the tag name
  1608        * from the field and save the size of the field too. Otherwise, the
  1609        * tag is the one from the array symbol.
  1610        */
  1611       if (lval2.ident==iCONSTEXPR && lval2.sym!=NULL
  1612           && lval2.sym->dim.array.length>0 && sym->dim.array.level==0)
  1613       {
  1614         lval1->tag=lval2.sym->x.tags.index;
  1615         lval1->constval=lval2.sym->dim.array.length;
  1616         if (lval2.tag==sym->x.tags.index && lval1->constval>1 && matchtoken('[')) {
  1617           /* an array indexed with an enumeration field may be considered a sub-array */
  1618           lexpush();
  1619           lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1620           lval1->ident=iREFARRAY;
  1621           /* initialize a dummy symbol, which is a copy of the current symbol,
  1622            * but with an adjusted index tag
  1623            */
  1624           assert(sym!=NULL);
  1625           dummysymbol=*sym;
  1626           /* get the tag of the root of the enumeration */
  1627           assert(lval2.sym!=NULL);
  1628           dummysymbol.x.tags.index=lval2.sym->x.tags.field;
  1629           dummysymbol.dim.array.length=lval2.sym->dim.array.length;
  1630           cursym=&dummysymbol;
  1631           /* recurse */
  1632           goto restart;
  1633         } /* if */
  1634       } else {
  1635         assert(sym!=NULL);
  1636         if (cursym!=&dummysymbol)
  1637           lval1->tag=sym->tag;
  1638         lval1->constval=0;
  1639       } /* if */
  1640       /* a cell in an array is an lvalue, a character in an array is not
  1641        * always a *valid* lvalue */
  1642       return TRUE;
  1643     } else {            /* tok=='(' -> function(...) */
  1644       assert(tok=='(');
  1645       if (sym==NULL
  1646           || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
  1647       {
  1648         if (sym==NULL && sc_status==statFIRST) {
  1649           /* could be a "use before declaration"; in that case, create a stub
  1650            * function so that the usage can be marked.
  1651            */
  1652           sym=fetchfunc(lastsymbol,0);
  1653           if (sym==NULL)
  1654             error(103); /* insufficient memory */
  1655           markusage(sym,uREAD);
  1656         } else {
  1657           return error(12);           /* invalid function call */
  1658         } /* if */
  1659       } else if ((sym->usage & uMISSING)!=0) {
  1660         char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
  1661         funcdisplayname(symname,sym->name);
  1662         error(4,symname);             /* function not defined */
  1663       } /* if */
  1664       callfunction(sym,lval1,TRUE);
  1665       return FALSE;             /* result of function call is no lvalue */
  1666     } /* if */
  1667   } /* if */
  1668   if (sym!=NULL && lval1->ident==iFUNCTN) {
  1669     assert(sym->ident==iFUNCTN);
  1670     if (sc_allowproccall) {
  1671       callfunction(sym,lval1,FALSE);
  1672     } else {
  1673       int n=-1,iter=0;
  1674       for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  1675         if (sym->ident==iFUNCTN
  1676             && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
  1677         {
  1678           assert(sym->vclass==sGLOBAL);
  1679           if (strcmp(sym->name, lval1->sym->name)==0) {
  1680             n = iter;
  1681             break;
  1682           }
  1683           iter++;
  1684         }
  1685       }
  1686       if (n!=-1) {
  1687         lval1->sym=NULL;
  1688         lval1->ident=iCONSTEXPR;
  1689         lval1->constval=n;
  1690         lval1->tag=pc_addtag("Function");
  1691       } else {
  1692         error(76);                /* invalid function call, or syntax error */
  1693       } /* if */
  1694       return FALSE;
  1695     }
  1696   } /* if */
  1697   return lvalue;
  1698 }
  1699 
  1700 /*  primary
  1701  *
  1702  *  Returns 1 if the operand is an lvalue (everything except arrays, functions
  1703  *  constants and -of course- errors).
  1704  *  Generates code to fetch the address of arrays. Code for constants is
  1705  *  already generated by constant().
  1706  *  This routine first clears the entire lval array (all fields are set to 0).
  1707  *
  1708  *  Global references: sc_intest  (may be altered, but restored upon termination)
  1709  */
  1710 static int primary(value *lval)
  1711 {
  1712   char *st;
  1713   int lvalue,tok;
  1714   cell val;
  1715   symbol *sym;
  1716 
  1717   if (matchtoken('(')){         /* sub-expression - (expression,...) */
  1718     PUSHSTK_I(sc_intest);
  1719     PUSHSTK_I(sc_allowtags);
  1720 
  1721     sc_intest=FALSE;            /* no longer in "test" expression */
  1722     sc_allowtags=TRUE;          /* allow tagnames to be used in parenthesized expressions */
  1723     sc_allowproccall=FALSE;
  1724     do
  1725       lvalue=hier14(lval);
  1726     while (matchtoken(','));
  1727     needtoken(')');
  1728     lexclr(FALSE);              /* clear lex() push-back, it should have been
  1729                                  * cleared already by needtoken() */
  1730     sc_allowtags=(short)POPSTK_I();
  1731     sc_intest=(short)POPSTK_I();
  1732     return lvalue;
  1733   } /* if */
  1734 
  1735   clear_value(lval);    /* clear lval */
  1736   tok=lex(&val,&st);
  1737   if (tok==tSYMBOL) {
  1738     /* lastsymbol is char[sNAMEMAX+1], lex() should have truncated any symbol
  1739      * to sNAMEMAX significant characters */
  1740     assert(strlen(st)<sizeof lastsymbol);
  1741     strcpy(lastsymbol,st);
  1742   } /* if */
  1743   if (tok==tSYMBOL && !findconst(st,NULL)) {
  1744     /* first look for a local variable */
  1745     if ((sym=findloc(st))!=0) {
  1746       if (sym->ident==iLABEL) {
  1747         error(29);          /* expression error, assumed 0 */
  1748         ldconst(0,sPRI);    /* load 0 */
  1749         return FALSE;       /* return 0 for labels (expression error) */
  1750       } /* if */
  1751       lval->sym=sym;
  1752       lval->ident=sym->ident;
  1753       lval->tag=sym->tag;
  1754       if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1755         address(sym,sPRI);  /* get starting address in primary register */
  1756         return FALSE;       /* return 0 for array (not lvalue) */
  1757       } else {
  1758         return TRUE;        /* return 1 if lvalue (not label or array) */
  1759       } /* if */
  1760     } /* if */
  1761     /* now try a global variable */
  1762     if ((sym=findglb(st,sSTATEVAR))!=0) {
  1763       if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
  1764         /* if the function is only in the table because it was inserted as a
  1765          * stub in the first pass (i.e. it was "used" but never declared or
  1766          * implemented, issue an error
  1767          */
  1768         if ((sym->usage & uPROTOTYPED)==0)
  1769           error(17,st);
  1770       } else {
  1771         if ((sym->usage & uDEFINE)==0)
  1772           error(17,st);
  1773         lval->sym=sym;
  1774         lval->ident=sym->ident;
  1775         lval->tag=sym->tag;
  1776         if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1777           address(sym,sPRI);    /* get starting address in primary register */
  1778           return FALSE;         /* return 0 for array (not lvalue) */
  1779         } else {
  1780           return TRUE;          /* return 1 if lvalue (not function or array) */
  1781         } /* if */
  1782       } /* if */
  1783     } else {
  1784       if (!sc_allowproccall)
  1785         return error(17,st);    /* undefined symbol */
  1786       /* an unknown symbol, but used in a way compatible with the "procedure
  1787        * call" syntax. So assume that the symbol refers to a function.
  1788        */
  1789       assert(sc_status==statFIRST);
  1790       sym=fetchfunc(st,0);
  1791       if (sym==NULL)
  1792         error(103);     /* insufficient memory */
  1793     } /* if */
  1794     assert(sym!=NULL);
  1795     assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
  1796     lval->sym=sym;
  1797     lval->ident=sym->ident;
  1798     lval->tag=sym->tag;
  1799     return FALSE;       /* return 0 for function (not an lvalue) */
  1800   } /* if */
  1801   lexpush();            /* push the token, it is analyzed by constant() */
  1802   if (constant(lval)==0) {
  1803     error(29);          /* expression error, assumed 0 */
  1804     ldconst(0,sPRI);    /* load 0 */
  1805   } /* if */
  1806   return FALSE;         /* return 0 for constants (or errors) */
  1807 }
  1808 
  1809 static void clear_value(value *lval)
  1810 {
  1811   lval->sym=NULL;
  1812   lval->constval=0L;
  1813   lval->tag=0;
  1814   lval->ident=0;
  1815   lval->boolresult=FALSE;
  1816   /* do not clear lval->arrayidx, it is preset in hier14() */
  1817   /* do not clear lval->cmptag */
  1818 }
  1819 
  1820 static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int fconst)
  1821 {
  1822   /* The routine must copy the default array data onto the heap, as to avoid
  1823    * that a function can change the default value. An optimization is that
  1824    * the default array data is "dumped" into the data segment only once (on the
  1825    * first use).
  1826    */
  1827   assert(string!=NULL);
  1828   assert(size>0);
  1829   /* check whether to dump the default array */
  1830   assert(dataaddr!=NULL);
  1831   if (sc_status==statWRITE && *dataaddr<0) {
  1832     int i;
  1833     *dataaddr=(litidx+glb_declared)*sizeof(cell);
  1834     for (i=0; i<size; i++)
  1835       litadd(*string++);
  1836   } /* if */
  1837 
  1838   /* if the function is known not to modify the array (meaning that it also
  1839    * does not modify the default value), directly pass the address of the
  1840    * array in the data segment.
  1841    */
  1842   if (fconst) {
  1843     ldconst(*dataaddr,sPRI);
  1844   } else {
  1845     /* Generate the code:
  1846      *  CONST.pri dataaddr                ;address of the default array data
  1847      *  HEAP      array_sz*sizeof(cell)   ;heap address in ALT
  1848      *  MOVS      size*sizeof(cell)       ;copy data from PRI to ALT
  1849      *  MOVE.PRI                          ;PRI = address on the heap
  1850      */
  1851     ldconst(*dataaddr,sPRI);
  1852     /* "array_sz" is the size of the argument (the value between the brackets
  1853      * in the declaration), "size" is the size of the default array data.
  1854      */
  1855     assert(array_sz>=size);
  1856     modheap((int)array_sz*sizeof(cell));
  1857     /* ??? should perhaps fill with zeros first */
  1858     memcopy(size*sizeof(cell));
  1859     moveto1();
  1860   } /* if */
  1861 }
  1862 
  1863 static int findnamedarg(arginfo *arg,char *name)
  1864 {
  1865   int i;
  1866 
  1867   for (i=0; arg[i].ident!=0 && arg[i].ident!=iVARARGS; i++)
  1868     if (strcmp(arg[i].name,name)==0)
  1869       return i;
  1870   return -1;
  1871 }
  1872 
  1873 static int checktag(int tags[],int numtags,int exprtag)
  1874 {
  1875   int i;
  1876 
  1877   assert(tags!=0);
  1878   assert(numtags>0);
  1879   for (i=0; i<numtags; i++)
  1880     if (matchtag(tags[i],exprtag,TRUE))
  1881       return TRUE;    /* matching tag */
  1882   return FALSE;       /* no tag matched */
  1883 }
  1884 
  1885 enum {
  1886   ARG_UNHANDLED,
  1887   ARG_IGNORED,
  1888   ARG_DONE,
  1889 };
  1890 
  1891 /*  callfunction
  1892  *
  1893  *  Generates code to call a function. This routine handles default arguments
  1894  *  and positional as well as named parameters.
  1895  */
  1896 static void callfunction(symbol *sym,value *lval_result,int matchparanthesis)
  1897 {
  1898 static long nest_stkusage=0L;
  1899 static int nesting=0;
  1900   int locheap;
  1901   int close,lvalue;
  1902   int argpos;       /* index in the output stream (argpos==nargs if positional parameters) */
  1903   int argidx=0;     /* index in "arginfo" list */
  1904   int nargs=0;      /* number of arguments */
  1905   int heapalloc=0;
  1906   int namedparams=FALSE;
  1907   value lval = {0};
  1908   arginfo *arg;
  1909   char arglist[sMAXARGS];
  1910   constvalue arrayszlst = { NULL, "", 0, 0};/* array size list starts empty */
  1911   constvalue taglst = { NULL, "", 0, 0};    /* tag list starts empty */
  1912   symbol *symret;
  1913   cell lexval;
  1914   char *lexstr;
  1915 
  1916   assert(sym!=NULL);
  1917   lval_result->ident=iEXPRESSION; /* preset, may be changed later */
  1918   lval_result->constval=0;
  1919   lval_result->tag=sym->tag;
  1920   /* check whether this is a function that returns an array */
  1921   symret=finddepend(sym);
  1922   assert(symret==NULL || symret->ident==iREFARRAY);
  1923   if (symret!=NULL) {
  1924     int retsize;
  1925     /* allocate space on the heap for the array, and pass the pointer to the
  1926      * reserved memory block as a hidden parameter
  1927      */
  1928     retsize=(int)array_totalsize(symret);
  1929     assert(retsize>0);
  1930     modheap(retsize*sizeof(cell));/* address is in ALT */
  1931     pushreg(sALT);                /* pass ALT as the last (hidden) parameter */
  1932     decl_heap+=retsize;
  1933     /* also mark the ident of the result as "array" */
  1934     lval_result->ident=iREFARRAY;
  1935     lval_result->sym=symret;
  1936   } /* if */
  1937   locheap=decl_heap;
  1938 
  1939   nesting++;
  1940   assert(nest_stkusage>=0);
  1941   #if !defined NDEBUG
  1942     if (nesting==1)
  1943       assert(nest_stkusage==0);
  1944   #endif
  1945   sc_allowproccall=FALSE;       /* parameters may not use procedure call syntax */
  1946 
  1947   if ((sym->flags & flgDEPRECATED)!=0) {
  1948     char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
  1949     error(234,sym->name,ptr);   /* deprecated (probably a native function) */
  1950   } /* if */
  1951 
  1952   /* run through the arguments */
  1953   arg=sym->dim.arglist;
  1954   assert(arg!=NULL);
  1955   stgmark(sSTARTREORDER);
  1956   memset(arglist,ARG_UNHANDLED,sizeof arglist);
  1957   if (matchparanthesis) {
  1958     /* Opening brace was already parsed, if closing brace follows, this
  1959      * call passes no parameters.
  1960      */
  1961     close=matchtoken(')');
  1962   } else {
  1963     /* When we find an end of line here, it may be a function call passing
  1964      * no parameters, or it may be that the first parameter is on a line
  1965      * below. But as a parameter can be anything, this is difficult to check.
  1966      * The only simple check that we have is the use of "named parameters".
  1967      */
  1968     close=matchtoken(tTERM);
  1969     if (close) {
  1970       close=!matchtoken('.');
  1971       if (!close)
  1972         lexpush();                /* reset the '.' */
  1973     } /* if */
  1974   } /* if */
  1975   if (!close) {
  1976     do {
  1977       if (matchtoken('.')) {
  1978         namedparams=TRUE;
  1979         if (needtoken(tSYMBOL))
  1980           tokeninfo(&lexval,&lexstr);
  1981         else
  1982           lexstr="";
  1983         argpos=findnamedarg(arg,lexstr);
  1984         if (argpos<0) {
  1985           error(17,lexstr);       /* undefined symbol */
  1986           break;                  /* exit loop, argpos is invalid */
  1987         } /* if */
  1988         needtoken('=');
  1989         argidx=argpos;
  1990       } else {
  1991         if (namedparams)
  1992           error(44);   /* positional parameters must precede named parameters */
  1993         argpos=nargs;
  1994       } /* if */
  1995       /* the number of arguments this was already checked at the declaration
  1996        * of the function; check it again for functions with a variable
  1997        * argument list
  1998        */
  1999       if (argpos>=sMAXARGS)
  2000         error(45);                /* too many function arguments */
  2001       stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */
  2002       if (arglist[argpos]!=ARG_UNHANDLED)
  2003         error(58);                /* argument already set */
  2004       if (matchtoken('_')) {
  2005         arglist[argpos]=ARG_IGNORED;  /* flag argument as "present, but ignored" */
  2006         if (arg[argidx].ident==0 || arg[argidx].ident==iVARARGS) {
  2007           error(92);             /* argument count mismatch */
  2008         } else if (!arg[argidx].hasdefault) {
  2009           error(34,nargs+1);      /* argument has no default value */
  2010         } /* if */
  2011         if (arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS)
  2012           argidx++;
  2013         /* The rest of the code to handle default values is at the bottom
  2014          * of this routine where default values for unspecified parameters
  2015          * are (also) handled. Note that above, the argument is flagged as
  2016          * ARG_IGNORED.
  2017          */
  2018       } else {
  2019         arglist[argpos]=ARG_DONE; /* flag argument as "present" */
  2020         if (arg[argidx].numtags==1)     /* set the expected tag, if any */
  2021           lval.cmptag=arg[argidx].tags[0];
  2022         lvalue=hier14(&lval);
  2023         assert(sc_status==statFIRST || arg[argidx].tags!=NULL);
  2024         switch (arg[argidx].ident) {
  2025         case 0:
  2026           error(92);             /* argument count mismatch */
  2027           break;
  2028         case iVARARGS:
  2029           /* always pass by reference */
  2030           if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  2031             assert(lval.sym!=NULL);
  2032             if ((lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) {
  2033               /* treat a "const" variable passed to a function with a non-const
  2034                * "variable argument list" as a constant here */
  2035               if (!lvalue) {
  2036                 error(22);        /* need lvalue */
  2037               } else {
  2038                 rvalue(&lval);    /* get value in PRI */
  2039                 setheap_pri();    /* address of the value on the heap in PRI */
  2040                 heapalloc++;
  2041                 nest_stkusage++;
  2042               } /* if */
  2043             } else if (lvalue) {
  2044               address(lval.sym,sPRI);
  2045             } else {
  2046               setheap_pri();      /* address of the value on the heap in PRI */
  2047               heapalloc++;
  2048               nest_stkusage++;
  2049             } /* if */
  2050           } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION
  2051                      || lval.ident==iARRAYCHAR)
  2052           {
  2053             /* fetch value if needed */
  2054             if (lval.ident==iARRAYCHAR)
  2055               rvalue(&lval);
  2056             /* allocate a cell on the heap and store the
  2057              * value (already in PRI) there */
  2058             setheap_pri();        /* address of the value on the heap in PRI */
  2059             heapalloc++;
  2060             nest_stkusage++;
  2061           } /* if */
  2062           /* ??? handle const array passed by reference */
  2063           /* otherwise, the address is already in PRI */
  2064           if (lval.sym!=NULL)
  2065             markusage(lval.sym,uWRITTEN);
  2066           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2067             error(213);
  2068           if (lval.tag!=0)
  2069             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2070           break;
  2071         case iVARIABLE:
  2072           if (lval.ident==iLABEL || lval.ident==iFUNCTN || lval.ident==iREFFUNC
  2073               || lval.ident==iARRAY || lval.ident==iREFARRAY)
  2074             error(35,argidx+1);   /* argument type mismatch */
  2075           if (lvalue)
  2076             rvalue(&lval);        /* get value (direct or indirect) */
  2077           /* otherwise, the expression result is already in PRI */
  2078           assert(arg[argidx].numtags>0);
  2079           check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag);
  2080           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2081             error(213);
  2082           if (lval.tag!=0)
  2083             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2084           argidx++;               /* argument done */
  2085           break;
  2086         case iREFERENCE:
  2087           if (!lvalue || lval.ident==iARRAYCHAR)
  2088             error(35,argidx+1);   /* argument type mismatch */
  2089           if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  2090             error(35,argidx+1);   /* argument type mismatch */
  2091           if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  2092             if (lvalue) {
  2093               assert(lval.sym!=NULL);
  2094               address(lval.sym,sPRI);
  2095             } else {
  2096               setheap_pri();      /* address of the value on the heap in PRI */
  2097               heapalloc++;
  2098               nest_stkusage++;
  2099             } /* if */
  2100           } /* if */
  2101           /* otherwise, the address is already in PRI */
  2102           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2103             error(213);
  2104           if (lval.tag!=0)
  2105             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2106           argidx++;               /* argument done */
  2107           if (lval.sym!=NULL)
  2108             markusage(lval.sym,uWRITTEN);
  2109           break;
  2110         case iREFARRAY:
  2111           if (lval.ident!=iARRAY && lval.ident!=iREFARRAY
  2112               && lval.ident!=iARRAYCELL)
  2113           {
  2114             error(35,argidx+1);   /* argument type mismatch */
  2115             break;
  2116           } /* if */
  2117           if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  2118             error(35,argidx+1); /* argument type mismatch */
  2119           /* Verify that the dimensions match with those in arg[argidx].
  2120            * A literal array always has a single dimension.
  2121            * An iARRAYCELL parameter is also assumed to have a single dimension.
  2122            */
  2123           if (lval.sym==NULL || lval.ident==iARRAYCELL) {
  2124             if (arg[argidx].numdim!=1) {
  2125               error(48);        /* array dimensions must match */
  2126             } else if (arg[argidx].dim[0]!=0) {
  2127               assert(arg[argidx].dim[0]>0);
  2128               if (lval.ident==iARRAYCELL) {
  2129                 error(47);        /* array sizes must match */
  2130               } else {
  2131                 assert(lval.constval!=0); /* literal array must have a size */
  2132                 /* A literal array must have exactly the same size as the
  2133                  * function argument; a literal string may be smaller than
  2134                  * the function argument.
  2135                  */
  2136                 if (lval.constval>0 && arg[argidx].dim[0]!=lval.constval
  2137                     || lval.constval<0 && arg[argidx].dim[0] < -lval.constval)
  2138                   error(47);      /* array sizes must match */
  2139               } /* if */
  2140             } /* if */
  2141             if (lval.ident!=iARRAYCELL) {
  2142               /* save array size, for default values with uSIZEOF flag */
  2143               cell array_sz=lval.constval;
  2144               assert(array_sz!=0);/* literal array must have a size */
  2145               if (array_sz<0)
  2146                 array_sz= -array_sz;
  2147               append_constval(&arrayszlst,arg[argidx].name,array_sz,0);
  2148             } /* if */
  2149           } else {
  2150             symbol *sym=lval.sym;
  2151             short level=0;
  2152             assert(sym!=NULL);
  2153             if (sym->dim.array.level+1!=arg[argidx].numdim)
  2154               error(48);          /* array dimensions must match */
  2155             /* the lengths for all dimensions must match, unless the dimension
  2156              * length was defined at zero (which means "undefined")
  2157              */
  2158             while (sym->dim.array.level>0) {
  2159               assert(level<sDIMEN_MAX);
  2160               if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  2161                 error(47);        /* array sizes must match */
  2162               else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  2163                 error(229,sym->name);   /* index tag mismatch */
  2164               append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  2165               sym=finddepend(sym);
  2166               assert(sym!=NULL);
  2167               level++;
  2168             } /* if */
  2169             /* the last dimension is checked too, again, unless it is zero */
  2170             assert(level<sDIMEN_MAX);
  2171             assert(sym!=NULL);
  2172             if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  2173               error(47);          /* array sizes must match */
  2174             else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  2175               error(229,sym->name);   /* index tag mismatch */
  2176             append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  2177           } /* if */
  2178           /* address already in PRI */
  2179           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2180             error(213);
  2181           if (lval.tag!=0)
  2182             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2183           // ??? set uWRITTEN?
  2184           argidx++;               /* argument done */
  2185           break;
  2186         } /* switch */
  2187         pushreg(sPRI);            /* store the function argument on the stack */
  2188         markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  2189         nest_stkusage++;
  2190       } /* if */
  2191       assert(arglist[argpos]!=ARG_UNHANDLED);
  2192       nargs++;
  2193       if (matchparanthesis) {
  2194         close=matchtoken(')');
  2195         if (!close)               /* if not paranthese... */
  2196           if (!needtoken(','))    /* ...should be comma... */
  2197             break;                /* ...but abort loop if neither */
  2198       } else {
  2199         close=!matchtoken(',');
  2200         if (close) {              /* if not comma... */
  2201           if (needtoken(tTERM)==1)/* ...must be end of statement */
  2202             lexpush();            /* push again, because end of statement is analised later */
  2203         } /* if */
  2204       } /* if */
  2205     } while (!close && freading && !matchtoken(tENDEXPR)); /* do */
  2206   } /* if */
  2207   /* check remaining function arguments (they may have default values) */
  2208   for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  2209     if (arglist[argidx]==ARG_DONE)
  2210       continue;                 /* already seen and handled this argument */
  2211     /* in this first stage, we also skip the arguments with uSIZEOF and uTAGOF;
  2212      * these are handled last
  2213      */
  2214     if ((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0) {
  2215       assert(arg[argidx].ident==iVARIABLE);
  2216       continue;
  2217     } /* if */
  2218     stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  2219     if (arg[argidx].hasdefault) {
  2220       if (arg[argidx].ident==iREFARRAY) {
  2221         short level;
  2222         setdefarray(arg[argidx].defvalue.array.data,
  2223                     arg[argidx].defvalue.array.size,
  2224                     arg[argidx].defvalue.array.arraysize,
  2225                     &arg[argidx].defvalue.array.addr,
  2226                     (arg[argidx].usage & uCONST)!=0);
  2227         if ((arg[argidx].usage & uCONST)==0) {
  2228           heapalloc+=arg[argidx].defvalue.array.arraysize;
  2229           nest_stkusage+=arg[argidx].defvalue.array.arraysize;
  2230         } /* if */
  2231         /* keep the lengths of all dimensions of a multi-dimensional default array */
  2232         assert(arg[argidx].numdim>0);
  2233         if (arg[argidx].numdim==1) {
  2234           append_constval(&arrayszlst,arg[argidx].name,arg[argidx].defvalue.array.arraysize,0);
  2235         } else {
  2236           for (level=0; level<arg[argidx].numdim; level++) {
  2237             assert(level<sDIMEN_MAX);
  2238             append_constval(&arrayszlst,arg[argidx].name,arg[argidx].dim[level],level);
  2239           } /* for */
  2240         } /* if */
  2241       } else if (arg[argidx].ident==iREFERENCE) {
  2242         setheap(arg[argidx].defvalue.val);
  2243         /* address of the value on the heap in PRI */
  2244         heapalloc++;
  2245         nest_stkusage++;
  2246       } else {
  2247         int dummytag=arg[argidx].tags[0];
  2248         ldconst(arg[argidx].defvalue.val,sPRI);
  2249         assert(arg[argidx].numtags>0);
  2250         check_userop(NULL,arg[argidx].defvalue_tag,arg[argidx].tags[0],2,NULL,&dummytag);
  2251         assert(dummytag==arg[argidx].tags[0]);
  2252       } /* if */
  2253       pushreg(sPRI);            /* store the function argument on the stack */
  2254       markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  2255       nest_stkusage++;
  2256     } else {
  2257       error(202,argidx);        /* argument count mismatch */
  2258     } /* if */
  2259     if (arglist[argidx]==ARG_UNHANDLED)
  2260       nargs++;
  2261     arglist[argidx]=ARG_DONE;
  2262   } /* for */
  2263   /* now a second loop to catch the arguments with default values that are
  2264    * the "sizeof" or "tagof" of other arguments
  2265    */
  2266   for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  2267     constvalue *asz;
  2268     cell array_sz;
  2269     if (arglist[argidx]==ARG_DONE)
  2270       continue;                 /* already seen and handled this argument */
  2271     stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  2272     assert(arg[argidx].ident==iVARIABLE);           /* if "sizeof", must be single cell */
  2273     /* if unseen, must be "sizeof" or "tagof" */
  2274     assert((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0);
  2275     if ((arg[argidx].hasdefault & uSIZEOF)!=0) {
  2276       /* find the argument; if it isn't found, the argument's default value
  2277        * was a "sizeof" of a non-array (a warning for this was already given
  2278        * when declaring the function)
  2279        */
  2280       asz=find_constval(&arrayszlst,arg[argidx].defvalue.size.symname,
  2281                         arg[argidx].defvalue.size.level);
  2282       if (asz!=NULL) {
  2283         array_sz=asz->value;
  2284         if (array_sz==0)
  2285           error(224,arg[argidx].name);    /* indeterminate array size in "sizeof" expression */
  2286       } else {
  2287         array_sz=1;
  2288       } /* if */
  2289     } else {
  2290       asz=find_constval(&taglst,arg[argidx].defvalue.size.symname,
  2291                         arg[argidx].defvalue.size.level);
  2292       if (asz != NULL) {
  2293         exporttag(asz->value);
  2294         array_sz=asz->value | PUBLICTAG;  /* must be set, because it just was exported */
  2295       } else {
  2296         array_sz=0;
  2297       } /* if */
  2298     } /* if */
  2299     ldconst(array_sz,sPRI);
  2300     pushreg(sPRI);              /* store the function argument on the stack */
  2301     markexpr(sPARM,NULL,0);
  2302     nest_stkusage++;
  2303     if (arglist[argidx]==ARG_UNHANDLED)
  2304       nargs++;
  2305     arglist[argidx]=ARG_DONE;
  2306   } /* for */
  2307   stgmark(sENDREORDER);         /* mark end of reversed evaluation */
  2308   pushval((cell)nargs*sizeof(cell));
  2309   nest_stkusage++;
  2310   ffcall(sym,NULL,nargs);
  2311   if (sc_status!=statSKIP)
  2312     markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
  2313   if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL)
  2314     sym->x.lib->value += 1;     /* increment "usage count" of the library */
  2315   modheap(-heapalloc*sizeof(cell));
  2316   if (symret!=NULL)
  2317     popreg(sPRI);               /* pop hidden parameter as function result */
  2318   sideeffect=TRUE;              /* assume functions carry out a side-effect */
  2319   delete_consttable(&arrayszlst);     /* clear list of array sizes */
  2320   delete_consttable(&taglst);   /* clear list of parameter tags */
  2321 
  2322   /* maintain max. amount of memory used */
  2323   {
  2324     long totalsize;
  2325     totalsize=declared+decl_heap+1;   /* local variables & return value size,
  2326                                        * +1 for PROC opcode */
  2327     if (lval_result->ident==iREFARRAY)
  2328       totalsize++;                    /* add hidden parameter (on the stack) */
  2329     if ((sym->usage & uNATIVE)==0)
  2330       totalsize++;                    /* add "call" opcode */
  2331     totalsize+=nest_stkusage;
  2332     assert(curfunc!=NULL);
  2333     if (curfunc->x.stacksize<totalsize)
  2334       curfunc->x.stacksize=totalsize;
  2335     nest_stkusage-=nargs+heapalloc+1; /* stack/heap space, +1 for argcount param */
  2336     /* if there is a syntax error in the script, the stack calculation is
  2337      * probably incorrect; but we may not allow it to drop below zero
  2338      */
  2339     if (nest_stkusage<0)
  2340       nest_stkusage=0;
  2341   }
  2342 
  2343   /* scrap any arrays left on the heap, with the exception of the array that
  2344    * this function has as a result (in other words, scrap all arrays on the
  2345    * heap that caused by expressions in the function arguments)
  2346    */
  2347   assert(decl_heap>=locheap);
  2348   modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
  2349   decl_heap=locheap;
  2350   nesting--;
  2351 }
  2352 
  2353 /*  dbltest
  2354  *
  2355  *  Returns a non-zero value if lval1 an array and lval2 is not an array and
  2356  *  the operation is addition or subtraction.
  2357  *
  2358  *  Returns the "shift" count (1 for 16-bit, 2 for 32-bit) to align a cell
  2359  *  to an array offset.
  2360  */
  2361 static int dbltest(void (*oper)(),value *lval1,value *lval2)
  2362 {
  2363   if ((oper!=ob_add) && (oper!=ob_sub))
  2364     return 0;
  2365   if (lval1->ident!=iARRAY)
  2366     return 0;
  2367   if (lval2->ident==iARRAY)
  2368     return 0;
  2369   return sizeof(cell)/2;        /* 1 for 16-bit, 2 for 32-bit */
  2370 }
  2371 
  2372 /*  commutative
  2373  *
  2374  *  Test whether an operator is commutative, i.e. x oper y == y oper x.
  2375  *  Commutative operators are: +  (addition)
  2376  *                             *  (multiplication)
  2377  *                             == (equality)
  2378  *                             != (inequality)
  2379  *                             &  (bitwise and)
  2380  *                             ^  (bitwise xor)
  2381  *                             |  (bitwise or)
  2382  *
  2383  *  If in an expression, code for the left operand has been generated and
  2384  *  the right operand is a constant and the operator is commutative, the
  2385  *  precautionary "push" of the primary register is scrapped and the constant
  2386  *  is read into the secondary register immediately.
  2387  */
  2388 static int commutative(void (*oper)())
  2389 {
  2390   return oper==ob_add || oper==os_mult
  2391          || oper==ob_eq || oper==ob_ne
  2392          || oper==ob_and || oper==ob_xor || oper==ob_or;
  2393 }
  2394 
  2395 /*  constant
  2396  *
  2397  *  Generates code to fetch a number, a literal character (which is returned
  2398  *  by lex() as a number as well) or a literal string (lex() stores the
  2399  *  strings in the literal queue). If the operand was a number, it is stored
  2400  *  in lval->constval.
  2401  *
  2402  *  The function returns 1 if the token was a constant or a string, 0
  2403  *  otherwise.
  2404  */
  2405 static int constant(value *lval)
  2406 {
  2407   int tok,index,ident;
  2408   cell val,item,cidx;
  2409   char *st;
  2410   symbol *sym;
  2411   int cmptag=lval->cmptag;
  2412 
  2413   tok=lex(&val,&st);
  2414   if (tok==tSYMBOL && (sym=findconst(st,&cmptag))!=0) {
  2415     if (cmptag>1)
  2416       error(91,sym->name);  /* ambiguity: multiple matching constants (different tags) */
  2417     lval->constval=sym->addr;
  2418     ldconst(lval->constval,sPRI);
  2419     lval->ident=iCONSTEXPR;
  2420     lval->tag=sym->tag;
  2421     lval->sym=sym;
  2422     markusage(sym,uREAD);
  2423   } else if (tok==tNUMBER) {
  2424     lval->constval=val;
  2425     ldconst(lval->constval,sPRI);
  2426     lval->ident=iCONSTEXPR;
  2427   } else if (tok==tRATIONAL) {
  2428     lval->constval=val;
  2429     ldconst(lval->constval,sPRI);
  2430     lval->ident=iCONSTEXPR;
  2431     lval->tag=sc_rationaltag;
  2432   } else if (tok==tSTRING) {
  2433     /* lex() stores starting index of string in the literal table in 'val' */
  2434     ldconst((val+glb_declared)*sizeof(cell),sPRI);
  2435     lval->ident=iARRAY;         /* pretend this is a global array */
  2436     lval->constval=val-litidx;  /* constval == the negative value of the
  2437                                  * size of the literal array; using a negative
  2438                                  * value distinguishes between literal arrays
  2439                                  * and literal strings (this was done for
  2440                                  * array assignment). */
  2441   } else if (tok=='{') {
  2442     int tag,lasttag=-1;
  2443     val=litidx;
  2444     do {
  2445       /* cannot call constexpr() here, because "staging" is already turned
  2446        * on at this point */
  2447       assert(staging);
  2448       stgget(&index,&cidx);     /* mark position in code generator */
  2449       ident=expression(&item,&tag,NULL,FALSE);
  2450       stgdel(index,cidx);       /* scratch generated code */
  2451       if (ident!=iCONSTEXPR)
  2452         error(8);               /* must be constant expression */
  2453       if (lasttag<0)
  2454         lasttag=tag;
  2455       else if (!matchtag(lasttag,tag,FALSE))
  2456         error(213);             /* tagname mismatch */
  2457       litadd(item);             /* store expression result in literal table */
  2458     } while (matchtoken(','));
  2459     if (!needtoken('}'))
  2460       lexclr(FALSE);
  2461     ldconst((val+glb_declared)*sizeof(cell),sPRI);
  2462     lval->ident=iARRAY;         /* pretend this is a global array */
  2463     lval->constval=litidx-val;  /* constval == the size of the literal array */
  2464   } else {
  2465     return FALSE;               /* no, it cannot be interpreted as a constant */
  2466   } /* if */
  2467   return TRUE;                  /* yes, it was a constant value */
  2468 }
  2469