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