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