]> git.sur5r.net Git - cc65/blob - src/cc65/expr.c
995e042689ff7412a2e65a990af7fcad9740f9f8
[cc65] / src / cc65 / expr.c
1 /*
2  * expr.c
3  *
4  * Ullrich von Bassewitz, 21.06.1998
5  */
6
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 /* common */
14 #include "check.h"
15 #include "xmalloc.h"
16
17 /* cc65 */
18 #include "asmcode.h"
19 #include "asmlabel.h"
20 #include "codegen.h"
21 #include "datatype.h"
22 #include "declare.h"
23 #include "error.h"
24 #include "funcdesc.h"
25 #include "function.h"
26 #include "global.h"
27 #include "litpool.h"
28 #include "macrotab.h"
29 #include "preproc.h"
30 #include "scanner.h"
31 #include "stdfunc.h"
32 #include "symtab.h"
33 #include "expr.h"
34
35
36
37 /*****************************************************************************/
38 /*                                   Data                                    */
39 /*****************************************************************************/
40
41
42
43 /* Generator attributes */
44 #define GEN_NOPUSH      0x01            /* Don't push lhs */
45
46 /* Map a generator function and its attributes to a token */
47 typedef struct {
48     unsigned char Tok;                  /* Token to map to */
49     unsigned char Flags;                /* Flags for generator function */
50     void          (*Func) (unsigned, unsigned long);    /* Generator func */
51 } GenDesc;
52
53 /* Descriptors for the operations */
54 static GenDesc GenMUL    = { TOK_STAR,          GEN_NOPUSH,     g_mul };
55 static GenDesc GenDIV    = { TOK_DIV,           GEN_NOPUSH,     g_div };
56 static GenDesc GenMOD    = { TOK_MOD,           GEN_NOPUSH,     g_mod };
57 static GenDesc GenASL    = { TOK_SHL,           GEN_NOPUSH,     g_asl };
58 static GenDesc GenASR    = { TOK_SHR,           GEN_NOPUSH,     g_asr };
59 static GenDesc GenLT     = { TOK_LT,            GEN_NOPUSH,     g_lt  };
60 static GenDesc GenLE     = { TOK_LE,            GEN_NOPUSH,     g_le  };
61 static GenDesc GenGE     = { TOK_GE,            GEN_NOPUSH,     g_ge  };
62 static GenDesc GenGT     = { TOK_GT,            GEN_NOPUSH,     g_gt  };
63 static GenDesc GenEQ     = { TOK_EQ,            GEN_NOPUSH,     g_eq  };
64 static GenDesc GenNE     = { TOK_NE,            GEN_NOPUSH,     g_ne  };
65 static GenDesc GenAND    = { TOK_AND,           GEN_NOPUSH,     g_and };
66 static GenDesc GenXOR    = { TOK_XOR,           GEN_NOPUSH,     g_xor };
67 static GenDesc GenOR     = { TOK_OR,            GEN_NOPUSH,     g_or  };
68 static GenDesc GenPASGN  = { TOK_PLUS_ASSIGN,   GEN_NOPUSH,     g_add };
69 static GenDesc GenSASGN  = { TOK_MINUS_ASSIGN,  GEN_NOPUSH,     g_sub };
70 static GenDesc GenMASGN  = { TOK_MUL_ASSIGN,    GEN_NOPUSH,     g_mul };
71 static GenDesc GenDASGN  = { TOK_DIV_ASSIGN,    GEN_NOPUSH,     g_div };
72 static GenDesc GenMOASGN = { TOK_MOD_ASSIGN,    GEN_NOPUSH,     g_mod };
73 static GenDesc GenSLASGN = { TOK_SHL_ASSIGN,    GEN_NOPUSH,     g_asl };
74 static GenDesc GenSRASGN = { TOK_SHR_ASSIGN,    GEN_NOPUSH,     g_asr };
75 static GenDesc GenAASGN  = { TOK_AND_ASSIGN,    GEN_NOPUSH,     g_and };
76 static GenDesc GenXOASGN = { TOK_XOR_ASSIGN,    GEN_NOPUSH,     g_xor };
77 static GenDesc GenOASGN  = { TOK_OR_ASSIGN,     GEN_NOPUSH,     g_or  };
78
79
80
81 /*****************************************************************************/
82 /*                             Function forwards                             */
83 /*****************************************************************************/
84
85
86
87 static int hie10 (struct expent* lval);
88 /* Handle ++, --, !, unary - etc. */
89
90
91
92 /*****************************************************************************/
93 /*                             Helper functions                              */
94 /*****************************************************************************/
95
96
97
98 static unsigned GlobalModeFlags (unsigned flags)
99 /* Return the addressing mode flags for the variable with the given flags */
100 {
101     flags &= E_MCTYPE;
102     if (flags == E_TGLAB) {
103         /* External linkage */
104         return CF_EXTERNAL;
105     } else if (flags == E_TREGISTER) {
106         /* Register variable */
107         return CF_REGVAR;
108     } else {
109         /* Static */
110         return CF_STATIC;
111     }
112 }
113
114
115
116 static int IsNullPtr (struct expent* lval)
117 /* Return true if this is the NULL pointer constant */
118 {
119     return (IsInt (lval->e_tptr) &&             /* Is it an int? */
120             lval->e_flags == E_MCONST &&        /* Is it constant? */
121             lval->e_const == 0);                /* And is it's value zero? */
122 }
123
124
125
126 static type* promoteint (type* lhst, type* rhst)
127 /* In an expression with two ints, return the type of the result */
128 {
129     /* Rules for integer types:
130      *   - If one of the values is a long, the result is long.
131      *   - If one of the values is unsigned, the result is also unsigned.
132      *   - Otherwise the result is an int.
133      */
134     if (IsLong (lhst) || IsLong (rhst)) {
135         if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
136             return type_ulong;
137         } else {
138             return type_long;
139         }
140     } else {
141         if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
142             return type_uint;
143         } else {
144             return type_int;
145         }
146     }
147 }
148
149
150
151 static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush)
152 /* Adjust the two values for a binary operation. lhs is expected on stack or
153  * to be constant, rhs is expected to be in the primary register or constant.
154  * The function will put the type of the result into lhs and return the
155  * code generator flags for the operation.
156  * If NoPush is given, it is assumed that the operation does not expect the lhs
157  * to be on stack, and that lhs is in a register instead.
158  * Beware: The function does only accept int types.
159  */
160 {
161     unsigned ltype, rtype;
162     unsigned flags;
163
164     /* Get the type strings */
165     type* lhst = lhs->e_tptr;
166     type* rhst = rhs->e_tptr;
167
168     /* Generate type adjustment code if needed */
169     ltype = TypeOf (lhst);
170     if (lhs->e_flags == E_MCONST) {
171         ltype |= CF_CONST;
172     }
173     if (NoPush) {
174         /* Value is in primary register*/
175         ltype |= CF_REG;
176     }
177     rtype = TypeOf (rhst);
178     if (rhs->e_flags == E_MCONST) {
179         rtype |= CF_CONST;
180     }
181     flags = g_typeadjust (ltype, rtype);
182
183     /* Set the type of the result */
184     lhs->e_tptr = promoteint (lhst, rhst);
185
186     /* Return the code generator flags */
187     return flags;
188 }
189
190
191
192 unsigned assignadjust (type* lhst, struct expent* rhs)
193 /* Adjust the type of the right hand expression so that it can be assigned to
194  * the type on the left hand side. This function is used for assignment and
195  * for converting parameters in a function call. It returns the code generator
196  * flags for the operation. The type string of the right hand side will be
197  * set to the type of the left hand side.
198  */
199 {
200     /* Get the type of the right hand side */
201     type* rhst = rhs->e_tptr;
202
203     /* After calling this function, rhs will have the type of the lhs */
204     rhs->e_tptr = lhst;
205
206     /* First, do some type checking */
207     if (IsTypeVoid (lhst) || IsTypeVoid (rhst)) {
208         /* If one of the sides are of type void, output a more apropriate
209          * error message.
210          */
211         Error (ERR_ILLEGAL_TYPE);
212     } else if (IsInt (lhst)) {
213         if (IsPtr (rhst)) {
214             /* Pointer -> int conversion */
215             Warning (WARN_PTR_TO_INT_CONV);
216         } else if (!IsInt (rhst)) {
217             Error (ERR_INCOMPATIBLE_TYPES);
218         } else {
219             /* Adjust the int types. To avoid manipulation of TOS mark lhs
220              * as const.
221              */
222             unsigned flags = TypeOf (rhst);
223             if (rhs->e_flags & E_MCONST) {
224                 flags |= CF_CONST;
225             }
226             return g_typeadjust (TypeOf (lhst) | CF_CONST, flags);
227         }
228     } else if (IsPtr (lhst)) {
229         if (IsPtr (rhst)) {
230             /* Pointer to pointer assignment is valid, if:
231              *   - both point to the same types, or
232              *   - the rhs pointer is a void pointer, or
233              *   - the lhs pointer is a void pointer.
234              */
235             type* left  = Indirect (lhst);
236             type* right = Indirect (rhst);
237             if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
238                 Error (ERR_INCOMPATIBLE_POINTERS);
239             }
240         } else if (IsInt (rhst)) {
241             /* Int to pointer assignment is valid only for constant zero */
242             if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) {
243                 Warning (WARN_INT_TO_PTR_CONV);
244             }
245         } else if (IsFuncPtr (lhst) && IsFunc(rhst)) {
246             /* Assignment of function to function pointer is allowed, provided
247              * that both functions have the same parameter list.
248              */
249             if (!EqualTypes(Indirect (lhst), rhst)) {
250                 Error (ERR_INCOMPATIBLE_TYPES);
251             }
252         } else {
253             Error (ERR_INCOMPATIBLE_TYPES);
254         }
255     } else {
256         Error (ERR_INCOMPATIBLE_TYPES);
257     }
258
259     /* Return an int value in all cases where the operands are not both ints */
260     return CF_INT;
261 }
262
263
264
265 void DefineData (struct expent* lval)
266 /* Output a data definition for the given expression */
267 {
268     unsigned flags = lval->e_flags;
269
270     switch (flags & E_MCTYPE) {
271
272         case E_TCONST:
273             /* Number */
274             g_defdata (TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
275             break;
276
277         case E_TREGISTER:
278             /* Register variable. Taking the address is usually not
279              * allowed.
280              */
281             if (!AllowRegVarAddr) {
282                 Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
283             }
284             /* FALLTHROUGH */
285
286         case E_TGLAB:
287         case E_TLLAB:
288             /* Local or global symbol */
289             g_defdata (GlobalModeFlags (flags), lval->e_name, lval->e_const);
290             break;
291
292         case E_TLIT:
293             /* a literal of some kind */
294             g_defdata (CF_STATIC, LiteralLabel, lval->e_const);
295             break;
296
297         default:
298             Internal ("Unknown constant type: %04X", flags);
299     }
300 }
301
302
303
304 static void lconst (unsigned flags, struct expent* lval)
305 /* Load primary reg with some constant value. */
306 {
307     switch (lval->e_flags & E_MCTYPE) {
308
309         case E_TLOFFS:
310             g_leasp (lval->e_const);
311             break;
312
313         case E_TCONST:
314             /* Number constant */
315             g_getimmed (flags | TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
316             break;
317
318         case E_TREGISTER:
319             /* Register variable. Taking the address is usually not
320              * allowed.
321              */
322             if (!AllowRegVarAddr) {
323                 Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
324             }
325             /* FALLTHROUGH */
326
327         case E_TGLAB:
328         case E_TLLAB:
329             /* Local or global symbol, load address */
330             flags |= GlobalModeFlags (lval->e_flags);
331             flags &= ~CF_CONST;
332             g_getimmed (flags, lval->e_name, lval->e_const);
333             break;
334
335         case E_TLIT:
336             /* Literal string */
337             g_getimmed (CF_STATIC, LiteralLabel, lval->e_const);
338             break;
339
340         default:
341             Internal ("Unknown constant type: %04X", lval->e_flags);
342     }
343 }
344
345
346
347 static int kcalc (int tok, long val1, long val2)
348 /* Calculate an operation with left and right operand constant. */
349 {
350     switch (tok) {
351         case TOK_EQ:
352             return (val1 == val2);
353         case TOK_NE:
354             return (val1 != val2);
355         case TOK_LT:
356             return (val1 < val2);
357         case TOK_LE:
358             return (val1 <= val2);
359         case TOK_GE:
360             return (val1 >= val2);
361         case TOK_GT:
362             return (val1 > val2);
363         case TOK_OR:
364             return (val1 | val2);
365         case TOK_XOR:
366             return (val1 ^ val2);
367         case TOK_AND:
368             return (val1 & val2);
369         case TOK_SHR:
370             return (val1 >> val2);
371         case TOK_SHL:
372             return (val1 << val2);
373         case TOK_STAR:
374             return (val1 * val2);
375         case TOK_DIV:
376             if (val2 == 0) {
377                 Error (ERR_DIV_BY_ZERO);
378                 return 0x7FFFFFFF;
379             }
380             return (val1 / val2);
381         case TOK_MOD:
382             if (val2 == 0) {
383                 Error (ERR_MOD_BY_ZERO);
384                 return 0;
385             }
386             return (val1 % val2);
387         default:
388             Internal ("kcalc: got token 0x%X\n", tok);
389             return 0;
390     }
391 }
392
393
394
395 static GenDesc* FindGen (int Tok, GenDesc** Table)
396 {
397     GenDesc* G;
398     while ((G = *Table) != 0) {
399         if (G->Tok == Tok) {
400             return G;
401         }
402         ++Table;
403     }
404     return 0;
405 }
406
407
408
409 static int istypeexpr (void)
410 /* Return true if some sort of variable or type is waiting (helper for cast
411  * and sizeof() in hie10).
412  */
413 {
414     SymEntry* Entry;
415
416     return curtok == TOK_LPAREN && (
417             (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) ||
418             (nxttok == TOK_CONST)                               ||
419             (nxttok  == TOK_IDENT                               &&
420             (Entry = FindSym (NextTok.Ident)) != 0              &&
421             IsTypeDef (Entry))
422            );
423 }
424
425
426
427 static void PushAddr (struct expent* lval)
428 /* If the expression contains an address that was somehow evaluated,
429  * push this address on the stack. This is a helper function for all
430  * sorts of implicit or explicit assignment functions where the lvalue
431  * must be saved if it's not constant, before evaluating the rhs.
432  */
433 {
434     /* Get the address on stack if needed */
435     if (lval->e_flags != E_MREG && (lval->e_flags & E_MEXPR)) {
436         /* Push the address (always a pointer) */
437         g_push (CF_PTR, 0);
438     }
439 }
440
441
442
443 /*****************************************************************************/
444 /*                                   code                                    */
445 /*****************************************************************************/
446
447
448
449 void exprhs (unsigned flags, int k, struct expent *lval)
450 /* Put the result of an expression into the primary register */
451 {
452     int f;
453
454     f = lval->e_flags;
455     if (k) {
456         /* Dereferenced lvalue */
457         flags |= TypeOf (lval->e_tptr);
458         if (lval->e_test & E_FORCETEST) {
459             flags |= CF_TEST;
460             lval->e_test &= ~E_FORCETEST;
461         }
462         if (f & E_MGLOBAL) {    /* ref to globalvar */
463             /* Generate code */
464             flags |= GlobalModeFlags (f);
465             g_getstatic (flags, lval->e_name, lval->e_const);
466         } else if (f & E_MLOCAL) {
467             /* ref to localvar */
468             g_getlocal (flags, lval->e_const);
469         } else if (f & E_MCONST) {
470             /* ref to absolute address */
471             g_getstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
472         } else if (f == E_MEOFFS) {
473             g_getind (flags, lval->e_const);
474         } else if (f != E_MREG) {
475             g_getind (flags, 0);
476         }
477     } else if (f == E_MEOFFS) {
478         /* reference not storable */
479         flags |= TypeOf (lval->e_tptr);
480         g_inc (flags | CF_CONST, lval->e_const);
481     } else if ((f & E_MEXPR) == 0) {
482         /* Constant of some sort, load it into the primary */
483         lconst (flags, lval);
484     }
485     if (lval->e_test & E_FORCETEST) {   /* we testing this value? */
486         /* debug... */
487         AddCodeHint ("forcetest");
488         flags |= TypeOf (lval->e_tptr);
489         g_test (flags);                 /* yes, force a test */
490         lval->e_test &= ~E_FORCETEST;
491     }
492 }
493
494
495 static void callfunction (struct expent* lval)
496 /* Perform a function call.  Called from hie11, this routine will
497  * either call the named function, or if the supplied ptr is zero,
498  * will call the contents of P.
499  */
500 {
501     struct expent lval2;
502     FuncDesc*     Func;         /* Function descriptor */
503     int           Ellipsis;     /* True if we have an open param list */
504     SymEntry*     Param;        /* Current formal parameter */
505     unsigned      ParamCount;   /* Actual parameter count */
506     unsigned      ParamSize;    /* Number of parameter bytes */
507     unsigned      Flags;
508     unsigned      CFlags;
509     CodeMark      Mark;
510
511
512     /* Get a pointer to the function descriptor from the type string */
513     Func = GetFuncDesc (lval->e_tptr);
514
515     /* Initialize vars to keep gcc silent */
516     Param = 0;
517     Mark  = 0;
518
519     /* Check if this is a function pointer. If so, save it. If not, check for
520      * special known library functions that may be inlined.
521      */
522     if (lval->e_flags & E_MEXPR) {
523         /* Function pointer is in primary register, save it */
524         Mark = GetCodePos ();
525         g_save (CF_PTR);
526     } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) {
527         /* Inline this function */
528         HandleStdFunc (lval);
529         return;
530     }
531
532     /* Parse the actual parameter list */
533     ParamSize  = 0;
534     ParamCount = 0;
535     Ellipsis   = 0;
536     while (curtok != TOK_RPAREN) {
537
538         /* Add a hint for the optimizer */
539         AddCodeHint ("param:start");
540
541         /* Count arguments */
542         ++ParamCount;
543
544         /* Fetch the pointer to the next argument, check for too many args */
545         if (ParamCount <= Func->ParamCount) {
546             if (ParamCount == 1) {
547                 /* First argument */
548                 Param = Func->SymTab->SymHead;
549             } else {
550                 /* Next argument */
551                 Param = Param->NextSym;
552                 CHECK ((Param->Flags & SC_PARAM) != 0);
553             }
554         } else if (!Ellipsis) {
555             /* Too many arguments. Do we have an open param list? */
556             if ((Func->Flags & FD_ELLIPSIS) == 0) {
557                 /* End of param list reached, no ellipsis */
558                 Error (ERR_TOO_MANY_FUNC_ARGS);
559             }
560             /* Assume an ellipsis even in case of errors to avoid an error
561              * message for each other argument.
562              */
563             Ellipsis = 1;
564         }
565
566         /* Do some optimization: If we have a constant value to push,
567          * use a special function that may optimize.
568          */
569         CFlags = CF_NONE;
570         if (!Ellipsis && SizeOf (Param->Type) == 1) {
571             CFlags = CF_FORCECHAR;
572         }
573         Flags = 0;
574         if (evalexpr (CFlags, hie1, &lval2) == 0) {
575             /* A constant value */
576             Flags |= CF_CONST;
577         }
578
579         /* If we don't have an argument spec, accept anything, otherwise
580          * convert the actual argument to the type needed.
581          */
582         if (!Ellipsis) {
583             /* Promote the argument if needed */
584             assignadjust (Param->Type, &lval2);
585             /* If we have a prototype, chars may be pushed as chars */
586             Flags |= CF_FORCECHAR;
587         }
588
589         /* Use the type of the argument for the push */
590         Flags |= TypeOf (lval2.e_tptr);
591
592         /* If this is a fastcall function, don't push the last argument */
593         if (ParamCount == Func->ParamCount && (Func->Flags & FD_FASTCALL) != 0) {
594             /* Just load the argument into the primary. This is only needed if
595              * we have a constant argument, otherwise the value is already in
596              * the primary.
597              */
598             if (Flags & CF_CONST) {
599                 exprhs (CF_FORCECHAR, 0, &lval2);
600             }
601         } else {
602             /* Push the argument, count the argument size */
603             g_push (Flags, lval2.e_const);
604             ParamSize += sizeofarg (Flags);
605         }
606
607         /* Add an optimizer hint */
608         AddCodeHint ("param:end");
609
610         /* Check for end of argument list */
611         if (curtok != TOK_COMMA) {
612             break;
613         }
614         NextToken ();
615     }
616
617     /* We need the closing bracket here */
618     ConsumeRParen ();
619
620     /* Check if we had enough parameters */
621     if (ParamCount < Func->ParamCount) {
622         Error (ERR_TOO_FEW_FUNC_ARGS);
623     }
624
625     /* */
626     if (lval->e_flags & E_MEXPR) {
627         /* Function called via pointer: Restore it and call function */
628         if (ParamSize != 0) {
629             g_restore (CF_PTR);
630         } else {
631             /* We had no parameters - remove save code */
632             RemoveCode (Mark);
633         }
634         g_callind (TypeOf (lval->e_tptr), ParamSize);
635     } else {
636         g_call (TypeOf (lval->e_tptr), (char*) lval->e_name, ParamSize);
637     }
638 }
639
640
641
642 void doasm (void)
643 /* This function parses ASM statements. The syntax of the ASM directive
644  * looks like the one defined for C++ (C has no ASM directive), that is,
645  * a string literal in parenthesis.
646  */
647 {
648     /* Skip the ASM */
649     NextToken ();
650
651     /* Need left parenthesis */
652     ConsumeLParen ();
653
654     /* String literal */
655     if (curtok != TOK_SCONST) {
656         Error (ERR_STRLIT_EXPECTED);
657     } else {
658         /* Write the string directly into the output, followed by a newline */
659         AddCodeLine (GetLiteral (curval));
660
661         /* Reset the string pointer, effectivly clearing the string from the
662          * string table. Since we're working with one token lookahead, this
663          * will fail if the next token is also a string token, but that's a
664          * syntax error anyway, because we expect a right paren.
665          */
666         ResetLiteralOffs (curval);
667     }
668
669     /* Skip the string token */
670     NextToken ();
671
672     /* Closing paren needed */
673     ConsumeRParen ();
674 }
675
676
677
678 static int primary (struct expent* lval)
679 /* This is the lowest level of the expression parser. */
680 {
681     int k;
682
683     /* not a test at all, yet */
684     lval->e_test = 0;
685
686     /* Character and integer constants. */
687     if (curtok == TOK_ICONST || curtok == TOK_CCONST) {
688         lval->e_flags = E_MCONST | E_TCONST;
689         lval->e_tptr  = curtype;
690         lval->e_const = curval;
691         NextToken ();
692         return 0;
693     }
694
695     /* Process parenthesized subexpression by calling the whole parser
696      * recursively.
697      */
698     if (curtok == TOK_LPAREN) {
699         NextToken ();
700         memset (lval, 0, sizeof (*lval));       /* Remove any attributes */
701         k = hie0 (lval);
702         ConsumeRParen ();
703         return k;
704     }
705
706     /* All others may only be used if the expression evaluation is not called
707      * recursively by the preprocessor.
708      */
709     if (Preprocessing) {
710         /* Illegal expression in PP mode */
711         Error (ERR_CPP_EXPR_EXPECTED);
712         lval->e_flags = E_MCONST;
713         lval->e_tptr = type_int;
714         return 0;
715     }
716
717     /* Identifier? */
718     if (curtok == TOK_IDENT) {
719
720         SymEntry* Sym;
721         ident Ident;
722
723         /* Get a pointer to the symbol table entry */
724         Sym = FindSym (CurTok.Ident);
725
726         /* Is the symbol known? */
727         if (Sym) {
728
729             /* We found the symbol - skip the name token */
730             NextToken ();
731
732             /* The expression type is the symbol type */
733             lval->e_tptr = Sym->Type;
734
735             /* Check for illegal symbol types */
736             if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
737                 /* Cannot use labels in expressions */
738                 Error (ERR_SYMBOL_KIND);
739                 return 1;
740             } else if (Sym->Flags & SC_TYPE) {
741                 /* Cannot use type symbols */
742                 Error (ERR_VAR_IDENT_EXPECTED);
743                 /* Assume an int type to make lval valid */
744                 lval->e_flags = E_MLOCAL | E_TLOFFS;
745                 lval->e_tptr = type_int;
746                 lval->e_const = 0;
747                 return 0;
748             }
749
750             /* Check for legal symbol types */
751             if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
752                 lval->e_flags = E_MCONST;
753                 lval->e_const = Sym->V.EnumVal;
754                 return 0;
755             } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
756                 /* Function */
757                 lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
758                 lval->e_name = (unsigned long) Sym->Name;
759                 lval->e_const = 0;
760             } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
761                 /* Local variable */
762                 lval->e_flags = E_MLOCAL | E_TLOFFS;
763                 lval->e_const = Sym->V.Offs;
764             } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
765                 /* Static variable */
766                 if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
767                     lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
768                     lval->e_name = (unsigned long) Sym->Name;
769                 } else {
770                     lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
771                     lval->e_name = Sym->V.Label;
772                 }
773                 lval->e_const = 0;
774             } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
775                 /* Register variable, zero page based */
776                 lval->e_flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
777                 lval->e_name  = Sym->V.Offs;
778                 lval->e_const = 0;
779             } else {
780                 /* Local static variable */
781                 lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
782                 lval->e_name  = Sym->V.Offs;
783                 lval->e_const = 0;
784             }
785
786             /* The symbol is referenced now */
787             Sym->Flags |= SC_REF;
788             if (IsFunc (lval->e_tptr) || IsArray (lval->e_tptr)) {
789                 return 0;
790             }
791             return 1;
792         }
793
794         /* We did not find the symbol. Remember the name, then skip it */
795         strcpy (Ident, CurTok.Ident);
796         NextToken ();
797
798         /* IDENT is either an auto-declared function or an undefined variable. */
799         if (curtok == TOK_LPAREN) {
800             /* Declare a function returning int. For that purpose, prepare a
801              * function signature for a function having an empty param list
802              * and returning int.
803              */
804             Warning (WARN_FUNC_WITHOUT_PROTO);
805             Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
806             lval->e_tptr  = Sym->Type;
807             lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
808             lval->e_name  = (unsigned long) Sym->Name;
809             lval->e_const = 0;
810             return 0;
811
812         } else {
813
814             /* Undeclared Variable */
815             Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
816             lval->e_flags = E_MLOCAL | E_TLOFFS;
817             lval->e_tptr = type_int;
818             lval->e_const = 0;
819             Error (ERR_UNDEFINED_SYMBOL, Ident);
820             return 1;
821
822         }
823     }
824
825     /* String literal? */
826     if (curtok == TOK_SCONST) {
827         lval->e_flags = E_MCONST | E_TLIT;
828         lval->e_const = curval;
829         lval->e_tptr  = GetCharArrayType (strlen (GetLiteral (curval)));
830         NextToken ();
831         return 0;
832     }
833
834     /* ASM statement? */
835     if (curtok == TOK_ASM) {
836         doasm ();
837         lval->e_tptr  = type_void;
838         lval->e_flags = E_MEXPR;
839         lval->e_const = 0;
840         return 0;
841     }
842
843     /* __AX__ and __EAX__ pseudo values? */
844     if (curtok == TOK_AX || curtok == TOK_EAX) {
845         lval->e_tptr  = (curtok == TOK_AX)? type_uint : type_ulong;
846         lval->e_flags = E_MREG;
847         lval->e_test &= ~E_CC;
848         lval->e_const = 0;
849         NextToken ();
850         return 1;               /* May be used as lvalue */
851     }
852
853     /* Illegal primary. */
854     Error (ERR_EXPR_EXPECTED);
855     lval->e_flags = E_MCONST;
856     lval->e_tptr = type_int;
857     return 0;
858 }
859
860
861
862 static int arrayref (int k, struct expent* lval)
863 /* Handle an array reference */
864 {
865     unsigned lflags;
866     unsigned rflags;
867     int ConstBaseAddr;
868     int ConstSubAddr;
869     int l;
870     struct expent lval2;
871     CodeMark Mark1;
872     CodeMark Mark2;
873     type* tptr1;
874     type* tptr2;
875
876
877     /* Skip the bracket */
878     NextToken ();
879
880     /* Get the type of left side */
881     tptr1 = lval->e_tptr;
882
883     /* We can apply a special treatment for arrays that have a const base
884      * address. This is true for most arrays and will produce a lot better
885      * code. Check if this is a const base address.
886      */
887     lflags = lval->e_flags & ~E_MCTYPE;
888     ConstBaseAddr = (lflags == E_MCONST)       || /* Constant numeric address */
889                      (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */
890                      lflags == E_MLOCAL;          /* Local array */
891
892     /* If we have a constant base, we delay the address fetch */
893     Mark1 = GetCodePos ();
894     Mark2 = 0;          /* Silence gcc */
895     if (!ConstBaseAddr) {
896         /* Get a pointer to the array into the primary */
897         exprhs (CF_NONE, k, lval);
898
899         /* Get the array pointer on stack. Do not push more than 16
900          * bit, even if this value is greater, since we cannot handle
901          * other than 16bit stuff when doing indexing.
902          */
903         Mark2 = GetCodePos ();
904         g_push (CF_PTR, 0);
905     }
906
907     /* TOS now contains ptr to array elements. Get the subscript. */
908     l = hie0 (&lval2);
909     if (l == 0 && lval2.e_flags == E_MCONST) {
910
911         /* The array subscript is a constant - remove value from stack */
912         if (!ConstBaseAddr) {
913             RemoveCode (Mark2);
914             pop (CF_PTR);
915         } else {
916             /* Get an array pointer into the primary */
917             exprhs (CF_NONE, k, lval);
918         }
919
920         if (IsPtr (tptr1)) {
921
922             /* Scale the subscript value according to element size */
923             lval2.e_const *= PSizeOf (tptr1);
924
925             /* Remove code for lhs load */
926             RemoveCode (Mark1);
927
928             /* Handle constant base array on stack. Be sure NOT to
929              * handle pointers the same way, this won't work.
930              */
931             if (IsArray (tptr1) &&
932                 ((lval->e_flags & ~E_MCTYPE) == E_MCONST ||
933                 (lval->e_flags & ~E_MCTYPE) == E_MLOCAL ||
934                 (lval->e_flags & E_MGLOBAL) != 0 ||
935                 (lval->e_flags == E_MEOFFS))) {
936                 lval->e_const += lval2.e_const;
937
938             } else {
939                 /* Pointer - load into primary and remember offset */
940                 if ((lval->e_flags & E_MEXPR) == 0 || k != 0) {
941                     exprhs (CF_NONE, k, lval);
942                 }
943                 lval->e_const = lval2.e_const;
944                 lval->e_flags = E_MEOFFS;
945             }
946
947             /* Result is of element type */
948             lval->e_tptr = Indirect (tptr1);
949
950             /* Done */
951             goto end_array;
952
953         } else if (IsPtr (tptr2 = lval2.e_tptr)) {
954             /* Subscript is pointer, get element type */
955             lval2.e_tptr = Indirect (tptr2);
956
957             /* Scale the rhs value in the primary register */
958             g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
959             /* */
960             lval->e_tptr = lval2.e_tptr;
961         } else {
962             Error (ERR_CANNOT_SUBSCRIPT);
963         }
964
965         /* Add the subscript. Since arrays are indexed by integers,
966          * we will ignore the true type of the subscript here and
967          * use always an int.
968          */
969         g_inc (CF_INT | CF_CONST, lval2.e_const);
970
971     } else {
972
973         /* Array subscript is not constant. Load it into the primary */
974         Mark2 = GetCodePos ();
975         exprhs (CF_NONE, l, &lval2);
976
977         tptr2 = lval2.e_tptr;
978         if (IsPtr (tptr1)) {
979
980             /* Get the element type */
981             lval->e_tptr = Indirect (tptr1);
982
983             /* Indexing is based on int's, so we will just use the integer
984              * portion of the index (which is in (e)ax, so there's no further
985              * action required).
986              */
987             g_scale (CF_INT, SizeOf (lval->e_tptr));
988
989         } else if (IsPtr (tptr2)) {
990
991             /* Get the element type */
992             lval2.e_tptr = Indirect (tptr2);
993
994             /* Get the int value on top. If we go here, we're sure,
995              * both values are 16 bit (the first one was truncated
996              * if necessary and the second one is a pointer).
997              * Note: If ConstBaseAddr is true, we don't have a value on
998              * stack, so to "swap" both, just push the subscript.
999              */
1000             if (ConstBaseAddr) {
1001                 g_push (CF_INT, 0);
1002                 exprhs (CF_NONE, k, lval);
1003                 ConstBaseAddr = 0;
1004             } else {
1005                 g_swap (CF_INT);
1006             }
1007
1008             /* Scale it */
1009             g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
1010             lval->e_tptr = lval2.e_tptr;
1011         } else {
1012             Error (ERR_CANNOT_SUBSCRIPT);
1013         }
1014
1015         /* The offset is now in the primary register. It didn't have a
1016          * constant base address for the lhs, the lhs address is already
1017          * on stack, and we must add the offset. If the base address was
1018          * constant, we call special functions to add the address to the
1019          * offset value.
1020          */
1021         if (!ConstBaseAddr) {
1022             /* Add the subscript. Both values are int sized. */
1023             g_add (CF_INT, 0);
1024         } else {
1025
1026             /* If the subscript has itself a constant address, it is often
1027              * a better idea to reverse again the order of the evaluation.
1028              * This will generate better code if the subscript is a byte
1029              * sized variable. But beware: This is only possible if the
1030              * subscript was not scaled, that is, if this was a byte array
1031              * or pointer.
1032              */
1033             rflags = lval2.e_flags & ~E_MCTYPE;
1034             ConstSubAddr = (rflags == E_MCONST)       || /* Constant numeric address */
1035                             (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */
1036                             rflags == E_MLOCAL;          /* Local array */
1037
1038             if (ConstSubAddr && SizeOf (lval->e_tptr) == 1) {
1039
1040                 type* SavedType;
1041
1042                 /* Reverse the order of evaluation */
1043                 unsigned flags = (SizeOf (lval2.e_tptr) == 1)? CF_CHAR : CF_INT;
1044                 RemoveCode (Mark2);
1045
1046                 /* Get a pointer to the array into the primary. We have changed
1047                  * e_tptr above but we need the original type to load the
1048                  * address, so restore it temporarily.
1049                  */
1050                 SavedType = lval->e_tptr;
1051                 lval->e_tptr = tptr1;
1052                 exprhs (CF_NONE, k, lval);
1053                 lval->e_tptr = SavedType;
1054
1055                 /* Add the variable */
1056                 if (rflags == E_MLOCAL) {
1057                     g_addlocal (flags, lval2.e_const);
1058                 } else {
1059                     flags |= GlobalModeFlags (lval2.e_flags);
1060                     g_addstatic (flags, lval2.e_name, lval2.e_const);
1061                 }
1062             } else {
1063                 if (lflags == E_MCONST) {
1064                     /* Constant numeric address. Just add it */
1065                     g_inc (CF_INT | CF_UNSIGNED, lval->e_const);
1066                 } else if (lflags == E_MLOCAL) {
1067                     /* Base address is a local variable address */
1068                     if (IsArray (tptr1)) {
1069                         g_addaddr_local (CF_INT, lval->e_const);
1070                     } else {
1071                         g_addlocal (CF_PTR, lval->e_const);
1072                     }
1073                 } else {
1074                     /* Base address is a static variable address */
1075                     unsigned flags = CF_INT;
1076                     flags |= GlobalModeFlags (lval->e_flags);
1077                     if (IsArray (tptr1)) {
1078                         g_addaddr_static (flags, lval->e_name, lval->e_const);
1079                     } else {
1080                         g_addstatic (flags, lval->e_name, lval->e_const);
1081                     }
1082                 }
1083             }
1084         }
1085     }
1086     lval->e_flags = E_MEXPR;
1087 end_array:
1088     ConsumeRBrack ();
1089     return !IsArray (lval->e_tptr);
1090
1091 }
1092
1093
1094
1095 static int structref (int k, struct expent* lval)
1096 /* Process struct field after . or ->. */
1097 {
1098     ident Ident;
1099     SymEntry* Field;
1100     int flags;
1101
1102     /* Skip the token and check for an identifier */
1103     NextToken ();
1104     if (curtok != TOK_IDENT) {
1105         Error (ERR_IDENT_EXPECTED);
1106         lval->e_tptr = type_int;
1107         return 0;
1108     }
1109
1110     /* Get the symbol table entry and check for a struct field */
1111     strcpy (Ident, CurTok.Ident);
1112     NextToken ();
1113     Field = FindStructField (lval->e_tptr, Ident);
1114     if (Field == 0) {
1115         Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
1116         lval->e_tptr = type_int;
1117         return 0;
1118     }
1119
1120     /* If we have constant input data, the result is also constant */
1121     flags = lval->e_flags & ~E_MCTYPE;
1122     if (flags == E_MCONST ||
1123         (k == 0 && (flags == E_MLOCAL ||
1124                     (flags & E_MGLOBAL) != 0 ||
1125                     lval->e_flags  == E_MEOFFS))) {
1126         lval->e_const += Field->V.Offs;
1127     } else {
1128         if ((flags & E_MEXPR) == 0 || k != 0) {
1129             exprhs (CF_NONE, k, lval);
1130         }
1131         lval->e_const = Field->V.Offs;
1132         lval->e_flags = E_MEOFFS;
1133     }
1134     lval->e_tptr = Field->Type;
1135     return !IsArray (Field->Type);
1136 }
1137
1138
1139
1140 static int hie11 (struct expent *lval)
1141 /* Handle compound types (structs and arrays) */
1142 {
1143     int k;
1144     type* tptr;
1145
1146
1147     k = primary (lval);
1148     if (curtok < TOK_LBRACK || curtok > TOK_PTR_REF) {
1149         /* Not for us */
1150         return k;
1151     }
1152
1153     while (1) {
1154
1155         if (curtok == TOK_LBRACK) {
1156
1157             /* Array reference */
1158             k = arrayref (k, lval);
1159
1160         } else if (curtok == TOK_LPAREN) {
1161
1162             /* Function call. Skip the opening parenthesis */
1163             NextToken ();
1164             tptr = lval->e_tptr;
1165             if (IsFunc (tptr) || IsFuncPtr (tptr)) {
1166                 if (IsFuncPtr (tptr)) {
1167                     /* Pointer to function. Handle transparently */
1168                     exprhs (CF_NONE, k, lval);  /* Function pointer to A/X */
1169                     ++lval->e_tptr;             /* Skip T_PTR */
1170                     lval->e_flags |= E_MEXPR;
1171                 }
1172                 callfunction (lval);
1173                 lval->e_flags = E_MEXPR;
1174                 lval->e_tptr += DECODE_SIZE + 1;        /* Set to result */
1175             } else {
1176                 Error (ERR_ILLEGAL_FUNC_CALL);
1177             }
1178             k = 0;
1179
1180         } else if (curtok == TOK_DOT) {
1181
1182             if (!IsStruct (lval->e_tptr)) {
1183                 Error (ERR_STRUCT_EXPECTED);
1184             }
1185             k = structref (0, lval);
1186
1187         } else if (curtok == TOK_PTR_REF) {
1188
1189             tptr = lval->e_tptr;
1190             if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) {
1191                 Error (ERR_STRUCT_PTR_EXPECTED);
1192             }
1193             k = structref (k, lval);
1194
1195         } else {
1196             return k;
1197         }
1198     }
1199 }
1200
1201
1202
1203 static void store (struct expent* lval)
1204 /* Store primary reg into this reference */
1205 {
1206     int f;
1207     unsigned flags;
1208
1209     f = lval->e_flags;
1210     flags = TypeOf (lval->e_tptr);
1211     if (f & E_MGLOBAL) {
1212         flags |= GlobalModeFlags (f);
1213         if (lval->e_test) {
1214             /* Just testing */
1215             flags |= CF_TEST;
1216         }
1217
1218         /* Generate code */
1219         g_putstatic (flags, lval->e_name, lval->e_const);
1220
1221     } else if (f & E_MLOCAL) {
1222         g_putlocal (flags, lval->e_const);
1223     } else if (f == E_MEOFFS) {
1224         g_putind (flags, lval->e_const);
1225     } else if (f != E_MREG) {
1226         if (f & E_MEXPR) {
1227             g_putind (flags, 0);
1228         } else {
1229             /* Store into absolute address */
1230             g_putstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
1231         }
1232     }
1233
1234     /* Assume that each one of the stores will invalidate CC */
1235     lval->e_test &= ~E_CC;
1236 }
1237
1238
1239
1240 static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned long))
1241 /* Handle --i and ++i */
1242 {
1243     int k;
1244     unsigned flags;
1245     unsigned long val;
1246
1247     NextToken ();
1248     if ((k = hie10 (lval)) == 0) {
1249         Error (ERR_LVALUE_EXPECTED);
1250         return;
1251     }
1252
1253     /* Get the data type */
1254     flags = TypeOf (lval->e_tptr) | CF_FORCECHAR | CF_CONST;
1255
1256     /* Get the increment value in bytes */
1257     val = (lval->e_tptr [0] == T_PTR)? PSizeOf (lval->e_tptr) : 1;
1258
1259     /* We're currently only able to handle some adressing modes */
1260     if ((lval->e_flags & E_MGLOBAL) == 0 &&     /* Global address? */
1261         (lval->e_flags & E_MLOCAL) == 0  &&     /* Local address? */
1262         (lval->e_flags & E_MCONST) == 0  &&     /* Constant address? */
1263         (lval->e_flags & E_MEXPR) == 0) {       /* Address in a/x? */
1264
1265         /* Use generic code. Push the address if needed */
1266         PushAddr (lval);
1267
1268         /* Fetch the value */
1269         exprhs (CF_NONE, k, lval);
1270
1271         /* Increment value in primary */
1272         inc (flags, val);
1273
1274         /* Store the result back */
1275         store (lval);
1276
1277     } else {
1278
1279         /* Special code for some addressing modes - use the special += ops */
1280         if (lval->e_flags & E_MGLOBAL) {
1281             flags |= GlobalModeFlags (lval->e_flags);
1282             if (inc == g_inc) {
1283                 g_addeqstatic (flags, lval->e_name, lval->e_const, val);
1284             } else {
1285                 g_subeqstatic (flags, lval->e_name, lval->e_const, val);
1286             }
1287         } else if (lval->e_flags & E_MLOCAL) {
1288             /* ref to localvar */
1289             if (inc == g_inc) {
1290                 g_addeqlocal (flags, lval->e_const, val);
1291             } else {
1292                 g_subeqlocal (flags, lval->e_const, val);
1293             }
1294         } else if (lval->e_flags & E_MCONST) {
1295             /* ref to absolute address */
1296             flags |= CF_ABSOLUTE;
1297             if (inc == g_inc) {
1298                 g_addeqstatic (flags, lval->e_const, 0, val);
1299             } else {
1300                 g_subeqstatic (flags, lval->e_const, 0, val);
1301             }
1302         } else if (lval->e_flags & E_MEXPR) {
1303             /* Address in a/x. */
1304             if (inc == g_inc) {
1305                 g_addeqind (flags, lval->e_const, val);
1306             } else {
1307                 g_subeqind (flags, lval->e_const, val);
1308             }
1309         } else {
1310             Internal ("Invalid addressing mode");
1311         }
1312
1313     }
1314
1315     /* Result is an expression */
1316     lval->e_flags = E_MEXPR;
1317 }
1318
1319
1320
1321 static void post_incdec (struct expent *lval, int k, void (*inc) (unsigned, unsigned long))
1322 /* Handle i-- and i++ */
1323 {
1324     unsigned flags;
1325
1326     NextToken ();
1327     if (k == 0) {
1328         Error (ERR_LVALUE_EXPECTED);
1329         return;
1330     }
1331
1332     /* Get the data type */
1333     flags = TypeOf (lval->e_tptr);
1334
1335     /* Push the address if needed */
1336     PushAddr (lval);
1337
1338     /* Fetch the value and save it (since it's the result of the expression) */
1339     exprhs (CF_NONE, 1, lval);
1340     g_save (flags | CF_FORCECHAR);
1341
1342     /* If we have a pointer expression, increment by the size of the type */
1343     if (lval->e_tptr[0] == T_PTR) {
1344         inc (flags | CF_CONST | CF_FORCECHAR, SizeOf (lval->e_tptr + 1));
1345     } else {
1346         inc (flags | CF_CONST | CF_FORCECHAR, 1);
1347     }
1348
1349     /* Store the result back */
1350     store (lval);
1351
1352     /* Restore the original value */
1353     g_restore (flags | CF_FORCECHAR);
1354     lval->e_flags = E_MEXPR;
1355 }
1356
1357
1358
1359 static void unaryop (int tok, struct expent* lval)
1360 /* Handle unary -/+ and ~ */
1361 {
1362     int k;
1363     unsigned flags;
1364
1365     NextToken ();
1366     k = hie10 (lval);
1367     if (k == 0 && lval->e_flags & E_MCONST) {
1368         /* Value is constant */
1369         switch (tok) {
1370             case TOK_MINUS: lval->e_const =     -lval->e_const; break;
1371             case TOK_PLUS:                                      break;
1372             case TOK_COMP:  lval->e_const = ~lval->e_const;     break;
1373             default:        Internal ("Unexpected token: %d", tok);
1374         }
1375     } else {
1376         /* Value is not constant */
1377         exprhs (CF_NONE, k, lval);
1378
1379         /* Get the type of the expression */
1380         flags = TypeOf (lval->e_tptr);
1381
1382         /* Handle the operation */
1383         switch (tok) {
1384             case TOK_MINUS: g_neg (flags);  break;
1385             case TOK_PLUS:                  break;
1386             case TOK_COMP:  g_com (flags);  break;
1387             default:    Internal ("Unexpected token: %d", tok);
1388         }
1389         lval->e_flags = E_MEXPR;
1390     }
1391 }
1392
1393
1394
1395 static int typecast (struct expent* lval)
1396 /* Handle an explicit cast */
1397 {
1398     int k;
1399     type Type[MAXTYPELEN];
1400     unsigned rflags;
1401
1402     /* Skip the left paren */
1403     NextToken ();
1404
1405     /* Read the type */
1406     ParseType (Type);
1407
1408     /* Closing paren */
1409     ConsumeRParen ();
1410
1411     /* Read the expression we have to cast */
1412     k = hie10 (lval);
1413
1414     /* Get the type of the expression and honor constant values */
1415     rflags = TypeOf (lval->e_tptr);
1416     if (lval->e_flags & E_MCONST) {
1417         rflags |= CF_CONST;
1418     }
1419
1420     /* Do the actual cast. Special handling for void casts */
1421     if (!IsTypeVoid (Type)) {
1422         /* Mark the lhs as const to avoid a manipulation of TOS */
1423         g_typecast (TypeOf (Type) | CF_CONST, rflags);
1424     }
1425
1426     /* Use the new type */
1427     lval->e_tptr = TypeDup (Type);
1428
1429     /* Done */
1430     return k;
1431 }
1432
1433
1434
1435 static int hie10 (struct expent* lval)
1436 /* Handle ++, --, !, unary - etc. */
1437 {
1438     int k;
1439     type* t;
1440
1441     switch (curtok) {
1442
1443         case TOK_INC:
1444             pre_incdec (lval, g_inc);
1445             return 0;
1446
1447         case TOK_DEC:
1448             pre_incdec (lval, g_dec);
1449             return 0;
1450
1451         case TOK_PLUS:
1452         case TOK_MINUS:
1453         case TOK_COMP:
1454             unaryop (curtok, lval);
1455             return 0;
1456
1457         case TOK_BOOL_NOT:
1458             NextToken ();
1459             if (evalexpr (CF_NONE, hie10, lval) == 0) {
1460                 /* Constant expression */
1461                 lval->e_const = !lval->e_const;
1462             } else {
1463                 g_bneg (TypeOf (lval->e_tptr));
1464                 lval->e_test |= E_CC;                   /* bneg will set cc */
1465                 lval->e_flags = E_MEXPR;                /* say it's an expr */
1466             }
1467             return 0;                           /* expr not storable */
1468
1469         case TOK_STAR:
1470             NextToken ();
1471             if (evalexpr (CF_NONE, hie10, lval) != 0) {
1472                 /* Expression is not const, indirect value loaded into primary */
1473                 lval->e_flags = E_MEXPR;
1474                 lval->e_const = 0;              /* Offset is zero now */
1475             }
1476             t = lval->e_tptr;
1477             if (IsPtr (t)) {
1478                 lval->e_tptr = Indirect (t);
1479             } else {
1480                 Error (ERR_ILLEGAL_INDIRECT);
1481             }
1482             return 1;
1483
1484         case TOK_AND:
1485             NextToken ();
1486             k = hie10 (lval);
1487             if (k == 0) {
1488                 /* Allow the & operator with an array */
1489                 if (!IsArray (lval->e_tptr)) {
1490                     Error (ERR_ILLEGAL_ADDRESS);
1491                 }
1492             } else {
1493                 t = TypeAlloc (TypeLen (lval->e_tptr) + 2);
1494                 t [0] = T_PTR;
1495                 TypeCpy (t + 1, lval->e_tptr);
1496                 lval->e_tptr = t;
1497             }
1498             return 0;
1499
1500         case TOK_SIZEOF:
1501             NextToken ();
1502             if (istypeexpr ()) {
1503                 type Type[MAXTYPELEN];
1504                 NextToken ();
1505                 lval->e_const = SizeOf (ParseType (Type));
1506                 ConsumeRParen ();
1507             } else {
1508                 /* Remember the output queue pointer */
1509                 CodeMark Mark = GetCodePos ();
1510                 hie10 (lval);
1511                 lval->e_const = SizeOf (lval->e_tptr);
1512                 /* Remove any generated code */
1513                 RemoveCode (Mark);
1514             }
1515             lval->e_flags = E_MCONST | E_TCONST;
1516             lval->e_tptr = type_uint;
1517             lval->e_test &= ~E_CC;
1518             return 0;
1519
1520         default:
1521             if (istypeexpr ()) {
1522                 /* A cast */
1523                 return typecast (lval);
1524             }
1525     }
1526
1527     k = hie11 (lval);
1528     switch (curtok) {
1529         case TOK_INC:
1530             post_incdec (lval, k, g_inc);
1531             return 0;
1532
1533         case TOK_DEC:
1534             post_incdec (lval, k, g_dec);
1535             return 0;
1536
1537         default:
1538             return k;
1539     }
1540 }
1541
1542
1543
1544 static int hie_internal (GenDesc** ops,         /* List of generators */
1545                          struct expent* lval,   /* parent expr's lval */
1546                          int (*hienext) (struct expent*),
1547                          int* UsedGen)          /* next higher level */
1548 /* Helper function */
1549 {
1550     int k;
1551     struct expent lval2;
1552     CodeMark Mark1;
1553     CodeMark Mark2;
1554     GenDesc* Gen;
1555     token_t tok;                        /* The operator token */
1556     unsigned ltype, type;
1557     int rconst;                         /* Operand is a constant */
1558
1559
1560     k = hienext (lval);
1561
1562     *UsedGen = 0;
1563     while ((Gen = FindGen (curtok, ops)) != 0) {
1564
1565         /* Tell the caller that we handled it's ops */
1566         *UsedGen = 1;
1567
1568         /* All operators that call this function expect an int on the lhs */
1569         if (!IsInt (lval->e_tptr)) {
1570             Error (ERR_INT_EXPR_EXPECTED);
1571         }
1572
1573         /* Remember the operator token, then skip it */
1574         tok = curtok;
1575         NextToken ();
1576
1577         /* Get the lhs on stack */
1578         Mark1 = GetCodePos ();
1579         ltype = TypeOf (lval->e_tptr);
1580         if (k == 0 && lval->e_flags == E_MCONST) {
1581             /* Constant value */
1582             Mark2 = GetCodePos ();
1583             g_push (ltype | CF_CONST, lval->e_const);
1584         } else {
1585             /* Value not constant */
1586             exprhs (CF_NONE, k, lval);
1587             Mark2 = GetCodePos ();
1588             g_push (ltype, 0);
1589         }
1590
1591         /* Get the right hand side */
1592         rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
1593
1594         /* Check the type of the rhs */
1595         if (!IsInt (lval2.e_tptr)) {
1596             Error (ERR_INT_EXPR_EXPECTED);
1597         }
1598
1599         /* Check for const operands */
1600         if (k == 0 && lval->e_flags == E_MCONST && rconst) {
1601
1602             /* Both operands are constant, remove the generated code */
1603             RemoveCode (Mark1);
1604             pop (ltype);
1605
1606             /* Evaluate the result */
1607             lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
1608
1609             /* Get the type of the result */
1610             lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
1611
1612         } else {
1613
1614             /* If the right hand side is constant, and the generator function
1615              * expects the lhs in the primary, remove the push of the primary
1616              * now.
1617              */
1618             unsigned rtype = TypeOf (lval2.e_tptr);
1619             type = 0;
1620             if (rconst) {
1621                 /* Second value is constant - check for div */
1622                 type |= CF_CONST;
1623                 rtype |= CF_CONST;
1624                 if (tok == TOK_DIV && lval2.e_const == 0) {
1625                     Error (ERR_DIV_BY_ZERO);
1626                 } else if (tok == TOK_MOD && lval2.e_const == 0) {
1627                     Error (ERR_MOD_BY_ZERO);
1628                 }
1629                 if ((Gen->Flags & GEN_NOPUSH) != 0) {
1630                     RemoveCode (Mark2);
1631                     pop (ltype);
1632                     ltype |= CF_REG;    /* Value is in register */
1633                 }
1634             }
1635
1636             /* Determine the type of the operation result. */
1637             type |= g_typeadjust (ltype, rtype);
1638             lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
1639
1640             /* Generate code */
1641             Gen->Func (type, lval2.e_const);
1642             lval->e_flags = E_MEXPR;
1643         }
1644
1645         /* We have a rvalue now */
1646         k = 0;
1647     }
1648
1649     return k;
1650 }
1651
1652
1653
1654 static int hie_compare (GenDesc** ops,          /* List of generators */
1655                         struct expent* lval,    /* parent expr's lval */
1656                         int (*hienext) (struct expent*))
1657 /* Helper function for the compare operators */
1658 {
1659     int k;
1660     struct expent lval2;
1661     CodeMark Mark1;
1662     CodeMark Mark2;
1663     GenDesc* Gen;
1664     token_t tok;                        /* The operator token */
1665     unsigned ltype;
1666     int rconst;                         /* Operand is a constant */
1667
1668
1669     k = hienext (lval);
1670
1671     while ((Gen = FindGen (curtok, ops)) != 0) {
1672
1673         /* Remember the operator token, then skip it */
1674         tok = curtok;
1675         NextToken ();
1676
1677         /* Get the lhs on stack */
1678         Mark1 = GetCodePos ();
1679         ltype = TypeOf (lval->e_tptr);
1680         if (k == 0 && lval->e_flags == E_MCONST) {
1681             /* Constant value */
1682             Mark2 = GetCodePos ();
1683             g_push (ltype | CF_CONST, lval->e_const);
1684         } else {
1685             /* Value not constant */
1686             exprhs (CF_NONE, k, lval);
1687             Mark2 = GetCodePos ();
1688             g_push (ltype, 0);
1689         }
1690
1691         /* Get the right hand side */
1692         rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
1693
1694         /* Make sure, the types are compatible */
1695         if (IsInt (lval->e_tptr)) {
1696             if (!IsInt (lval2.e_tptr) && !(IsPtr(lval2.e_tptr) && IsNullPtr(lval))) {
1697                 Error (ERR_INCOMPATIBLE_TYPES);
1698             }
1699         } else if (IsPtr (lval->e_tptr)) {
1700             if (IsPtr (lval2.e_tptr)) {
1701                 /* Both pointers are allowed in comparison if they point to
1702                  * the same type, or if one of them is a void pointer.
1703                  */
1704                 type* left  = Indirect (lval->e_tptr);
1705                 type* right = Indirect (lval2.e_tptr);
1706                 if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
1707                     /* Incomatible pointers */
1708                     Error (ERR_INCOMPATIBLE_TYPES);
1709                 }
1710             } else if (!IsNullPtr (&lval2)) {
1711                 Error (ERR_INCOMPATIBLE_TYPES);
1712             }
1713         }
1714
1715         /* Check for const operands */
1716         if (k == 0 && lval->e_flags == E_MCONST && rconst) {
1717
1718             /* Both operands are constant, remove the generated code */
1719             RemoveCode (Mark1);
1720             pop (ltype);
1721
1722             /* Evaluate the result */
1723             lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
1724
1725         } else {
1726
1727             /* If the right hand side is constant, and the generator function
1728              * expects the lhs in the primary, remove the push of the primary
1729              * now.
1730              */
1731             unsigned flags = 0;
1732             if (rconst) {
1733                 flags |= CF_CONST;
1734                 if ((Gen->Flags & GEN_NOPUSH) != 0) {
1735                     RemoveCode (Mark2);
1736                     pop (ltype);
1737                     ltype |= CF_REG;    /* Value is in register */
1738                 }
1739             }
1740
1741             /* Determine the type of the operation result. If the left
1742              * operand is of type char and the right is a constant, or
1743              * if both operands are of type char, we will encode the
1744              * operation as char operation. Otherwise the default
1745              * promotions are used.
1746              */
1747             if (IsChar (lval->e_tptr) && (IsChar (lval2.e_tptr) || rconst)) {
1748                 flags |= CF_CHAR;
1749                 if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) {
1750                     flags |= CF_UNSIGNED;
1751                 }
1752                 if (rconst) {
1753                     flags |= CF_FORCECHAR;
1754                 }
1755             } else {
1756                 unsigned rtype = TypeOf (lval2.e_tptr) | (flags & CF_CONST);
1757                 flags |= g_typeadjust (ltype, rtype);
1758             }
1759
1760             /* Generate code */
1761             Gen->Func (flags, lval2.e_const);
1762             lval->e_flags = E_MEXPR;
1763         }
1764
1765         /* Result type is always int */
1766         lval->e_tptr = type_int;
1767
1768         /* We have a rvalue now, condition codes are set */
1769         k = 0;
1770         lval->e_test |= E_CC;
1771     }
1772
1773     return k;
1774 }
1775
1776
1777
1778 static int hie9 (struct expent *lval)
1779 /* Process * and / operators. */
1780 {
1781     static GenDesc* hie9_ops [] = {
1782         &GenMUL, &GenDIV, &GenMOD, 0
1783     };
1784     int UsedGen;
1785
1786     return hie_internal (hie9_ops, lval, hie10, &UsedGen);
1787 }
1788
1789
1790
1791 static void parseadd (int k, struct expent* lval)
1792 /* Parse an expression with the binary plus operator. lval contains the
1793  * unprocessed left hand side of the expression and will contain the
1794  * result of the expression on return.
1795  */
1796 {
1797     struct expent lval2;
1798     unsigned flags;             /* Operation flags */
1799     CodeMark Mark;              /* Remember code position */
1800     type* lhst;                 /* Type of left hand side */
1801     type* rhst;                 /* Type of right hand side */
1802
1803
1804     /* Skip the PLUS token */
1805     NextToken ();
1806
1807     /* Get the left hand side type, initialize operation flags */
1808     lhst = lval->e_tptr;
1809     flags = 0;
1810
1811     /* Check for constness on both sides */
1812     if (k == 0 && lval->e_flags == E_MCONST) {
1813
1814         /* The left hand side is a constant. Good. Get rhs */
1815         if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
1816
1817             /* Right hand side is also constant. Get the rhs type */
1818             rhst = lval2.e_tptr;
1819
1820             /* Both expressions are constants. Check for pointer arithmetic */
1821             if (IsPtr (lhst) && IsInt (rhst)) {
1822                 /* Left is pointer, right is int, must scale rhs */
1823                 lval->e_const = lval->e_const + lval2.e_const * PSizeOf (lhst);
1824                 /* Result type is a pointer */
1825             } else if (IsInt (lhst) && IsPtr (rhst)) {
1826                 /* Left is int, right is pointer, must scale lhs */
1827                 lval->e_const = lval->e_const * PSizeOf (rhst) + lval2.e_const;
1828                 /* Result type is a pointer */
1829                 lval->e_tptr = lval2.e_tptr;
1830             } else if (IsInt (lhst) && IsInt (rhst)) {
1831                 /* Integer addition */
1832                 lval->e_const += lval2.e_const;
1833                 typeadjust (lval, &lval2, 1);
1834             } else {
1835                 /* OOPS */
1836                 Error (ERR_OP_NOT_ALLOWED);
1837             }
1838
1839             /* Result is constant, condition codes not set */
1840             lval->e_test = E_MCONST;
1841
1842         } else {
1843
1844             /* lhs is constant, rhs is not. Get the rhs type. */
1845             rhst = lval2.e_tptr;
1846
1847             /* Check for pointer arithmetic */
1848             if (IsPtr (lhst) && IsInt (rhst)) {
1849                 /* Left is pointer, right is int, must scale rhs */
1850                 g_scale (CF_INT, PSizeOf (lhst));
1851                 /* Operate on pointers, result type is a pointer */
1852                 flags = CF_PTR;
1853             } else if (IsInt (lhst) && IsPtr (rhst)) {
1854                 /* Left is int, right is pointer, must scale lhs */
1855                 lval->e_const *= PSizeOf (rhst);
1856                 /* Operate on pointers, result type is a pointer */
1857                 flags = CF_PTR;
1858                 lval->e_tptr = lval2.e_tptr;
1859             } else if (IsInt (lhst) && IsInt (rhst)) {
1860                 /* Integer addition */
1861                 flags = typeadjust (lval, &lval2, 1);
1862             } else {
1863                 /* OOPS */
1864                 Error (ERR_OP_NOT_ALLOWED);
1865             }
1866
1867             /* Generate code for the add */
1868             g_inc (flags | CF_CONST, lval->e_const);
1869
1870             /* Result is in primary register */
1871             lval->e_flags = E_MEXPR;
1872             lval->e_test &= ~E_CC;
1873
1874         }
1875
1876     } else {
1877
1878         /* Left hand side is not constant. Get the value onto the stack. */
1879         exprhs (CF_NONE, k, lval);              /* --> primary register */
1880         Mark = GetCodePos ();
1881         g_push (TypeOf (lval->e_tptr), 0);      /* --> stack */
1882
1883         /* Evaluate the rhs */
1884         if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
1885
1886             /* Right hand side is a constant. Get the rhs type */
1887             rhst = lval2.e_tptr;
1888
1889             /* Remove pushed value from stack */
1890             RemoveCode (Mark);
1891             pop (TypeOf (lval->e_tptr));
1892
1893             /* Check for pointer arithmetic */
1894             if (IsPtr (lhst) && IsInt (rhst)) {
1895                 /* Left is pointer, right is int, must scale rhs */
1896                 lval2.e_const *= PSizeOf (lhst);
1897                 /* Operate on pointers, result type is a pointer */
1898                 flags = CF_PTR;
1899             } else if (IsInt (lhst) && IsPtr (rhst)) {
1900                 /* Left is int, right is pointer, must scale lhs (ptr only) */
1901                 g_scale (CF_INT | CF_CONST, PSizeOf (rhst));
1902                 /* Operate on pointers, result type is a pointer */
1903                 flags = CF_PTR;
1904                 lval->e_tptr = lval2.e_tptr;
1905             } else if (IsInt (lhst) && IsInt (rhst)) {
1906                 /* Integer addition */
1907                 flags = typeadjust (lval, &lval2, 1);
1908             } else {
1909                 /* OOPS */
1910                 Error (ERR_OP_NOT_ALLOWED);
1911             }
1912
1913             /* Generate code for the add */
1914             g_inc (flags | CF_CONST, lval2.e_const);
1915
1916             /* Result is in primary register */
1917             lval->e_flags = E_MEXPR;
1918             lval->e_test &= ~E_CC;
1919
1920         } else {
1921
1922             /* lhs and rhs are not constant. Get the rhs type. */
1923             rhst = lval2.e_tptr;
1924
1925             /* Check for pointer arithmetic */
1926             if (IsPtr (lhst) && IsInt (rhst)) {
1927                 /* Left is pointer, right is int, must scale rhs */
1928                 g_scale (CF_INT, PSizeOf (lhst));
1929                 /* Operate on pointers, result type is a pointer */
1930                 flags = CF_PTR;
1931             } else if (IsInt (lhst) && IsPtr (rhst)) {
1932                 /* Left is int, right is pointer, must scale lhs */
1933                 g_tosint (TypeOf (rhst));       /* Make sure, TOS is int */
1934                 g_swap (CF_INT);                /* Swap TOS and primary */
1935                 g_scale (CF_INT, PSizeOf (rhst));
1936                 /* Operate on pointers, result type is a pointer */
1937                 flags = CF_PTR;
1938                 lval->e_tptr = lval2.e_tptr;
1939             } else if (IsInt (lhst) && IsInt (rhst)) {
1940                 /* Integer addition */
1941                 flags = typeadjust (lval, &lval2, 0);
1942             } else {
1943                 /* OOPS */
1944                 Error (ERR_OP_NOT_ALLOWED);
1945             }
1946
1947             /* Generate code for the add */
1948             g_add (flags, 0);
1949
1950             /* Result is in primary register */
1951             lval->e_flags = E_MEXPR;
1952             lval->e_test &= ~E_CC;
1953
1954         }
1955
1956     }
1957 }
1958
1959
1960
1961 static void parsesub (int k, struct expent* lval)
1962 /* Parse an expression with the binary minus operator. lval contains the
1963  * unprocessed left hand side of the expression and will contain the
1964  * result of the expression on return.
1965  */
1966 {
1967     struct expent lval2;
1968     unsigned flags;             /* Operation flags */
1969     type* lhst;                 /* Type of left hand side */
1970     type* rhst;                 /* Type of right hand side */
1971     CodeMark Mark1;             /* Save position of output queue */
1972     CodeMark Mark2;             /* Another position in the queue */
1973     int rscale;                 /* Scale factor for the result */
1974
1975
1976     /* Skip the MINUS token */
1977     NextToken ();
1978
1979     /* Get the left hand side type, initialize operation flags */
1980     lhst = lval->e_tptr;
1981     flags = 0;
1982     rscale = 1;                 /* Scale by 1, that is, don't scale */
1983
1984     /* Remember the output queue position, then bring the value onto the stack */
1985     Mark1 = GetCodePos ();
1986     exprhs (CF_NONE, k, lval);  /* --> primary register */
1987     Mark2 = GetCodePos ();
1988     g_push (TypeOf (lhst), 0);  /* --> stack */
1989
1990     /* Parse the right hand side */
1991     if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
1992
1993         /* The right hand side is constant. Get the rhs type. */
1994         rhst = lval2.e_tptr;
1995
1996         /* Check left hand side */
1997         if (k == 0 && lval->e_flags & E_MCONST) {
1998
1999             /* Both sides are constant, remove generated code */
2000             RemoveCode (Mark1);
2001             pop (TypeOf (lhst));        /* Clean up the stack */
2002
2003             /* Check for pointer arithmetic */
2004             if (IsPtr (lhst) && IsInt (rhst)) {
2005                 /* Left is pointer, right is int, must scale rhs */
2006                 lval->e_const -= lval2.e_const * PSizeOf (lhst);
2007                 /* Operate on pointers, result type is a pointer */
2008             } else if (IsPtr (lhst) && IsPtr (rhst)) {
2009                 /* Left is pointer, right is pointer, must scale result */
2010                 if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
2011                     Error (ERR_INCOMPATIBLE_POINTERS);
2012                 } else {
2013                     lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst);
2014                 }
2015                 /* Operate on pointers, result type is an integer */
2016                 lval->e_tptr = type_int;
2017             } else if (IsInt (lhst) && IsInt (rhst)) {
2018                 /* Integer subtraction */
2019                 typeadjust (lval, &lval2, 1);
2020                 lval->e_const -= lval2.e_const;
2021             } else {
2022                 /* OOPS */
2023                 Error (ERR_OP_NOT_ALLOWED);
2024             }
2025
2026             /* Result is constant, condition codes not set */
2027             lval->e_flags = E_MCONST;
2028             lval->e_test &= ~E_CC;
2029
2030         } else {
2031
2032             /* Left hand side is not constant, right hand side is.
2033              * Remove pushed value from stack.
2034              */
2035             RemoveCode (Mark2);
2036             pop (TypeOf (lhst));
2037
2038             if (IsPtr (lhst) && IsInt (rhst)) {
2039                 /* Left is pointer, right is int, must scale rhs */
2040                 lval2.e_const *= PSizeOf (lhst);
2041                 /* Operate on pointers, result type is a pointer */
2042                 flags = CF_PTR;
2043             } else if (IsPtr (lhst) && IsPtr (rhst)) {
2044                 /* Left is pointer, right is pointer, must scale result */
2045                 if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
2046                     Error (ERR_INCOMPATIBLE_POINTERS);
2047                 } else {
2048                     rscale = PSizeOf (lhst);
2049                 }
2050                 /* Operate on pointers, result type is an integer */
2051                 flags = CF_PTR;
2052                 lval->e_tptr = type_int;
2053             } else if (IsInt (lhst) && IsInt (rhst)) {
2054                 /* Integer subtraction */
2055                 flags = typeadjust (lval, &lval2, 1);
2056             } else {
2057                 /* OOPS */
2058                 Error (ERR_OP_NOT_ALLOWED);
2059             }
2060
2061             /* Do the subtraction */
2062             g_dec (flags | CF_CONST, lval2.e_const);
2063
2064             /* If this was a pointer subtraction, we must scale the result */
2065             if (rscale != 1) {
2066                 g_scale (flags, -rscale);
2067             }
2068
2069             /* Result is in primary register */
2070             lval->e_flags = E_MEXPR;
2071             lval->e_test &= ~E_CC;
2072
2073         }
2074
2075     } else {
2076
2077         /* Right hand side is not constant. Get the rhs type. */
2078         rhst = lval2.e_tptr;
2079
2080         /* Check for pointer arithmetic */
2081         if (IsPtr (lhst) && IsInt (rhst)) {
2082             /* Left is pointer, right is int, must scale rhs */
2083             g_scale (CF_INT, PSizeOf (lhst));
2084             /* Operate on pointers, result type is a pointer */
2085             flags = CF_PTR;
2086         } else if (IsPtr (lhst) && IsPtr (rhst)) {
2087             /* Left is pointer, right is pointer, must scale result */
2088             if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
2089                 Error (ERR_INCOMPATIBLE_POINTERS);
2090             } else {
2091                 rscale = PSizeOf (lhst);
2092             }
2093             /* Operate on pointers, result type is an integer */
2094             flags = CF_PTR;
2095             lval->e_tptr = type_int;
2096         } else if (IsInt (lhst) && IsInt (rhst)) {
2097             /* Integer subtraction. If the left hand side descriptor says that
2098              * the lhs is const, we have to remove this mark, since this is no
2099              * longer true, lhs is on stack instead.
2100              */
2101             if (lval->e_flags == E_MCONST) {
2102                 lval->e_flags = E_MEXPR;
2103             }
2104             /* Adjust operand types */
2105             flags = typeadjust (lval, &lval2, 0);
2106         } else {
2107             /* OOPS */
2108             Error (ERR_OP_NOT_ALLOWED);
2109         }
2110
2111         /* Generate code for the sub (the & is a hack here) */
2112         g_sub (flags & ~CF_CONST, 0);
2113
2114         /* If this was a pointer subtraction, we must scale the result */
2115         if (rscale != 1) {
2116             g_scale (flags, -rscale);
2117         }
2118
2119         /* Result is in primary register */
2120         lval->e_flags = E_MEXPR;
2121         lval->e_test &= ~E_CC;
2122     }
2123 }
2124
2125
2126
2127 static int hie8 (struct expent* lval)
2128 /* Process + and - binary operators. */
2129 {
2130     int k = hie9 (lval);
2131     while (curtok == TOK_PLUS || curtok == TOK_MINUS) {
2132
2133         if (curtok == TOK_PLUS) {
2134             parseadd (k, lval);
2135         } else {
2136             parsesub (k, lval);
2137         }
2138         k = 0;
2139     }
2140     return k;
2141 }
2142
2143
2144
2145
2146 static int hie7 (struct expent *lval)
2147 /* Parse << and >>. */
2148 {
2149     static GenDesc* hie7_ops [] = {
2150         &GenASL, &GenASR, 0
2151     };
2152     int UsedGen;
2153
2154     return hie_internal (hie7_ops, lval, hie8, &UsedGen);
2155 }
2156
2157
2158
2159 static int hie6 (struct expent *lval)
2160 /* process greater-than type comparators */
2161 {
2162     static GenDesc* hie6_ops [] = {
2163         &GenLT, &GenLE, &GenGE, &GenGT, 0
2164     };
2165     return hie_compare (hie6_ops, lval, hie7);
2166 }
2167
2168
2169
2170 static int hie5 (struct expent *lval)
2171 {
2172     static GenDesc* hie5_ops[] = {
2173         &GenEQ, &GenNE, 0
2174     };
2175     return hie_compare (hie5_ops, lval, hie6);
2176 }
2177
2178
2179
2180 static int hie4 (struct expent* lval)
2181 /* Handle & (bitwise and) */
2182 {
2183     static GenDesc* hie4_ops [] = {
2184         &GenAND, 0
2185     };
2186     int UsedGen;
2187
2188     return hie_internal (hie4_ops, lval, hie5, &UsedGen);
2189 }
2190
2191
2192
2193 static int hie3 (struct expent *lval)
2194 /* Handle ^ (bitwise exclusive or) */
2195 {
2196     static GenDesc* hie3_ops [] = {
2197         &GenXOR, 0
2198     };
2199     int UsedGen;
2200
2201     return hie_internal (hie3_ops, lval, hie4, &UsedGen);
2202 }
2203
2204
2205
2206 static int hie2 (struct expent *lval)
2207 /* Handle | (bitwise or) */
2208 {
2209     static GenDesc* hie2_ops [] = {
2210         &GenOR, 0
2211     };
2212     int UsedGen;
2213
2214     return hie_internal (hie2_ops, lval, hie3, &UsedGen);
2215 }
2216
2217
2218
2219 static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp)
2220 /* Process "exp && exp" */
2221 {
2222     int k;
2223     int lab;
2224     struct expent lval2;
2225
2226     k = hie2 (lval);
2227     if (curtok == TOK_BOOL_AND) {
2228
2229         /* Tell our caller that we're evaluating a boolean */
2230         *BoolOp = 1;
2231
2232         /* Get a label that we will use for false expressions */
2233         lab = GetLabel ();
2234
2235         /* If the expr hasn't set condition codes, set the force-test flag */
2236         if ((lval->e_test & E_CC) == 0) {
2237             lval->e_test |= E_FORCETEST;
2238         }
2239
2240         /* Load the value */
2241         exprhs (CF_FORCECHAR, k, lval);
2242
2243         /* Generate the jump */
2244         g_falsejump (CF_NONE, lab);
2245
2246         /* Parse more boolean and's */
2247         while (curtok == TOK_BOOL_AND) {
2248
2249             /* Skip the && */
2250             NextToken ();
2251
2252             /* Get rhs */
2253             k = hie2 (&lval2);
2254             if ((lval2.e_test & E_CC) == 0) {
2255                 lval2.e_test |= E_FORCETEST;
2256             }
2257             exprhs (CF_FORCECHAR, k, &lval2);
2258
2259             /* Do short circuit evaluation */
2260             if (curtok == TOK_BOOL_AND) {
2261                 g_falsejump (CF_NONE, lab);
2262             } else {
2263                 /* Last expression - will evaluate to true */
2264                 g_truejump (CF_NONE, TrueLab);
2265             }
2266         }
2267
2268         /* Define the false jump label here */
2269         g_defloclabel (lab);
2270
2271         /* Define the label */
2272         lval->e_flags = E_MEXPR;
2273         lval->e_test |= E_CC;   /* Condition codes are set */
2274         k = 0;
2275     }
2276     return k;
2277 }
2278
2279
2280
2281 static int hieOr (struct expent *lval)
2282 /* Process "exp || exp". */
2283 {
2284     int k;
2285     struct expent lval2;
2286     int BoolOp = 0;             /* Did we have a boolean op? */
2287     int AndOp;                  /* Did we have a && operation? */
2288     unsigned TrueLab;           /* Jump to this label if true */
2289     unsigned DoneLab;
2290
2291     /* Get a label */
2292     TrueLab = GetLabel ();
2293
2294     /* Call the next level parser */
2295     k = hieAnd (lval, TrueLab, &BoolOp);
2296
2297     /* Any boolean or's? */
2298     if (curtok == TOK_BOOL_OR) {
2299
2300         /* If the expr hasn't set condition codes, set the force-test flag */
2301         if ((lval->e_test & E_CC) == 0) {
2302             lval->e_test |= E_FORCETEST;
2303         }
2304
2305         /* Get first expr */
2306         exprhs (CF_FORCECHAR, k, lval);
2307
2308         /* For each expression jump to TrueLab if true. Beware: If we
2309          * had && operators, the jump is already in place!
2310          */
2311         if (!BoolOp) {
2312             g_truejump (CF_NONE, TrueLab);
2313         }
2314
2315         /* Remember that we had a boolean op */
2316         BoolOp = 1;
2317
2318         /* while there's more expr */
2319         while (curtok == TOK_BOOL_OR) {
2320
2321             /* skip the || */
2322             NextToken ();
2323
2324             /* Get a subexpr */
2325             AndOp = 0;
2326             k = hieAnd (&lval2, TrueLab, &AndOp);
2327             if ((lval2.e_test & E_CC) == 0) {
2328                 lval2.e_test |= E_FORCETEST;
2329             }
2330             exprhs (CF_FORCECHAR, k, &lval2);
2331
2332             /* If there is more to come, add shortcut boolean eval.
2333              * Beware: If we had && operators, the jump is already
2334              * in place!
2335              */
2336 #if     0
2337 /* Seems this sometimes generates wrong code */
2338             if (curtok == TOK_BOOL_OR && !AndOp) {
2339                 g_truejump (CF_NONE, TrueLab);
2340             }
2341 #else
2342             g_truejump (CF_NONE, TrueLab);
2343 #endif
2344         }
2345         lval->e_flags = E_MEXPR;
2346         lval->e_test |= E_CC;                   /* Condition codes are set */
2347         k = 0;
2348     }
2349
2350     /* If we really had boolean ops, generate the end sequence */
2351     if (BoolOp) {
2352         DoneLab = GetLabel ();
2353         g_getimmed (CF_INT | CF_CONST, 0, 0);   /* Load FALSE */
2354         g_falsejump (CF_NONE, DoneLab);
2355         g_defloclabel (TrueLab);
2356         g_getimmed (CF_INT | CF_CONST, 1, 0);   /* Load TRUE */
2357         g_defloclabel (DoneLab);
2358     }
2359     return k;
2360 }
2361
2362
2363
2364 static int hieQuest (struct expent *lval)
2365 /* Parse "lvalue ? exp : exp" */
2366 {
2367     int k;
2368     int labf;
2369     int labt;
2370     struct expent lval2;        /* Expression 2 */
2371     struct expent lval3;        /* Expression 3 */
2372     type* type2;                /* Type of expression 2 */
2373     type* type3;                /* Type of expression 3 */
2374     type* rtype;                /* Type of result */
2375     CodeMark Mark1;             /* Save position in output code */
2376     CodeMark Mark2;             /* Save position in output code */
2377
2378
2379
2380     k = hieOr (lval);
2381     if (curtok == TOK_QUEST) {
2382         NextToken ();
2383         if ((lval->e_test & E_CC) == 0) {
2384             /* Condition codes not set, force a test */
2385             lval->e_test |= E_FORCETEST;
2386         }
2387         exprhs (CF_NONE, k, lval);
2388         labf = GetLabel ();
2389         g_falsejump (CF_NONE, labf);
2390
2391         /* Parse second and third expression */
2392         expression1 (&lval2);
2393         labt = GetLabel ();
2394         ConsumeColon ();
2395         g_jump (labt);
2396         g_defloclabel (labf);
2397         expression1 (&lval3);
2398
2399         /* Check if any conversions are needed, if so, do them.
2400          * Conversion rules for ?: expression are:
2401          *   - if both expressions are int expressions, default promotion
2402          *     rules for ints apply.
2403          *   - if both expressions are pointers of the same type, the
2404          *     result of the expression is of this type.
2405          *   - if one of the expressions is a pointer and the other is
2406          *     a zero constant, the resulting type is that of the pointer
2407          *     type.
2408          *   - all other cases are flagged by an error.
2409          */
2410         type2 = lval2.e_tptr;
2411         type3 = lval3.e_tptr;
2412         if (IsInt (type2) && IsInt (type3)) {
2413
2414             /* Get common type */
2415             rtype = promoteint (type2, type3);
2416
2417             /* Convert the third expression to this type if needed */
2418             g_typecast (TypeOf (rtype), TypeOf (type3));
2419
2420             /* Setup a new label so that the expr3 code will jump around
2421              * the type cast code for expr2.
2422              */
2423             labf = GetLabel ();         /* Get new label */
2424             Mark1 = GetCodePos ();      /* Remember current position */
2425             g_jump (labf);              /* Jump around code */
2426
2427             /* The jump for expr2 goes here */
2428             g_defloclabel (labt);
2429
2430             /* Create the typecast code for expr2 */
2431             Mark2 = GetCodePos ();      /* Remember position */
2432             g_typecast (TypeOf (rtype), TypeOf (type2));
2433
2434             /* If the typecast did not produce code, remove the jump,
2435              * otherwise output the label.
2436              */
2437             if (GetCodePos() == Mark2) {
2438                 RemoveCode (Mark1);     /* Remove code */
2439             } else {
2440                 /* We have typecast code, output label */
2441                 g_defloclabel (labf);
2442                 labt = 0;               /* Mark other label as invalid */
2443             }
2444
2445         } else if (IsPtr (type2) && IsPtr (type3)) {
2446             /* Must point to same type */
2447             if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) {
2448                 Error (ERR_INCOMPATIBLE_TYPES);
2449             }
2450             /* Result has the common type */
2451             rtype = lval2.e_tptr;
2452         } else if (IsPtr (type2) && IsNullPtr (&lval3)) {
2453             /* Result type is pointer, no cast needed */
2454             rtype = lval2.e_tptr;
2455         } else if (IsNullPtr (&lval2) && IsPtr (type3)) {
2456             /* Result type is pointer, no cast needed */
2457             rtype = lval3.e_tptr;
2458         } else {
2459             Error (ERR_INCOMPATIBLE_TYPES);
2460             rtype = lval2.e_tptr;               /* Doesn't matter here */
2461         }
2462
2463         /* If we don't have the label defined until now, do it */
2464         if (labt) {
2465             g_defloclabel (labt);
2466         }
2467
2468         /* Setup the target expression */
2469         lval->e_flags = E_MEXPR;
2470         lval->e_tptr = rtype;
2471         k = 0;
2472     }
2473     return k;
2474 }
2475
2476
2477
2478 static void opeq (GenDesc* Gen, struct expent *lval, int k)
2479 /* Process "op=" operators. */
2480 {
2481     struct expent lval2;
2482     unsigned flags;
2483     CodeMark Mark;
2484     int MustScale;
2485
2486     NextToken ();
2487     if (k == 0) {
2488         Error (ERR_LVALUE_EXPECTED);
2489         return;
2490     }
2491
2492     /* Determine the type of the lhs */
2493     flags = TypeOf (lval->e_tptr);
2494     MustScale = (Gen->Func == g_add || Gen->Func == g_sub) &&
2495                 lval->e_tptr [0] == T_PTR;
2496
2497     /* Get the lhs address on stack (if needed) */
2498     PushAddr (lval);
2499
2500     /* Fetch the lhs into the primary register if needed */
2501     exprhs (CF_NONE, k, lval);
2502
2503     /* Bring the lhs on stack */
2504     Mark = GetCodePos ();
2505     g_push (flags, 0);
2506
2507     /* Evaluate the rhs */
2508     if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
2509         /* The resulting value is a constant. If the generator has the NOPUSH
2510          * flag set, don't push the lhs.
2511          */
2512         if (Gen->Flags & GEN_NOPUSH) {
2513             RemoveCode (Mark);
2514             pop (flags);
2515         }
2516         if (MustScale) {
2517             /* lhs is a pointer, scale rhs */
2518             lval2.e_const *= SizeOf (lval->e_tptr+1);
2519         }
2520
2521         /* If the lhs is character sized, the operation may be later done
2522          * with characters.
2523          */
2524         if (SizeOf (lval->e_tptr) == 1) {
2525             flags |= CF_FORCECHAR;
2526         }
2527
2528         /* Special handling for add and sub - some sort of a hack, but short code */
2529         if (Gen->Func == g_add) {
2530             g_inc (flags | CF_CONST, lval2.e_const);
2531         } else if (Gen->Func == g_sub) {
2532             g_dec (flags | CF_CONST, lval2.e_const);
2533         } else {
2534             Gen->Func (flags | CF_CONST, lval2.e_const);
2535         }
2536     } else {
2537         /* rhs is not constant and already in the primary register */
2538         if (MustScale) {
2539             /* lhs is a pointer, scale rhs */
2540             g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
2541         }
2542
2543         /* If the lhs is character sized, the operation may be later done
2544          * with characters.
2545          */
2546         if (SizeOf (lval->e_tptr) == 1) {
2547             flags |= CF_FORCECHAR;
2548         }
2549
2550         /* Adjust the types of the operands if needed */
2551         Gen->Func (g_typeadjust (flags, TypeOf (lval2.e_tptr)), 0);
2552     }
2553     store (lval);
2554     lval->e_flags = E_MEXPR;
2555 }
2556
2557
2558
2559 static void addsubeq (GenDesc* Gen, struct expent *lval, int k)
2560 /* Process the += and -= operators */
2561 {
2562     struct expent lval2;
2563     unsigned flags;
2564     int MustScale;
2565
2566
2567     if (k == 0) {
2568         Error (ERR_LVALUE_EXPECTED);
2569         return;
2570     }
2571
2572
2573     /* We're currently only able to handle some adressing modes */
2574     if ((lval->e_flags & E_MGLOBAL) == 0 &&     /* Global address? */
2575         (lval->e_flags & E_MLOCAL) == 0  &&     /* Local address? */
2576         (lval->e_flags & E_MCONST) == 0) {      /* Constant address? */
2577         /* Use generic routine */
2578         opeq (Gen, lval, k);
2579         return;
2580     }
2581
2582     /* Skip the operator */
2583     NextToken ();
2584
2585     /* Check if we have a pointer expression and must scale rhs */
2586     MustScale = (lval->e_tptr [0] == T_PTR);
2587
2588     /* Determine the code generator flags */
2589     flags = TypeOf (lval->e_tptr) | CF_FORCECHAR;
2590
2591     /* Evaluate the rhs */
2592     if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
2593         /* The resulting value is a constant. */
2594         if (MustScale) {
2595             /* lhs is a pointer, scale rhs */
2596             lval2.e_const *= SizeOf (lval->e_tptr+1);
2597         }
2598         flags |= CF_CONST;
2599     } else {
2600         /* rhs is not constant and already in the primary register */
2601         if (MustScale) {
2602             /* lhs is a pointer, scale rhs */
2603             g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
2604         }
2605     }
2606
2607     /* Adjust the rhs to the lhs */
2608     g_typeadjust (flags, TypeOf (lval2.e_tptr));
2609
2610     /* Output apropriate code */
2611     if (lval->e_flags & E_MGLOBAL) {
2612         /* Static variable */
2613         flags |= GlobalModeFlags (lval->e_flags);
2614         if (Gen->Tok == TOK_PLUS_ASSIGN) {
2615             g_addeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
2616         } else {
2617             g_subeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
2618         }
2619     } else if (lval->e_flags & E_MLOCAL) {
2620         /* ref to localvar */
2621         if (Gen->Tok == TOK_PLUS_ASSIGN) {
2622             g_addeqlocal (flags, lval->e_const, lval2.e_const);
2623         } else {
2624             g_subeqlocal (flags, lval->e_const, lval2.e_const);
2625         }
2626     } else if (lval->e_flags & E_MCONST) {
2627         /* ref to absolute address */
2628         flags |= CF_ABSOLUTE;
2629         if (Gen->Tok == TOK_PLUS_ASSIGN) {
2630             g_addeqstatic (flags, lval->e_const, 0, lval2.e_const);
2631         } else {
2632             g_subeqstatic (flags, lval->e_const, 0, lval2.e_const);
2633         }
2634     } else if (lval->e_flags & E_MEXPR) {
2635         /* Address in a/x. */
2636         if (Gen->Tok == TOK_PLUS_ASSIGN) {
2637             g_addeqind (flags, lval->e_const, lval2.e_const);
2638         } else {
2639             g_subeqind (flags, lval->e_const, lval2.e_const);
2640         }
2641     } else {
2642         Internal ("Invalid addressing mode");
2643     }
2644
2645     /* Expression is in the primary now */
2646     lval->e_flags = E_MEXPR;
2647 }
2648
2649
2650
2651 static void Assignment (struct expent* lval)
2652 /* Parse an assignment */
2653 {
2654     int k;
2655     struct expent lval2;
2656     unsigned flags;
2657     type* ltype = lval->e_tptr;
2658
2659     /* cc65 does not have full support for handling structs by value. Since
2660      * assigning structs is one of the more useful operations from this
2661      * familiy, allow it here.
2662      */
2663     if (IsStruct (ltype)) {
2664
2665         /* Bring the address of the lhs into the primary and push it */
2666         exprhs (0, 0, lval);
2667         g_push (CF_PTR | CF_UNSIGNED, 0);
2668
2669         /* Get the expression on the right of the '=' into the primary */
2670         k = hie1 (&lval2);
2671         if (k) {
2672             /* Get the address */
2673             exprhs (0, 0, &lval2);
2674         } else {
2675             /* We need an lvalue */
2676             Error (ERR_LVALUE_EXPECTED);
2677         }
2678
2679         /* Push the address (or whatever is in ax in case of errors) */
2680         g_push (CF_PTR | CF_UNSIGNED, 0);
2681
2682         /* Check for equality of the structs */
2683         if (!EqualTypes (ltype, lval2.e_tptr)) {
2684             Error (ERR_INCOMPATIBLE_TYPES);
2685         }
2686
2687         /* Load the size of the struct into the primary */
2688         g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, SizeOf (ltype), 0);
2689
2690         /* Call the memcpy function */
2691         g_call (CF_FIXARGC, "memcpy", 4);
2692
2693     } else {
2694
2695         /* Get the address on stack if needed */
2696         PushAddr (lval);
2697
2698         /* No struct, setup flags for the load */
2699         flags = SizeOf (ltype) == 1? CF_FORCECHAR : CF_NONE;
2700
2701         /* Get the expression on the right of the '=' into the primary */
2702         if (evalexpr (flags, hie1, &lval2) == 0) {
2703             /* Constant expression. Adjust the types */
2704             assignadjust (ltype, &lval2);
2705             /* Put the value into the primary register */
2706             lconst (flags, &lval2);
2707         } else {
2708             /* Expression is not constant and already in the primary */
2709             assignadjust (ltype, &lval2);
2710         }
2711
2712         /* Generate a store instruction */
2713         store (lval);
2714
2715     }
2716
2717     /* Value is still in primary */
2718     lval->e_flags = E_MEXPR;
2719 }
2720
2721
2722
2723 int hie1 (struct expent* lval)
2724 /* Parse first level of expression hierarchy. */
2725 {
2726     int k;
2727
2728     k = hieQuest (lval);
2729     switch (curtok) {
2730
2731         case TOK_RPAREN:
2732         case TOK_SEMI:
2733             return k;
2734
2735         case TOK_ASSIGN:
2736             NextToken ();
2737             if (k == 0) {
2738                 Error (ERR_LVALUE_EXPECTED);
2739             } else {
2740                 Assignment (lval);
2741             }
2742             break;
2743
2744         case TOK_PLUS_ASSIGN:
2745             addsubeq (&GenPASGN, lval, k);
2746             break;
2747
2748         case TOK_MINUS_ASSIGN:
2749             addsubeq (&GenSASGN, lval, k);
2750             break;
2751
2752         case TOK_MUL_ASSIGN:
2753             opeq (&GenMASGN, lval, k);
2754             break;
2755
2756         case TOK_DIV_ASSIGN:
2757             opeq (&GenDASGN, lval, k);
2758             break;
2759
2760         case TOK_MOD_ASSIGN:
2761             opeq (&GenMOASGN, lval, k);
2762             break;
2763
2764         case TOK_SHL_ASSIGN:
2765             opeq (&GenSLASGN, lval, k);
2766             break;
2767
2768         case TOK_SHR_ASSIGN:
2769             opeq (&GenSRASGN, lval, k);
2770             break;
2771
2772         case TOK_AND_ASSIGN:
2773             opeq (&GenAASGN, lval, k);
2774             break;
2775
2776         case TOK_XOR_ASSIGN:
2777             opeq (&GenXOASGN, lval, k);
2778             break;
2779
2780         case TOK_OR_ASSIGN:
2781             opeq (&GenOASGN, lval, k);
2782             break;
2783
2784         default:
2785             return k;
2786     }
2787     return 0;
2788 }
2789
2790
2791
2792 int hie0 (struct expent *lval)
2793 /* Parse comma operator. */
2794 {
2795     int k;
2796
2797     k = hie1 (lval);
2798     while (curtok == TOK_COMMA) {
2799         NextToken ();
2800         k = hie1 (lval);
2801     }
2802     return k;
2803 }
2804
2805
2806
2807 int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval)
2808 /* Will evaluate an expression via the given function. If the result is a
2809  * constant, 0 is returned and the value is put in the lval struct. If the
2810  * result is not constant, exprhs is called to bring the value into the
2811  * primary register and 1 is returned.
2812  */
2813 {
2814     int k;
2815
2816     /* Evaluate */
2817     k = f (lval);
2818     if (k == 0 && lval->e_flags == E_MCONST) {
2819         /* Constant expression */
2820         return 0;
2821     } else {
2822         /* Not constant, load into the primary */
2823         exprhs (flags, k, lval);
2824         return 1;
2825     }
2826 }
2827
2828
2829
2830 int expr (int (*func) (), struct expent *lval)
2831 /* Expression parser; func is either hie0 or hie1. */
2832 {
2833     int k;
2834     int savsp;
2835
2836     savsp = oursp;
2837
2838     k = (*func) (lval);
2839
2840     /* Do some checks if code generation is still constistent */
2841     if (savsp != oursp) {
2842         if (Debug) {
2843             fprintf (stderr, "oursp != savesp (%d != %d)\n", oursp, savsp);
2844         } else {
2845             Internal ("oursp != savsp (%d != %d)", oursp, savsp);
2846         }
2847     }
2848     return k;
2849 }
2850
2851
2852
2853 void expression1 (struct expent* lval)
2854 /* Evaluate an expression on level 1 (no comma operator) and put it into
2855  * the primary register
2856  */
2857 {
2858     memset (lval, 0, sizeof (*lval));
2859     exprhs (CF_NONE, expr (hie1, lval), lval);
2860 }
2861
2862
2863
2864 void expression (struct expent* lval)
2865 /* Evaluate an expression and put it into the primary register */
2866 {
2867     memset (lval, 0, sizeof (*lval));
2868     exprhs (CF_NONE, expr (hie0, lval), lval);
2869 }
2870
2871
2872
2873 void constexpr (struct expent* lval)
2874 /* Get a constant value */
2875 {
2876     memset (lval, 0, sizeof (*lval));
2877     if (expr (hie1, lval) != 0 || (lval->e_flags & E_MCONST) == 0) {
2878         Error (ERR_CONST_EXPR_EXPECTED);
2879         /* To avoid any compiler errors, make the expression a valid const */
2880         lval->e_flags = E_MCONST;
2881         lval->e_tptr = type_int;
2882         lval->e_const = 0;
2883     }
2884 }
2885
2886
2887
2888 void intexpr (struct expent* lval)
2889 /* Get an integer expression */
2890 {
2891     expression (lval);
2892     if (!IsInt (lval->e_tptr)) {
2893         Error (ERR_INT_EXPR_EXPECTED);
2894         /* To avoid any compiler errors, make the expression a valid int */
2895         lval->e_flags = E_MCONST;
2896         lval->e_tptr = type_int;
2897         lval->e_const = 0;
2898     }
2899 }
2900
2901
2902
2903 void boolexpr (struct expent* lval)
2904 /* Get a boolean expression */
2905 {
2906     /* Read an expression */
2907     expression (lval);
2908
2909     /* If it's an integer, it's ok. If it's not an integer, but a pointer,
2910      * the pointer used in a boolean context is also ok (Ootherwise check if it's a pointer
2911      * expression.
2912      */
2913     if (!IsInt (lval->e_tptr) && !IsPtr (lval->e_tptr)) {
2914         Error (ERR_INT_EXPR_EXPECTED);
2915         /* To avoid any compiler errors, make the expression a valid int */
2916         lval->e_flags = E_MCONST;
2917         lval->e_tptr = type_int;
2918         lval->e_const = 0;
2919     }
2920 }
2921
2922
2923
2924 void test (unsigned label, int cond)
2925 /* Generate code to perform test and jump if false. */
2926 {
2927     int k;
2928     struct expent lval;
2929
2930     /* Eat the parenthesis */
2931     ConsumeLParen ();
2932
2933     /* Prepare the expression, setup labels */
2934     memset (&lval, 0, sizeof (lval));
2935     lval.e_test = E_TEST;
2936
2937     /* Generate code to eval the expr */
2938     k = expr (hie0, &lval);
2939     if (k == 0 && lval.e_flags == E_MCONST) {
2940         /* Constant rvalue */
2941         if (cond == 0 && lval.e_const == 0) {
2942             g_jump (label);
2943             Warning (WARN_UNREACHABLE_CODE);
2944         } else if (cond && lval.e_const) {
2945             g_jump (label);
2946         }
2947         ConsumeRParen ();
2948         return;
2949     }
2950
2951     /* If the expr hasn't set condition codes, set the force-test flag */
2952     if ((lval.e_test & E_CC) == 0) {
2953         lval.e_test |= E_FORCETEST;
2954     }
2955
2956     /* Load the value into the primary register */
2957     exprhs (CF_FORCECHAR, k, &lval);
2958
2959     /* Check for the closing brace */
2960     ConsumeRParen ();
2961
2962     /* Generate the jump */
2963     if (cond) {
2964         g_truejump (CF_NONE, label);
2965     } else {
2966         /* Special case (putting this here is a small hack - but hey, the
2967          * compiler itself is one big hack...): If a semicolon follows, we
2968          * don't have a statement and may omit the jump.
2969          */
2970         if (curtok != TOK_SEMI) {
2971             g_falsejump (CF_NONE, label);
2972         }
2973     }
2974 }
2975
2976
2977
2978