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