sourcepawn/compiler/sc3.c
author Borja Ferrer <faluco@alliedmods.net>
Mon Aug 28 15:22:02 2006 +0000 (2006-08-28)
changeset 62 7c24f0801ae1
parent 52 97bdc78041aa
child 64 cc302adaac00
permissions -rw-r--r--
updated compiler to 3.2.3636
     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 3635 2006-08-13 12:19:41Z 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 flooreddiv(cell a,cell b,int return_remainder)
   623 {
   624   cell q,r;
   625 
   626   if (b==0) {
   627     error(29);
   628     return 0;
   629   } /* if */
   630   /* first implement truncated division in a portable way */
   631   #define IABS(a)       ((a)>=0 ? (a) : (-a))
   632   q=IABS(a)/IABS(b);
   633   if ((cell)(a ^ b)<0)
   634     q=-q;               /* swap sign if either "a" or "b" is negative (but not both) */
   635   r=a-q*b;              /* calculate the matching remainder */
   636   /* now "fiddle" with the values to get floored division */
   637   if (r!=0 && (cell)(r ^ b)<0) {
   638     q--;
   639     r+=b;
   640   } /* if */
   641   return return_remainder ? r : q;
   642 }
   643 
   644 static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
   645 {
   646   if (oper==ob_or)
   647     return (left | right);
   648   else if (oper==ob_xor)
   649     return (left ^ right);
   650   else if (oper==ob_and)
   651     return (left & right);
   652   else if (oper==ob_eq)
   653     return (left == right);
   654   else if (oper==ob_ne)
   655     return (left != right);
   656   else if (oper==os_le)
   657     return *boolresult &= (char)(left <= right), right;
   658   else if (oper==os_ge)
   659     return *boolresult &= (char)(left >= right), right;
   660   else if (oper==os_lt)
   661     return *boolresult &= (char)(left < right), right;
   662   else if (oper==os_gt)
   663     return *boolresult &= (char)(left > right), right;
   664   else if (oper==os_sar)
   665     return (left >> (int)right);
   666   else if (oper==ou_sar)
   667     return ((ucell)left >> (ucell)right);
   668   else if (oper==ob_sal)
   669     return ((ucell)left << (int)right);
   670   else if (oper==ob_add)
   671     return (left + right);
   672   else if (oper==ob_sub)
   673     return (left - right);
   674   else if (oper==os_mult)
   675     return (left * right);
   676   else if (oper==os_div)
   677     return flooreddiv(left,right,0);
   678   else if (oper==os_mod)
   679     return flooreddiv(left,right,1);
   680   else
   681     error(29);  /* invalid expression, assumed 0 (this should never occur) */
   682   return 0;
   683 }
   684 
   685 SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
   686 {
   687   int locheap=decl_heap;
   688   value lval={0};
   689 
   690   if (hier14(&lval))
   691     rvalue(&lval);
   692   /* scrap any arrays left on the heap */
   693   assert(decl_heap>=locheap);
   694   modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
   695   decl_heap=locheap;
   696 
   697   if (lval.ident==iCONSTEXPR && val!=NULL)    /* constant expression */
   698     *val=lval.constval;
   699   if (tag!=NULL)
   700     *tag=lval.tag;
   701   if (symptr!=NULL)
   702     *symptr=lval.sym;
   703   if (chkfuncresult)
   704     checkfunction(&lval);
   705   return lval.ident;
   706 }
   707 
   708 SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
   709 {
   710   char name[sNAMEMAX+1];
   711   cell val;
   712   char *str;
   713   int fsa,islabel;
   714 
   715   assert(automaton!=NULL);
   716   assert(state!=NULL);
   717   if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL))
   718     return 0;
   719 
   720   tokeninfo(&val,&str);
   721   assert(strlen(str)<sizeof name);
   722   strcpy(name,str);
   723   if (islabel || matchtoken(':')) {
   724     /* token is an automaton name, add the name and get a new token */
   725     *automaton=automaton_find(name);
   726     /* read in the state name before checking the automaton, to keep the parser
   727      * going (an "unknown automaton" error may occur when the "state" instruction
   728      * precedes any state definition)
   729      */
   730     if (!needtoken(tSYMBOL))
   731       return 0;
   732     tokeninfo(&val,&str);        /* do not copy the name yet, must check automaton first */
   733     if (*automaton==NULL) {
   734       error(86,name);            /* unknown automaton */
   735       return 0;
   736     } /* if */
   737     assert((*automaton)->index>0);
   738     assert(strlen(str)<sizeof name);
   739     strcpy(name,str);
   740   } else {
   741     *automaton=automaton_find("");
   742     assert(*automaton!=NULL);
   743     assert((*automaton)->index==0);
   744   } /* if */
   745   assert(*automaton!=NULL);
   746   fsa=(*automaton)->index;
   747 
   748   assert(*automaton!=NULL);
   749   *state=state_find(name,fsa);
   750   if (*state==NULL) {
   751     char *fsaname=(*automaton)->name;
   752     if (*fsaname=='\0')
   753       fsaname="<main>";
   754     error(87,name,fsaname);   /* unknown state for automaton */
   755     return 0;
   756   } /* if */
   757 
   758   return 1;
   759 }
   760 
   761 SC_FUNC cell array_totalsize(symbol *sym)
   762 {
   763   cell length;
   764 
   765   assert(sym!=NULL);
   766   assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   767   length=sym->dim.array.length;
   768   if (sym->dim.array.level > 0) {
   769     cell sublength=array_totalsize(finddepend(sym));
   770     if (sublength>0)
   771       length=length+length*sublength;
   772     else
   773       length=0;
   774   } /* if */
   775   return length;
   776 }
   777 
   778 static cell array_levelsize(symbol *sym,int level)
   779 {
   780   assert(sym!=NULL);
   781   assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   782   assert(level <= sym->dim.array.level);
   783   while (level-- > 0) {
   784     sym=finddepend(sym);
   785     assert(sym!=NULL);
   786   } /* if */
   787   return sym->dim.array.length;
   788 }
   789 
   790 /*  hier14
   791  *
   792  *  Lowest hierarchy level (except for the , operator).
   793  *
   794  *  Global references: sc_intest        (reffered to only)
   795  *                     sc_allowproccall (modified)
   796  */
   797 static int hier14(value *lval1)
   798 {
   799   int lvalue;
   800   value lval2={0},lval3={0};
   801   void (*oper)(void);
   802   int tok,level,i;
   803   cell val;
   804   char *st;
   805   int bwcount,leftarray;
   806   cell arrayidx1[sDIMEN_MAX],arrayidx2[sDIMEN_MAX];  /* last used array indices */
   807   cell *org_arrayidx;
   808 
   809   bwcount=bitwise_opercount;
   810   bitwise_opercount=0;
   811   /* initialize the index arrays with unlikely constant indices; note that
   812    * these indices will only be changed when the array is indexed with a
   813    * constant, and that negative array indices are invalid (so actually, any
   814    * negative value would do).
   815    */
   816   for (i=0; i<sDIMEN_MAX; i++)
   817     arrayidx1[i]=arrayidx2[i]=(cell)(-1L << (sizeof(cell)*8-1));
   818   org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */
   819   if (lval1->arrayidx==NULL)
   820     lval1->arrayidx=arrayidx1;
   821   lvalue=plnge1(hier13,lval1);
   822   if (lval1->ident!=iARRAYCELL && lval1->ident!=iARRAYCHAR)
   823     lval1->arrayidx=NULL;
   824   if (lval1->ident==iCONSTEXPR) /* load constant here */
   825     ldconst(lval1->constval,sPRI);
   826   tok=lex(&val,&st);
   827   switch (tok) {
   828     case taOR:
   829       oper=ob_or;
   830       break;
   831     case taXOR:
   832       oper=ob_xor;
   833       break;
   834     case taAND:
   835       oper=ob_and;
   836       break;
   837     case taADD:
   838       oper=ob_add;
   839       break;
   840     case taSUB:
   841       oper=ob_sub;
   842       break;
   843     case taMULT:
   844       oper=os_mult;
   845       break;
   846     case taDIV:
   847       oper=os_div;
   848       break;
   849     case taMOD:
   850       oper=os_mod;
   851       break;
   852     case taSHRU:
   853       oper=ou_sar;
   854       break;
   855     case taSHR:
   856       oper=os_sar;
   857       break;
   858     case taSHL:
   859       oper=ob_sal;
   860       break;
   861     case '=':           /* simple assignment */
   862       oper=NULL;
   863       if (sc_intest)
   864         error(211);     /* possibly unintended assignment */
   865       break;
   866     default:
   867       lexpush();
   868       bitwise_opercount=bwcount;
   869       lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   870       return lvalue;
   871   } /* switch */
   872 
   873   /* if we get here, it was an assignment; first check a few special cases
   874    * and then the general */
   875   if (lval1->ident==iARRAYCHAR) {
   876     /* special case, assignment to packed character in a cell is permitted */
   877     lvalue=TRUE;
   878   } else if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
   879     /* array assignment is permitted too (with restrictions) */
   880     if (oper)
   881       return error(23); /* array assignment must be simple assigment */
   882     assert(lval1->sym!=NULL);
   883     if (array_totalsize(lval1->sym)==0)
   884       return error(46,lval1->sym->name);        /* unknown array size */
   885     lvalue=TRUE;
   886   } /* if */
   887 
   888   /* operand on left side of assignment must be lvalue */
   889   if (!lvalue)
   890     return error(22);                   /* must be lvalue */
   891   /* may not change "constant" parameters */
   892   assert(lval1->sym!=NULL);
   893   if ((lval1->sym->usage & uCONST)!=0)
   894     return error(22);           /* assignment to const argument */
   895   sc_allowproccall=FALSE;       /* may no longer use "procedure call" syntax */
   896 
   897   lval3=*lval1;         /* save symbol to enable storage of expresion result */
   898   lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   899   if (lval1->ident==iARRAYCELL || lval1->ident==iARRAYCHAR
   900       || lval1->ident==iARRAY || lval1->ident==iREFARRAY)
   901   {
   902     /* if indirect fetch: save PRI (cell address) */
   903     if (oper) {
   904       pushreg(sPRI);
   905       rvalue(lval1);
   906     } /* if */
   907     lval2.arrayidx=arrayidx2;
   908     plnge2(oper,hier14,lval1,&lval2);
   909     if (lval2.ident!=iARRAYCELL && lval2.ident!=iARRAYCHAR)
   910       lval2.arrayidx=NULL;
   911     if (oper)
   912       popreg(sALT);
   913     if (!oper && lval3.arrayidx!=NULL && lval2.arrayidx!=NULL
   914         && lval3.ident==lval2.ident && lval3.sym==lval2.sym)
   915     {
   916       int same=TRUE;
   917       assert(lval2.arrayidx==arrayidx2);
   918       for (i=0; i<sDIMEN_MAX; i++)
   919         same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]);
   920         if (same)
   921           error(226,lval3.sym->name);   /* self-assignment */
   922     } /* if */
   923   } else {
   924     if (oper){
   925       rvalue(lval1);
   926       plnge2(oper,hier14,lval1,&lval2);
   927     } else {
   928       /* if direct fetch and simple assignment: no "push"
   929        * and "pop" needed -> call hier14() directly, */
   930       if (hier14(&lval2))
   931         rvalue(&lval2);         /* instead of plnge2(). */
   932       else if (lval2.ident==iVARIABLE)
   933         lval2.ident=iEXPRESSION;/* mark as "rvalue" if it is not an "lvalue" */
   934       checkfunction(&lval2);
   935       /* check whether lval2 and lval3 (old lval1) refer to the same variable */
   936       if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) {
   937         assert(lval3.sym!=NULL);
   938         error(226,lval3.sym->name);     /* self-assignment */
   939       } /* if */
   940     } /* if */
   941   } /* if */
   942   /* Array elements are sometimes considered as sub-arrays --when the
   943    * array index is an enumeration field and the enumeration size is greater
   944    * than 1. If the expression on the right side of the assignment is a cell,
   945    * or if an operation is in effect, this does not apply.
   946    */
   947   leftarray= lval3.ident==iARRAY || lval3.ident==iREFARRAY
   948              || ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   949                  && lval3.constval>1 && lval3.sym->dim.array.level==0
   950                  && !oper && (lval2.ident==iARRAY || lval2.ident==iREFARRAY));
   951   if (leftarray) {
   952     /* Left operand is an array, right operand should be an array variable
   953      * of the same size and the same dimension, an array literal (of the
   954      * same size) or a literal string. For single-dimensional arrays without
   955      * tag for the index, it is permitted to assign a smaller array into a
   956      * larger one (without warning). This is to make it easier to work with
   957      * strings.
   958      */
   959     int exactmatch=TRUE;
   960     int idxtag=0;
   961     int ltlength=(int)lval3.sym->dim.array.length;
   962     if ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   963         && lval3.constval>0 && lval3.sym->dim.array.level==0)
   964     {
   965       ltlength=(int)lval3.constval;
   966     } /* if */
   967     if (lval2.ident!=iARRAY && lval2.ident!=iREFARRAY
   968         && (lval2.sym==NULL || lval2.constval<=0))
   969       error(33,lval3.sym->name);        /* array must be indexed */
   970     if (lval2.sym!=NULL) {
   971       if (lval2.constval==0) {
   972         val=lval2.sym->dim.array.length;/* array variable */
   973       } else {
   974         val=lval2.constval;
   975         if (lval2.sym->dim.array.level!=0)
   976           error(28,lval2.sym->name);
   977       } /* if */
   978       level=lval2.sym->dim.array.level;
   979       idxtag=lval2.sym->x.tags.index;
   980       if (level==0 && idxtag==0 && lval3.sym->x.tags.index==0)
   981         exactmatch=FALSE;
   982     } else {
   983       val=lval2.constval;               /* literal array */
   984       level=0;
   985       /* If val is negative, it means that lval2 is a literal string.
   986        * The string array size may be smaller than the destination
   987        * array, provided that the destination array does not have an
   988        * index tag.
   989        */
   990       if (val<0) {
   991         val=-val;
   992         if (lval3.sym->x.tags.index==0)
   993           exactmatch=FALSE;
   994       } /* if */
   995     } /* if */
   996     if (lval3.sym->dim.array.level!=level)
   997       return error(48); /* array dimensions must match */
   998     else if (ltlength<val || exactmatch && ltlength>val || val==0)
   999       return error(47); /* array sizes must match */
  1000     else if (lval3.ident!=iARRAYCELL && !matchtag(lval3.sym->x.tags.index,idxtag,TRUE))
  1001       error(229,(lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name); /* index tag mismatch */
  1002     if (level>0) {
  1003       /* check the sizes of all sublevels too */
  1004       symbol *sym1 = lval3.sym;
  1005       symbol *sym2 = lval2.sym;
  1006       int i;
  1007       assert(sym1!=NULL && sym2!=NULL);
  1008       /* ^^^ sym2 must be valid, because only variables can be
  1009        *     multi-dimensional (there are no multi-dimensional literals),
  1010        *     sym1 must be valid because it must be an lvalue
  1011        */
  1012       assert(exactmatch);
  1013       for (i=0; i<level; i++) {
  1014         sym1=finddepend(sym1);
  1015         sym2=finddepend(sym2);
  1016         assert(sym1!=NULL && sym2!=NULL);
  1017         /* ^^^ both arrays have the same dimensions (this was checked
  1018          *     earlier) so the dependend should always be found
  1019          */
  1020         if (sym1->dim.array.length!=sym2->dim.array.length)
  1021           error(47);    /* array sizes must match */
  1022         else if (!matchtag(sym1->x.tags.index,sym2->x.tags.index,TRUE))
  1023           error(229,sym2->name);  /* index tag mismatch */
  1024       } /* for */
  1025       /* get the total size in cells of the multi-dimensional array */
  1026       val=array_totalsize(lval3.sym);
  1027       assert(val>0);    /* already checked */
  1028     } /* if */
  1029   } else {
  1030     /* left operand is not an array, right operand should then not be either */
  1031     if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1032       error(6);         /* must be assigned to an array */
  1033   } /* if */
  1034   if (leftarray) {
  1035     memcopy(val*sizeof(cell));
  1036   } else {
  1037     check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag);
  1038     store(&lval3);      /* now, store the expression result */
  1039   } /* if */
  1040   if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE))
  1041     error(213);         /* tagname mismatch (if "oper", warning already given in plunge2()) */
  1042   if (lval3.sym)
  1043     markusage(lval3.sym,uWRITTEN);
  1044   sideeffect=TRUE;
  1045   bitwise_opercount=bwcount;
  1046   lval1->ident=iEXPRESSION;
  1047   return FALSE;         /* expression result is never an lvalue */
  1048 }
  1049 
  1050 static int hier13(value *lval)
  1051 {
  1052   int lvalue=plnge1(hier12,lval);
  1053   if (matchtoken('?')) {
  1054     int flab1=getlabel();
  1055     int flab2=getlabel();
  1056     value lval2={0};
  1057     int array1,array2;
  1058 
  1059     if (lvalue) {
  1060       rvalue(lval);
  1061     } else if (lval->ident==iCONSTEXPR) {
  1062       ldconst(lval->constval,sPRI);
  1063       error(lval->constval ? 206 : 205);        /* redundant test */
  1064     } /* if */
  1065     jmp_eq0(flab1);             /* go to second expression if primary register==0 */
  1066     PUSHSTK_I(sc_allowtags);
  1067     sc_allowtags=FALSE;         /* do not allow tagnames here (colon is a special token) */
  1068     if (hier13(lval))
  1069       rvalue(lval);
  1070     if (lval->ident==iCONSTEXPR)        /* load constant here */
  1071       ldconst(lval->constval,sPRI);
  1072     sc_allowtags=(short)POPSTK_I();     /* restore */
  1073     jumplabel(flab2);
  1074     setlabel(flab1);
  1075     needtoken(':');
  1076     if (hier13(&lval2))
  1077       rvalue(&lval2);
  1078     if (lval2.ident==iCONSTEXPR)        /* load constant here */
  1079       ldconst(lval2.constval,sPRI);
  1080     array1= (lval->ident==iARRAY || lval->ident==iREFARRAY);
  1081     array2= (lval2.ident==iARRAY || lval2.ident==iREFARRAY);
  1082     if (array1 && !array2) {
  1083       char *ptr=(lval->sym->name!=NULL) ? lval->sym->name : "-unknown-";
  1084       error(33,ptr);            /* array must be indexed */
  1085     } else if (!array1 && array2) {
  1086       char *ptr=(lval2.sym->name!=NULL) ? lval2.sym->name : "-unknown-";
  1087       error(33,ptr);            /* array must be indexed */
  1088     } /* if */
  1089     /* ??? if both are arrays, should check dimensions */
  1090     if (!matchtag(lval->tag,lval2.tag,FALSE))
  1091       error(213);               /* tagname mismatch ('true' and 'false' expressions) */
  1092     setlabel(flab2);
  1093     if (lval->ident==iARRAY)
  1094       lval->ident=iREFARRAY;    /* iARRAY becomes iREFARRAY */
  1095     else if (lval->ident!=iREFARRAY)
  1096       lval->ident=iEXPRESSION;  /* iREFARRAY stays iREFARRAY, rest becomes iEXPRESSION */
  1097     return FALSE;               /* conditional expression is no lvalue */
  1098   } else {
  1099     return lvalue;
  1100   } /* if */
  1101 }
  1102 
  1103 /* the order of the operators in these lists is important and must be
  1104  * the same as the order of the operators in the array "op1"
  1105  */
  1106 static int list3[]  = {'*','/','%',0};
  1107 static int list4[]  = {'+','-',0};
  1108 static int list5[]  = {tSHL,tSHR,tSHRU,0};
  1109 static int list6[]  = {'&',0};
  1110 static int list7[]  = {'^',0};
  1111 static int list8[]  = {'|',0};
  1112 static int list9[]  = {tlLE,tlGE,'<','>',0};
  1113 static int list10[] = {tlEQ,tlNE,0};
  1114 static int list11[] = {tlAND,0};
  1115 static int list12[] = {tlOR,0};
  1116 
  1117 static int hier12(value *lval)
  1118 {
  1119   return skim(list12,jmp_ne0,1,0,hier11,lval);
  1120 }
  1121 
  1122 static int hier11(value *lval)
  1123 {
  1124   return skim(list11,jmp_eq0,0,1,hier10,lval);
  1125 }
  1126 
  1127 static int hier10(value *lval)
  1128 { /* ==, != */
  1129   return plnge(list10,15,hier9,lval,"bool",TRUE);
  1130 }                  /* ^ this variable is the starting index in the op1[]
  1131                     *   array of the operators of this hierarchy level */
  1132 
  1133 static int hier9(value *lval)
  1134 { /* <=, >=, <, > */
  1135   return plnge_rel(list9,11,hier8,lval);
  1136 }
  1137 
  1138 static int hier8(value *lval)
  1139 { /* | */
  1140   return plnge(list8,10,hier7,lval,NULL,FALSE);
  1141 }
  1142 
  1143 static int hier7(value *lval)
  1144 { /* ^ */
  1145   return plnge(list7,9,hier6,lval,NULL,FALSE);
  1146 }
  1147 
  1148 static int hier6(value *lval)
  1149 { /* & */
  1150   return plnge(list6,8,hier5,lval,NULL,FALSE);
  1151 }
  1152 
  1153 static int hier5(value *lval)
  1154 { /* <<, >>, >>> */
  1155   return plnge(list5,5,hier4,lval,NULL,FALSE);
  1156 }
  1157 
  1158 static int hier4(value *lval)
  1159 { /* +, - */
  1160   return plnge(list4,3,hier3,lval,NULL,FALSE);
  1161 }
  1162 
  1163 static int hier3(value *lval)
  1164 { /* *, /, % */
  1165   return plnge(list3,0,hier2,lval,NULL,FALSE);
  1166 }
  1167 
  1168 static int hier2(value *lval)
  1169 {
  1170   int lvalue,tok;
  1171   int tag,paranthese;
  1172   cell val;
  1173   char *st;
  1174   symbol *sym;
  1175   int saveresult;
  1176 
  1177   tok=lex(&val,&st);
  1178   switch (tok) {
  1179   case tINC:                    /* ++lval */
  1180     if (!hier2(lval))
  1181       return error(22);         /* must be lvalue */
  1182     assert(lval->sym!=NULL);
  1183     if ((lval->sym->usage & uCONST)!=0)
  1184       return error(22);         /* assignment to const argument */
  1185     if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1186       inc(lval);                /* increase variable first */
  1187     rvalue(lval);               /* and read the result into PRI */
  1188     sideeffect=TRUE;
  1189     return FALSE;               /* result is no longer lvalue */
  1190   case tDEC:                    /* --lval */
  1191     if (!hier2(lval))
  1192       return error(22);         /* must be lvalue */
  1193     assert(lval->sym!=NULL);
  1194     if ((lval->sym->usage & uCONST)!=0)
  1195       return error(22);         /* assignment to const argument */
  1196     if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1197       dec(lval);                /* decrease variable first */
  1198     rvalue(lval);               /* and read the result into PRI */
  1199     sideeffect=TRUE;
  1200     return FALSE;               /* result is no longer lvalue */
  1201   case '~':                     /* ~ (one's complement) */
  1202     if (hier2(lval))
  1203       rvalue(lval);
  1204     invert();                   /* bitwise NOT */
  1205     lval->constval=~lval->constval;
  1206     return FALSE;
  1207   case '!':                     /* ! (logical negate) */
  1208     if (hier2(lval))
  1209       rvalue(lval);
  1210     if (check_userop(lneg,lval->tag,0,1,NULL,&lval->tag)) {
  1211       lval->ident=iEXPRESSION;
  1212       lval->constval=0;
  1213     } else {
  1214       lneg();                   /* 0 -> 1,  !0 -> 0 */
  1215       lval->constval=!lval->constval;
  1216       lval->tag=pc_addtag("bool");
  1217     } /* if */
  1218     return FALSE;
  1219   case '-':                     /* unary - (two's complement) */
  1220     if (hier2(lval))
  1221       rvalue(lval);
  1222     /* make a special check for a constant expression with the tag of a
  1223      * rational number, so that we can simple swap the sign of that constant.
  1224      */
  1225     if (lval->ident==iCONSTEXPR && lval->tag==sc_rationaltag && sc_rationaltag!=0) {
  1226       if (rational_digits==0) {
  1227         #if PAWN_CELL_SIZE==32
  1228           float *f = (float *)&lval->constval;
  1229         #elif PAWN_CELL_SIZE==64
  1230           double *f = (double *)&lval->constval;
  1231         #else
  1232           #error Unsupported cell size
  1233         #endif
  1234         *f= - *f; /* this modifies lval->constval */
  1235       } else {
  1236         /* the negation of a fixed point number is just an integer negation */
  1237         lval->constval=-lval->constval;
  1238       } /* if */
  1239     } else if (check_userop(neg,lval->tag,0,1,NULL,&lval->tag)) {
  1240       lval->ident=iEXPRESSION;
  1241       lval->constval=0;
  1242     } else {
  1243       neg();                    /* arithmic negation */
  1244       lval->constval=-lval->constval;
  1245     } /* if */
  1246     return FALSE;
  1247   case tLABEL:                  /* tagname override */
  1248     tag=pc_addtag(st);
  1249     lval->cmptag=tag;
  1250     lvalue=hier2(lval);
  1251     lval->tag=tag;
  1252     return lvalue;
  1253   case tDEFINED:
  1254     paranthese=0;
  1255     while (matchtoken('('))
  1256       paranthese++;
  1257     tok=lex(&val,&st);
  1258     if (tok!=tSYMBOL)
  1259       return error(20,st);      /* illegal symbol name */
  1260     sym=findloc(st);
  1261     if (sym==NULL)
  1262       sym=findglb(st,sSTATEVAR);
  1263     if (sym!=NULL && sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0)
  1264       sym=NULL;                 /* symbol is not a function, it is in the table, but not "defined" */
  1265     val= (sym!=NULL);
  1266     if (!val && find_subst(st,strlen(st))!=NULL)
  1267       val=1;
  1268     clear_value(lval);
  1269     lval->ident=iCONSTEXPR;
  1270     lval->constval= val;
  1271     lval->tag=pc_addtag("bool");
  1272     ldconst(lval->constval,sPRI);
  1273     while (paranthese--)
  1274       needtoken(')');
  1275     return FALSE;
  1276   case tSIZEOF:
  1277     paranthese=0;
  1278     while (matchtoken('('))
  1279       paranthese++;
  1280     tok=lex(&val,&st);
  1281     if (tok!=tSYMBOL)
  1282       return error(20,st);      /* illegal symbol name */
  1283     sym=findloc(st);
  1284     if (sym==NULL)
  1285       sym=findglb(st,sSTATEVAR);
  1286     if (sym==NULL)
  1287       return error(17,st);      /* undefined symbol */
  1288     if (sym->ident==iCONSTEXPR)
  1289       error(39);                /* constant symbol has no size */
  1290     else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC)
  1291       error(72);                /* "function" symbol has no size */
  1292     else if ((sym->usage & uDEFINE)==0)
  1293       return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1294     clear_value(lval);
  1295     lval->ident=iCONSTEXPR;
  1296     lval->constval=1;           /* preset */
  1297     if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1298       int level;
  1299       symbol *idxsym=NULL;
  1300       symbol *subsym=sym;
  1301       for (level=0; matchtoken('['); level++) {
  1302         idxsym=NULL;
  1303         if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1304           char *idxname;
  1305           int cmptag=subsym->x.tags.index;
  1306           tokeninfo(&val,&idxname);
  1307           if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1308             error(80,idxname);  /* unknown symbol, or non-constant */
  1309           else if (cmptag>1)
  1310             error(91,idxname);  /* ambiguous constant */
  1311         } /* if */
  1312         needtoken(']');
  1313         if (subsym!=NULL)
  1314           subsym=finddepend(subsym);
  1315       } /* for */
  1316       if (level>sym->dim.array.level+1)
  1317         error(28,sym->name);  /* invalid subscript */
  1318       else if (level==sym->dim.array.level+1)
  1319         lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1;
  1320       else
  1321         lval->constval=array_levelsize(sym,level);
  1322       if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL)
  1323         error(224,st);          /* indeterminate array size in "sizeof" expression */
  1324     } /* if */
  1325     ldconst(lval->constval,sPRI);
  1326     while (paranthese--)
  1327       needtoken(')');
  1328     return FALSE;
  1329   case tTAGOF:
  1330     paranthese=0;
  1331     while (matchtoken('('))
  1332       paranthese++;
  1333     tok=lex(&val,&st);
  1334     if (tok!=tSYMBOL && tok!=tLABEL)
  1335       return error(20,st);      /* illegal symbol name */
  1336     if (tok==tLABEL) {
  1337       constvalue *tagsym=find_constval(&tagname_tab,st,0);
  1338       tag=(int)((tagsym!=NULL) ? tagsym->value : 0);
  1339     } else {
  1340       sym=findloc(st);
  1341       if (sym==NULL)
  1342         sym=findglb(st,sSTATEVAR);
  1343       if (sym==NULL)
  1344         return error(17,st);      /* undefined symbol */
  1345       if ((sym->usage & uDEFINE)==0)
  1346         return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1347       tag=sym->tag;
  1348     } /* if */
  1349     if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1350       int level;
  1351       symbol *idxsym=NULL;
  1352       symbol *subsym=sym;
  1353       for (level=0; matchtoken('['); level++) {
  1354         idxsym=NULL;
  1355         if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1356           char *idxname;
  1357           int cmptag=subsym->x.tags.index;
  1358           tokeninfo(&val,&idxname);
  1359           if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1360             error(80,idxname);  /* unknown symbol, or non-constant */
  1361           else if (cmptag>1)
  1362             error(91,idxname);  /* ambiguous constant */
  1363         } /* if */
  1364         needtoken(']');
  1365         if (subsym!=NULL)
  1366           subsym=finddepend(subsym);
  1367       } /* for */
  1368       if (level>sym->dim.array.level+1)
  1369         error(28,sym->name);  /* invalid subscript */
  1370       else if (level==sym->dim.array.level+1 && idxsym!=NULL)
  1371         tag= idxsym->x.tags.index;
  1372     } /* if */
  1373     exporttag(tag);
  1374     clear_value(lval);
  1375     lval->ident=iCONSTEXPR;
  1376     lval->constval=tag | PUBLICTAG;
  1377     ldconst(lval->constval,sPRI);
  1378     while (paranthese--)
  1379       needtoken(')');
  1380     return FALSE;
  1381   case tSTATE: {
  1382     constvalue *automaton;
  1383     constvalue *state;
  1384     if (sc_getstateid(&automaton,&state)) {
  1385       assert(automaton!=NULL);
  1386       assert(automaton->index==0 && automaton->name[0]=='\0' || automaton->index>0);
  1387       loadreg(automaton->value,sALT);
  1388       assert(state!=NULL);
  1389       ldconst(state->value,sPRI);
  1390       ob_eq();
  1391       clear_value(lval);
  1392       lval->ident=iEXPRESSION;
  1393       lval->tag=pc_addtag("bool");
  1394     } /* if */
  1395     return FALSE;
  1396   } /* case */
  1397   default:
  1398     lexpush();
  1399     lvalue=hier1(lval);
  1400     /* check for postfix operators */
  1401     if (matchtoken(';')) {
  1402       /* Found a ';', do not look further for postfix operators */
  1403       lexpush();                /* push ';' back after successful match */
  1404       return lvalue;
  1405     } else if (matchtoken(tTERM)) {
  1406       /* Found a newline that ends a statement (this is the case when
  1407        * semicolons are optional). Note that an explicit semicolon was
  1408        * handled above. This case is similar, except that the token must
  1409        * not be pushed back.
  1410        */
  1411       return lvalue;
  1412     } else {
  1413       tok=lex(&val,&st);
  1414       switch (tok) {
  1415       case tINC:                /* lval++ */
  1416         if (!lvalue)
  1417           return error(22);     /* must be lvalue */
  1418         assert(lval->sym!=NULL);
  1419         if ((lval->sym->usage & uCONST)!=0)
  1420           return error(22);     /* assignment to const argument */
  1421         /* on incrementing array cells, the address in PRI must be saved for
  1422          * incremening the value, whereas the current value must be in PRI
  1423          * on exit.
  1424          */
  1425         saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1426         if (saveresult)
  1427           pushreg(sPRI);        /* save address in PRI */
  1428         rvalue(lval);           /* read current value into PRI */
  1429         if (saveresult)
  1430           swap1();              /* save PRI on the stack, restore address in PRI */
  1431         if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1432           inc(lval);            /* increase variable afterwards */
  1433         if (saveresult)
  1434           popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1435         sideeffect=TRUE;
  1436         return FALSE;           /* result is no longer lvalue */
  1437       case tDEC:                /* lval-- */
  1438         if (!lvalue)
  1439           return error(22);     /* must be lvalue */
  1440         assert(lval->sym!=NULL);
  1441         if ((lval->sym->usage & uCONST)!=0)
  1442           return error(22);     /* assignment to const argument */
  1443         saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1444         if (saveresult)
  1445           pushreg(sPRI);        /* save address in PRI */
  1446         rvalue(lval);           /* read current value into PRI */
  1447         if (saveresult)
  1448           swap1();              /* save PRI on the stack, restore address in PRI */
  1449         if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1450           dec(lval);            /* decrease variable afterwards */
  1451         if (saveresult)
  1452           popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1453         sideeffect=TRUE;
  1454         return FALSE;
  1455       case tCHAR:               /* char (compute required # of cells */
  1456         if (lval->ident==iCONSTEXPR) {
  1457           lval->constval *= sCHARBITS/8;  /* from char to bytes */
  1458           lval->constval = (lval->constval + sizeof(cell)-1) / sizeof(cell);
  1459         } else {
  1460           if (lvalue)
  1461             rvalue(lval);       /* fetch value if not already in PRI */
  1462           char2addr();          /* from characters to bytes */
  1463           addconst(sizeof(cell)-1);     /* make sure the value is rounded up */
  1464           addr2cell();          /* truncate to number of cells */
  1465         } /* if */
  1466         return FALSE;
  1467       default:
  1468         lexpush();
  1469         return lvalue;
  1470       } /* switch */
  1471     } /* if */
  1472   } /* switch */
  1473 }
  1474 
  1475 /*  hier1
  1476  *
  1477  *  The highest hierarchy level: it looks for pointer and array indices
  1478  *  and function calls.
  1479  *  Generates code to fetch a pointer value if it is indexed and code to
  1480  *  add to the pointer value or the array address (the address is already
  1481  *  read at primary()). It also generates code to fetch a function address
  1482  *  if that hasn't already been done at primary() (check lval[4]) and calls
  1483  *  callfunction() to call the function.
  1484  */
  1485 static int hier1(value *lval1)
  1486 {
  1487   int lvalue,index,tok,symtok;
  1488   cell val,cidx;
  1489   value lval2={0};
  1490   char *st;
  1491   char close;
  1492   symbol *sym;
  1493   symbol dummysymbol,*cursym;   /* for changing the index tags in case of enumerated pseudo-arrays */
  1494 
  1495   lvalue=primary(lval1);
  1496   symtok=tokeninfo(&val,&st);   /* get token read by primary() */
  1497   cursym=lval1->sym;
  1498 restart:
  1499   sym=cursym;
  1500   if (matchtoken('[') || matchtoken('{') || matchtoken('(')) {
  1501     tok=tokeninfo(&val,&st);    /* get token read by matchtoken() */
  1502     if (sym==NULL && symtok!=tSYMBOL) {
  1503       /* we do not have a valid symbol and we appear not to have read a valid
  1504        * symbol name (so it is unlikely that we would have read a name of an
  1505        * undefined symbol) */
  1506       error(29);                /* expression error, assumed 0 */
  1507       lexpush();                /* analyse '(', '{' or '[' again later */
  1508       return FALSE;
  1509     } /* if */
  1510     if (tok=='[' || tok=='{') { /* subscript */
  1511       close = (char)((tok=='[') ? ']' : '}');
  1512       if (sym==NULL) {  /* sym==NULL if lval is a constant or a literal */
  1513         error(28,"<no variable>");  /* cannot subscript */
  1514         needtoken(close);
  1515         return FALSE;
  1516       } else if (sym->ident!=iARRAY && sym->ident!=iREFARRAY){
  1517         error(28,sym->name);    /* cannot subscript, variable is not an array */
  1518         needtoken(close);
  1519         return FALSE;
  1520       } else if (sym->dim.array.level>0 && close!=']') {
  1521         error(51);      /* invalid subscript, must use [ ] */
  1522         needtoken(close);
  1523         return FALSE;
  1524       } /* if */
  1525       /* set the tag to match (enumeration fields as indices) */
  1526       lval2.cmptag=sym->x.tags.index;
  1527       stgget(&index,&cidx);     /* mark position in code generator */
  1528       pushreg(sPRI);            /* save base address of the array */
  1529       if (hier14(&lval2))       /* create expression for the array index */
  1530         rvalue(&lval2);
  1531       if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1532         error(33,lval2.sym->name);      /* array must be indexed */
  1533       needtoken(close);
  1534       if (!matchtag(sym->x.tags.index,lval2.tag,TRUE))
  1535         error(213);
  1536       if (lval2.ident==iCONSTEXPR) {    /* constant expression */
  1537         stgdel(index,cidx);             /* scratch generated code */
  1538         if (lval1->arrayidx!=NULL) {    /* keep constant index, for checking */
  1539           assert(sym->dim.array.level>=0 && sym->dim.array.level<sDIMEN_MAX);
  1540           lval1->arrayidx[sym->dim.array.level]=lval2.constval;
  1541         } /* if */
  1542         if (close==']') {
  1543           /* normal array index */
  1544           if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval)
  1545             error(32,sym->name);        /* array index out of bounds */
  1546           if (lval2.constval!=0) {
  1547             /* don't add offsets for zero subscripts */
  1548             #if PAWN_CELL_SIZE==16
  1549               ldconst(lval2.constval<<1,sALT);
  1550             #elif PAWN_CELL_SIZE==32
  1551               ldconst(lval2.constval<<2,sALT);
  1552             #elif PAWN_CELL_SIZE==64
  1553               ldconst(lval2.constval<<3,sALT);
  1554             #else
  1555               #error Unsupported cell size
  1556             #endif
  1557             ob_add();
  1558           } /* if */
  1559         } else {
  1560           /* character index */
  1561           if (lval2.constval<0 || sym->dim.array.length!=0
  1562               && sym->dim.array.length*((8*sizeof(cell))/sCHARBITS)<=(ucell)lval2.constval)
  1563             error(32,sym->name);        /* array index out of bounds */
  1564           if (lval2.constval!=0) {
  1565             /* don't add offsets for zero subscripts */
  1566             #if sCHARBITS==16
  1567               ldconst(lval2.constval<<1,sALT);/* 16-bit character */
  1568             #else
  1569               ldconst(lval2.constval,sALT);   /* 8-bit character */
  1570             #endif
  1571             ob_add();
  1572           } /* if */
  1573           charalign();                  /* align character index into array */
  1574         } /* if */
  1575         /* if the array index is a field from an enumeration, get the tag name
  1576          * from the field and save the size of the field too.
  1577          */
  1578         assert(lval2.sym==NULL || lval2.sym->dim.array.level==0);
  1579         if (lval2.sym!=NULL && lval2.sym->dim.array.length>0 && sym->dim.array.level==0) {
  1580           lval1->tag=lval2.sym->x.tags.index;
  1581           lval1->constval=lval2.sym->dim.array.length;
  1582         } /* if */
  1583       } else {
  1584         /* array index is not constant */
  1585         lval1->arrayidx=NULL;           /* reset, so won't be checked */
  1586         if (close==']') {
  1587           if (sym->dim.array.length!=0)
  1588             ffbounds(sym->dim.array.length-1);  /* run time check for array bounds */
  1589           cell2addr();  /* normal array index */
  1590         } else {
  1591           if (sym->dim.array.length!=0)
  1592             ffbounds(sym->dim.array.length*(32/sCHARBITS)-1);
  1593           char2addr();  /* character array index */
  1594         } /* if */
  1595         popreg(sALT);
  1596         ob_add();       /* base address was popped into secondary register */
  1597         if (close!=']')
  1598           charalign();  /* align character index into array */
  1599       } /* if */
  1600       /* the indexed item may be another array (multi-dimensional arrays) */
  1601       assert(cursym==sym && sym!=NULL); /* should still be set */
  1602       if (sym->dim.array.level>0) {
  1603         assert(close==']');     /* checked earlier */
  1604         assert(cursym==lval1->sym);
  1605         /* read the offset to the subarray and add it to the current address */
  1606         lval1->ident=iARRAYCELL;
  1607         pushreg(sPRI);          /* the optimizer makes this to a MOVE.alt */
  1608         rvalue(lval1);
  1609         popreg(sALT);
  1610         ob_add();
  1611         /* adjust the "value" structure and find the referenced array */
  1612         lval1->ident=iREFARRAY;
  1613         lval1->sym=finddepend(sym);
  1614         assert(lval1->sym!=NULL);
  1615         assert(lval1->sym->dim.array.level==sym->dim.array.level-1);
  1616         cursym=lval1->sym;
  1617         /* try to parse subsequent array indices */
  1618         lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1619         goto restart;
  1620       } /* if */
  1621       assert(sym->dim.array.level==0);
  1622       /* set type to fetch... INDIRECTLY */
  1623       lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR);
  1624       /* if the array index is a field from an enumeration, get the tag name
  1625        * from the field and save the size of the field too. Otherwise, the
  1626        * tag is the one from the array symbol.
  1627        */
  1628       if (lval2.ident==iCONSTEXPR && lval2.sym!=NULL
  1629           && lval2.sym->dim.array.length>0 && sym->dim.array.level==0)
  1630       {
  1631         lval1->tag=lval2.sym->x.tags.index;
  1632         lval1->constval=lval2.sym->dim.array.length;
  1633         if (lval2.tag==sym->x.tags.index && lval1->constval>1 && matchtoken('[')) {
  1634           /* an array indexed with an enumeration field may be considered a sub-array */
  1635           lexpush();
  1636           lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1637           lval1->ident=iREFARRAY;
  1638           /* initialize a dummy symbol, which is a copy of the current symbol,
  1639            * but with an adjusted index tag
  1640            */
  1641           assert(sym!=NULL);
  1642           dummysymbol=*sym;
  1643           /* get the tag of the root of the enumeration */
  1644           assert(lval2.sym!=NULL);
  1645           dummysymbol.x.tags.index=lval2.sym->x.tags.field;
  1646           dummysymbol.dim.array.length=lval2.sym->dim.array.length;
  1647           cursym=&dummysymbol;
  1648           /* recurse */
  1649           goto restart;
  1650         } /* if */
  1651       } else {
  1652         assert(sym!=NULL);
  1653         if (cursym!=&dummysymbol)
  1654           lval1->tag=sym->tag;
  1655         lval1->constval=0;
  1656       } /* if */
  1657       /* a cell in an array is an lvalue, a character in an array is not
  1658        * always a *valid* lvalue */
  1659       return TRUE;
  1660     } else {            /* tok=='(' -> function(...) */
  1661       assert(tok=='(');
  1662       if (sym==NULL
  1663           || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
  1664       {
  1665         if (sym==NULL && sc_status==statFIRST) {
  1666           /* could be a "use before declaration"; in that case, create a stub
  1667            * function so that the usage can be marked.
  1668            */
  1669           sym=fetchfunc(lastsymbol,0);
  1670           if (sym==NULL)
  1671             error(103); /* insufficient memory */
  1672           markusage(sym,uREAD);
  1673         } else {
  1674           return error(12);           /* invalid function call */
  1675         } /* if */
  1676       } else if ((sym->usage & uMISSING)!=0) {
  1677         char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
  1678         funcdisplayname(symname,sym->name);
  1679         error(4,symname);             /* function not defined */
  1680       } /* if */
  1681       callfunction(sym,lval1,TRUE);
  1682       return FALSE;             /* result of function call is no lvalue */
  1683     } /* if */
  1684   } /* if */
  1685   if (sym!=NULL && lval1->ident==iFUNCTN) {
  1686     assert(sym->ident==iFUNCTN);
  1687     if (sc_allowproccall) {
  1688       callfunction(sym,lval1,FALSE);
  1689     } else {
  1690       int n=-1,iter=0;
  1691       for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  1692         if (sym->ident==iFUNCTN
  1693             && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
  1694         {
  1695           assert(sym->vclass==sGLOBAL);
  1696           if (strcmp(sym->name, lval1->sym->name)==0) {
  1697             n = iter;
  1698             break;
  1699           }
  1700           iter++;
  1701         }
  1702       }
  1703       if (n!=-1) {
  1704         lval1->sym=NULL;
  1705         lval1->ident=iCONSTEXPR;
  1706         lval1->constval=n;
  1707         lval1->tag=pc_addtag("Function");
  1708       } else {
  1709         error(76);                /* invalid function call, or syntax error */
  1710       } /* if */
  1711       return FALSE;
  1712     }
  1713   } /* if */
  1714   return lvalue;
  1715 }
  1716 
  1717 /*  primary
  1718  *
  1719  *  Returns 1 if the operand is an lvalue (everything except arrays, functions
  1720  *  constants and -of course- errors).
  1721  *  Generates code to fetch the address of arrays. Code for constants is
  1722  *  already generated by constant().
  1723  *  This routine first clears the entire lval array (all fields are set to 0).
  1724  *
  1725  *  Global references: sc_intest  (may be altered, but restored upon termination)
  1726  */
  1727 static int primary(value *lval)
  1728 {
  1729   char *st;
  1730   int lvalue,tok;
  1731   cell val;
  1732   symbol *sym;
  1733 
  1734   if (matchtoken('(')){         /* sub-expression - (expression,...) */
  1735     PUSHSTK_I(sc_intest);
  1736     PUSHSTK_I(sc_allowtags);
  1737 
  1738     sc_intest=FALSE;            /* no longer in "test" expression */
  1739     sc_allowtags=TRUE;          /* allow tagnames to be used in parenthesized expressions */
  1740     sc_allowproccall=FALSE;
  1741     do
  1742       lvalue=hier14(lval);
  1743     while (matchtoken(','));
  1744     needtoken(')');
  1745     lexclr(FALSE);              /* clear lex() push-back, it should have been
  1746                                  * cleared already by needtoken() */
  1747     sc_allowtags=(short)POPSTK_I();
  1748     sc_intest=(short)POPSTK_I();
  1749     return lvalue;
  1750   } /* if */
  1751 
  1752   clear_value(lval);    /* clear lval */
  1753   tok=lex(&val,&st);
  1754   if (tok==tSYMBOL) {
  1755     /* lastsymbol is char[sNAMEMAX+1], lex() should have truncated any symbol
  1756      * to sNAMEMAX significant characters */
  1757     assert(strlen(st)<sizeof lastsymbol);
  1758     strcpy(lastsymbol,st);
  1759   } /* if */
  1760   if (tok==tSYMBOL && !findconst(st,NULL)) {
  1761     /* first look for a local variable */
  1762     if ((sym=findloc(st))!=0) {
  1763       if (sym->ident==iLABEL) {
  1764         error(29);          /* expression error, assumed 0 */
  1765         ldconst(0,sPRI);    /* load 0 */
  1766         return FALSE;       /* return 0 for labels (expression error) */
  1767       } /* if */
  1768       lval->sym=sym;
  1769       lval->ident=sym->ident;
  1770       lval->tag=sym->tag;
  1771       if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1772         address(sym,sPRI);  /* get starting address in primary register */
  1773         return FALSE;       /* return 0 for array (not lvalue) */
  1774       } else {
  1775         return TRUE;        /* return 1 if lvalue (not label or array) */
  1776       } /* if */
  1777     } /* if */
  1778     /* now try a global variable */
  1779     if ((sym=findglb(st,sSTATEVAR))!=0) {
  1780       if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
  1781         /* if the function is only in the table because it was inserted as a
  1782          * stub in the first pass (i.e. it was "used" but never declared or
  1783          * implemented, issue an error
  1784          */
  1785         if ((sym->usage & uPROTOTYPED)==0)
  1786           error(17,st);
  1787       } else {
  1788         if ((sym->usage & uDEFINE)==0)
  1789           error(17,st);
  1790         lval->sym=sym;
  1791         lval->ident=sym->ident;
  1792         lval->tag=sym->tag;
  1793         if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1794           address(sym,sPRI);    /* get starting address in primary register */
  1795           return FALSE;         /* return 0 for array (not lvalue) */
  1796         } else {
  1797           return TRUE;          /* return 1 if lvalue (not function or array) */
  1798         } /* if */
  1799       } /* if */
  1800     } else {
  1801       if (!sc_allowproccall)
  1802         return error(17,st);    /* undefined symbol */
  1803       /* an unknown symbol, but used in a way compatible with the "procedure
  1804        * call" syntax. So assume that the symbol refers to a function.
  1805        */
  1806       assert(sc_status==statFIRST);
  1807       sym=fetchfunc(st,0);
  1808       if (sym==NULL)
  1809         error(103);     /* insufficient memory */
  1810     } /* if */
  1811     assert(sym!=NULL);
  1812     assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
  1813     lval->sym=sym;
  1814     lval->ident=sym->ident;
  1815     lval->tag=sym->tag;
  1816     return FALSE;       /* return 0 for function (not an lvalue) */
  1817   } /* if */
  1818   lexpush();            /* push the token, it is analyzed by constant() */
  1819   if (constant(lval)==0) {
  1820     error(29);          /* expression error, assumed 0 */
  1821     ldconst(0,sPRI);    /* load 0 */
  1822   } /* if */
  1823   return FALSE;         /* return 0 for constants (or errors) */
  1824 }
  1825 
  1826 static void clear_value(value *lval)
  1827 {
  1828   lval->sym=NULL;
  1829   lval->constval=0L;
  1830   lval->tag=0;
  1831   lval->ident=0;
  1832   lval->boolresult=FALSE;
  1833   /* do not clear lval->arrayidx, it is preset in hier14() */
  1834   /* do not clear lval->cmptag */
  1835 }
  1836 
  1837 static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int fconst)
  1838 {
  1839   /* The routine must copy the default array data onto the heap, as to avoid
  1840    * that a function can change the default value. An optimization is that
  1841    * the default array data is "dumped" into the data segment only once (on the
  1842    * first use).
  1843    */
  1844   assert(string!=NULL);
  1845   assert(size>0);
  1846   /* check whether to dump the default array */
  1847   assert(dataaddr!=NULL);
  1848   if (sc_status==statWRITE && *dataaddr<0) {
  1849     int i;
  1850     *dataaddr=(litidx+glb_declared)*sizeof(cell);
  1851     for (i=0; i<size; i++)
  1852       litadd(*string++);
  1853   } /* if */
  1854 
  1855   /* if the function is known not to modify the array (meaning that it also
  1856    * does not modify the default value), directly pass the address of the
  1857    * array in the data segment.
  1858    */
  1859   if (fconst) {
  1860     ldconst(*dataaddr,sPRI);
  1861   } else {
  1862     /* Generate the code:
  1863      *  CONST.pri dataaddr                ;address of the default array data
  1864      *  HEAP      array_sz*sizeof(cell)   ;heap address in ALT
  1865      *  MOVS      size*sizeof(cell)       ;copy data from PRI to ALT
  1866      *  MOVE.PRI                          ;PRI = address on the heap
  1867      */
  1868     ldconst(*dataaddr,sPRI);
  1869     /* "array_sz" is the size of the argument (the value between the brackets
  1870      * in the declaration), "size" is the size of the default array data.
  1871      */
  1872     assert(array_sz>=size);
  1873     modheap((int)array_sz*sizeof(cell));
  1874     /* ??? should perhaps fill with zeros first */
  1875     memcopy(size*sizeof(cell));
  1876     moveto1();
  1877   } /* if */
  1878 }
  1879 
  1880 static int findnamedarg(arginfo *arg,char *name)
  1881 {
  1882   int i;
  1883 
  1884   for (i=0; arg[i].ident!=0 && arg[i].ident!=iVARARGS; i++)
  1885     if (strcmp(arg[i].name,name)==0)
  1886       return i;
  1887   return -1;
  1888 }
  1889 
  1890 static int checktag(int tags[],int numtags,int exprtag)
  1891 {
  1892   int i;
  1893 
  1894   assert(tags!=0);
  1895   assert(numtags>0);
  1896   for (i=0; i<numtags; i++)
  1897     if (matchtag(tags[i],exprtag,TRUE))
  1898       return TRUE;    /* matching tag */
  1899   return FALSE;       /* no tag matched */
  1900 }
  1901 
  1902 enum {
  1903   ARG_UNHANDLED,
  1904   ARG_IGNORED,
  1905   ARG_DONE,
  1906 };
  1907 
  1908 /*  callfunction
  1909  *
  1910  *  Generates code to call a function. This routine handles default arguments
  1911  *  and positional as well as named parameters.
  1912  */
  1913 static void callfunction(symbol *sym,value *lval_result,int matchparanthesis)
  1914 {
  1915 static long nest_stkusage=0L;
  1916 static int nesting=0;
  1917   int locheap;
  1918   int close,lvalue;
  1919   int argpos;       /* index in the output stream (argpos==nargs if positional parameters) */
  1920   int argidx=0;     /* index in "arginfo" list */
  1921   int nargs=0;      /* number of arguments */
  1922   int heapalloc=0;
  1923   int namedparams=FALSE;
  1924   value lval = {0};
  1925   arginfo *arg;
  1926   char arglist[sMAXARGS];
  1927   constvalue arrayszlst = { NULL, "", 0, 0};/* array size list starts empty */
  1928   constvalue taglst = { NULL, "", 0, 0};    /* tag list starts empty */
  1929   symbol *symret;
  1930   cell lexval;
  1931   char *lexstr;
  1932 
  1933   assert(sym!=NULL);
  1934   lval_result->ident=iEXPRESSION; /* preset, may be changed later */
  1935   lval_result->constval=0;
  1936   lval_result->tag=sym->tag;
  1937   /* check whether this is a function that returns an array */
  1938   symret=finddepend(sym);
  1939   assert(symret==NULL || symret->ident==iREFARRAY);
  1940   if (symret!=NULL) {
  1941     int retsize;
  1942     /* allocate space on the heap for the array, and pass the pointer to the
  1943      * reserved memory block as a hidden parameter
  1944      */
  1945     retsize=(int)array_totalsize(symret);
  1946     assert(retsize>0);
  1947     modheap(retsize*sizeof(cell));/* address is in ALT */
  1948     pushreg(sALT);                /* pass ALT as the last (hidden) parameter */
  1949     decl_heap+=retsize;
  1950     /* also mark the ident of the result as "array" */
  1951     lval_result->ident=iREFARRAY;
  1952     lval_result->sym=symret;
  1953   } /* if */
  1954   locheap=decl_heap;
  1955 
  1956   nesting++;
  1957   assert(nest_stkusage>=0);
  1958   #if !defined NDEBUG
  1959     if (nesting==1)
  1960       assert(nest_stkusage==0);
  1961   #endif
  1962   sc_allowproccall=FALSE;       /* parameters may not use procedure call syntax */
  1963 
  1964   if ((sym->flags & flgDEPRECATED)!=0) {
  1965     char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
  1966     error(234,sym->name,ptr);   /* deprecated (probably a native function) */
  1967   } /* if */
  1968 
  1969   /* run through the arguments */
  1970   arg=sym->dim.arglist;
  1971   assert(arg!=NULL);
  1972   stgmark(sSTARTREORDER);
  1973   memset(arglist,ARG_UNHANDLED,sizeof arglist);
  1974   if (matchparanthesis) {
  1975     /* Opening brace was already parsed, if closing brace follows, this
  1976      * call passes no parameters.
  1977      */
  1978     close=matchtoken(')');
  1979   } else {
  1980     /* When we find an end of line here, it may be a function call passing
  1981      * no parameters, or it may be that the first parameter is on a line
  1982      * below. But as a parameter can be anything, this is difficult to check.
  1983      * The only simple check that we have is the use of "named parameters".
  1984      */
  1985     close=matchtoken(tTERM);
  1986     if (close) {
  1987       close=!matchtoken('.');
  1988       if (!close)
  1989         lexpush();                /* reset the '.' */
  1990     } /* if */
  1991   } /* if */
  1992   if (!close) {
  1993     do {
  1994       if (matchtoken('.')) {
  1995         namedparams=TRUE;
  1996         if (needtoken(tSYMBOL))
  1997           tokeninfo(&lexval,&lexstr);
  1998         else
  1999           lexstr="";
  2000         argpos=findnamedarg(arg,lexstr);
  2001         if (argpos<0) {
  2002           error(17,lexstr);       /* undefined symbol */
  2003           break;                  /* exit loop, argpos is invalid */
  2004         } /* if */
  2005         needtoken('=');
  2006         argidx=argpos;
  2007       } else {
  2008         if (namedparams)
  2009           error(44);   /* positional parameters must precede named parameters */
  2010         argpos=nargs;
  2011       } /* if */
  2012       /* the number of arguments this was already checked at the declaration
  2013        * of the function; check it again for functions with a variable
  2014        * argument list
  2015        */
  2016       if (argpos>=sMAXARGS)
  2017         error(45);                /* too many function arguments */
  2018       stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */
  2019       if (arglist[argpos]!=ARG_UNHANDLED)
  2020         error(58);                /* argument already set */
  2021       if (matchtoken('_')) {
  2022         arglist[argpos]=ARG_IGNORED;  /* flag argument as "present, but ignored" */
  2023         if (arg[argidx].ident==0 || arg[argidx].ident==iVARARGS) {
  2024           error(92);             /* argument count mismatch */
  2025         } else if (!arg[argidx].hasdefault) {
  2026           error(34,nargs+1);      /* argument has no default value */
  2027         } /* if */
  2028         if (arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS)
  2029           argidx++;
  2030         /* The rest of the code to handle default values is at the bottom
  2031          * of this routine where default values for unspecified parameters
  2032          * are (also) handled. Note that above, the argument is flagged as
  2033          * ARG_IGNORED.
  2034          */
  2035       } else {
  2036         arglist[argpos]=ARG_DONE; /* flag argument as "present" */
  2037         if (arg[argidx].numtags==1)     /* set the expected tag, if any */
  2038           lval.cmptag=arg[argidx].tags[0];
  2039         lvalue=hier14(&lval);
  2040         assert(sc_status==statFIRST || arg[argidx].tags!=NULL);
  2041         switch (arg[argidx].ident) {
  2042         case 0:
  2043           error(92);             /* argument count mismatch */
  2044           break;
  2045         case iVARARGS:
  2046           /* always pass by reference */
  2047           if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  2048             assert(lval.sym!=NULL);
  2049             if ((lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) {
  2050               /* treat a "const" variable passed to a function with a non-const
  2051                * "variable argument list" as a constant here */
  2052               if (!lvalue) {
  2053                 error(22);        /* need lvalue */
  2054               } else {
  2055                 rvalue(&lval);    /* get value in PRI */
  2056                 setheap_pri();    /* address of the value on the heap in PRI */
  2057                 heapalloc++;
  2058                 nest_stkusage++;
  2059               } /* if */
  2060             } else if (lvalue) {
  2061               address(lval.sym,sPRI);
  2062             } else {
  2063               setheap_pri();      /* address of the value on the heap in PRI */
  2064               heapalloc++;
  2065               nest_stkusage++;
  2066             } /* if */
  2067           } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION
  2068                      || lval.ident==iARRAYCHAR)
  2069           {
  2070             /* fetch value if needed */
  2071             if (lval.ident==iARRAYCHAR)
  2072               rvalue(&lval);
  2073             /* allocate a cell on the heap and store the
  2074              * value (already in PRI) there */
  2075             setheap_pri();        /* address of the value on the heap in PRI */
  2076             heapalloc++;
  2077             nest_stkusage++;
  2078           } /* if */
  2079           /* ??? handle const array passed by reference */
  2080           /* otherwise, the address is already in PRI */
  2081           if (lval.sym!=NULL)
  2082             markusage(lval.sym,uWRITTEN);
  2083           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2084             error(213);
  2085           if (lval.tag!=0)
  2086             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2087           break;
  2088         case iVARIABLE:
  2089           if (lval.ident==iLABEL || lval.ident==iFUNCTN || lval.ident==iREFFUNC
  2090               || lval.ident==iARRAY || lval.ident==iREFARRAY)
  2091             error(35,argidx+1);   /* argument type mismatch */
  2092           if (lvalue)
  2093             rvalue(&lval);        /* get value (direct or indirect) */
  2094           /* otherwise, the expression result is already in PRI */
  2095           assert(arg[argidx].numtags>0);
  2096           check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag);
  2097           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2098             error(213);
  2099           if (lval.tag!=0)
  2100             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2101           argidx++;               /* argument done */
  2102           break;
  2103         case iREFERENCE:
  2104           if (!lvalue || lval.ident==iARRAYCHAR)
  2105             error(35,argidx+1);   /* argument type mismatch */
  2106           if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  2107             error(35,argidx+1);   /* argument type mismatch */
  2108           if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  2109             if (lvalue) {
  2110               assert(lval.sym!=NULL);
  2111               address(lval.sym,sPRI);
  2112             } else {
  2113               setheap_pri();      /* address of the value on the heap in PRI */
  2114               heapalloc++;
  2115               nest_stkusage++;
  2116             } /* if */
  2117           } /* if */
  2118           /* otherwise, the address is already in PRI */
  2119           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2120             error(213);
  2121           if (lval.tag!=0)
  2122             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2123           argidx++;               /* argument done */
  2124           if (lval.sym!=NULL)
  2125             markusage(lval.sym,uWRITTEN);
  2126           break;
  2127         case iREFARRAY:
  2128           if (lval.ident!=iARRAY && lval.ident!=iREFARRAY
  2129               && lval.ident!=iARRAYCELL)
  2130           {
  2131             error(35,argidx+1);   /* argument type mismatch */
  2132             break;
  2133           } /* if */
  2134           if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  2135             error(35,argidx+1); /* argument type mismatch */
  2136           /* Verify that the dimensions match with those in arg[argidx].
  2137            * A literal array always has a single dimension.
  2138            * An iARRAYCELL parameter is also assumed to have a single dimension.
  2139            */
  2140           if (lval.sym==NULL || lval.ident==iARRAYCELL) {
  2141             if (arg[argidx].numdim!=1) {
  2142               error(48);        /* array dimensions must match */
  2143             } else if (arg[argidx].dim[0]!=0) {
  2144               assert(arg[argidx].dim[0]>0);
  2145               if (lval.ident==iARRAYCELL) {
  2146                 error(47);        /* array sizes must match */
  2147               } else {
  2148                 assert(lval.constval!=0); /* literal array must have a size */
  2149                 /* A literal array must have exactly the same size as the
  2150                  * function argument; a literal string may be smaller than
  2151                  * the function argument.
  2152                  */
  2153                 if (lval.constval>0 && arg[argidx].dim[0]!=lval.constval
  2154                     || lval.constval<0 && arg[argidx].dim[0] < -lval.constval)
  2155                   error(47);      /* array sizes must match */
  2156               } /* if */
  2157             } /* if */
  2158             if (lval.ident!=iARRAYCELL) {
  2159               /* save array size, for default values with uSIZEOF flag */
  2160               cell array_sz=lval.constval;
  2161               assert(array_sz!=0);/* literal array must have a size */
  2162               if (array_sz<0)
  2163                 array_sz= -array_sz;
  2164               append_constval(&arrayszlst,arg[argidx].name,array_sz,0);
  2165             } /* if */
  2166           } else {
  2167             symbol *sym=lval.sym;
  2168             short level=0;
  2169             assert(sym!=NULL);
  2170             if (sym->dim.array.level+1!=arg[argidx].numdim)
  2171               error(48);          /* array dimensions must match */
  2172             /* the lengths for all dimensions must match, unless the dimension
  2173              * length was defined at zero (which means "undefined")
  2174              */
  2175             while (sym->dim.array.level>0) {
  2176               assert(level<sDIMEN_MAX);
  2177               if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  2178                 error(47);        /* array sizes must match */
  2179               else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  2180                 error(229,sym->name);   /* index tag mismatch */
  2181               append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  2182               sym=finddepend(sym);
  2183               assert(sym!=NULL);
  2184               level++;
  2185             } /* if */
  2186             /* the last dimension is checked too, again, unless it is zero */
  2187             assert(level<sDIMEN_MAX);
  2188             assert(sym!=NULL);
  2189             if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  2190               error(47);          /* array sizes must match */
  2191             else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  2192               error(229,sym->name);   /* index tag mismatch */
  2193             append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  2194           } /* if */
  2195           /* address already in PRI */
  2196           if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  2197             error(213);
  2198           if (lval.tag!=0)
  2199             append_constval(&taglst,arg[argidx].name,lval.tag,0);
  2200           // ??? set uWRITTEN?
  2201           argidx++;               /* argument done */
  2202           break;
  2203         } /* switch */
  2204         pushreg(sPRI);            /* store the function argument on the stack */
  2205         markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  2206         nest_stkusage++;
  2207       } /* if */
  2208       assert(arglist[argpos]!=ARG_UNHANDLED);
  2209       nargs++;
  2210       if (matchparanthesis) {
  2211         close=matchtoken(')');
  2212         if (!close)               /* if not paranthese... */
  2213           if (!needtoken(','))    /* ...should be comma... */
  2214             break;                /* ...but abort loop if neither */
  2215       } else {
  2216         close=!matchtoken(',');
  2217         if (close) {              /* if not comma... */
  2218           if (needtoken(tTERM)==1)/* ...must be end of statement */
  2219             lexpush();            /* push again, because end of statement is analised later */
  2220         } /* if */
  2221       } /* if */
  2222     } while (!close && freading && !matchtoken(tENDEXPR)); /* do */
  2223   } /* if */
  2224   /* check remaining function arguments (they may have default values) */
  2225   for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  2226     if (arglist[argidx]==ARG_DONE)
  2227       continue;                 /* already seen and handled this argument */
  2228     /* in this first stage, we also skip the arguments with uSIZEOF and uTAGOF;
  2229      * these are handled last
  2230      */
  2231     if ((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0) {
  2232       assert(arg[argidx].ident==iVARIABLE);
  2233       continue;
  2234     } /* if */
  2235     stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  2236     if (arg[argidx].hasdefault) {
  2237       if (arg[argidx].ident==iREFARRAY) {
  2238         short level;
  2239         setdefarray(arg[argidx].defvalue.array.data,
  2240                     arg[argidx].defvalue.array.size,
  2241                     arg[argidx].defvalue.array.arraysize,
  2242                     &arg[argidx].defvalue.array.addr,
  2243                     (arg[argidx].usage & uCONST)!=0);
  2244         if ((arg[argidx].usage & uCONST)==0) {
  2245           heapalloc+=arg[argidx].defvalue.array.arraysize;
  2246           nest_stkusage+=arg[argidx].defvalue.array.arraysize;
  2247         } /* if */
  2248         /* keep the lengths of all dimensions of a multi-dimensional default array */
  2249         assert(arg[argidx].numdim>0);
  2250         if (arg[argidx].numdim==1) {
  2251           append_constval(&arrayszlst,arg[argidx].name,arg[argidx].defvalue.array.arraysize,0);
  2252         } else {
  2253           for (level=0; level<arg[argidx].numdim; level++) {
  2254             assert(level<sDIMEN_MAX);
  2255             append_constval(&arrayszlst,arg[argidx].name,arg[argidx].dim[level],level);
  2256           } /* for */
  2257         } /* if */
  2258       } else if (arg[argidx].ident==iREFERENCE) {
  2259         setheap(arg[argidx].defvalue.val);
  2260         /* address of the value on the heap in PRI */
  2261         heapalloc++;
  2262         nest_stkusage++;
  2263       } else {
  2264         int dummytag=arg[argidx].tags[0];
  2265         ldconst(arg[argidx].defvalue.val,sPRI);
  2266         assert(arg[argidx].numtags>0);
  2267         check_userop(NULL,arg[argidx].defvalue_tag,arg[argidx].tags[0],2,NULL,&dummytag);
  2268         assert(dummytag==arg[argidx].tags[0]);
  2269       } /* if */
  2270       pushreg(sPRI);            /* store the function argument on the stack */
  2271       markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  2272       nest_stkusage++;
  2273     } else {
  2274       error(202,argidx);        /* argument count mismatch */
  2275     } /* if */
  2276     if (arglist[argidx]==ARG_UNHANDLED)
  2277       nargs++;
  2278     arglist[argidx]=ARG_DONE;
  2279   } /* for */
  2280   /* now a second loop to catch the arguments with default values that are
  2281    * the "sizeof" or "tagof" of other arguments
  2282    */
  2283   for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  2284     constvalue *asz;
  2285     cell array_sz;
  2286     if (arglist[argidx]==ARG_DONE)
  2287       continue;                 /* already seen and handled this argument */
  2288     stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  2289     assert(arg[argidx].ident==iVARIABLE);           /* if "sizeof", must be single cell */
  2290     /* if unseen, must be "sizeof" or "tagof" */
  2291     assert((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0);
  2292     if ((arg[argidx].hasdefault & uSIZEOF)!=0) {
  2293       /* find the argument; if it isn't found, the argument's default value
  2294        * was a "sizeof" of a non-array (a warning for this was already given
  2295        * when declaring the function)
  2296        */
  2297       asz=find_constval(&arrayszlst,arg[argidx].defvalue.size.symname,
  2298                         arg[argidx].defvalue.size.level);
  2299       if (asz!=NULL) {
  2300         array_sz=asz->value;
  2301         if (array_sz==0)
  2302           error(224,arg[argidx].name);    /* indeterminate array size in "sizeof" expression */
  2303       } else {
  2304         array_sz=1;
  2305       } /* if */
  2306     } else {
  2307       asz=find_constval(&taglst,arg[argidx].defvalue.size.symname,
  2308                         arg[argidx].defvalue.size.level);
  2309       if (asz != NULL) {
  2310         exporttag(asz->value);
  2311         array_sz=asz->value | PUBLICTAG;  /* must be set, because it just was exported */
  2312       } else {
  2313         array_sz=0;
  2314       } /* if */
  2315     } /* if */
  2316     ldconst(array_sz,sPRI);
  2317     pushreg(sPRI);              /* store the function argument on the stack */
  2318     markexpr(sPARM,NULL,0);
  2319     nest_stkusage++;
  2320     if (arglist[argidx]==ARG_UNHANDLED)
  2321       nargs++;
  2322     arglist[argidx]=ARG_DONE;
  2323   } /* for */
  2324   stgmark(sENDREORDER);         /* mark end of reversed evaluation */
  2325   pushval((cell)nargs*sizeof(cell));
  2326   nest_stkusage++;
  2327   ffcall(sym,NULL,nargs);
  2328   if (sc_status!=statSKIP)
  2329     markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
  2330   if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL)
  2331     sym->x.lib->value += 1;     /* increment "usage count" of the library */
  2332   modheap(-heapalloc*sizeof(cell));
  2333   if (symret!=NULL)
  2334     popreg(sPRI);               /* pop hidden parameter as function result */
  2335   sideeffect=TRUE;              /* assume functions carry out a side-effect */
  2336   delete_consttable(&arrayszlst);     /* clear list of array sizes */
  2337   delete_consttable(&taglst);   /* clear list of parameter tags */
  2338 
  2339   /* maintain max. amount of memory used */
  2340   {
  2341     long totalsize;
  2342     totalsize=declared+decl_heap+1;   /* local variables & return value size,
  2343                                        * +1 for PROC opcode */
  2344     if (lval_result->ident==iREFARRAY)
  2345       totalsize++;                    /* add hidden parameter (on the stack) */
  2346     if ((sym->usage & uNATIVE)==0)
  2347       totalsize++;                    /* add "call" opcode */
  2348     totalsize+=nest_stkusage;
  2349     assert(curfunc!=NULL);
  2350     if (curfunc->x.stacksize<totalsize)
  2351       curfunc->x.stacksize=totalsize;
  2352     nest_stkusage-=nargs+heapalloc+1; /* stack/heap space, +1 for argcount param */
  2353     /* if there is a syntax error in the script, the stack calculation is
  2354      * probably incorrect; but we may not allow it to drop below zero
  2355      */
  2356     if (nest_stkusage<0)
  2357       nest_stkusage=0;
  2358   }
  2359 
  2360   /* scrap any arrays left on the heap, with the exception of the array that
  2361    * this function has as a result (in other words, scrap all arrays on the
  2362    * heap that caused by expressions in the function arguments)
  2363    */
  2364   assert(decl_heap>=locheap);
  2365   modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
  2366   decl_heap=locheap;
  2367   nesting--;
  2368 }
  2369 
  2370 /*  dbltest
  2371  *
  2372  *  Returns a non-zero value if lval1 an array and lval2 is not an array and
  2373  *  the operation is addition or subtraction.
  2374  *
  2375  *  Returns the "shift" count (1 for 16-bit, 2 for 32-bit) to align a cell
  2376  *  to an array offset.
  2377  */
  2378 static int dbltest(void (*oper)(),value *lval1,value *lval2)
  2379 {
  2380   if ((oper!=ob_add) && (oper!=ob_sub))
  2381     return 0;
  2382   if (lval1->ident!=iARRAY)
  2383     return 0;
  2384   if (lval2->ident==iARRAY)
  2385     return 0;
  2386   return sizeof(cell)/2;        /* 1 for 16-bit, 2 for 32-bit */
  2387 }
  2388 
  2389 /*  commutative
  2390  *
  2391  *  Test whether an operator is commutative, i.e. x oper y == y oper x.
  2392  *  Commutative operators are: +  (addition)
  2393  *                             *  (multiplication)
  2394  *                             == (equality)
  2395  *                             != (inequality)
  2396  *                             &  (bitwise and)
  2397  *                             ^  (bitwise xor)
  2398  *                             |  (bitwise or)
  2399  *
  2400  *  If in an expression, code for the left operand has been generated and
  2401  *  the right operand is a constant and the operator is commutative, the
  2402  *  precautionary "push" of the primary register is scrapped and the constant
  2403  *  is read into the secondary register immediately.
  2404  */
  2405 static int commutative(void (*oper)())
  2406 {
  2407   return oper==ob_add || oper==os_mult
  2408          || oper==ob_eq || oper==ob_ne
  2409          || oper==ob_and || oper==ob_xor || oper==ob_or;
  2410 }
  2411 
  2412 /*  constant
  2413  *
  2414  *  Generates code to fetch a number, a literal character (which is returned
  2415  *  by lex() as a number as well) or a literal string (lex() stores the
  2416  *  strings in the literal queue). If the operand was a number, it is stored
  2417  *  in lval->constval.
  2418  *
  2419  *  The function returns 1 if the token was a constant or a string, 0
  2420  *  otherwise.
  2421  */
  2422 static int constant(value *lval)
  2423 {
  2424   int tok,index,ident;
  2425   cell val,item,cidx;
  2426   char *st;
  2427   symbol *sym;
  2428   int cmptag=lval->cmptag;
  2429 
  2430   tok=lex(&val,&st);
  2431   if (tok==tSYMBOL && (sym=findconst(st,&cmptag))!=0) {
  2432     if (cmptag>1)
  2433       error(91,sym->name);  /* ambiguity: multiple matching constants (different tags) */
  2434     lval->constval=sym->addr;
  2435     ldconst(lval->constval,sPRI);
  2436     lval->ident=iCONSTEXPR;
  2437     lval->tag=sym->tag;
  2438     lval->sym=sym;
  2439     markusage(sym,uREAD);
  2440   } else if (tok==tNUMBER) {
  2441     lval->constval=val;
  2442     ldconst(lval->constval,sPRI);
  2443     lval->ident=iCONSTEXPR;
  2444   } else if (tok==tRATIONAL) {
  2445     lval->constval=val;
  2446     ldconst(lval->constval,sPRI);
  2447     lval->ident=iCONSTEXPR;
  2448     lval->tag=sc_rationaltag;
  2449   } else if (tok==tSTRING) {
  2450     /* lex() stores starting index of string in the literal table in 'val' */
  2451     ldconst((val+glb_declared)*sizeof(cell),sPRI);
  2452     lval->ident=iARRAY;         /* pretend this is a global array */
  2453     lval->constval=val-litidx;  /* constval == the negative value of the
  2454                                  * size of the literal array; using a negative
  2455                                  * value distinguishes between literal arrays
  2456                                  * and literal strings (this was done for
  2457                                  * array assignment). */
  2458   } else if (tok=='{') {
  2459     int tag,lasttag=-1;
  2460     val=litidx;
  2461     do {
  2462       /* cannot call constexpr() here, because "staging" is already turned
  2463        * on at this point */
  2464       assert(staging);
  2465       stgget(&index,&cidx);     /* mark position in code generator */
  2466       ident=expression(&item,&tag,NULL,FALSE);
  2467       stgdel(index,cidx);       /* scratch generated code */
  2468       if (ident!=iCONSTEXPR)
  2469         error(8);               /* must be constant expression */
  2470       if (lasttag<0)
  2471         lasttag=tag;
  2472       else if (!matchtag(lasttag,tag,FALSE))
  2473         error(213);             /* tagname mismatch */
  2474       litadd(item);             /* store expression result in literal table */
  2475     } while (matchtoken(','));
  2476     if (!needtoken('}'))
  2477       lexclr(FALSE);
  2478     ldconst((val+glb_declared)*sizeof(cell),sPRI);
  2479     lval->ident=iARRAY;         /* pretend this is a global array */
  2480     lval->constval=litidx-val;  /* constval == the size of the literal array */
  2481   } else {
  2482     return FALSE;               /* no, it cannot be interpreted as a constant */
  2483   } /* if */
  2484   return TRUE;                  /* yes, it was a constant value */
  2485 }
  2486