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