compiler-init/sc3.c
branchdvander
changeset 26 cddce0804b2a
parent 23 040a84cd0eee
child 2286 34e6e8ca7db2
     1.1 --- a/compiler-init/sc3.c	Sat Jul 15 05:02:38 2006 +0000
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,2469 +0,0 @@
     1.4 -/*  Pawn compiler - Recursive descend expresion parser
     1.5 - *
     1.6 - *  Copyright (c) ITB CompuPhase, 1997-2005
     1.7 - *
     1.8 - *  This software is provided "as-is", without any express or implied warranty.
     1.9 - *  In no event will the authors be held liable for any damages arising from
    1.10 - *  the use of this software.
    1.11 - *
    1.12 - *  Permission is granted to anyone to use this software for any purpose,
    1.13 - *  including commercial applications, and to alter it and redistribute it
    1.14 - *  freely, subject to the following restrictions:
    1.15 - *
    1.16 - *  1.  The origin of this software must not be misrepresented; you must not
    1.17 - *      claim that you wrote the original software. If you use this software in
    1.18 - *      a product, an acknowledgment in the product documentation would be
    1.19 - *      appreciated but is not required.
    1.20 - *  2.  Altered source versions must be plainly marked as such, and must not be
    1.21 - *      misrepresented as being the original software.
    1.22 - *  3.  This notice may not be removed or altered from any source distribution.
    1.23 - *
    1.24 - *  Version: $Id: sc3.c 3598 2006-07-04 13:44:04Z thiadmer $
    1.25 - */
    1.26 -#include <assert.h>
    1.27 -#include <stdio.h>
    1.28 -#include <stdlib.h>     /* for _MAX_PATH */
    1.29 -#include <string.h>
    1.30 -#if defined FORTIFY
    1.31 -  #include <alloc/fortify.h>
    1.32 -#endif
    1.33 -#include "sc.h"
    1.34 -
    1.35 -static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
    1.36 -                int (*hier)(value*),value *lval);
    1.37 -static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval);
    1.38 -static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
    1.39 -                 char *forcetag,int chkbitwise);
    1.40 -static int plnge1(int (*hier)(value *lval),value *lval);
    1.41 -static void plnge2(void (*oper)(void),
    1.42 -                   int (*hier)(value *lval),
    1.43 -                   value *lval1,value *lval2);
    1.44 -static cell calc(cell left,void (*oper)(),cell right,char *boolresult);
    1.45 -static int hier14(value *lval);
    1.46 -static int hier13(value *lval);
    1.47 -static int hier12(value *lval);
    1.48 -static int hier11(value *lval);
    1.49 -static int hier10(value *lval);
    1.50 -static int hier9(value *lval);
    1.51 -static int hier8(value *lval);
    1.52 -static int hier7(value *lval);
    1.53 -static int hier6(value *lval);
    1.54 -static int hier5(value *lval);
    1.55 -static int hier4(value *lval);
    1.56 -static int hier3(value *lval);
    1.57 -static int hier2(value *lval);
    1.58 -static int hier1(value *lval1);
    1.59 -static int primary(value *lval);
    1.60 -static void clear_value(value *lval);
    1.61 -static void callfunction(symbol *sym,value *lval_result,int matchparanthesis);
    1.62 -static int dbltest(void (*oper)(),value *lval1,value *lval2);
    1.63 -static int commutative(void (*oper)());
    1.64 -static int constant(value *lval);
    1.65 -
    1.66 -static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */
    1.67 -static int bitwise_opercount;   /* count of bitwise operators in an expression */
    1.68 -static int decl_heap=0;
    1.69 -
    1.70 -/* Function addresses of binary operators for signed operations */
    1.71 -static void (*op1[17])(void) = {
    1.72 -  os_mult,os_div,os_mod,        /* hier3, index 0 */
    1.73 -  ob_add,ob_sub,                /* hier4, index 3 */
    1.74 -  ob_sal,os_sar,ou_sar,         /* hier5, index 5 */
    1.75 -  ob_and,                       /* hier6, index 8 */
    1.76 -  ob_xor,                       /* hier7, index 9 */
    1.77 -  ob_or,                        /* hier8, index 10 */
    1.78 -  os_le,os_ge,os_lt,os_gt,      /* hier9, index 11 */
    1.79 -  ob_eq,ob_ne,                  /* hier10, index 15 */
    1.80 -};
    1.81 -/* These two functions are defined because the functions inc() and dec() in
    1.82 - * SC4.C have a different prototype than the other code generation functions.
    1.83 - * The arrays for user-defined functions use the function pointers for
    1.84 - * identifying what kind of operation is requested; these functions must all
    1.85 - * have the same prototype. As inc() and dec() are special cases already, it
    1.86 - * is simplest to add two "do-nothing" functions.
    1.87 - */
    1.88 -static void user_inc(void) {}
    1.89 -static void user_dec(void) {}
    1.90 -
    1.91 -/*
    1.92 - *  Searches for a binary operator a list of operators. The list is stored in
    1.93 - *  the array "list". The last entry in the list should be set to 0.
    1.94 - *
    1.95 - *  The index of an operator in "list" (if found) is returned in "opidx". If
    1.96 - *  no operator is found, nextop() returns 0.
    1.97 - *
    1.98 - *  If an operator is found in the expression, it cannot be used in a function
    1.99 - *  call with omitted parantheses. Mark this...
   1.100 - *
   1.101 - *  Global references: sc_allowproccall   (modified)
   1.102 - */
   1.103 -static int nextop(int *opidx,int *list)
   1.104 -{
   1.105 -  *opidx=0;
   1.106 -  while (*list){
   1.107 -    if (matchtoken(*list)){
   1.108 -      sc_allowproccall=FALSE;
   1.109 -      return TRUE;      /* found! */
   1.110 -    } else {
   1.111 -      list+=1;
   1.112 -      *opidx+=1;
   1.113 -    } /* if */
   1.114 -  } /* while */
   1.115 -  return FALSE;         /* entire list scanned, nothing found */
   1.116 -}
   1.117 -
   1.118 -SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
   1.119 -                         value *lval,int *resulttag)
   1.120 -{
   1.121 -static char *binoperstr[] = { "*", "/", "%", "+", "-", "", "", "",
   1.122 -                              "", "", "", "<=", ">=", "<", ">", "==", "!=" };
   1.123 -static int binoper_savepri[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1.124 -                                 FALSE, FALSE, FALSE, FALSE, FALSE,
   1.125 -                                 TRUE, TRUE, TRUE, TRUE, FALSE, FALSE };
   1.126 -static char *unoperstr[] = { "!", "-", "++", "--" };
   1.127 -static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
   1.128 -  char opername[4] = "", symbolname[sNAMEMAX+1];
   1.129 -  int i,swapparams,savepri,savealt;
   1.130 -  int paramspassed;
   1.131 -  symbol *sym;
   1.132 -
   1.133 -  /* since user-defined operators on untagged operands are forbidden, we have
   1.134 -   * a quick exit.
   1.135 -   */
   1.136 -  assert(numparam==1 || numparam==2);
   1.137 -  if (tag1==0 && (numparam==1 || tag2==0))
   1.138 -    return FALSE;
   1.139 -
   1.140 -  savepri=savealt=FALSE;
   1.141 -  /* find the name with the operator */
   1.142 -  if (numparam==2) {
   1.143 -    if (oper==NULL) {
   1.144 -      /* assignment operator: a special case */
   1.145 -      strcpy(opername,"=");
   1.146 -      if (lval!=NULL && (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR))
   1.147 -        savealt=TRUE;
   1.148 -    } else {
   1.149 -      assert( (sizeof binoperstr / sizeof binoperstr[0]) == (sizeof op1 / sizeof op1[0]) );
   1.150 -      for (i=0; i<sizeof op1 / sizeof op1[0]; i++) {
   1.151 -        if (oper==op1[i]) {
   1.152 -          strcpy(opername,binoperstr[i]);
   1.153 -          savepri=binoper_savepri[i];
   1.154 -          break;
   1.155 -        } /* if */
   1.156 -      } /* for */
   1.157 -    } /* if */
   1.158 -  } else {
   1.159 -    assert(oper!=NULL);
   1.160 -    assert(numparam==1);
   1.161 -    /* try a select group of unary operators */
   1.162 -    assert( (sizeof unoperstr / sizeof unoperstr[0]) == (sizeof unopers / sizeof unopers[0]) );
   1.163 -    if (opername[0]=='\0') {
   1.164 -      for (i=0; i<sizeof unopers / sizeof unopers[0]; i++) {
   1.165 -        if (oper==unopers[i]) {
   1.166 -          strcpy(opername,unoperstr[i]);
   1.167 -          break;
   1.168 -        } /* if */
   1.169 -      } /* for */
   1.170 -    } /* if */
   1.171 -  } /* if */
   1.172 -  /* if not found, quit */
   1.173 -  if (opername[0]=='\0')
   1.174 -    return FALSE;
   1.175 -
   1.176 -  /* create a symbol name from the tags and the operator name */
   1.177 -  assert(numparam==1 || numparam==2);
   1.178 -  operator_symname(symbolname,opername,tag1,tag2,numparam,tag2);
   1.179 -  swapparams=FALSE;
   1.180 -  sym=findglb(symbolname,sGLOBAL);
   1.181 -  if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/) {  /* ??? should not check uDEFINE; first pass clears these bits */
   1.182 -    /* check for commutative operators */
   1.183 -    if (tag1==tag2 || oper==NULL || !commutative(oper))
   1.184 -      return FALSE;             /* not commutative, cannot swap operands */
   1.185 -    /* if arrived here, the operator is commutative and the tags are different,
   1.186 -     * swap tags and try again
   1.187 -     */
   1.188 -    assert(numparam==2);        /* commutative operator must be a binary operator */
   1.189 -    operator_symname(symbolname,opername,tag2,tag1,numparam,tag1);
   1.190 -    swapparams=TRUE;
   1.191 -    sym=findglb(symbolname,sGLOBAL);
   1.192 -    if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/)
   1.193 -      return FALSE;
   1.194 -  } /* if */
   1.195 -
   1.196 -  /* check existance and the proper declaration of this function */
   1.197 -  if ((sym->usage & uMISSING)!=0 || (sym->usage & uPROTOTYPED)==0) {
   1.198 -    char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
   1.199 -    funcdisplayname(symname,sym->name);
   1.200 -    if ((sym->usage & uMISSING)!=0)
   1.201 -      error(4,symname);           /* function not defined */
   1.202 -    if ((sym->usage & uPROTOTYPED)==0)
   1.203 -      error(71,symname);          /* operator must be declared before use */
   1.204 -  } /* if */
   1.205 -
   1.206 -  /* we don't want to use the redefined operator in the function that
   1.207 -   * redefines the operator itself, otherwise the snippet below gives
   1.208 -   * an unexpected recursion:
   1.209 -   *    fixed:operator+(fixed:a, fixed:b)
   1.210 -   *        return a + b
   1.211 -   */
   1.212 -  if (sym==curfunc)
   1.213 -    return FALSE;
   1.214 -
   1.215 -  /* for increment and decrement operators, the symbol must first be loaded
   1.216 -   * (and stored back afterwards)
   1.217 -   */
   1.218 -  if (oper==user_inc || oper==user_dec) {
   1.219 -    assert(!savepri);
   1.220 -    assert(lval!=NULL);
   1.221 -    if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
   1.222 -      pushreg(sPRI);            /* save current address in PRI */
   1.223 -    rvalue(lval);               /* get the symbol's value in PRI */
   1.224 -  } /* if */
   1.225 -
   1.226 -  assert(!savepri || !savealt); /* either one MAY be set, but not both */
   1.227 -  if (savepri) {
   1.228 -    /* the chained comparison operators require that the ALT register is
   1.229 -     * unmodified, so we save it here; actually, we save PRI because the normal
   1.230 -     * instruction sequence (without user operator) swaps PRI and ALT
   1.231 -     */
   1.232 -    pushreg(sPRI);              /* right-hand operand is in PRI */
   1.233 -  } else if (savealt) {
   1.234 -    /* for the assignment operator, ALT may contain an address at which the
   1.235 -     * result must be stored; this address must be preserved accross the
   1.236 -     * call
   1.237 -     */
   1.238 -    assert(lval!=NULL);         /* this was checked earlier */
   1.239 -    assert(lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR); /* checked earlier */
   1.240 -    pushreg(sALT);
   1.241 -  } /* if */
   1.242 -
   1.243 -  /* push parameters, call the function */
   1.244 -  paramspassed= (oper==NULL) ? 1 : numparam;
   1.245 -  switch (paramspassed) {
   1.246 -  case 1:
   1.247 -    pushreg(sPRI);
   1.248 -    break;
   1.249 -  case 2:
   1.250 -    /* note that 1) a function expects that the parameters are pushed
   1.251 -     * in reversed order, and 2) the left operand is in the secondary register
   1.252 -     * and the right operand is in the primary register */
   1.253 -    if (swapparams) {
   1.254 -      pushreg(sALT);
   1.255 -      pushreg(sPRI);
   1.256 -    } else {
   1.257 -      pushreg(sPRI);
   1.258 -      pushreg(sALT);
   1.259 -    } /* if */
   1.260 -    break;
   1.261 -  default:
   1.262 -    assert(0);
   1.263 -  } /* switch */
   1.264 -  markexpr(sPARM,NULL,0);       /* mark the end of a sub-expression */
   1.265 -  pushval((cell)paramspassed*sizeof(cell));
   1.266 -  assert(sym->ident==iFUNCTN);
   1.267 -  ffcall(sym,NULL,paramspassed);
   1.268 -  if (sc_status!=statSKIP)
   1.269 -    markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
   1.270 -  if ((sym->usage & uNATIVE)!=0 && sym->x.lib!=NULL)
   1.271 -    sym->x.lib->value += 1;     /* increment "usage count" of the library */
   1.272 -  sideeffect=TRUE;              /* assume functions carry out a side-effect */
   1.273 -  assert(resulttag!=NULL);
   1.274 -  *resulttag=sym->tag;          /* save tag of the called function */
   1.275 -
   1.276 -  if (savepri || savealt)
   1.277 -    popreg(sALT);               /* restore the saved PRI/ALT that into ALT */
   1.278 -  if (oper==user_inc || oper==user_dec) {
   1.279 -    assert(lval!=NULL);
   1.280 -    if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
   1.281 -      popreg(sALT);             /* restore address (in ALT) */
   1.282 -    store(lval);                /* store PRI in the symbol */
   1.283 -    moveto1();                  /* make sure PRI is restored on exit */
   1.284 -  } /* if */
   1.285 -  return TRUE;
   1.286 -}
   1.287 -
   1.288 -SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce)
   1.289 -{
   1.290 -  if (formaltag!=actualtag) {
   1.291 -    /* if the formal tag is zero and the actual tag is not "fixed", the actual
   1.292 -     * tag is "coerced" to zero
   1.293 -     */
   1.294 -    if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0)
   1.295 -      return FALSE;
   1.296 -  } /* if */
   1.297 -  return TRUE;
   1.298 -}
   1.299 -
   1.300 -/*
   1.301 - *  The AMX pseudo-processor has no direct support for logical (boolean)
   1.302 - *  operations. These have to be done via comparing and jumping. Since we are
   1.303 - *  already jumping through the code, we might as well implement an "early
   1.304 - *  drop-out" evaluation (also called "short-circuit"). This conforms to
   1.305 - *  standard C:
   1.306 - *
   1.307 - *  expr1 || expr2           expr2 will only be evaluated if expr1 is false.
   1.308 - *  expr1 && expr2           expr2 will only be evaluated if expr1 is true.
   1.309 - *
   1.310 - *  expr1 || expr2 && expr3  expr2 will only be evaluated if expr1 is false
   1.311 - *                           and expr3 will only be evaluated if expr1 is
   1.312 - *                           false and expr2 is true.
   1.313 - *
   1.314 - *  Code generation for the last example proceeds thus:
   1.315 - *
   1.316 - *      evaluate expr1
   1.317 - *      operator || found
   1.318 - *      jump to "l1" if result of expr1 not equal to 0
   1.319 - *      evaluate expr2
   1.320 - *      ->  operator && found; skip to higher level in hierarchy diagram
   1.321 - *          jump to "l2" if result of expr2 equal to 0
   1.322 - *          evaluate expr3
   1.323 - *          jump to "l2" if result of expr3 equal to 0
   1.324 - *          set expression result to 1 (true)
   1.325 - *          jump to "l3"
   1.326 - *      l2: set expression result to 0 (false)
   1.327 - *      l3:
   1.328 - *      <-  drop back to previous hierarchy level
   1.329 - *      jump to "l1" if result of expr2 && expr3 not equal to 0
   1.330 - *      set expression result to 0 (false)
   1.331 - *      jump to "l4"
   1.332 - *  l1: set expression result to 1 (true)
   1.333 - *  l4:
   1.334 - *
   1.335 - */
   1.336 -
   1.337 -/*  Skim over terms adjoining || and && operators
   1.338 - *  dropval   The value of the expression after "dropping out". An "or" drops
   1.339 - *            out when the left hand is TRUE, so dropval must be 1 on "or"
   1.340 - *            expressions.
   1.341 - *  endval    The value of the expression when no expression drops out. In an
   1.342 - *            "or" expression, this happens when both the left hand and the
   1.343 - *            right hand are FALSE, so endval must be 0 for "or" expressions.
   1.344 - */
   1.345 -static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
   1.346 -                int (*hier)(value*),value *lval)
   1.347 -{
   1.348 -  int lvalue,hits,droplab,endlab,opidx;
   1.349 -  int allconst,foundop;
   1.350 -  cell constval;
   1.351 -  int index;
   1.352 -  cell cidx;
   1.353 -
   1.354 -  stgget(&index,&cidx);         /* mark position in code generator */
   1.355 -  hits=FALSE;                   /* no logical operators "hit" yet */
   1.356 -  allconst=TRUE;                /* assume all values "const" */
   1.357 -  constval=0;
   1.358 -  droplab=0;                    /* to avoid a compiler warning */
   1.359 -  for ( ;; ) {
   1.360 -    lvalue=plnge1(hier,lval);   /* evaluate left expression */
   1.361 -
   1.362 -    allconst= allconst && (lval->ident==iCONSTEXPR);
   1.363 -    if (allconst) {
   1.364 -      if (hits) {
   1.365 -        /* one operator was already found */
   1.366 -        if (testfunc==jmp_ne0)
   1.367 -          lval->constval= lval->constval || constval;
   1.368 -        else
   1.369 -          lval->constval= lval->constval && constval;
   1.370 -      } /* if */
   1.371 -      constval=lval->constval;  /* save result accumulated so far */
   1.372 -    } /* if */
   1.373 -
   1.374 -    foundop=nextop(&opidx,opstr);
   1.375 -    if ((foundop || hits) && (lval->ident==iARRAY || lval->ident==iREFARRAY))
   1.376 -      error(33, lval->sym ? (lval->sym->name ? lval->sym->name : "-unknown") : "-unknown-");  /* array was not indexed in an expression */
   1.377 -    if (foundop) {
   1.378 -      if (!hits) {
   1.379 -        /* this is the first operator in the list */
   1.380 -        hits=TRUE;
   1.381 -        droplab=getlabel();
   1.382 -      } /* if */
   1.383 -      dropout(lvalue,testfunc,droplab,lval);
   1.384 -    } else if (hits) {                       /* no (more) identical operators */
   1.385 -      dropout(lvalue,testfunc,droplab,lval); /* found at least one operator! */
   1.386 -      ldconst(endval,sPRI);
   1.387 -      jumplabel(endlab=getlabel());
   1.388 -      setlabel(droplab);
   1.389 -      ldconst(dropval,sPRI);
   1.390 -      setlabel(endlab);
   1.391 -      lval->sym=NULL;
   1.392 -      lval->tag=pc_addtag("bool");  /* force tag to be "bool" */
   1.393 -      if (allconst) {
   1.394 -        lval->ident=iCONSTEXPR;
   1.395 -        lval->constval=constval;
   1.396 -        stgdel(index,cidx);         /* scratch generated code and calculate */
   1.397 -      } else {
   1.398 -        lval->ident=iEXPRESSION;
   1.399 -        lval->constval=0;
   1.400 -      } /* if */
   1.401 -      return FALSE;
   1.402 -    } else {
   1.403 -      return lvalue;            /* none of the operators in "opstr" were found */
   1.404 -    } /* if */
   1.405 -
   1.406 -  } /* while */
   1.407 -}
   1.408 -
   1.409 -/*
   1.410 - *  Reads into the primary register the variable pointed to by lval if
   1.411 - *  plunging through the hierarchy levels detected an lvalue. Otherwise
   1.412 - *  if a constant was detected, it is loaded. If there is no constant and
   1.413 - *  no lvalue, the primary register must already contain the expression
   1.414 - *  result.
   1.415 - *
   1.416 - *  After that, the compare routines "jmp_ne0" or "jmp_eq0" are called, which
   1.417 - *  compare the primary register against 0, and jump to the "early drop-out"
   1.418 - *  label "exit1" if the condition is true.
   1.419 - */
   1.420 -static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval)
   1.421 -{
   1.422 -  if (lvalue)
   1.423 -    rvalue(lval);
   1.424 -  else if (lval->ident==iCONSTEXPR)
   1.425 -    ldconst(lval->constval,sPRI);
   1.426 -  (*testfunc)(exit1);
   1.427 -}
   1.428 -
   1.429 -static void checkfunction(value *lval)
   1.430 -{
   1.431 -  symbol *sym=lval->sym;
   1.432 -
   1.433 -  if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
   1.434 -    return;             /* no known symbol, or not a function result */
   1.435 -
   1.436 -  if ((sym->usage & uDEFINE)!=0) {
   1.437 -    /* function is defined, can now check the return value (but make an
   1.438 -     * exception for directly recursive functions)
   1.439 -     */
   1.440 -    if (sym!=curfunc && (sym->usage & uRETVALUE)==0) {
   1.441 -      char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
   1.442 -      funcdisplayname(symname,sym->name);
   1.443 -      error(209,symname);       /* function should return a value */
   1.444 -    } /* if */
   1.445 -  } else {
   1.446 -    /* function not yet defined, set */
   1.447 -    sym->usage|=uRETVALUE;      /* make sure that a future implementation of
   1.448 -                                 * the function uses "return <value>" */
   1.449 -  } /* if */
   1.450 -}
   1.451 -
   1.452 -/*
   1.453 - *  Plunge to a lower level
   1.454 - */
   1.455 -static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
   1.456 -                 char *forcetag,int chkbitwise)
   1.457 -{
   1.458 -  int lvalue,opidx;
   1.459 -  int count;
   1.460 -  value lval2 = {0};
   1.461 -
   1.462 -  lvalue=plnge1(hier,lval);
   1.463 -  if (nextop(&opidx,opstr)==0)
   1.464 -    return lvalue;              /* no operator in "opstr" found */
   1.465 -  if (lvalue)
   1.466 -    rvalue(lval);
   1.467 -  count=0;
   1.468 -  do {
   1.469 -    if (chkbitwise && count++>0 && bitwise_opercount!=0)
   1.470 -      error(212);
   1.471 -    opidx+=opoff;               /* add offset to index returned by nextop() */
   1.472 -    plnge2(op1[opidx],hier,lval,&lval2);
   1.473 -    if (op1[opidx]==ob_and || op1[opidx]==ob_or)
   1.474 -      bitwise_opercount++;
   1.475 -    if (forcetag!=NULL)
   1.476 -      lval->tag=pc_addtag(forcetag);
   1.477 -  } while (nextop(&opidx,opstr)); /* do */
   1.478 -  return FALSE;         /* result of expression is not an lvalue */
   1.479 -}
   1.480 -
   1.481 -/*  plnge_rel
   1.482 - *
   1.483 - *  Binary plunge to lower level; this is very simular to plnge, but
   1.484 - *  it has special code generation sequences for chained operations.
   1.485 - */
   1.486 -static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
   1.487 -{
   1.488 -  int lvalue,opidx;
   1.489 -  value lval2={0};
   1.490 -  int count;
   1.491 -
   1.492 -  /* this function should only be called for relational operators */
   1.493 -  assert(op1[opoff]==os_le);
   1.494 -  lvalue=plnge1(hier,lval);
   1.495 -  if (nextop(&opidx,opstr)==0)
   1.496 -    return lvalue;              /* no operator in "opstr" found */
   1.497 -  if (lvalue)
   1.498 -    rvalue(lval);
   1.499 -  count=0;
   1.500 -  lval->boolresult=TRUE;
   1.501 -  do {
   1.502 -    /* same check as in plnge(), but "chkbitwise" is always TRUE */
   1.503 -    if (count>0 && bitwise_opercount!=0)
   1.504 -      error(212);
   1.505 -    if (count>0) {
   1.506 -      relop_prefix();
   1.507 -      *lval=lval2;      /* copy right hand expression of the previous iteration */
   1.508 -    } /* if */
   1.509 -    opidx+=opoff;
   1.510 -    plnge2(op1[opidx],hier,lval,&lval2);
   1.511 -    if (count++>0)
   1.512 -      relop_suffix();
   1.513 -  } while (nextop(&opidx,opstr)); /* enddo */
   1.514 -  lval->constval=lval->boolresult;
   1.515 -  lval->tag=pc_addtag("bool");    /* force tag to be "bool" */
   1.516 -  return FALSE;         /* result of expression is not an lvalue */
   1.517 -}
   1.518 -
   1.519 -/*  plnge1
   1.520 - *
   1.521 - *  Unary plunge to lower level
   1.522 - *  Called by: skim(), plnge(), plnge2(), plnge_rel(), hier14() and hier13()
   1.523 - */
   1.524 -static int plnge1(int (*hier)(value *lval),value *lval)
   1.525 -{
   1.526 -  int lvalue,index;
   1.527 -  cell cidx;
   1.528 -
   1.529 -  stgget(&index,&cidx); /* mark position in code generator */
   1.530 -  lvalue=(*hier)(lval);
   1.531 -  if (lval->ident==iCONSTEXPR)
   1.532 -    stgdel(index,cidx); /* load constant later */
   1.533 -  return lvalue;
   1.534 -}
   1.535 -
   1.536 -/*  plnge2
   1.537 - *
   1.538 - *  Binary plunge to lower level
   1.539 - *  Called by: plnge(), plnge_rel(), hier14() and hier1()
   1.540 - */
   1.541 -static void plnge2(void (*oper)(void),
   1.542 -                   int (*hier)(value *lval),
   1.543 -                   value *lval1,value *lval2)
   1.544 -{
   1.545 -  int index;
   1.546 -  cell cidx;
   1.547 -
   1.548 -  stgget(&index,&cidx);             /* mark position in code generator */
   1.549 -  if (lval1->ident==iCONSTEXPR) {   /* constant on left side; it is not yet loaded */
   1.550 -    if (plnge1(hier,lval2))
   1.551 -      rvalue(lval2);                /* load lvalue now */
   1.552 -    else if (lval2->ident==iCONSTEXPR)
   1.553 -      ldconst(lval2->constval<<dbltest(oper,lval2,lval1),sPRI);
   1.554 -    ldconst(lval1->constval<<dbltest(oper,lval2,lval1),sALT);
   1.555 -                   /* ^ doubling of constants operating on integer addresses */
   1.556 -                   /*   is restricted to "add" and "subtract" operators */
   1.557 -  } else {                          /* non-constant on left side */
   1.558 -    pushreg(sPRI);
   1.559 -    if (plnge1(hier,lval2))
   1.560 -      rvalue(lval2);
   1.561 -    if (lval2->ident==iCONSTEXPR) { /* constant on right side */
   1.562 -      if (commutative(oper)) {      /* test for commutative operators */
   1.563 -        value lvaltmp = {0};
   1.564 -        stgdel(index,cidx);         /* scratch pushreg() and constant fetch (then
   1.565 -                                     * fetch the constant again */
   1.566 -        ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sALT);
   1.567 -        /* now, the primary register has the left operand and the secondary
   1.568 -         * register the right operand; swap the "lval" variables so that lval1
   1.569 -         * is associated with the secondary register and lval2 with the
   1.570 -         * primary register, as is the "normal" case.
   1.571 -         */
   1.572 -        lvaltmp=*lval1;
   1.573 -        *lval1=*lval2;
   1.574 -        *lval2=lvaltmp;
   1.575 -      } else {
   1.576 -        ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sPRI);
   1.577 -        popreg(sALT);   /* pop result of left operand into secondary register */
   1.578 -      } /* if */
   1.579 -    } else {            /* non-constants on both sides */
   1.580 -      popreg(sALT);
   1.581 -      if (dbltest(oper,lval1,lval2))
   1.582 -        cell2addr();                    /* double primary register */
   1.583 -      if (dbltest(oper,lval2,lval1))
   1.584 -        cell2addr_alt();                /* double secondary register */
   1.585 -    } /* if */
   1.586 -  } /* if */
   1.587 -  if (oper) {
   1.588 -    /* If used in an expression, a function should return a value.
   1.589 -     * If the function has been defined, we can check this. If the
   1.590 -     * function was not defined, we can set this requirement (so that
   1.591 -     * a future function definition can check this bit.
   1.592 -     */
   1.593 -    checkfunction(lval1);
   1.594 -    checkfunction(lval2);
   1.595 -    if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
   1.596 -      char *ptr=(lval1->sym!=NULL) ? lval1->sym->name : "-unknown-";
   1.597 -      error(33,ptr);                    /* array must be indexed */
   1.598 -    } else if (lval2->ident==iARRAY || lval2->ident==iREFARRAY) {
   1.599 -      char *ptr=(lval2->sym!=NULL) ? lval2->sym->name : "-unknown-";
   1.600 -      error(33,ptr);                    /* array must be indexed */
   1.601 -    } /* if */
   1.602 -    /* ??? ^^^ should do same kind of error checking with functions */
   1.603 -
   1.604 -    /* check whether an "operator" function is defined for the tag names
   1.605 -     * (a constant expression cannot be optimized in that case)
   1.606 -     */
   1.607 -    if (check_userop(oper,lval1->tag,lval2->tag,2,NULL,&lval1->tag)) {
   1.608 -      lval1->ident=iEXPRESSION;
   1.609 -      lval1->constval=0;
   1.610 -    } else if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
   1.611 -      /* only constant expression if both constant */
   1.612 -      stgdel(index,cidx);       /* scratch generated code and calculate */
   1.613 -      if (!matchtag(lval1->tag,lval2->tag,FALSE))
   1.614 -        error(213);             /* tagname mismatch */
   1.615 -      lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
   1.616 -    } else {
   1.617 -      if (!matchtag(lval1->tag,lval2->tag,FALSE))
   1.618 -        error(213);             /* tagname mismatch */
   1.619 -      (*oper)();                /* do the (signed) operation */
   1.620 -      lval1->ident=iEXPRESSION;
   1.621 -    } /* if */
   1.622 -  } /* if */
   1.623 -}
   1.624 -
   1.625 -static cell truemodulus(cell a,cell b)
   1.626 -{
   1.627 -  return (a % b + b) % b;
   1.628 -}
   1.629 -
   1.630 -static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
   1.631 -{
   1.632 -  if (oper==ob_or)
   1.633 -    return (left | right);
   1.634 -  else if (oper==ob_xor)
   1.635 -    return (left ^ right);
   1.636 -  else if (oper==ob_and)
   1.637 -    return (left & right);
   1.638 -  else if (oper==ob_eq)
   1.639 -    return (left == right);
   1.640 -  else if (oper==ob_ne)
   1.641 -    return (left != right);
   1.642 -  else if (oper==os_le)
   1.643 -    return *boolresult &= (char)(left <= right), right;
   1.644 -  else if (oper==os_ge)
   1.645 -    return *boolresult &= (char)(left >= right), right;
   1.646 -  else if (oper==os_lt)
   1.647 -    return *boolresult &= (char)(left < right), right;
   1.648 -  else if (oper==os_gt)
   1.649 -    return *boolresult &= (char)(left > right), right;
   1.650 -  else if (oper==os_sar)
   1.651 -    return (left >> (int)right);
   1.652 -  else if (oper==ou_sar)
   1.653 -    return ((ucell)left >> (ucell)right);
   1.654 -  else if (oper==ob_sal)
   1.655 -    return ((ucell)left << (int)right);
   1.656 -  else if (oper==ob_add)
   1.657 -    return (left + right);
   1.658 -  else if (oper==ob_sub)
   1.659 -    return (left - right);
   1.660 -  else if (oper==os_mult)
   1.661 -    return (left * right);
   1.662 -  else if (oper==os_div)
   1.663 -    return (left - truemodulus(left,right)) / right;
   1.664 -  else if (oper==os_mod)
   1.665 -    return truemodulus(left,right);
   1.666 -  else
   1.667 -    error(29);  /* invalid expression, assumed 0 (this should never occur) */
   1.668 -  return 0;
   1.669 -}
   1.670 -
   1.671 -SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
   1.672 -{
   1.673 -  int locheap=decl_heap;
   1.674 -  value lval={0};
   1.675 -
   1.676 -  if (hier14(&lval))
   1.677 -    rvalue(&lval);
   1.678 -  /* scrap any arrays left on the heap */
   1.679 -  assert(decl_heap>=locheap);
   1.680 -  modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
   1.681 -  decl_heap=locheap;
   1.682 -
   1.683 -  if (lval.ident==iCONSTEXPR && val!=NULL)    /* constant expression */
   1.684 -    *val=lval.constval;
   1.685 -  if (tag!=NULL)
   1.686 -    *tag=lval.tag;
   1.687 -  if (symptr!=NULL)
   1.688 -    *symptr=lval.sym;
   1.689 -  if (chkfuncresult)
   1.690 -    checkfunction(&lval);
   1.691 -  return lval.ident;
   1.692 -}
   1.693 -
   1.694 -SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
   1.695 -{
   1.696 -  char name[sNAMEMAX+1];
   1.697 -  cell val;
   1.698 -  char *str;
   1.699 -  int fsa,islabel;
   1.700 -
   1.701 -  assert(automaton!=NULL);
   1.702 -  assert(state!=NULL);
   1.703 -  if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL))
   1.704 -    return 0;
   1.705 -
   1.706 -  tokeninfo(&val,&str);
   1.707 -  assert(strlen(str)<sizeof name);
   1.708 -  strcpy(name,str);
   1.709 -  if (islabel || matchtoken(':')) {
   1.710 -    /* token is an automaton name, add the name and get a new token */
   1.711 -    *automaton=automaton_find(name);
   1.712 -    /* read in the state name before checking the automaton, to keep the parser
   1.713 -     * going (an "unknown automaton" error may occur when the "state" instruction
   1.714 -     * precedes any state definition)
   1.715 -     */
   1.716 -    if (!needtoken(tSYMBOL))
   1.717 -      return 0;
   1.718 -    tokeninfo(&val,&str);        /* do not copy the name yet, must check automaton first */
   1.719 -    if (*automaton==NULL) {
   1.720 -      error(86,name);            /* unknown automaton */
   1.721 -      return 0;
   1.722 -    } /* if */
   1.723 -    assert((*automaton)->index>0);
   1.724 -    assert(strlen(str)<sizeof name);
   1.725 -    strcpy(name,str);
   1.726 -  } else {
   1.727 -    *automaton=automaton_find("");
   1.728 -    assert(*automaton!=NULL);
   1.729 -    assert((*automaton)->index==0);
   1.730 -  } /* if */
   1.731 -  assert(*automaton!=NULL);
   1.732 -  fsa=(*automaton)->index;
   1.733 -
   1.734 -  assert(*automaton!=NULL);
   1.735 -  *state=state_find(name,fsa);
   1.736 -  if (*state==NULL) {
   1.737 -    char *fsaname=(*automaton)->name;
   1.738 -    if (*fsaname=='\0')
   1.739 -      fsaname="<main>";
   1.740 -    error(87,name,fsaname);   /* unknown state for automaton */
   1.741 -    return 0;
   1.742 -  } /* if */
   1.743 -
   1.744 -  return 1;
   1.745 -}
   1.746 -
   1.747 -SC_FUNC cell array_totalsize(symbol *sym)
   1.748 -{
   1.749 -  cell length;
   1.750 -
   1.751 -  assert(sym!=NULL);
   1.752 -  assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   1.753 -  length=sym->dim.array.length;
   1.754 -  if (sym->dim.array.level > 0) {
   1.755 -    cell sublength=array_totalsize(finddepend(sym));
   1.756 -    if (sublength>0)
   1.757 -      length=length+length*sublength;
   1.758 -    else
   1.759 -      length=0;
   1.760 -  } /* if */
   1.761 -  return length;
   1.762 -}
   1.763 -
   1.764 -static cell array_levelsize(symbol *sym,int level)
   1.765 -{
   1.766 -  assert(sym!=NULL);
   1.767 -  assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
   1.768 -  assert(level <= sym->dim.array.level);
   1.769 -  while (level-- > 0) {
   1.770 -    sym=finddepend(sym);
   1.771 -    assert(sym!=NULL);
   1.772 -  } /* if */
   1.773 -  return sym->dim.array.length;
   1.774 -}
   1.775 -
   1.776 -/*  hier14
   1.777 - *
   1.778 - *  Lowest hierarchy level (except for the , operator).
   1.779 - *
   1.780 - *  Global references: sc_intest        (reffered to only)
   1.781 - *                     sc_allowproccall (modified)
   1.782 - */
   1.783 -static int hier14(value *lval1)
   1.784 -{
   1.785 -  int lvalue;
   1.786 -  value lval2={0},lval3={0};
   1.787 -  void (*oper)(void);
   1.788 -  int tok,level,i;
   1.789 -  cell val;
   1.790 -  char *st;
   1.791 -  int bwcount,leftarray;
   1.792 -  cell arrayidx1[sDIMEN_MAX],arrayidx2[sDIMEN_MAX];  /* last used array indices */
   1.793 -  cell *org_arrayidx;
   1.794 -
   1.795 -  bwcount=bitwise_opercount;
   1.796 -  bitwise_opercount=0;
   1.797 -  /* initialize the index arrays with unlikely constant indices; note that
   1.798 -   * these indices will only be changed when the array is indexed with a
   1.799 -   * constant, and that negative array indices are invalid (so actually, any
   1.800 -   * negative value would do).
   1.801 -   */
   1.802 -  for (i=0; i<sDIMEN_MAX; i++)
   1.803 -    arrayidx1[i]=arrayidx2[i]=(cell)(-1L << (sizeof(cell)*8-1));
   1.804 -  org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */
   1.805 -  if (lval1->arrayidx==NULL)
   1.806 -    lval1->arrayidx=arrayidx1;
   1.807 -  lvalue=plnge1(hier13,lval1);
   1.808 -  if (lval1->ident!=iARRAYCELL && lval1->ident!=iARRAYCHAR)
   1.809 -    lval1->arrayidx=NULL;
   1.810 -  if (lval1->ident==iCONSTEXPR) /* load constant here */
   1.811 -    ldconst(lval1->constval,sPRI);
   1.812 -  tok=lex(&val,&st);
   1.813 -  switch (tok) {
   1.814 -    case taOR:
   1.815 -      oper=ob_or;
   1.816 -      break;
   1.817 -    case taXOR:
   1.818 -      oper=ob_xor;
   1.819 -      break;
   1.820 -    case taAND:
   1.821 -      oper=ob_and;
   1.822 -      break;
   1.823 -    case taADD:
   1.824 -      oper=ob_add;
   1.825 -      break;
   1.826 -    case taSUB:
   1.827 -      oper=ob_sub;
   1.828 -      break;
   1.829 -    case taMULT:
   1.830 -      oper=os_mult;
   1.831 -      break;
   1.832 -    case taDIV:
   1.833 -      oper=os_div;
   1.834 -      break;
   1.835 -    case taMOD:
   1.836 -      oper=os_mod;
   1.837 -      break;
   1.838 -    case taSHRU:
   1.839 -      oper=ou_sar;
   1.840 -      break;
   1.841 -    case taSHR:
   1.842 -      oper=os_sar;
   1.843 -      break;
   1.844 -    case taSHL:
   1.845 -      oper=ob_sal;
   1.846 -      break;
   1.847 -    case '=':           /* simple assignment */
   1.848 -      oper=NULL;
   1.849 -      if (sc_intest)
   1.850 -        error(211);     /* possibly unintended assignment */
   1.851 -      break;
   1.852 -    default:
   1.853 -      lexpush();
   1.854 -      bitwise_opercount=bwcount;
   1.855 -      lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   1.856 -      return lvalue;
   1.857 -  } /* switch */
   1.858 -
   1.859 -  /* if we get here, it was an assignment; first check a few special cases
   1.860 -   * and then the general */
   1.861 -  if (lval1->ident==iARRAYCHAR) {
   1.862 -    /* special case, assignment to packed character in a cell is permitted */
   1.863 -    lvalue=TRUE;
   1.864 -  } else if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
   1.865 -    /* array assignment is permitted too (with restrictions) */
   1.866 -    if (oper)
   1.867 -      return error(23); /* array assignment must be simple assigment */
   1.868 -    assert(lval1->sym!=NULL);
   1.869 -    if (array_totalsize(lval1->sym)==0)
   1.870 -      return error(46,lval1->sym->name);        /* unknown array size */
   1.871 -    lvalue=TRUE;
   1.872 -  } /* if */
   1.873 -
   1.874 -  /* operand on left side of assignment must be lvalue */
   1.875 -  if (!lvalue)
   1.876 -    return error(22);                   /* must be lvalue */
   1.877 -  /* may not change "constant" parameters */
   1.878 -  assert(lval1->sym!=NULL);
   1.879 -  if ((lval1->sym->usage & uCONST)!=0)
   1.880 -    return error(22);           /* assignment to const argument */
   1.881 -  sc_allowproccall=FALSE;       /* may no longer use "procedure call" syntax */
   1.882 -
   1.883 -  lval3=*lval1;         /* save symbol to enable storage of expresion result */
   1.884 -  lval1->arrayidx=org_arrayidx; /* restore array index pointer */
   1.885 -  if (lval1->ident==iARRAYCELL || lval1->ident==iARRAYCHAR
   1.886 -      || lval1->ident==iARRAY || lval1->ident==iREFARRAY)
   1.887 -  {
   1.888 -    /* if indirect fetch: save PRI (cell address) */
   1.889 -    if (oper) {
   1.890 -      pushreg(sPRI);
   1.891 -      rvalue(lval1);
   1.892 -    } /* if */
   1.893 -    lval2.arrayidx=arrayidx2;
   1.894 -    plnge2(oper,hier14,lval1,&lval2);
   1.895 -    if (lval2.ident!=iARRAYCELL && lval2.ident!=iARRAYCHAR)
   1.896 -      lval2.arrayidx=NULL;
   1.897 -    if (oper)
   1.898 -      popreg(sALT);
   1.899 -    if (!oper && lval3.arrayidx!=NULL && lval2.arrayidx!=NULL
   1.900 -        && lval3.ident==lval2.ident && lval3.sym==lval2.sym)
   1.901 -    {
   1.902 -      int same=TRUE;
   1.903 -      assert(lval2.arrayidx==arrayidx2);
   1.904 -      for (i=0; i<sDIMEN_MAX; i++)
   1.905 -        same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]);
   1.906 -        if (same)
   1.907 -          error(226,lval3.sym->name);   /* self-assignment */
   1.908 -    } /* if */
   1.909 -  } else {
   1.910 -    if (oper){
   1.911 -      rvalue(lval1);
   1.912 -      plnge2(oper,hier14,lval1,&lval2);
   1.913 -    } else {
   1.914 -      /* if direct fetch and simple assignment: no "push"
   1.915 -       * and "pop" needed -> call hier14() directly, */
   1.916 -      if (hier14(&lval2))
   1.917 -        rvalue(&lval2);         /* instead of plnge2(). */
   1.918 -      else if (lval2.ident==iVARIABLE)
   1.919 -        lval2.ident=iEXPRESSION;/* mark as "rvalue" if it is not an "lvalue" */
   1.920 -      checkfunction(&lval2);
   1.921 -      /* check whether lval2 and lval3 (old lval1) refer to the same variable */
   1.922 -      if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) {
   1.923 -        assert(lval3.sym!=NULL);
   1.924 -        error(226,lval3.sym->name);     /* self-assignment */
   1.925 -      } /* if */
   1.926 -    } /* if */
   1.927 -  } /* if */
   1.928 -  /* Array elements are sometimes considered as sub-arrays --when the
   1.929 -   * array index is an enumeration field and the enumeration size is greater
   1.930 -   * than 1. If the expression on the right side of the assignment is a cell,
   1.931 -   * or if an operation is in effect, this does not apply.
   1.932 -   */
   1.933 -  leftarray= lval3.ident==iARRAY || lval3.ident==iREFARRAY
   1.934 -             || ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   1.935 -                 && lval3.constval>1 && lval3.sym->dim.array.level==0
   1.936 -                 && !oper && (lval2.ident==iARRAY || lval2.ident==iREFARRAY));
   1.937 -  if (leftarray) {
   1.938 -    /* Left operand is an array, right operand should be an array variable
   1.939 -     * of the same size and the same dimension, an array literal (of the
   1.940 -     * same size) or a literal string. For single-dimensional arrays without
   1.941 -     * tag for the index, it is permitted to assign a smaller array into a
   1.942 -     * larger one (without warning). This is to make it easier to work with
   1.943 -     * strings.
   1.944 -     */
   1.945 -    int exactmatch=TRUE;
   1.946 -    int idxtag=0;
   1.947 -    int ltlength=(int)lval3.sym->dim.array.length;
   1.948 -    if ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
   1.949 -        && lval3.constval>0 && lval3.sym->dim.array.level==0)
   1.950 -    {
   1.951 -      ltlength=(int)lval3.constval;
   1.952 -    } /* if */
   1.953 -    if (lval2.ident!=iARRAY && lval2.ident!=iREFARRAY
   1.954 -        && (lval2.sym==NULL || lval2.constval<=0))
   1.955 -      error(33,lval3.sym->name);        /* array must be indexed */
   1.956 -    if (lval2.sym!=NULL) {
   1.957 -      if (lval2.constval==0) {
   1.958 -        val=lval2.sym->dim.array.length;/* array variable */
   1.959 -      } else {
   1.960 -        val=lval2.constval;
   1.961 -        if (lval2.sym->dim.array.level!=0)
   1.962 -          error(28,lval2.sym->name);
   1.963 -      } /* if */
   1.964 -      level=lval2.sym->dim.array.level;
   1.965 -      idxtag=lval2.sym->x.tags.index;
   1.966 -      if (level==0 && idxtag==0 && lval3.sym->x.tags.index==0)
   1.967 -        exactmatch=FALSE;
   1.968 -    } else {
   1.969 -      val=lval2.constval;               /* literal array */
   1.970 -      level=0;
   1.971 -      /* If val is negative, it means that lval2 is a literal string.
   1.972 -       * The string array size may be smaller than the destination
   1.973 -       * array, provided that the destination array does not have an
   1.974 -       * index tag.
   1.975 -       */
   1.976 -      if (val<0) {
   1.977 -        val=-val;
   1.978 -        if (lval3.sym->x.tags.index==0)
   1.979 -          exactmatch=FALSE;
   1.980 -      } /* if */
   1.981 -    } /* if */
   1.982 -    if (lval3.sym->dim.array.level!=level)
   1.983 -      return error(48); /* array dimensions must match */
   1.984 -    else if (ltlength<val || exactmatch && ltlength>val || val==0)
   1.985 -      return error(47); /* array sizes must match */
   1.986 -    else if (lval3.ident!=iARRAYCELL && !matchtag(lval3.sym->x.tags.index,idxtag,TRUE))
   1.987 -      error(229,(lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name); /* index tag mismatch */
   1.988 -    if (level>0) {
   1.989 -      /* check the sizes of all sublevels too */
   1.990 -      symbol *sym1 = lval3.sym;
   1.991 -      symbol *sym2 = lval2.sym;
   1.992 -      int i;
   1.993 -      assert(sym1!=NULL && sym2!=NULL);
   1.994 -      /* ^^^ sym2 must be valid, because only variables can be
   1.995 -       *     multi-dimensional (there are no multi-dimensional literals),
   1.996 -       *     sym1 must be valid because it must be an lvalue
   1.997 -       */
   1.998 -      assert(exactmatch);
   1.999 -      for (i=0; i<level; i++) {
  1.1000 -        sym1=finddepend(sym1);
  1.1001 -        sym2=finddepend(sym2);
  1.1002 -        assert(sym1!=NULL && sym2!=NULL);
  1.1003 -        /* ^^^ both arrays have the same dimensions (this was checked
  1.1004 -         *     earlier) so the dependend should always be found
  1.1005 -         */
  1.1006 -        if (sym1->dim.array.length!=sym2->dim.array.length)
  1.1007 -          error(47);    /* array sizes must match */
  1.1008 -        else if (!matchtag(sym1->x.tags.index,sym2->x.tags.index,TRUE))
  1.1009 -          error(229,sym2->name);  /* index tag mismatch */
  1.1010 -      } /* for */
  1.1011 -      /* get the total size in cells of the multi-dimensional array */
  1.1012 -      val=array_totalsize(lval3.sym);
  1.1013 -      assert(val>0);    /* already checked */
  1.1014 -    } /* if */
  1.1015 -  } else {
  1.1016 -    /* left operand is not an array, right operand should then not be either */
  1.1017 -    if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1.1018 -      error(6);         /* must be assigned to an array */
  1.1019 -  } /* if */
  1.1020 -  if (leftarray) {
  1.1021 -    memcopy(val*sizeof(cell));
  1.1022 -  } else {
  1.1023 -    check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag);
  1.1024 -    store(&lval3);      /* now, store the expression result */
  1.1025 -  } /* if */
  1.1026 -  if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE))
  1.1027 -    error(213);         /* tagname mismatch (if "oper", warning already given in plunge2()) */
  1.1028 -  if (lval3.sym)
  1.1029 -    markusage(lval3.sym,uWRITTEN);
  1.1030 -  sideeffect=TRUE;
  1.1031 -  bitwise_opercount=bwcount;
  1.1032 -  lval1->ident=iEXPRESSION;
  1.1033 -  return FALSE;         /* expression result is never an lvalue */
  1.1034 -}
  1.1035 -
  1.1036 -static int hier13(value *lval)
  1.1037 -{
  1.1038 -  int lvalue=plnge1(hier12,lval);
  1.1039 -  if (matchtoken('?')) {
  1.1040 -    int flab1=getlabel();
  1.1041 -    int flab2=getlabel();
  1.1042 -    value lval2={0};
  1.1043 -    int array1,array2;
  1.1044 -
  1.1045 -    if (lvalue) {
  1.1046 -      rvalue(lval);
  1.1047 -    } else if (lval->ident==iCONSTEXPR) {
  1.1048 -      ldconst(lval->constval,sPRI);
  1.1049 -      error(lval->constval ? 206 : 205);        /* redundant test */
  1.1050 -    } /* if */
  1.1051 -    jmp_eq0(flab1);             /* go to second expression if primary register==0 */
  1.1052 -    PUSHSTK_I(sc_allowtags);
  1.1053 -    sc_allowtags=FALSE;         /* do not allow tagnames here (colon is a special token) */
  1.1054 -    if (hier13(lval))
  1.1055 -      rvalue(lval);
  1.1056 -    if (lval->ident==iCONSTEXPR)        /* load constant here */
  1.1057 -      ldconst(lval->constval,sPRI);
  1.1058 -    sc_allowtags=(short)POPSTK_I();     /* restore */
  1.1059 -    jumplabel(flab2);
  1.1060 -    setlabel(flab1);
  1.1061 -    needtoken(':');
  1.1062 -    if (hier13(&lval2))
  1.1063 -      rvalue(&lval2);
  1.1064 -    if (lval2.ident==iCONSTEXPR)        /* load constant here */
  1.1065 -      ldconst(lval2.constval,sPRI);
  1.1066 -    array1= (lval->ident==iARRAY || lval->ident==iREFARRAY);
  1.1067 -    array2= (lval2.ident==iARRAY || lval2.ident==iREFARRAY);
  1.1068 -    if (array1 && !array2) {
  1.1069 -      char *ptr=(lval->sym->name!=NULL) ? lval->sym->name : "-unknown-";
  1.1070 -      error(33,ptr);            /* array must be indexed */
  1.1071 -    } else if (!array1 && array2) {
  1.1072 -      char *ptr=(lval2.sym->name!=NULL) ? lval2.sym->name : "-unknown-";
  1.1073 -      error(33,ptr);            /* array must be indexed */
  1.1074 -    } /* if */
  1.1075 -    /* ??? if both are arrays, should check dimensions */
  1.1076 -    if (!matchtag(lval->tag,lval2.tag,FALSE))
  1.1077 -      error(213);               /* tagname mismatch ('true' and 'false' expressions) */
  1.1078 -    setlabel(flab2);
  1.1079 -    if (lval->ident==iARRAY)
  1.1080 -      lval->ident=iREFARRAY;    /* iARRAY becomes iREFARRAY */
  1.1081 -    else if (lval->ident!=iREFARRAY)
  1.1082 -      lval->ident=iEXPRESSION;  /* iREFARRAY stays iREFARRAY, rest becomes iEXPRESSION */
  1.1083 -    return FALSE;               /* conditional expression is no lvalue */
  1.1084 -  } else {
  1.1085 -    return lvalue;
  1.1086 -  } /* if */
  1.1087 -}
  1.1088 -
  1.1089 -/* the order of the operators in these lists is important and must be
  1.1090 - * the same as the order of the operators in the array "op1"
  1.1091 - */
  1.1092 -static int list3[]  = {'*','/','%',0};
  1.1093 -static int list4[]  = {'+','-',0};
  1.1094 -static int list5[]  = {tSHL,tSHR,tSHRU,0};
  1.1095 -static int list6[]  = {'&',0};
  1.1096 -static int list7[]  = {'^',0};
  1.1097 -static int list8[]  = {'|',0};
  1.1098 -static int list9[]  = {tlLE,tlGE,'<','>',0};
  1.1099 -static int list10[] = {tlEQ,tlNE,0};
  1.1100 -static int list11[] = {tlAND,0};
  1.1101 -static int list12[] = {tlOR,0};
  1.1102 -
  1.1103 -static int hier12(value *lval)
  1.1104 -{
  1.1105 -  return skim(list12,jmp_ne0,1,0,hier11,lval);
  1.1106 -}
  1.1107 -
  1.1108 -static int hier11(value *lval)
  1.1109 -{
  1.1110 -  return skim(list11,jmp_eq0,0,1,hier10,lval);
  1.1111 -}
  1.1112 -
  1.1113 -static int hier10(value *lval)
  1.1114 -{ /* ==, != */
  1.1115 -  return plnge(list10,15,hier9,lval,"bool",TRUE);
  1.1116 -}                  /* ^ this variable is the starting index in the op1[]
  1.1117 -                    *   array of the operators of this hierarchy level */
  1.1118 -
  1.1119 -static int hier9(value *lval)
  1.1120 -{ /* <=, >=, <, > */
  1.1121 -  return plnge_rel(list9,11,hier8,lval);
  1.1122 -}
  1.1123 -
  1.1124 -static int hier8(value *lval)
  1.1125 -{ /* | */
  1.1126 -  return plnge(list8,10,hier7,lval,NULL,FALSE);
  1.1127 -}
  1.1128 -
  1.1129 -static int hier7(value *lval)
  1.1130 -{ /* ^ */
  1.1131 -  return plnge(list7,9,hier6,lval,NULL,FALSE);
  1.1132 -}
  1.1133 -
  1.1134 -static int hier6(value *lval)
  1.1135 -{ /* & */
  1.1136 -  return plnge(list6,8,hier5,lval,NULL,FALSE);
  1.1137 -}
  1.1138 -
  1.1139 -static int hier5(value *lval)
  1.1140 -{ /* <<, >>, >>> */
  1.1141 -  return plnge(list5,5,hier4,lval,NULL,FALSE);
  1.1142 -}
  1.1143 -
  1.1144 -static int hier4(value *lval)
  1.1145 -{ /* +, - */
  1.1146 -  return plnge(list4,3,hier3,lval,NULL,FALSE);
  1.1147 -}
  1.1148 -
  1.1149 -static int hier3(value *lval)
  1.1150 -{ /* *, /, % */
  1.1151 -  return plnge(list3,0,hier2,lval,NULL,FALSE);
  1.1152 -}
  1.1153 -
  1.1154 -static int hier2(value *lval)
  1.1155 -{
  1.1156 -  int lvalue,tok;
  1.1157 -  int tag,paranthese;
  1.1158 -  cell val;
  1.1159 -  char *st;
  1.1160 -  symbol *sym;
  1.1161 -  int saveresult;
  1.1162 -
  1.1163 -  tok=lex(&val,&st);
  1.1164 -  switch (tok) {
  1.1165 -  case tINC:                    /* ++lval */
  1.1166 -    if (!hier2(lval))
  1.1167 -      return error(22);         /* must be lvalue */
  1.1168 -    assert(lval->sym!=NULL);
  1.1169 -    if ((lval->sym->usage & uCONST)!=0)
  1.1170 -      return error(22);         /* assignment to const argument */
  1.1171 -    if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1.1172 -      inc(lval);                /* increase variable first */
  1.1173 -    rvalue(lval);               /* and read the result into PRI */
  1.1174 -    sideeffect=TRUE;
  1.1175 -    return FALSE;               /* result is no longer lvalue */
  1.1176 -  case tDEC:                    /* --lval */
  1.1177 -    if (!hier2(lval))
  1.1178 -      return error(22);         /* must be lvalue */
  1.1179 -    assert(lval->sym!=NULL);
  1.1180 -    if ((lval->sym->usage & uCONST)!=0)
  1.1181 -      return error(22);         /* assignment to const argument */
  1.1182 -    if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1.1183 -      dec(lval);                /* decrease variable first */
  1.1184 -    rvalue(lval);               /* and read the result into PRI */
  1.1185 -    sideeffect=TRUE;
  1.1186 -    return FALSE;               /* result is no longer lvalue */
  1.1187 -  case '~':                     /* ~ (one's complement) */
  1.1188 -    if (hier2(lval))
  1.1189 -      rvalue(lval);
  1.1190 -    invert();                   /* bitwise NOT */
  1.1191 -    lval->constval=~lval->constval;
  1.1192 -    return FALSE;
  1.1193 -  case '!':                     /* ! (logical negate) */
  1.1194 -    if (hier2(lval))
  1.1195 -      rvalue(lval);
  1.1196 -    if (check_userop(lneg,lval->tag,0,1,NULL,&lval->tag)) {
  1.1197 -      lval->ident=iEXPRESSION;
  1.1198 -      lval->constval=0;
  1.1199 -    } else {
  1.1200 -      lneg();                   /* 0 -> 1,  !0 -> 0 */
  1.1201 -      lval->constval=!lval->constval;
  1.1202 -      lval->tag=pc_addtag("bool");
  1.1203 -    } /* if */
  1.1204 -    return FALSE;
  1.1205 -  case '-':                     /* unary - (two's complement) */
  1.1206 -    if (hier2(lval))
  1.1207 -      rvalue(lval);
  1.1208 -    /* make a special check for a constant expression with the tag of a
  1.1209 -     * rational number, so that we can simple swap the sign of that constant.
  1.1210 -     */
  1.1211 -    if (lval->ident==iCONSTEXPR && lval->tag==sc_rationaltag && sc_rationaltag!=0) {
  1.1212 -      if (rational_digits==0) {
  1.1213 -        #if PAWN_CELL_SIZE==32
  1.1214 -          float *f = (float *)&lval->constval;
  1.1215 -        #elif PAWN_CELL_SIZE==64
  1.1216 -          double *f = (double *)&lval->constval;
  1.1217 -        #else
  1.1218 -          #error Unsupported cell size
  1.1219 -        #endif
  1.1220 -        *f= - *f; /* this modifies lval->constval */
  1.1221 -      } else {
  1.1222 -        /* the negation of a fixed point number is just an integer negation */
  1.1223 -        lval->constval=-lval->constval;
  1.1224 -      } /* if */
  1.1225 -    } else if (check_userop(neg,lval->tag,0,1,NULL,&lval->tag)) {
  1.1226 -      lval->ident=iEXPRESSION;
  1.1227 -      lval->constval=0;
  1.1228 -    } else {
  1.1229 -      neg();                    /* arithmic negation */
  1.1230 -      lval->constval=-lval->constval;
  1.1231 -    } /* if */
  1.1232 -    return FALSE;
  1.1233 -  case tLABEL:                  /* tagname override */
  1.1234 -    tag=pc_addtag(st);
  1.1235 -    lval->cmptag=tag;
  1.1236 -    lvalue=hier2(lval);
  1.1237 -    lval->tag=tag;
  1.1238 -    return lvalue;
  1.1239 -  case tDEFINED:
  1.1240 -    paranthese=0;
  1.1241 -    while (matchtoken('('))
  1.1242 -      paranthese++;
  1.1243 -    tok=lex(&val,&st);
  1.1244 -    if (tok!=tSYMBOL)
  1.1245 -      return error(20,st);      /* illegal symbol name */
  1.1246 -    sym=findloc(st);
  1.1247 -    if (sym==NULL)
  1.1248 -      sym=findglb(st,sSTATEVAR);
  1.1249 -    if (sym!=NULL && sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0)
  1.1250 -      sym=NULL;                 /* symbol is not a function, it is in the table, but not "defined" */
  1.1251 -    val= (sym!=NULL);
  1.1252 -    if (!val && find_subst(st,strlen(st))!=NULL)
  1.1253 -      val=1;
  1.1254 -    clear_value(lval);
  1.1255 -    lval->ident=iCONSTEXPR;
  1.1256 -    lval->constval= val;
  1.1257 -    lval->tag=pc_addtag("bool");
  1.1258 -    ldconst(lval->constval,sPRI);
  1.1259 -    while (paranthese--)
  1.1260 -      needtoken(')');
  1.1261 -    return FALSE;
  1.1262 -  case tSIZEOF:
  1.1263 -    paranthese=0;
  1.1264 -    while (matchtoken('('))
  1.1265 -      paranthese++;
  1.1266 -    tok=lex(&val,&st);
  1.1267 -    if (tok!=tSYMBOL)
  1.1268 -      return error(20,st);      /* illegal symbol name */
  1.1269 -    sym=findloc(st);
  1.1270 -    if (sym==NULL)
  1.1271 -      sym=findglb(st,sSTATEVAR);
  1.1272 -    if (sym==NULL)
  1.1273 -      return error(17,st);      /* undefined symbol */
  1.1274 -    if (sym->ident==iCONSTEXPR)
  1.1275 -      error(39);                /* constant symbol has no size */
  1.1276 -    else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC)
  1.1277 -      error(72);                /* "function" symbol has no size */
  1.1278 -    else if ((sym->usage & uDEFINE)==0)
  1.1279 -      return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1.1280 -    clear_value(lval);
  1.1281 -    lval->ident=iCONSTEXPR;
  1.1282 -    lval->constval=1;           /* preset */
  1.1283 -    if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1.1284 -      int level;
  1.1285 -      symbol *idxsym=NULL;
  1.1286 -      symbol *subsym=sym;
  1.1287 -      for (level=0; matchtoken('['); level++) {
  1.1288 -        idxsym=NULL;
  1.1289 -        if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1.1290 -          char *idxname;
  1.1291 -          int cmptag=subsym->x.tags.index;
  1.1292 -          tokeninfo(&val,&idxname);
  1.1293 -          if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1.1294 -            error(80,idxname);  /* unknown symbol, or non-constant */
  1.1295 -          else if (cmptag>1)
  1.1296 -            error(91,idxname);  /* ambiguous constant */
  1.1297 -        } /* if */
  1.1298 -        needtoken(']');
  1.1299 -        if (subsym!=NULL)
  1.1300 -          subsym=finddepend(subsym);
  1.1301 -      } /* for */
  1.1302 -      if (level>sym->dim.array.level+1)
  1.1303 -        error(28,sym->name);  /* invalid subscript */
  1.1304 -      else if (level==sym->dim.array.level+1)
  1.1305 -        lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1;
  1.1306 -      else
  1.1307 -        lval->constval=array_levelsize(sym,level);
  1.1308 -      if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL)
  1.1309 -        error(224,st);          /* indeterminate array size in "sizeof" expression */
  1.1310 -    } /* if */
  1.1311 -    ldconst(lval->constval,sPRI);
  1.1312 -    while (paranthese--)
  1.1313 -      needtoken(')');
  1.1314 -    return FALSE;
  1.1315 -  case tTAGOF:
  1.1316 -    paranthese=0;
  1.1317 -    while (matchtoken('('))
  1.1318 -      paranthese++;
  1.1319 -    tok=lex(&val,&st);
  1.1320 -    if (tok!=tSYMBOL && tok!=tLABEL)
  1.1321 -      return error(20,st);      /* illegal symbol name */
  1.1322 -    if (tok==tLABEL) {
  1.1323 -      constvalue *tagsym=find_constval(&tagname_tab,st,0);
  1.1324 -      tag=(int)((tagsym!=NULL) ? tagsym->value : 0);
  1.1325 -    } else {
  1.1326 -      sym=findloc(st);
  1.1327 -      if (sym==NULL)
  1.1328 -        sym=findglb(st,sSTATEVAR);
  1.1329 -      if (sym==NULL)
  1.1330 -        return error(17,st);      /* undefined symbol */
  1.1331 -      if ((sym->usage & uDEFINE)==0)
  1.1332 -        return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
  1.1333 -      tag=sym->tag;
  1.1334 -    } /* if */
  1.1335 -    if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1.1336 -      int level;
  1.1337 -      symbol *idxsym=NULL;
  1.1338 -      symbol *subsym=sym;
  1.1339 -      for (level=0; matchtoken('['); level++) {
  1.1340 -        idxsym=NULL;
  1.1341 -        if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
  1.1342 -          char *idxname;
  1.1343 -          int cmptag=subsym->x.tags.index;
  1.1344 -          tokeninfo(&val,&idxname);
  1.1345 -          if ((idxsym=findconst(idxname,&cmptag))==NULL)
  1.1346 -            error(80,idxname);  /* unknown symbol, or non-constant */
  1.1347 -          else if (cmptag>1)
  1.1348 -            error(91,idxname);  /* ambiguous constant */
  1.1349 -        } /* if */
  1.1350 -        needtoken(']');
  1.1351 -        if (subsym!=NULL)
  1.1352 -          subsym=finddepend(subsym);
  1.1353 -      } /* for */
  1.1354 -      if (level>sym->dim.array.level+1)
  1.1355 -        error(28,sym->name);  /* invalid subscript */
  1.1356 -      else if (level==sym->dim.array.level+1 && idxsym!=NULL)
  1.1357 -        tag= idxsym->x.tags.index;
  1.1358 -    } /* if */
  1.1359 -    exporttag(tag);
  1.1360 -    clear_value(lval);
  1.1361 -    lval->ident=iCONSTEXPR;
  1.1362 -    lval->constval=tag | PUBLICTAG;
  1.1363 -    ldconst(lval->constval,sPRI);
  1.1364 -    while (paranthese--)
  1.1365 -      needtoken(')');
  1.1366 -    return FALSE;
  1.1367 -  case tSTATE: {
  1.1368 -    constvalue *automaton;
  1.1369 -    constvalue *state;
  1.1370 -    if (sc_getstateid(&automaton,&state)) {
  1.1371 -      assert(automaton!=NULL);
  1.1372 -      assert(automaton->index==0 && automaton->name[0]=='\0' || automaton->index>0);
  1.1373 -      loadreg(automaton->value,sALT);
  1.1374 -      assert(state!=NULL);
  1.1375 -      ldconst(state->value,sPRI);
  1.1376 -      ob_eq();
  1.1377 -      clear_value(lval);
  1.1378 -      lval->ident=iEXPRESSION;
  1.1379 -      lval->tag=pc_addtag("bool");
  1.1380 -    } /* if */
  1.1381 -    return FALSE;
  1.1382 -  } /* case */
  1.1383 -  default:
  1.1384 -    lexpush();
  1.1385 -    lvalue=hier1(lval);
  1.1386 -    /* check for postfix operators */
  1.1387 -    if (matchtoken(';')) {
  1.1388 -      /* Found a ';', do not look further for postfix operators */
  1.1389 -      lexpush();                /* push ';' back after successful match */
  1.1390 -      return lvalue;
  1.1391 -    } else if (matchtoken(tTERM)) {
  1.1392 -      /* Found a newline that ends a statement (this is the case when
  1.1393 -       * semicolons are optional). Note that an explicit semicolon was
  1.1394 -       * handled above. This case is similar, except that the token must
  1.1395 -       * not be pushed back.
  1.1396 -       */
  1.1397 -      return lvalue;
  1.1398 -    } else {
  1.1399 -      tok=lex(&val,&st);
  1.1400 -      switch (tok) {
  1.1401 -      case tINC:                /* lval++ */
  1.1402 -        if (!lvalue)
  1.1403 -          return error(22);     /* must be lvalue */
  1.1404 -        assert(lval->sym!=NULL);
  1.1405 -        if ((lval->sym->usage & uCONST)!=0)
  1.1406 -          return error(22);     /* assignment to const argument */
  1.1407 -        /* on incrementing array cells, the address in PRI must be saved for
  1.1408 -         * incremening the value, whereas the current value must be in PRI
  1.1409 -         * on exit.
  1.1410 -         */
  1.1411 -        saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1.1412 -        if (saveresult)
  1.1413 -          pushreg(sPRI);        /* save address in PRI */
  1.1414 -        rvalue(lval);           /* read current value into PRI */
  1.1415 -        if (saveresult)
  1.1416 -          swap1();              /* save PRI on the stack, restore address in PRI */
  1.1417 -        if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
  1.1418 -          inc(lval);            /* increase variable afterwards */
  1.1419 -        if (saveresult)
  1.1420 -          popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1.1421 -        sideeffect=TRUE;
  1.1422 -        return FALSE;           /* result is no longer lvalue */
  1.1423 -      case tDEC:                /* lval-- */
  1.1424 -        if (!lvalue)
  1.1425 -          return error(22);     /* must be lvalue */
  1.1426 -        assert(lval->sym!=NULL);
  1.1427 -        if ((lval->sym->usage & uCONST)!=0)
  1.1428 -          return error(22);     /* assignment to const argument */
  1.1429 -        saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
  1.1430 -        if (saveresult)
  1.1431 -          pushreg(sPRI);        /* save address in PRI */
  1.1432 -        rvalue(lval);           /* read current value into PRI */
  1.1433 -        if (saveresult)
  1.1434 -          swap1();              /* save PRI on the stack, restore address in PRI */
  1.1435 -        if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
  1.1436 -          dec(lval);            /* decrease variable afterwards */
  1.1437 -        if (saveresult)
  1.1438 -          popreg(sPRI);         /* restore PRI (result of rvalue()) */
  1.1439 -        sideeffect=TRUE;
  1.1440 -        return FALSE;
  1.1441 -      case tCHAR:               /* char (compute required # of cells */
  1.1442 -        if (lval->ident==iCONSTEXPR) {
  1.1443 -          lval->constval *= sCHARBITS/8;  /* from char to bytes */
  1.1444 -          lval->constval = (lval->constval + sizeof(cell)-1) / sizeof(cell);
  1.1445 -        } else {
  1.1446 -          if (lvalue)
  1.1447 -            rvalue(lval);       /* fetch value if not already in PRI */
  1.1448 -          char2addr();          /* from characters to bytes */
  1.1449 -          addconst(sizeof(cell)-1);     /* make sure the value is rounded up */
  1.1450 -          addr2cell();          /* truncate to number of cells */
  1.1451 -        } /* if */
  1.1452 -        return FALSE;
  1.1453 -      default:
  1.1454 -        lexpush();
  1.1455 -        return lvalue;
  1.1456 -      } /* switch */
  1.1457 -    } /* if */
  1.1458 -  } /* switch */
  1.1459 -}
  1.1460 -
  1.1461 -/*  hier1
  1.1462 - *
  1.1463 - *  The highest hierarchy level: it looks for pointer and array indices
  1.1464 - *  and function calls.
  1.1465 - *  Generates code to fetch a pointer value if it is indexed and code to
  1.1466 - *  add to the pointer value or the array address (the address is already
  1.1467 - *  read at primary()). It also generates code to fetch a function address
  1.1468 - *  if that hasn't already been done at primary() (check lval[4]) and calls
  1.1469 - *  callfunction() to call the function.
  1.1470 - */
  1.1471 -static int hier1(value *lval1)
  1.1472 -{
  1.1473 -  int lvalue,index,tok,symtok;
  1.1474 -  cell val,cidx;
  1.1475 -  value lval2={0};
  1.1476 -  char *st;
  1.1477 -  char close;
  1.1478 -  symbol *sym;
  1.1479 -  symbol dummysymbol,*cursym;   /* for changing the index tags in case of enumerated pseudo-arrays */
  1.1480 -
  1.1481 -  lvalue=primary(lval1);
  1.1482 -  symtok=tokeninfo(&val,&st);   /* get token read by primary() */
  1.1483 -  cursym=lval1->sym;
  1.1484 -restart:
  1.1485 -  sym=cursym;
  1.1486 -  if (matchtoken('[') || matchtoken('{') || matchtoken('(')) {
  1.1487 -    tok=tokeninfo(&val,&st);    /* get token read by matchtoken() */
  1.1488 -    if (sym==NULL && symtok!=tSYMBOL) {
  1.1489 -      /* we do not have a valid symbol and we appear not to have read a valid
  1.1490 -       * symbol name (so it is unlikely that we would have read a name of an
  1.1491 -       * undefined symbol) */
  1.1492 -      error(29);                /* expression error, assumed 0 */
  1.1493 -      lexpush();                /* analyse '(', '{' or '[' again later */
  1.1494 -      return FALSE;
  1.1495 -    } /* if */
  1.1496 -    if (tok=='[' || tok=='{') { /* subscript */
  1.1497 -      close = (char)((tok=='[') ? ']' : '}');
  1.1498 -      if (sym==NULL) {  /* sym==NULL if lval is a constant or a literal */
  1.1499 -        error(28,"<no variable>");  /* cannot subscript */
  1.1500 -        needtoken(close);
  1.1501 -        return FALSE;
  1.1502 -      } else if (sym->ident!=iARRAY && sym->ident!=iREFARRAY){
  1.1503 -        error(28,sym->name);    /* cannot subscript, variable is not an array */
  1.1504 -        needtoken(close);
  1.1505 -        return FALSE;
  1.1506 -      } else if (sym->dim.array.level>0 && close!=']') {
  1.1507 -        error(51);      /* invalid subscript, must use [ ] */
  1.1508 -        needtoken(close);
  1.1509 -        return FALSE;
  1.1510 -      } /* if */
  1.1511 -      /* set the tag to match (enumeration fields as indices) */
  1.1512 -      lval2.cmptag=sym->x.tags.index;
  1.1513 -      stgget(&index,&cidx);     /* mark position in code generator */
  1.1514 -      pushreg(sPRI);            /* save base address of the array */
  1.1515 -      if (hier14(&lval2))       /* create expression for the array index */
  1.1516 -        rvalue(&lval2);
  1.1517 -      if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
  1.1518 -        error(33,lval2.sym->name);      /* array must be indexed */
  1.1519 -      needtoken(close);
  1.1520 -      if (!matchtag(sym->x.tags.index,lval2.tag,TRUE))
  1.1521 -        error(213);
  1.1522 -      if (lval2.ident==iCONSTEXPR) {    /* constant expression */
  1.1523 -        stgdel(index,cidx);             /* scratch generated code */
  1.1524 -        if (lval1->arrayidx!=NULL) {    /* keep constant index, for checking */
  1.1525 -          assert(sym->dim.array.level>=0 && sym->dim.array.level<sDIMEN_MAX);
  1.1526 -          lval1->arrayidx[sym->dim.array.level]=lval2.constval;
  1.1527 -        } /* if */
  1.1528 -        if (close==']') {
  1.1529 -          /* normal array index */
  1.1530 -          if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval)
  1.1531 -            error(32,sym->name);        /* array index out of bounds */
  1.1532 -          if (lval2.constval!=0) {
  1.1533 -            /* don't add offsets for zero subscripts */
  1.1534 -            #if PAWN_CELL_SIZE==16
  1.1535 -              ldconst(lval2.constval<<1,sALT);
  1.1536 -            #elif PAWN_CELL_SIZE==32
  1.1537 -              ldconst(lval2.constval<<2,sALT);
  1.1538 -            #elif PAWN_CELL_SIZE==64
  1.1539 -              ldconst(lval2.constval<<3,sALT);
  1.1540 -            #else
  1.1541 -              #error Unsupported cell size
  1.1542 -            #endif
  1.1543 -            ob_add();
  1.1544 -          } /* if */
  1.1545 -        } else {
  1.1546 -          /* character index */
  1.1547 -          if (lval2.constval<0 || sym->dim.array.length!=0
  1.1548 -              && sym->dim.array.length*((8*sizeof(cell))/sCHARBITS)<=(ucell)lval2.constval)
  1.1549 -            error(32,sym->name);        /* array index out of bounds */
  1.1550 -          if (lval2.constval!=0) {
  1.1551 -            /* don't add offsets for zero subscripts */
  1.1552 -            #if sCHARBITS==16
  1.1553 -              ldconst(lval2.constval<<1,sALT);/* 16-bit character */
  1.1554 -            #else
  1.1555 -              ldconst(lval2.constval,sALT);   /* 8-bit character */
  1.1556 -            #endif
  1.1557 -            ob_add();
  1.1558 -          } /* if */
  1.1559 -          charalign();                  /* align character index into array */
  1.1560 -        } /* if */
  1.1561 -        /* if the array index is a field from an enumeration, get the tag name
  1.1562 -         * from the field and save the size of the field too.
  1.1563 -         */
  1.1564 -        assert(lval2.sym==NULL || lval2.sym->dim.array.level==0);
  1.1565 -        if (lval2.sym!=NULL && lval2.sym->dim.array.length>0 && sym->dim.array.level==0) {
  1.1566 -          lval1->tag=lval2.sym->x.tags.index;
  1.1567 -          lval1->constval=lval2.sym->dim.array.length;
  1.1568 -        } /* if */
  1.1569 -      } else {
  1.1570 -        /* array index is not constant */
  1.1571 -        lval1->arrayidx=NULL;           /* reset, so won't be checked */
  1.1572 -        if (close==']') {
  1.1573 -          if (sym->dim.array.length!=0)
  1.1574 -            ffbounds(sym->dim.array.length-1);  /* run time check for array bounds */
  1.1575 -          cell2addr();  /* normal array index */
  1.1576 -        } else {
  1.1577 -          if (sym->dim.array.length!=0)
  1.1578 -            ffbounds(sym->dim.array.length*(32/sCHARBITS)-1);
  1.1579 -          char2addr();  /* character array index */
  1.1580 -        } /* if */
  1.1581 -        popreg(sALT);
  1.1582 -        ob_add();       /* base address was popped into secondary register */
  1.1583 -        if (close!=']')
  1.1584 -          charalign();  /* align character index into array */
  1.1585 -      } /* if */
  1.1586 -      /* the indexed item may be another array (multi-dimensional arrays) */
  1.1587 -      assert(cursym==sym && sym!=NULL); /* should still be set */
  1.1588 -      if (sym->dim.array.level>0) {
  1.1589 -        assert(close==']');     /* checked earlier */
  1.1590 -        assert(cursym==lval1->sym);
  1.1591 -        /* read the offset to the subarray and add it to the current address */
  1.1592 -        lval1->ident=iARRAYCELL;
  1.1593 -        pushreg(sPRI);          /* the optimizer makes this to a MOVE.alt */
  1.1594 -        rvalue(lval1);
  1.1595 -        popreg(sALT);
  1.1596 -        ob_add();
  1.1597 -        /* adjust the "value" structure and find the referenced array */
  1.1598 -        lval1->ident=iREFARRAY;
  1.1599 -        lval1->sym=finddepend(sym);
  1.1600 -        assert(lval1->sym!=NULL);
  1.1601 -        assert(lval1->sym->dim.array.level==sym->dim.array.level-1);
  1.1602 -        cursym=lval1->sym;
  1.1603 -        /* try to parse subsequent array indices */
  1.1604 -        lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1.1605 -        goto restart;
  1.1606 -      } /* if */
  1.1607 -      assert(sym->dim.array.level==0);
  1.1608 -      /* set type to fetch... INDIRECTLY */
  1.1609 -      lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR);
  1.1610 -      /* if the array index is a field from an enumeration, get the tag name
  1.1611 -       * from the field and save the size of the field too. Otherwise, the
  1.1612 -       * tag is the one from the array symbol.
  1.1613 -       */
  1.1614 -      if (lval2.ident==iCONSTEXPR && lval2.sym!=NULL
  1.1615 -          && lval2.sym->dim.array.length>0 && sym->dim.array.level==0)
  1.1616 -      {
  1.1617 -        lval1->tag=lval2.sym->x.tags.index;
  1.1618 -        lval1->constval=lval2.sym->dim.array.length;
  1.1619 -        if (lval2.tag==sym->x.tags.index && lval1->constval>1 && matchtoken('[')) {
  1.1620 -          /* an array indexed with an enumeration field may be considered a sub-array */
  1.1621 -          lexpush();
  1.1622 -          lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
  1.1623 -          lval1->ident=iREFARRAY;
  1.1624 -          /* initialize a dummy symbol, which is a copy of the current symbol,
  1.1625 -           * but with an adjusted index tag
  1.1626 -           */
  1.1627 -          assert(sym!=NULL);
  1.1628 -          dummysymbol=*sym;
  1.1629 -          /* get the tag of the root of the enumeration */
  1.1630 -          assert(lval2.sym!=NULL);
  1.1631 -          dummysymbol.x.tags.index=lval2.sym->x.tags.field;
  1.1632 -          dummysymbol.dim.array.length=lval2.sym->dim.array.length;
  1.1633 -          cursym=&dummysymbol;
  1.1634 -          /* recurse */
  1.1635 -          goto restart;
  1.1636 -        } /* if */
  1.1637 -      } else {
  1.1638 -        assert(sym!=NULL);
  1.1639 -        if (cursym!=&dummysymbol)
  1.1640 -          lval1->tag=sym->tag;
  1.1641 -        lval1->constval=0;
  1.1642 -      } /* if */
  1.1643 -      /* a cell in an array is an lvalue, a character in an array is not
  1.1644 -       * always a *valid* lvalue */
  1.1645 -      return TRUE;
  1.1646 -    } else {            /* tok=='(' -> function(...) */
  1.1647 -      assert(tok=='(');
  1.1648 -      if (sym==NULL
  1.1649 -          || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
  1.1650 -      {
  1.1651 -        if (sym==NULL && sc_status==statFIRST) {
  1.1652 -          /* could be a "use before declaration"; in that case, create a stub
  1.1653 -           * function so that the usage can be marked.
  1.1654 -           */
  1.1655 -          sym=fetchfunc(lastsymbol,0);
  1.1656 -          if (sym==NULL)
  1.1657 -            error(103); /* insufficient memory */
  1.1658 -          markusage(sym,uREAD);
  1.1659 -        } else {
  1.1660 -          return error(12);           /* invalid function call */
  1.1661 -        } /* if */
  1.1662 -      } else if ((sym->usage & uMISSING)!=0) {
  1.1663 -        char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
  1.1664 -        funcdisplayname(symname,sym->name);
  1.1665 -        error(4,symname);             /* function not defined */
  1.1666 -      } /* if */
  1.1667 -      callfunction(sym,lval1,TRUE);
  1.1668 -      return FALSE;             /* result of function call is no lvalue */
  1.1669 -    } /* if */
  1.1670 -  } /* if */
  1.1671 -  if (sym!=NULL && lval1->ident==iFUNCTN) {
  1.1672 -    assert(sym->ident==iFUNCTN);
  1.1673 -    if (sc_allowproccall) {
  1.1674 -      callfunction(sym,lval1,FALSE);
  1.1675 -    } else {
  1.1676 -      int n=-1,iter=0;
  1.1677 -      for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  1.1678 -        if (sym->ident==iFUNCTN
  1.1679 -            && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
  1.1680 -        {
  1.1681 -          assert(sym->vclass==sGLOBAL);
  1.1682 -          if (strcmp(sym->name, lval1->sym->name)==0) {
  1.1683 -            n = iter;
  1.1684 -            break;
  1.1685 -          }
  1.1686 -          iter++;
  1.1687 -        }
  1.1688 -      }
  1.1689 -      if (n!=-1) {
  1.1690 -        lval1->sym=NULL;
  1.1691 -        lval1->ident=iCONSTEXPR;
  1.1692 -        lval1->constval=n;
  1.1693 -        lval1->tag=pc_addtag("Function");
  1.1694 -      } else {
  1.1695 -        error(76);                /* invalid function call, or syntax error */
  1.1696 -      } /* if */
  1.1697 -      return FALSE;
  1.1698 -    }
  1.1699 -  } /* if */
  1.1700 -  return lvalue;
  1.1701 -}
  1.1702 -
  1.1703 -/*  primary
  1.1704 - *
  1.1705 - *  Returns 1 if the operand is an lvalue (everything except arrays, functions
  1.1706 - *  constants and -of course- errors).
  1.1707 - *  Generates code to fetch the address of arrays. Code for constants is
  1.1708 - *  already generated by constant().
  1.1709 - *  This routine first clears the entire lval array (all fields are set to 0).
  1.1710 - *
  1.1711 - *  Global references: sc_intest  (may be altered, but restored upon termination)
  1.1712 - */
  1.1713 -static int primary(value *lval)
  1.1714 -{
  1.1715 -  char *st;
  1.1716 -  int lvalue,tok;
  1.1717 -  cell val;
  1.1718 -  symbol *sym;
  1.1719 -
  1.1720 -  if (matchtoken('(')){         /* sub-expression - (expression,...) */
  1.1721 -    PUSHSTK_I(sc_intest);
  1.1722 -    PUSHSTK_I(sc_allowtags);
  1.1723 -
  1.1724 -    sc_intest=FALSE;            /* no longer in "test" expression */
  1.1725 -    sc_allowtags=TRUE;          /* allow tagnames to be used in parenthesized expressions */
  1.1726 -    sc_allowproccall=FALSE;
  1.1727 -    do
  1.1728 -      lvalue=hier14(lval);
  1.1729 -    while (matchtoken(','));
  1.1730 -    needtoken(')');
  1.1731 -    lexclr(FALSE);              /* clear lex() push-back, it should have been
  1.1732 -                                 * cleared already by needtoken() */
  1.1733 -    sc_allowtags=(short)POPSTK_I();
  1.1734 -    sc_intest=(short)POPSTK_I();
  1.1735 -    return lvalue;
  1.1736 -  } /* if */
  1.1737 -
  1.1738 -  clear_value(lval);    /* clear lval */
  1.1739 -  tok=lex(&val,&st);
  1.1740 -  if (tok==tSYMBOL) {
  1.1741 -    /* lastsymbol is char[sNAMEMAX+1], lex() should have truncated any symbol
  1.1742 -     * to sNAMEMAX significant characters */
  1.1743 -    assert(strlen(st)<sizeof lastsymbol);
  1.1744 -    strcpy(lastsymbol,st);
  1.1745 -  } /* if */
  1.1746 -  if (tok==tSYMBOL && !findconst(st,NULL)) {
  1.1747 -    /* first look for a local variable */
  1.1748 -    if ((sym=findloc(st))!=0) {
  1.1749 -      if (sym->ident==iLABEL) {
  1.1750 -        error(29);          /* expression error, assumed 0 */
  1.1751 -        ldconst(0,sPRI);    /* load 0 */
  1.1752 -        return FALSE;       /* return 0 for labels (expression error) */
  1.1753 -      } /* if */
  1.1754 -      lval->sym=sym;
  1.1755 -      lval->ident=sym->ident;
  1.1756 -      lval->tag=sym->tag;
  1.1757 -      if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1.1758 -        address(sym,sPRI);  /* get starting address in primary register */
  1.1759 -        return FALSE;       /* return 0 for array (not lvalue) */
  1.1760 -      } else {
  1.1761 -        return TRUE;        /* return 1 if lvalue (not label or array) */
  1.1762 -      } /* if */
  1.1763 -    } /* if */
  1.1764 -    /* now try a global variable */
  1.1765 -    if ((sym=findglb(st,sSTATEVAR))!=0) {
  1.1766 -      if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
  1.1767 -        /* if the function is only in the table because it was inserted as a
  1.1768 -         * stub in the first pass (i.e. it was "used" but never declared or
  1.1769 -         * implemented, issue an error
  1.1770 -         */
  1.1771 -        if ((sym->usage & uPROTOTYPED)==0)
  1.1772 -          error(17,st);
  1.1773 -      } else {
  1.1774 -        if ((sym->usage & uDEFINE)==0)
  1.1775 -          error(17,st);
  1.1776 -        lval->sym=sym;
  1.1777 -        lval->ident=sym->ident;
  1.1778 -        lval->tag=sym->tag;
  1.1779 -        if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  1.1780 -          address(sym,sPRI);    /* get starting address in primary register */
  1.1781 -          return FALSE;         /* return 0 for array (not lvalue) */
  1.1782 -        } else {
  1.1783 -          return TRUE;          /* return 1 if lvalue (not function or array) */
  1.1784 -        } /* if */
  1.1785 -      } /* if */
  1.1786 -    } else {
  1.1787 -      if (!sc_allowproccall)
  1.1788 -        return error(17,st);    /* undefined symbol */
  1.1789 -      /* an unknown symbol, but used in a way compatible with the "procedure
  1.1790 -       * call" syntax. So assume that the symbol refers to a function.
  1.1791 -       */
  1.1792 -      assert(sc_status==statFIRST);
  1.1793 -      sym=fetchfunc(st,0);
  1.1794 -      if (sym==NULL)
  1.1795 -        error(103);     /* insufficient memory */
  1.1796 -    } /* if */
  1.1797 -    assert(sym!=NULL);
  1.1798 -    assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
  1.1799 -    lval->sym=sym;
  1.1800 -    lval->ident=sym->ident;
  1.1801 -    lval->tag=sym->tag;
  1.1802 -    return FALSE;       /* return 0 for function (not an lvalue) */
  1.1803 -  } /* if */
  1.1804 -  lexpush();            /* push the token, it is analyzed by constant() */
  1.1805 -  if (constant(lval)==0) {
  1.1806 -    error(29);          /* expression error, assumed 0 */
  1.1807 -    ldconst(0,sPRI);    /* load 0 */
  1.1808 -  } /* if */
  1.1809 -  return FALSE;         /* return 0 for constants (or errors) */
  1.1810 -}
  1.1811 -
  1.1812 -static void clear_value(value *lval)
  1.1813 -{
  1.1814 -  lval->sym=NULL;
  1.1815 -  lval->constval=0L;
  1.1816 -  lval->tag=0;
  1.1817 -  lval->ident=0;
  1.1818 -  lval->boolresult=FALSE;
  1.1819 -  /* do not clear lval->arrayidx, it is preset in hier14() */
  1.1820 -  /* do not clear lval->cmptag */
  1.1821 -}
  1.1822 -
  1.1823 -static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int fconst)
  1.1824 -{
  1.1825 -  /* The routine must copy the default array data onto the heap, as to avoid
  1.1826 -   * that a function can change the default value. An optimization is that
  1.1827 -   * the default array data is "dumped" into the data segment only once (on the
  1.1828 -   * first use).
  1.1829 -   */
  1.1830 -  assert(string!=NULL);
  1.1831 -  assert(size>0);
  1.1832 -  /* check whether to dump the default array */
  1.1833 -  assert(dataaddr!=NULL);
  1.1834 -  if (sc_status==statWRITE && *dataaddr<0) {
  1.1835 -    int i;
  1.1836 -    *dataaddr=(litidx+glb_declared)*sizeof(cell);
  1.1837 -    for (i=0; i<size; i++)
  1.1838 -      litadd(*string++);
  1.1839 -  } /* if */
  1.1840 -
  1.1841 -  /* if the function is known not to modify the array (meaning that it also
  1.1842 -   * does not modify the default value), directly pass the address of the
  1.1843 -   * array in the data segment.
  1.1844 -   */
  1.1845 -  if (fconst) {
  1.1846 -    ldconst(*dataaddr,sPRI);
  1.1847 -  } else {
  1.1848 -    /* Generate the code:
  1.1849 -     *  CONST.pri dataaddr                ;address of the default array data
  1.1850 -     *  HEAP      array_sz*sizeof(cell)   ;heap address in ALT
  1.1851 -     *  MOVS      size*sizeof(cell)       ;copy data from PRI to ALT
  1.1852 -     *  MOVE.PRI                          ;PRI = address on the heap
  1.1853 -     */
  1.1854 -    ldconst(*dataaddr,sPRI);
  1.1855 -    /* "array_sz" is the size of the argument (the value between the brackets
  1.1856 -     * in the declaration), "size" is the size of the default array data.
  1.1857 -     */
  1.1858 -    assert(array_sz>=size);
  1.1859 -    modheap((int)array_sz*sizeof(cell));
  1.1860 -    /* ??? should perhaps fill with zeros first */
  1.1861 -    memcopy(size*sizeof(cell));
  1.1862 -    moveto1();
  1.1863 -  } /* if */
  1.1864 -}
  1.1865 -
  1.1866 -static int findnamedarg(arginfo *arg,char *name)
  1.1867 -{
  1.1868 -  int i;
  1.1869 -
  1.1870 -  for (i=0; arg[i].ident!=0 && arg[i].ident!=iVARARGS; i++)
  1.1871 -    if (strcmp(arg[i].name,name)==0)
  1.1872 -      return i;
  1.1873 -  return -1;
  1.1874 -}
  1.1875 -
  1.1876 -static int checktag(int tags[],int numtags,int exprtag)
  1.1877 -{
  1.1878 -  int i;
  1.1879 -
  1.1880 -  assert(tags!=0);
  1.1881 -  assert(numtags>0);
  1.1882 -  for (i=0; i<numtags; i++)
  1.1883 -    if (matchtag(tags[i],exprtag,TRUE))
  1.1884 -      return TRUE;    /* matching tag */
  1.1885 -  return FALSE;       /* no tag matched */
  1.1886 -}
  1.1887 -
  1.1888 -enum {
  1.1889 -  ARG_UNHANDLED,
  1.1890 -  ARG_IGNORED,
  1.1891 -  ARG_DONE,
  1.1892 -};
  1.1893 -
  1.1894 -/*  callfunction
  1.1895 - *
  1.1896 - *  Generates code to call a function. This routine handles default arguments
  1.1897 - *  and positional as well as named parameters.
  1.1898 - */
  1.1899 -static void callfunction(symbol *sym,value *lval_result,int matchparanthesis)
  1.1900 -{
  1.1901 -static long nest_stkusage=0L;
  1.1902 -static int nesting=0;
  1.1903 -  int locheap;
  1.1904 -  int close,lvalue;
  1.1905 -  int argpos;       /* index in the output stream (argpos==nargs if positional parameters) */
  1.1906 -  int argidx=0;     /* index in "arginfo" list */
  1.1907 -  int nargs=0;      /* number of arguments */
  1.1908 -  int heapalloc=0;
  1.1909 -  int namedparams=FALSE;
  1.1910 -  value lval = {0};
  1.1911 -  arginfo *arg;
  1.1912 -  char arglist[sMAXARGS];
  1.1913 -  constvalue arrayszlst = { NULL, "", 0, 0};/* array size list starts empty */
  1.1914 -  constvalue taglst = { NULL, "", 0, 0};    /* tag list starts empty */
  1.1915 -  symbol *symret;
  1.1916 -  cell lexval;
  1.1917 -  char *lexstr;
  1.1918 -
  1.1919 -  assert(sym!=NULL);
  1.1920 -  lval_result->ident=iEXPRESSION; /* preset, may be changed later */
  1.1921 -  lval_result->constval=0;
  1.1922 -  lval_result->tag=sym->tag;
  1.1923 -  /* check whether this is a function that returns an array */
  1.1924 -  symret=finddepend(sym);
  1.1925 -  assert(symret==NULL || symret->ident==iREFARRAY);
  1.1926 -  if (symret!=NULL) {
  1.1927 -    int retsize;
  1.1928 -    /* allocate space on the heap for the array, and pass the pointer to the
  1.1929 -     * reserved memory block as a hidden parameter
  1.1930 -     */
  1.1931 -    retsize=(int)array_totalsize(symret);
  1.1932 -    assert(retsize>0);
  1.1933 -    modheap(retsize*sizeof(cell));/* address is in ALT */
  1.1934 -    pushreg(sALT);                /* pass ALT as the last (hidden) parameter */
  1.1935 -    decl_heap+=retsize;
  1.1936 -    /* also mark the ident of the result as "array" */
  1.1937 -    lval_result->ident=iREFARRAY;
  1.1938 -    lval_result->sym=symret;
  1.1939 -  } /* if */
  1.1940 -  locheap=decl_heap;
  1.1941 -
  1.1942 -  nesting++;
  1.1943 -  assert(nest_stkusage>=0);
  1.1944 -  #if !defined NDEBUG
  1.1945 -    if (nesting==1)
  1.1946 -      assert(nest_stkusage==0);
  1.1947 -  #endif
  1.1948 -  sc_allowproccall=FALSE;       /* parameters may not use procedure call syntax */
  1.1949 -
  1.1950 -  if ((sym->flags & flgDEPRICATED)!=0) {
  1.1951 -    char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
  1.1952 -    error(234,sym->name,ptr);   /* depricated (probably a native function) */
  1.1953 -  } /* if */
  1.1954 -
  1.1955 -  /* run through the arguments */
  1.1956 -  arg=sym->dim.arglist;
  1.1957 -  assert(arg!=NULL);
  1.1958 -  stgmark(sSTARTREORDER);
  1.1959 -  memset(arglist,ARG_UNHANDLED,sizeof arglist);
  1.1960 -  if (matchparanthesis) {
  1.1961 -    /* Opening brace was already parsed, if closing brace follows, this
  1.1962 -     * call passes no parameters.
  1.1963 -     */
  1.1964 -    close=matchtoken(')');
  1.1965 -  } else {
  1.1966 -    /* When we find an end of line here, it may be a function call passing
  1.1967 -     * no parameters, or it may be that the first parameter is on a line
  1.1968 -     * below. But as a parameter can be anything, this is difficult to check.
  1.1969 -     * The only simple check that we have is the use of "named parameters".
  1.1970 -     */
  1.1971 -    close=matchtoken(tTERM);
  1.1972 -    if (close) {
  1.1973 -      close=!matchtoken('.');
  1.1974 -      if (!close)
  1.1975 -        lexpush();                /* reset the '.' */
  1.1976 -    } /* if */
  1.1977 -  } /* if */
  1.1978 -  if (!close) {
  1.1979 -    do {
  1.1980 -      if (matchtoken('.')) {
  1.1981 -        namedparams=TRUE;
  1.1982 -        if (needtoken(tSYMBOL))
  1.1983 -          tokeninfo(&lexval,&lexstr);
  1.1984 -        else
  1.1985 -          lexstr="";
  1.1986 -        argpos=findnamedarg(arg,lexstr);
  1.1987 -        if (argpos<0) {
  1.1988 -          error(17,lexstr);       /* undefined symbol */
  1.1989 -          break;                  /* exit loop, argpos is invalid */
  1.1990 -        } /* if */
  1.1991 -        needtoken('=');
  1.1992 -        argidx=argpos;
  1.1993 -      } else {
  1.1994 -        if (namedparams)
  1.1995 -          error(44);   /* positional parameters must precede named parameters */
  1.1996 -        argpos=nargs;
  1.1997 -      } /* if */
  1.1998 -      /* the number of arguments this was already checked at the declaration
  1.1999 -       * of the function; check it again for functions with a variable
  1.2000 -       * argument list
  1.2001 -       */
  1.2002 -      if (argpos>=sMAXARGS)
  1.2003 -        error(45);                /* too many function arguments */
  1.2004 -      stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */
  1.2005 -      if (arglist[argpos]!=ARG_UNHANDLED)
  1.2006 -        error(58);                /* argument already set */
  1.2007 -      if (matchtoken('_')) {
  1.2008 -        arglist[argpos]=ARG_IGNORED;  /* flag argument as "present, but ignored" */
  1.2009 -        if (arg[argidx].ident==0 || arg[argidx].ident==iVARARGS) {
  1.2010 -          error(92);             /* argument count mismatch */
  1.2011 -        } else if (!arg[argidx].hasdefault) {
  1.2012 -          error(34,nargs+1);      /* argument has no default value */
  1.2013 -        } /* if */
  1.2014 -        if (arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS)
  1.2015 -          argidx++;
  1.2016 -        /* The rest of the code to handle default values is at the bottom
  1.2017 -         * of this routine where default values for unspecified parameters
  1.2018 -         * are (also) handled. Note that above, the argument is flagged as
  1.2019 -         * ARG_IGNORED.
  1.2020 -         */
  1.2021 -      } else {
  1.2022 -        arglist[argpos]=ARG_DONE; /* flag argument as "present" */
  1.2023 -        if (arg[argidx].numtags==1)     /* set the expected tag, if any */
  1.2024 -          lval.cmptag=arg[argidx].tags[0];
  1.2025 -        lvalue=hier14(&lval);
  1.2026 -        assert(sc_status==statFIRST || arg[argidx].tags!=NULL);
  1.2027 -        switch (arg[argidx].ident) {
  1.2028 -        case 0:
  1.2029 -          error(92);             /* argument count mismatch */
  1.2030 -          break;
  1.2031 -        case iVARARGS:
  1.2032 -          /* always pass by reference */
  1.2033 -          if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  1.2034 -            assert(lval.sym!=NULL);
  1.2035 -            if ((lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) {
  1.2036 -              /* treat a "const" variable passed to a function with a non-const
  1.2037 -               * "variable argument list" as a constant here */
  1.2038 -              if (!lvalue) {
  1.2039 -                error(22);        /* need lvalue */
  1.2040 -              } else {
  1.2041 -                rvalue(&lval);    /* get value in PRI */
  1.2042 -                setheap_pri();    /* address of the value on the heap in PRI */
  1.2043 -                heapalloc++;
  1.2044 -                nest_stkusage++;
  1.2045 -              } /* if */
  1.2046 -            } else if (lvalue) {
  1.2047 -              address(lval.sym,sPRI);
  1.2048 -            } else {
  1.2049 -              setheap_pri();      /* address of the value on the heap in PRI */
  1.2050 -              heapalloc++;
  1.2051 -              nest_stkusage++;
  1.2052 -            } /* if */
  1.2053 -          } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION
  1.2054 -                     || lval.ident==iARRAYCHAR)
  1.2055 -          {
  1.2056 -            /* fetch value if needed */
  1.2057 -            if (lval.ident==iARRAYCHAR)
  1.2058 -              rvalue(&lval);
  1.2059 -            /* allocate a cell on the heap and store the
  1.2060 -             * value (already in PRI) there */
  1.2061 -            setheap_pri();        /* address of the value on the heap in PRI */
  1.2062 -            heapalloc++;
  1.2063 -            nest_stkusage++;
  1.2064 -          } /* if */
  1.2065 -          /* ??? handle const array passed by reference */
  1.2066 -          /* otherwise, the address is already in PRI */
  1.2067 -          if (lval.sym!=NULL)
  1.2068 -            markusage(lval.sym,uWRITTEN);
  1.2069 -          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  1.2070 -            error(213);
  1.2071 -          if (lval.tag!=0)
  1.2072 -            append_constval(&taglst,arg[argidx].name,lval.tag,0);
  1.2073 -          break;
  1.2074 -        case iVARIABLE:
  1.2075 -          if (lval.ident==iLABEL || lval.ident==iFUNCTN || lval.ident==iREFFUNC
  1.2076 -              || lval.ident==iARRAY || lval.ident==iREFARRAY)
  1.2077 -            error(35,argidx+1);   /* argument type mismatch */
  1.2078 -          if (lvalue)
  1.2079 -            rvalue(&lval);        /* get value (direct or indirect) */
  1.2080 -          /* otherwise, the expression result is already in PRI */
  1.2081 -          assert(arg[argidx].numtags>0);
  1.2082 -          check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag);
  1.2083 -          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  1.2084 -            error(213);
  1.2085 -          if (lval.tag!=0)
  1.2086 -            append_constval(&taglst,arg[argidx].name,lval.tag,0);
  1.2087 -          argidx++;               /* argument done */
  1.2088 -          break;
  1.2089 -        case iREFERENCE:
  1.2090 -          if (!lvalue || lval.ident==iARRAYCHAR)
  1.2091 -            error(35,argidx+1);   /* argument type mismatch */
  1.2092 -          if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  1.2093 -            error(35,argidx+1);   /* argument type mismatch */
  1.2094 -          if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
  1.2095 -            if (lvalue) {
  1.2096 -              assert(lval.sym!=NULL);
  1.2097 -              address(lval.sym,sPRI);
  1.2098 -            } else {
  1.2099 -              setheap_pri();      /* address of the value on the heap in PRI */
  1.2100 -              heapalloc++;
  1.2101 -              nest_stkusage++;
  1.2102 -            } /* if */
  1.2103 -          } /* if */
  1.2104 -          /* otherwise, the address is already in PRI */
  1.2105 -          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  1.2106 -            error(213);
  1.2107 -          if (lval.tag!=0)
  1.2108 -            append_constval(&taglst,arg[argidx].name,lval.tag,0);
  1.2109 -          argidx++;               /* argument done */
  1.2110 -          if (lval.sym!=NULL)
  1.2111 -            markusage(lval.sym,uWRITTEN);
  1.2112 -          break;
  1.2113 -        case iREFARRAY:
  1.2114 -          if (lval.ident!=iARRAY && lval.ident!=iREFARRAY
  1.2115 -              && lval.ident!=iARRAYCELL)
  1.2116 -          {
  1.2117 -            error(35,argidx+1);   /* argument type mismatch */
  1.2118 -            break;
  1.2119 -          } /* if */
  1.2120 -          if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
  1.2121 -            error(35,argidx+1); /* argument type mismatch */
  1.2122 -          /* Verify that the dimensions match with those in arg[argidx].
  1.2123 -           * A literal array always has a single dimension.
  1.2124 -           * An iARRAYCELL parameter is also assumed to have a single dimension.
  1.2125 -           */
  1.2126 -          if (lval.sym==NULL || lval.ident==iARRAYCELL) {
  1.2127 -            if (arg[argidx].numdim!=1) {
  1.2128 -              error(48);        /* array dimensions must match */
  1.2129 -            } else if (arg[argidx].dim[0]!=0) {
  1.2130 -              assert(arg[argidx].dim[0]>0);
  1.2131 -              if (lval.ident==iARRAYCELL) {
  1.2132 -                error(47);        /* array sizes must match */
  1.2133 -              } else {
  1.2134 -                assert(lval.constval!=0); /* literal array must have a size */
  1.2135 -                /* A literal array must have exactly the same size as the
  1.2136 -                 * function argument; a literal string may be smaller than
  1.2137 -                 * the function argument.
  1.2138 -                 */
  1.2139 -                if (lval.constval>0 && arg[argidx].dim[0]!=lval.constval
  1.2140 -                    || lval.constval<0 && arg[argidx].dim[0] < -lval.constval)
  1.2141 -                  error(47);      /* array sizes must match */
  1.2142 -              } /* if */
  1.2143 -            } /* if */
  1.2144 -            if (lval.ident!=iARRAYCELL) {
  1.2145 -              /* save array size, for default values with uSIZEOF flag */
  1.2146 -              cell array_sz=lval.constval;
  1.2147 -              assert(array_sz!=0);/* literal array must have a size */
  1.2148 -              if (array_sz<0)
  1.2149 -                array_sz= -array_sz;
  1.2150 -              append_constval(&arrayszlst,arg[argidx].name,array_sz,0);
  1.2151 -            } /* if */
  1.2152 -          } else {
  1.2153 -            symbol *sym=lval.sym;
  1.2154 -            short level=0;
  1.2155 -            assert(sym!=NULL);
  1.2156 -            if (sym->dim.array.level+1!=arg[argidx].numdim)
  1.2157 -              error(48);          /* array dimensions must match */
  1.2158 -            /* the lengths for all dimensions must match, unless the dimension
  1.2159 -             * length was defined at zero (which means "undefined")
  1.2160 -             */
  1.2161 -            while (sym->dim.array.level>0) {
  1.2162 -              assert(level<sDIMEN_MAX);
  1.2163 -              if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  1.2164 -                error(47);        /* array sizes must match */
  1.2165 -              else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  1.2166 -                error(229,sym->name);   /* index tag mismatch */
  1.2167 -              append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  1.2168 -              sym=finddepend(sym);
  1.2169 -              assert(sym!=NULL);
  1.2170 -              level++;
  1.2171 -            } /* if */
  1.2172 -            /* the last dimension is checked too, again, unless it is zero */
  1.2173 -            assert(level<sDIMEN_MAX);
  1.2174 -            assert(sym!=NULL);
  1.2175 -            if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
  1.2176 -              error(47);          /* array sizes must match */
  1.2177 -            else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
  1.2178 -              error(229,sym->name);   /* index tag mismatch */
  1.2179 -            append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
  1.2180 -          } /* if */
  1.2181 -          /* address already in PRI */
  1.2182 -          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
  1.2183 -            error(213);
  1.2184 -          if (lval.tag!=0)
  1.2185 -            append_constval(&taglst,arg[argidx].name,lval.tag,0);
  1.2186 -          // ??? set uWRITTEN?
  1.2187 -          argidx++;               /* argument done */
  1.2188 -          break;
  1.2189 -        } /* switch */
  1.2190 -        pushreg(sPRI);            /* store the function argument on the stack */
  1.2191 -        markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  1.2192 -        nest_stkusage++;
  1.2193 -      } /* if */
  1.2194 -      assert(arglist[argpos]!=ARG_UNHANDLED);
  1.2195 -      nargs++;
  1.2196 -      if (matchparanthesis) {
  1.2197 -        close=matchtoken(')');
  1.2198 -        if (!close)               /* if not paranthese... */
  1.2199 -          if (!needtoken(','))    /* ...should be comma... */
  1.2200 -            break;                /* ...but abort loop if neither */
  1.2201 -      } else {
  1.2202 -        close=!matchtoken(',');
  1.2203 -        if (close) {              /* if not comma... */
  1.2204 -          if (needtoken(tTERM)==1)/* ...must be end of statement */
  1.2205 -            lexpush();            /* push again, because end of statement is analised later */
  1.2206 -        } /* if */
  1.2207 -      } /* if */
  1.2208 -    } while (!close && freading && !matchtoken(tENDEXPR)); /* do */
  1.2209 -  } /* if */
  1.2210 -  /* check remaining function arguments (they may have default values) */
  1.2211 -  for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  1.2212 -    if (arglist[argidx]==ARG_DONE)
  1.2213 -      continue;                 /* already seen and handled this argument */
  1.2214 -    /* in this first stage, we also skip the arguments with uSIZEOF and uTAGOF;
  1.2215 -     * these are handled last
  1.2216 -     */
  1.2217 -    if ((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0) {
  1.2218 -      assert(arg[argidx].ident==iVARIABLE);
  1.2219 -      continue;
  1.2220 -    } /* if */
  1.2221 -    stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  1.2222 -    if (arg[argidx].hasdefault) {
  1.2223 -      if (arg[argidx].ident==iREFARRAY) {
  1.2224 -        short level;
  1.2225 -        setdefarray(arg[argidx].defvalue.array.data,
  1.2226 -                    arg[argidx].defvalue.array.size,
  1.2227 -                    arg[argidx].defvalue.array.arraysize,
  1.2228 -                    &arg[argidx].defvalue.array.addr,
  1.2229 -                    (arg[argidx].usage & uCONST)!=0);
  1.2230 -        if ((arg[argidx].usage & uCONST)==0) {
  1.2231 -          heapalloc+=arg[argidx].defvalue.array.arraysize;
  1.2232 -          nest_stkusage+=arg[argidx].defvalue.array.arraysize;
  1.2233 -        } /* if */
  1.2234 -        /* keep the lengths of all dimensions of a multi-dimensional default array */
  1.2235 -        assert(arg[argidx].numdim>0);
  1.2236 -        if (arg[argidx].numdim==1) {
  1.2237 -          append_constval(&arrayszlst,arg[argidx].name,arg[argidx].defvalue.array.arraysize,0);
  1.2238 -        } else {
  1.2239 -          for (level=0; level<arg[argidx].numdim; level++) {
  1.2240 -            assert(level<sDIMEN_MAX);
  1.2241 -            append_constval(&arrayszlst,arg[argidx].name,arg[argidx].dim[level],level);
  1.2242 -          } /* for */
  1.2243 -        } /* if */
  1.2244 -      } else if (arg[argidx].ident==iREFERENCE) {
  1.2245 -        setheap(arg[argidx].defvalue.val);
  1.2246 -        /* address of the value on the heap in PRI */
  1.2247 -        heapalloc++;
  1.2248 -        nest_stkusage++;
  1.2249 -      } else {
  1.2250 -        int dummytag=arg[argidx].tags[0];
  1.2251 -        ldconst(arg[argidx].defvalue.val,sPRI);
  1.2252 -        assert(arg[argidx].numtags>0);
  1.2253 -        check_userop(NULL,arg[argidx].defvalue_tag,arg[argidx].tags[0],2,NULL,&dummytag);
  1.2254 -        assert(dummytag==arg[argidx].tags[0]);
  1.2255 -      } /* if */
  1.2256 -      pushreg(sPRI);            /* store the function argument on the stack */
  1.2257 -      markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
  1.2258 -      nest_stkusage++;
  1.2259 -    } else {
  1.2260 -      error(202,argidx);        /* argument count mismatch */
  1.2261 -    } /* if */
  1.2262 -    if (arglist[argidx]==ARG_UNHANDLED)
  1.2263 -      nargs++;
  1.2264 -    arglist[argidx]=ARG_DONE;
  1.2265 -  } /* for */
  1.2266 -  /* now a second loop to catch the arguments with default values that are
  1.2267 -   * the "sizeof" or "tagof" of other arguments
  1.2268 -   */
  1.2269 -  for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
  1.2270 -    constvalue *asz;
  1.2271 -    cell array_sz;
  1.2272 -    if (arglist[argidx]==ARG_DONE)
  1.2273 -      continue;                 /* already seen and handled this argument */
  1.2274 -    stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
  1.2275 -    assert(arg[argidx].ident==iVARIABLE);           /* if "sizeof", must be single cell */
  1.2276 -    /* if unseen, must be "sizeof" or "tagof" */
  1.2277 -    assert((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0);
  1.2278 -    if ((arg[argidx].hasdefault & uSIZEOF)!=0) {
  1.2279 -      /* find the argument; if it isn't found, the argument's default value
  1.2280 -       * was a "sizeof" of a non-array (a warning for this was already given
  1.2281 -       * when declaring the function)
  1.2282 -       */
  1.2283 -      asz=find_constval(&arrayszlst,arg[argidx].defvalue.size.symname,
  1.2284 -                        arg[argidx].defvalue.size.level);
  1.2285 -      if (asz!=NULL) {
  1.2286 -        array_sz=asz->value;
  1.2287 -        if (array_sz==0)
  1.2288 -          error(224,arg[argidx].name);    /* indeterminate array size in "sizeof" expression */
  1.2289 -      } else {
  1.2290 -        array_sz=1;
  1.2291 -      } /* if */
  1.2292 -    } else {
  1.2293 -      asz=find_constval(&taglst,arg[argidx].defvalue.size.symname,
  1.2294 -                        arg[argidx].defvalue.size.level);
  1.2295 -      if (asz != NULL) {
  1.2296 -        exporttag(asz->value);
  1.2297 -        array_sz=asz->value | PUBLICTAG;  /* must be set, because it just was exported */
  1.2298 -      } else {
  1.2299 -        array_sz=0;
  1.2300 -      } /* if */
  1.2301 -    } /* if */
  1.2302 -    ldconst(array_sz,sPRI);
  1.2303 -    pushreg(sPRI);              /* store the function argument on the stack */
  1.2304 -    markexpr(sPARM,NULL,0);
  1.2305 -    nest_stkusage++;
  1.2306 -    if (arglist[argidx]==ARG_UNHANDLED)
  1.2307 -      nargs++;
  1.2308 -    arglist[argidx]=ARG_DONE;
  1.2309 -  } /* for */
  1.2310 -  stgmark(sENDREORDER);         /* mark end of reversed evaluation */
  1.2311 -  pushval((cell)nargs*sizeof(cell));
  1.2312 -  nest_stkusage++;
  1.2313 -  ffcall(sym,NULL,nargs);
  1.2314 -  if (sc_status!=statSKIP)
  1.2315 -    markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
  1.2316 -  if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL)
  1.2317 -    sym->x.lib->value += 1;     /* increment "usage count" of the library */
  1.2318 -  modheap(-heapalloc*sizeof(cell));
  1.2319 -  if (symret!=NULL)
  1.2320 -    popreg(sPRI);               /* pop hidden parameter as function result */
  1.2321 -  sideeffect=TRUE;              /* assume functions carry out a side-effect */
  1.2322 -  delete_consttable(&arrayszlst);     /* clear list of array sizes */
  1.2323 -  delete_consttable(&taglst);   /* clear list of parameter tags */
  1.2324 -
  1.2325 -  /* maintain max. amount of memory used */
  1.2326 -  {
  1.2327 -    long totalsize;
  1.2328 -    totalsize=declared+decl_heap+1;   /* local variables & return value size,
  1.2329 -                                       * +1 for PROC opcode */
  1.2330 -    if (lval_result->ident==iREFARRAY)
  1.2331 -      totalsize++;                    /* add hidden parameter (on the stack) */
  1.2332 -    if ((sym->usage & uNATIVE)==0)
  1.2333 -      totalsize++;                    /* add "call" opcode */
  1.2334 -    totalsize+=nest_stkusage;
  1.2335 -    assert(curfunc!=NULL);
  1.2336 -    if (curfunc->x.stacksize<totalsize)
  1.2337 -      curfunc->x.stacksize=totalsize;
  1.2338 -    nest_stkusage-=nargs+heapalloc+1; /* stack/heap space, +1 for argcount param */
  1.2339 -    /* if there is a syntax error in the script, the stack calculation is
  1.2340 -     * probably incorrect; but we may not allow it to drop below zero
  1.2341 -     */
  1.2342 -    if (nest_stkusage<0)
  1.2343 -      nest_stkusage=0;
  1.2344 -  }
  1.2345 -
  1.2346 -  /* scrap any arrays left on the heap, with the exception of the array that
  1.2347 -   * this function has as a result (in other words, scrap all arrays on the
  1.2348 -   * heap that caused by expressions in the function arguments)
  1.2349 -   */
  1.2350 -  assert(decl_heap>=locheap);
  1.2351 -  modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
  1.2352 -  decl_heap=locheap;
  1.2353 -  nesting--;
  1.2354 -}
  1.2355 -
  1.2356 -/*  dbltest
  1.2357 - *
  1.2358 - *  Returns a non-zero value if lval1 an array and lval2 is not an array and
  1.2359 - *  the operation is addition or subtraction.
  1.2360 - *
  1.2361 - *  Returns the "shift" count (1 for 16-bit, 2 for 32-bit) to align a cell
  1.2362 - *  to an array offset.
  1.2363 - */
  1.2364 -static int dbltest(void (*oper)(),value *lval1,value *lval2)
  1.2365 -{
  1.2366 -  if ((oper!=ob_add) && (oper!=ob_sub))
  1.2367 -    return 0;
  1.2368 -  if (lval1->ident!=iARRAY)
  1.2369 -    return 0;
  1.2370 -  if (lval2->ident==iARRAY)
  1.2371 -    return 0;
  1.2372 -  return sizeof(cell)/2;        /* 1 for 16-bit, 2 for 32-bit */
  1.2373 -}
  1.2374 -
  1.2375 -/*  commutative
  1.2376 - *
  1.2377 - *  Test whether an operator is commutative, i.e. x oper y == y oper x.
  1.2378 - *  Commutative operators are: +  (addition)
  1.2379 - *                             *  (multiplication)
  1.2380 - *                             == (equality)
  1.2381 - *                             != (inequality)
  1.2382 - *                             &  (bitwise and)
  1.2383 - *                             ^  (bitwise xor)
  1.2384 - *                             |  (bitwise or)
  1.2385 - *
  1.2386 - *  If in an expression, code for the left operand has been generated and
  1.2387 - *  the right operand is a constant and the operator is commutative, the
  1.2388 - *  precautionary "push" of the primary register is scrapped and the constant
  1.2389 - *  is read into the secondary register immediately.
  1.2390 - */
  1.2391 -static int commutative(void (*oper)())
  1.2392 -{
  1.2393 -  return oper==ob_add || oper==os_mult
  1.2394 -         || oper==ob_eq || oper==ob_ne
  1.2395 -         || oper==ob_and || oper==ob_xor || oper==ob_or;
  1.2396 -}
  1.2397 -
  1.2398 -/*  constant
  1.2399 - *
  1.2400 - *  Generates code to fetch a number, a literal character (which is returned
  1.2401 - *  by lex() as a number as well) or a literal string (lex() stores the
  1.2402 - *  strings in the literal queue). If the operand was a number, it is stored
  1.2403 - *  in lval->constval.
  1.2404 - *
  1.2405 - *  The function returns 1 if the token was a constant or a string, 0
  1.2406 - *  otherwise.
  1.2407 - */
  1.2408 -static int constant(value *lval)
  1.2409 -{
  1.2410 -  int tok,index,ident;
  1.2411 -  cell val,item,cidx;
  1.2412 -  char *st;
  1.2413 -  symbol *sym;
  1.2414 -  int cmptag=lval->cmptag;
  1.2415 -
  1.2416 -  tok=lex(&val,&st);
  1.2417 -  if (tok==tSYMBOL && (sym=findconst(st,&cmptag))!=0) {
  1.2418 -    if (cmptag>1)
  1.2419 -      error(91,sym->name);  /* ambiguity: multiple matching constants (different tags) */
  1.2420 -    lval->constval=sym->addr;
  1.2421 -    ldconst(lval->constval,sPRI);
  1.2422 -    lval->ident=iCONSTEXPR;
  1.2423 -    lval->tag=sym->tag;
  1.2424 -    lval->sym=sym;
  1.2425 -    markusage(sym,uREAD);
  1.2426 -  } else if (tok==tNUMBER) {
  1.2427 -    lval->constval=val;
  1.2428 -    ldconst(lval->constval,sPRI);
  1.2429 -    lval->ident=iCONSTEXPR;
  1.2430 -  } else if (tok==tRATIONAL) {
  1.2431 -    lval->constval=val;
  1.2432 -    ldconst(lval->constval,sPRI);
  1.2433 -    lval->ident=iCONSTEXPR;
  1.2434 -    lval->tag=sc_rationaltag;
  1.2435 -  } else if (tok==tSTRING) {
  1.2436 -    /* lex() stores starting index of string in the literal table in 'val' */
  1.2437 -    ldconst((val+glb_declared)*sizeof(cell),sPRI);
  1.2438 -    lval->ident=iARRAY;         /* pretend this is a global array */
  1.2439 -    lval->constval=val-litidx;  /* constval == the negative value of the
  1.2440 -                                 * size of the literal array; using a negative
  1.2441 -                                 * value distinguishes between literal arrays
  1.2442 -                                 * and literal strings (this was done for
  1.2443 -                                 * array assignment). */
  1.2444 -  } else if (tok=='{') {
  1.2445 -    int tag,lasttag=-1;
  1.2446 -    val=litidx;
  1.2447 -    do {
  1.2448 -      /* cannot call constexpr() here, because "staging" is already turned
  1.2449 -       * on at this point */
  1.2450 -      assert(staging);
  1.2451 -      stgget(&index,&cidx);     /* mark position in code generator */
  1.2452 -      ident=expression(&item,&tag,NULL,FALSE);
  1.2453 -      stgdel(index,cidx);       /* scratch generated code */
  1.2454 -      if (ident!=iCONSTEXPR)
  1.2455 -        error(8);               /* must be constant expression */
  1.2456 -      if (lasttag<0)
  1.2457 -        lasttag=tag;
  1.2458 -      else if (!matchtag(lasttag,tag,FALSE))
  1.2459 -        error(213);             /* tagname mismatch */
  1.2460 -      litadd(item);             /* store expression result in literal table */
  1.2461 -    } while (matchtoken(','));
  1.2462 -    if (!needtoken('}'))
  1.2463 -      lexclr(FALSE);
  1.2464 -    ldconst((val+glb_declared)*sizeof(cell),sPRI);
  1.2465 -    lval->ident=iARRAY;         /* pretend this is a global array */
  1.2466 -    lval->constval=litidx-val;  /* constval == the size of the literal array */
  1.2467 -  } else {
  1.2468 -    return FALSE;               /* no, it cannot be interpreted as a constant */
  1.2469 -  } /* if */
  1.2470 -  return TRUE;                  /* yes, it was a constant value */
  1.2471 -}
  1.2472 -