]> git.sur5r.net Git - cc65/blob - src/cc65/parser.c
1d22b397c33146f55b46607cafc02ba3f751b0bb
[cc65] / src / cc65 / parser.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 parser.c                                  */
4 /*                                                                           */
5 /*                             Expression parser                             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 /* common */
41 #include "check.h"
42 #include "xmalloc.h"
43
44 /* cc65 */
45 #include "datatype.h"
46 #include "declare.h"
47 #include "error.h"
48 #include "exprheap.h"
49 #include "funcdesc.h"
50 #include "function.h"
51 #include "global.h"
52 #include "litpool.h"
53 #include "macrotab.h"
54 #include "preproc.h"
55 #include "scanner.h"
56 #include "stdfunc.h"
57 #include "symtab.h"
58 #include "typecmp.h"
59 #include "parser.h"
60
61
62
63 /*****************************************************************************/
64 /*                                 Forwards                                  */
65 /*****************************************************************************/
66
67
68
69 static ExprNode* UnaryExpr (void);
70 ExprNode* AssignExpr (void);
71 ExprNode* Expression (void);
72
73
74
75 /*****************************************************************************/
76 /*                             Helper functions                              */
77 /*****************************************************************************/
78
79
80
81 static int IsTypeExpr (void)
82 /* Return true if some sort of variable or type is waiting (helper for cast
83  * and sizeof() in hie10).
84  */
85 {
86     SymEntry* Entry;
87
88     return CurTok.Tok == TOK_LPAREN && (
89             (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) ||
90             (nxttok == TOK_CONST)                               ||
91             (nxttok  == TOK_IDENT                               &&
92             (Entry = FindSym (NextTok.Ident)) != 0              &&
93             IsTypeDef (Entry))
94            );
95 }
96
97
98
99 static int GetBoolRep (const ExprNode* N)
100 /* Get the boolean representation of a constant expression node */
101 {
102     if (IsClassInt (N->Type)) {
103         /* An integer constant */
104         return (N->IVal != 0);
105     } else if (IsClassFloat (N->Type)) {
106         /* A float constant */
107         return (N->FVal != 0.0);
108     } else if (IsTypeArray (N->Type) && IsTypeChar (Indirect (N->Type))) {
109         /* A string constant - useless but allowed */
110         return 1;
111     } else {
112         Internal ("GetBoolRep: Unknown type");
113         /* NOTREACHED */
114         return 0;
115     }
116 }
117
118
119
120 /*****************************************************************************/
121 /*                     Expression node helper functions                      */
122 /*****************************************************************************/
123
124
125
126 static ExprNode* GetIntNode (int Value)
127 /* Allocate a new expression node from the tree, make it a valid integer
128  * node and return it. Often used if an error occurs to get a safe expression
129  * tree.
130  */
131 {
132     ExprNode* N = AllocExprNode (NT_CONST, type_int, RVALUE);
133     N->IVal = Value;
134     return N;
135 }
136
137
138
139 /*****************************************************************************/
140 /*                                   Code                                    */
141 /*****************************************************************************/
142
143
144
145 ExprNode* DoAsm (void)
146 /* This function parses ASM statements. The syntax of the ASM directive
147  * looks like the one defined for C++ (C has no ASM directive), that is,
148  * a string literal in parenthesis.
149  */
150 {
151     ExprNode* N;
152
153
154     /* Skip the ASM */
155     NextToken ();
156
157     /* Need left parenthesis */
158     ConsumeLParen ();
159
160     /* Create a new expression node and assign a void type */
161     N = AllocExprNode (NT_ASM, type_void, RVALUE);
162
163     /* String literal */
164     if (CurTok.Tok != TOK_SCONST) {
165
166         /* Print an error */
167         Error (ERR_STRLIT_EXPECTED);
168
169         /* To be on the safe side later, insert an empty asm string */
170         AppendItem (N, xstrdup (""));
171
172     } else {
173
174         /* Insert a copy of the string into the expression node */
175         AppendItem (N, xstrdup (GetLiteral (CurTok.IVal)));
176
177         /* Reset the string pointer, effectivly clearing the string from the
178          * string table. Since we're working with one token lookahead, this
179          * will fail if the next token is also a string token, but that's a
180          * syntax error anyway, because we expect a right paren.
181          */
182         ResetLiteralOffs (CurTok.IVal);
183     }
184
185     /* Skip the string token */
186     NextToken ();
187
188     /* Closing paren needed */
189     ConsumeRParen ();
190
191     /* Return the created node */
192     return N;
193 }
194
195
196
197 static ExprNode* Primary (void)
198 /* Evaluate a primary expression */
199 {
200     ExprNode* N;
201
202     /* Process a parenthesized subexpression. In this case we don't need to
203      * allocate a new node ourselves.
204      */
205     if (CurTok.Tok == TOK_LPAREN) {
206         NextToken ();
207         N = Expression ();
208         ConsumeRParen ();
209         return N;
210     }
211
212     /* Check for an integer or character constant */
213     if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
214
215         /* Create the new node */
216         N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
217         N->IVal = CurTok.IVal;
218
219         /* Skip the token and return the result */
220         NextToken ();
221         return N;
222     }
223
224     /* Check for a float constant */
225     if (CurTok.Tok == TOK_FCONST) {
226
227         /* Create the new node */
228         N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
229         N->FVal = CurTok.FVal;
230
231         /* Skip the token and return the result */
232         NextToken ();
233         return N;
234     }
235
236     /* All others may only be used if the expression evaluation is not called
237      * recursively by the preprocessor.
238      */
239     if (Preprocessing) {
240         /* Illegal expression in PP mode */
241         Error (ERR_CPP_EXPR_EXPECTED);
242
243         /* Skip the token for error recovery */
244         NextToken ();
245
246         /* Return an integer constant */
247         return GetIntNode (0);
248     }
249
250     /* Identifier? */
251     if (CurTok.Tok == TOK_IDENT) {
252
253         /* Identifier */
254         SymEntry* Sym;
255         ident Ident;
256
257         /* Get a pointer to the symbol table entry */
258         Sym = FindSym (CurTok.Ident);
259
260         /* Is the symbol known? */
261         if (Sym) {
262
263             /* We found the symbol - skip the name token */
264             NextToken ();
265
266             /* Check for illegal symbol types */
267             if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
268                 /* Cannot use labels in expressions */
269                 Error (ERR_SYMBOL_KIND);
270                 return GetIntNode (0);
271             } else if (Sym->Flags & SC_TYPE) {
272                 /* Cannot use type symbols */
273                 Error (ERR_VAR_IDENT_EXPECTED);
274                 /* Assume an int type to make lval valid */
275                 return GetIntNode (0);
276             }
277
278             /* Handle enum values as constant integers */
279             if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
280
281                 N = GetIntNode (Sym->V.EnumVal);
282
283             } else {
284
285                 /* All symbols besides functions and arrays are lvalues */
286                 int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type));
287
288                 /* Create the node */
289                 N = AllocExprNode (NT_SYM, Sym->Type, LVal);
290
291                 /* Set the symbol pointer */
292                 SetNodeSym (N, Sym);
293             }
294
295             /* The symbol is referenced now */
296             Sym->Flags |= SC_REF;
297
298         } else {
299
300             /* We did not find the symbol. Remember the name, then skip it */
301             strcpy (Ident, CurTok.Ident);
302             NextToken ();
303
304             /* IDENT is either an auto-declared function or an undefined
305              * variable.
306              */
307             if (CurTok.Tok == TOK_LPAREN) {
308
309                 /* Warn about the use of a function without prototype */
310                 Warning (WARN_FUNC_WITHOUT_PROTO);
311
312                 /* Declare a function returning int. For that purpose, prepare
313                  * a function signature for a function having an empty param
314                  * list and returning int.
315                  */
316                 Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
317                 N   = AllocExprNode (NT_SYM, Sym->Type, RVALUE);
318                 SetNodeSym (N, Sym);
319
320             } else {
321
322                 /* Print an error about an undeclared variable */
323                 Error (ERR_UNDEFINED_SYMBOL, Ident);
324
325                 /* Undeclared Variable */
326                 Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
327                 N   = AllocExprNode (NT_SYM, Sym->Type, LVALUE);
328                 SetNodeSym (N, Sym);
329
330             }
331
332         }
333
334     } else if (CurTok.Tok == TOK_SCONST) {
335
336         /* String literal */
337         N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (CurTok.IVal))), RVALUE);
338         N->IVal = CurTok.IVal;
339
340     } else if (CurTok.Tok == TOK_ASM) {
341
342         /* ASM statement? */
343         N = DoAsm ();
344
345     } else if (CurTok.Tok == TOK_A) {
346
347         /* A register */
348         N = AllocExprNode (NT_REG_A, type_uchar, LVALUE);
349
350     } else if (CurTok.Tok == TOK_X) {
351
352         /* X register */
353         N = AllocExprNode (NT_REG_X, type_uchar, LVALUE);
354
355     } else if (CurTok.Tok == TOK_Y) {
356
357         /* Y register */
358         N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE);
359
360     } else if (CurTok.Tok == TOK_AX) {
361
362         /* AX pseudo register */
363         N = AllocExprNode (NT_REG_AX, type_uint, LVALUE);
364
365     } else if (CurTok.Tok == TOK_EAX) {
366
367         /* EAX pseudo register */
368         N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE);
369
370     } else {
371
372         /* Illegal primary. */
373         Error (ERR_EXPR_EXPECTED);
374         N = GetIntNode (0);
375
376     }
377
378     /* Return the new node */
379     return N;
380 }
381
382
383
384 static ExprNode* DoArray (ExprNode* Left)
385 /* Handle arrays */
386 {
387     ExprNode* Right;
388     ExprNode* Root;
389     type*     ElementType;
390
391
392     /* Skip the bracket */
393     NextToken ();
394
395     /* Get the index */
396     Right = Expression ();
397
398     /* Check the types. As special "C" feature, accept a reversal of base and
399      * index types:
400      *   char C = 3["abcdefg"];
401      * is legal C!
402      */
403     if (IsClassPtr (Left->Type)) {
404         /* Right side must be some sort of integer */
405         if (!IsClassInt (Right->Type)) {
406             /* Print an error */
407             Error (ERR_CANNOT_SUBSCRIPT);
408             /* To avoid problems later, create a new, legal subscript
409              * expression
410              */
411             Right = GetIntNode (0);
412         }
413     } else if (IsClassPtr (Right->Type)) {
414
415         ExprNode* Tmp;
416
417         /* Left side must be some sort of integer */
418         if (!IsClassInt (Right->Type)) {
419             /* Print an error */
420             Error (ERR_CANNOT_SUBSCRIPT);
421             /* To avoid problems later, create a new, legal subscript
422              * expression
423              */
424             Left = GetIntNode (0);
425         }
426
427         /* Swap the expression to it's normal form */
428         Tmp   = Right;
429         Right = Left;
430         Left  = Tmp;
431
432     } else {
433         /* Invalid array expression. Skip the closing bracket, then return
434          * an integer instead of the array expression to be safe later.
435          */
436         Error (ERR_CANNOT_SUBSCRIPT);
437         ConsumeRBrack ();
438         return GetIntNode (0);
439     }
440
441     /* Skip the right bracket */
442     ConsumeRBrack ();
443
444     /* Get the type of the array elements */
445     ElementType = Indirect (Left->Type);
446
447     /* Allocate the branch node for the array expression */
448     Root = AllocExprNode (NT_ARRAY_SUBSCRIPT,
449                           ElementType,
450                           IsTypeArray (ElementType)? RVALUE : LVALUE);
451
452     /* Setup the branches */
453     SetLeftNode (Root, Left);
454     SetRightNode (Root, Right);
455
456     /* ...and return it */
457     return Root;
458 }
459
460
461
462 static ExprNode* DoStruct (ExprNode* Left)
463 /* Process struct field access */
464 {
465     nodetype_t  NT;
466     ident       Ident;
467     type*       StructType;
468     ExprNode*   Right;
469     ExprNode*   Root;
470     SymEntry*   Field;
471
472
473     /* Type check */
474     StructType = Left->Type;
475     if (CurTok.Tok == TOK_PTR_REF) {
476         NT = NT_STRUCTPTR_ACCESS;
477         if (!IsTypePtr (StructType)) {
478             Error (ERR_STRUCT_PTR_EXPECTED);
479             return GetIntNode (0);
480         }
481         StructType = Indirect (StructType);
482     } else {
483         NT = NT_STRUCT_ACCESS;
484     }
485     if (!IsClassStruct (StructType)) {
486         Error (ERR_STRUCT_EXPECTED);
487         return GetIntNode (0);
488     }
489
490     /* Skip the token and check for an identifier */
491     NextToken ();
492     if (CurTok.Tok != TOK_IDENT) {
493         /* Print an error */
494         Error (ERR_IDENT_EXPECTED);
495         /* Return an integer expression instead */
496         return GetIntNode (0);
497     }
498
499     /* Get the symbol table entry and check for a struct field */
500     strcpy (Ident, CurTok.Ident);
501     NextToken ();
502     Field = FindStructField (StructType, Ident);
503     if (Field == 0) {
504         /* Struct field not found */
505         Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
506         /* Return an integer expression instead */
507         return GetIntNode (0);
508     }
509
510     /* Allocate and set up the right (== field) node */
511     Right = AllocExprNode (NT_SYM, Field->Type, RVALUE);
512     SetNodeSym (Right, Field);
513
514     /* Allocate the branch node for the resulting expression */
515     Root = AllocExprNode (NT, Right->Type,
516                           IsTypeArray (Right->Type)? RVALUE : LVALUE);
517
518     /* Setup the branches */
519     SetLeftNode (Root, Left);
520     SetRightNode (Root, Right);
521
522     /* ...and return it */
523     return Root;
524 }
525
526
527
528 static ExprNode* DoFunctionCall (ExprNode* Left)
529 /* Process a function call */
530 {
531     type*       ResultType;     /* Type of function result */
532     FuncDesc*   Func;           /* Function descriptor */
533     ExprNode*   Root;           /* Function call node */
534     int         Ellipsis;       /* True if we have an open param list */
535     SymEntry*   Param;          /* Current formal parameter */
536     unsigned    ParamCount;     /* Actual parameter count */
537     unsigned    ParamSize;      /* Number of parameter bytes */
538
539
540     /* Type check */
541     if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) {
542
543         /* Call to non function */
544         Error (ERR_ILLEGAL_FUNC_CALL);
545
546         /* Free the old node */
547         FreeExprNode (Left);
548
549         /* Return something safe */
550         return GetIntNode (0);
551     }
552
553     /* Get the type of the function result */
554     ResultType = Left->Type;
555     if (IsTypeFuncPtr (Left->Type)) {
556         ++ResultType;
557     }
558     ResultType += DECODE_SIZE + 1;      /* Set to result type */
559
560     /* Skip the opening parenthesis */
561     NextToken ();
562
563     /* Allocate the function call node */
564     Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE);
565
566     /* Get a pointer to the function descriptor from the type string */
567     Func = GetFuncDesc (Left->Type);
568
569     /* Initialize vars to keep gcc silent */
570     Param = 0;
571
572     /* Parse the parameter list */
573     ParamSize  = 0;
574     ParamCount = 0;
575     Ellipsis   = 0;
576     while (CurTok.Tok != TOK_RPAREN) {
577
578         /* Count arguments */
579         ++ParamCount;
580
581         /* Fetch the pointer to the next argument, check for too many args */
582         if (ParamCount <= Func->ParamCount) {
583             if (ParamCount == 1) {
584                 /* First argument */
585                 Param = Func->SymTab->SymHead;
586             } else {
587                 /* Next argument */
588                 Param = Param->NextSym;
589                 CHECK ((Param->Flags & SC_PARAM) != 0);
590             }
591         } else if (!Ellipsis) {
592             /* Too many arguments. Do we have an open param list? */
593             if ((Func->Flags & FD_ELLIPSIS) == 0) {
594                 /* End of param list reached, no ellipsis */
595                 Error (ERR_TOO_MANY_FUNC_ARGS);
596             }
597             /* Assume an ellipsis even in case of errors to avoid an error
598              * message for each other argument.
599              */
600             Ellipsis = 1;
601         }
602
603         /* Get the parameter value expression tree and add it to the parameter
604          * list.
605          */
606         AppendItem (Root, AssignExpr ());
607
608         /* Check for end of argument list */
609         if (CurTok.Tok != TOK_COMMA) {
610             break;
611         }
612         NextToken ();
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     /* Return the function call node */
624     return Root;
625 }
626
627
628
629 static ExprNode* DoPostIncDec (ExprNode* Left)
630 /* Handle postincrement and postdecrement */
631 {
632     ExprNode* Root;
633
634     /* Determine the type of the node */
635     nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_POST_INC : NT_POST_DEC;
636
637     /* Skip the operator token */
638     NextToken ();
639
640     /* The operand must be an lvalue */
641     if (Left->LValue == 0) {
642
643         /* Print a diagnostics */
644         Error (ERR_LVALUE_EXPECTED);
645
646         /* It is safe to return the operand expression and probably better
647          * than returning an int, since the operand expression already has
648          * the correct type as expected by the program at this place, and
649          * it is even an rvalue.
650          */
651         return Left;
652     }
653
654     /* Setup the expression tree */
655     Root = AllocExprNode (NT, Left->Type, RVALUE);
656     SetLeftNode (Root, Left);
657
658     /* Return the new node */
659     return Root;
660 }
661
662
663
664 static ExprNode* PostfixExpr (void)
665 {
666     /* Get the lower level expression */
667     ExprNode* Root = Primary ();
668
669     /* */
670     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN  ||
671            CurTok.Tok == TOK_DOT    || CurTok.Tok == TOK_PTR_REF ||
672            CurTok.Tok == TOK_INC    || CurTok.Tok == TOK_DEC) {
673
674         /* This is for us */
675         switch (CurTok.Tok) {
676
677             case TOK_LBRACK:
678                 Root = DoArray (Root);
679                 break;
680
681             case TOK_LPAREN:
682                 Root = DoFunctionCall (Root);
683                 break;
684
685             case TOK_DOT:
686             case TOK_PTR_REF:
687                 Root = DoStruct (Root);
688                 break;
689
690             case TOK_INC:
691             case TOK_DEC:
692                 Root = DoPostIncDec (Root);
693                 break;
694
695             default:
696                 Internal ("Unexpected token");
697
698         }
699     }
700
701     /* Return the result */
702     return Root;
703 }
704
705
706
707 static ExprNode* DoPreIncDec (void)
708 /* Handle preincrement and predecrement */
709 {
710     ExprNode* Op;
711     ExprNode* Root;
712
713     /* Determine the type of the node */
714     nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_PRE_INC : NT_PRE_DEC;
715
716     /* Skip the operator token */
717     NextToken ();
718
719     /* Get the expression to increment or decrement */
720     Op = UnaryExpr ();
721
722     /* The operand must be an lvalue */
723     if (Op->LValue == 0) {
724
725         /* Print a diagnostics */
726         Error (ERR_LVALUE_EXPECTED);
727
728         /* It is safe to return the operand expression and probably better
729          * than returning an int, since the operand expression already has
730          * the correct type as expected by the program at this place, and
731          * it is even an rvalue.
732          */
733         return Op;
734     }
735
736     /* Setup the expression tree */
737     Root = AllocExprNode (NT, Op->Type, RVALUE);
738     SetLeftNode (Root, Op);
739
740     /* Return the new node */
741     return Root;
742 }
743
744
745
746 static ExprNode* DoUnaryPlusMinus (void)
747 /* Handle unary +/- */
748 {
749     ExprNode* Op;
750     ExprNode* Root;
751
752     /* Remember the current token for later, then skip it */
753     token_t Tok = CurTok.Tok;
754     NextToken ();
755
756     /* Get the operand */
757     Op = UnaryExpr ();
758
759     /* Type check */
760     if (!IsClassInt (Op->Type) && !IsClassFloat (Op->Type)) {
761
762         /* Display diagnostic */
763         Error (ERR_SYNTAX);
764
765         /* Free the errorneous node */
766         FreeExprNode (Op);
767
768         /* Return something that makes sense later */
769         return GetIntNode (0);
770     }
771
772     /* In case of PLUS, we must do nothing */
773     if (Tok == TOK_PLUS) {
774
775         /* Return the operand unchanged */
776         return Op;
777
778     } else if (Op->NT == NT_CONST) {
779
780         /* The value is constant, change it according to the insn */
781         if (IsClassInt (Op->Type)) {
782             /* Integer */
783             Op->IVal = -Op->IVal;
784         } else {
785             /* Float */
786             Op->FVal = -Op->FVal;
787         }
788
789         /* Return the operand itself */
790         return Op;
791
792     } else {
793
794         /* Non constant value, setup the expression tree */
795         Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
796         SetLeftNode (Root, Op);
797
798     }
799
800     /* Return the new node */
801     return Root;
802 }
803
804
805
806 static ExprNode* DoComplement (void)
807 /* Handle ~ */
808 {
809     ExprNode* Op;
810     ExprNode* Root;
811
812     /* Skip the operator token */
813     NextToken ();
814
815     /* Get the operand */
816     Op = UnaryExpr ();
817
818     /* Type check */
819     if (!IsClassInt (Op->Type)) {
820
821         /* Display diagnostic */
822         Error (ERR_OP_NOT_ALLOWED);
823
824         /* Free the errorneous node */
825         FreeExprNode (Op);
826
827         /* Return something that makes sense later */
828         return GetIntNode (0);
829     }
830
831     /* If the operand is constant, handle the operation directly */
832     if (Op->NT == NT_CONST) {
833
834         /* Change the value and return the operand node */
835         Op->IVal = ~Op->IVal;
836         return Op;
837
838     } else {
839
840         /* Setup the expression tree and return the new node */
841         Root = AllocExprNode (NT_COMPLEMENT, Op->Type, RVALUE);
842         SetLeftNode (Root, Op);
843         return Root;
844     }
845 }
846
847
848
849 static ExprNode* DoBoolNot (void)
850 /* Handle ! */
851 {
852     ExprNode* Op;
853     ExprNode* Root;
854
855     /* Skip the operator token */
856     NextToken ();
857
858     /* Get the operand */
859     Op = UnaryExpr ();
860
861     /* The boolean NOT operator eats anything - no need for a type check. */
862
863     /* Setup the expression tree and return the new node */
864     Root = AllocExprNode (NT_BOOL_NOT, type_int, RVALUE);
865     SetLeftNode (Root, Op);
866     return Root;
867 }
868
869
870
871 static ExprNode* DoAddress (void)
872 /* Handle the address operator & */
873 {
874     ExprNode* Op;
875
876     /* Skip the operator */
877     NextToken ();
878
879     /* Get the operand */
880     Op = UnaryExpr ();
881
882     /* Accept using the address operator with arrays. This is harmless, it
883      * will just be as using the array without the operator.
884      */
885     if (IsTypeArray (Op->Type)) {
886         return Op;
887     }
888
889     /* We cannot operate on rvalues */
890     if (Op->LValue == 0) {
891
892         ExprNode* Root;
893
894         /* Print diagnostics */
895         Error (ERR_ILLEGAL_ADDRESS);
896
897         /* Free the problematic node */
898         FreeExprNode (Op);
899
900         /* Return something that is safe later */
901         Root = AllocExprNode (NT_CONST, PointerTo (type_void), 0);
902         return Root;
903
904     }
905
906     /* Create the operator node and return it */
907     return AllocExprNode (NT_ADDRESS, PointerTo (Op->Type), RVALUE);
908 }
909
910
911
912 static ExprNode* DoIndirect (void)
913 /* Handle the indirection operaror * */
914 {
915     ExprNode* Op;
916     type*     ResultType;
917     int       LVal;
918
919     /* Skip the operator */
920     NextToken ();
921
922     /* Get the operand */
923     Op = UnaryExpr ();
924
925     /* Type check */
926     if (!IsClassPtr (Op->Type)) {
927
928         /* Print diagnostics */
929         Error (ERR_ILLEGAL_INDIRECT);
930
931         /* Free the problematic node */
932         FreeExprNode (Op);
933
934         /* Return something that is safe later ### */
935         return GetIntNode (0);
936
937     }
938
939     /* Get the type of the result */
940     ResultType = Indirect (Op->Type);
941
942     /* The result is an lvalue if it is not an array */
943     LVal = IsTypeArray (ResultType)? RVALUE : LVALUE;
944
945     /* Create the operator node and return it */
946     return AllocExprNode (NT_INDIRECT, ResultType, LVal);
947 }
948
949
950
951 static ExprNode* DoSizeOf (void)
952 /* Handle the sizeof operator */
953 {
954     ExprNode*     N;
955     unsigned long Size;
956
957     /* Skip the left paren */
958     NextToken ();
959
960     /* A type or an actual variable access may follow */
961     if (IsTypeExpr ()) {
962
963         type    Type[MAXTYPELEN];
964
965         /* A type in parenthesis. Skip the left paren. */
966         NextToken ();
967
968         /* Read the type and calculate the size. */
969         Size = SizeOf (ParseType (Type));
970
971         /* Closing paren must follow */
972         ConsumeRParen ();
973
974     } else {
975
976         /* Some other entity */
977         N = UnaryExpr ();
978
979         /* Get the size */
980         Size = SizeOf (N->Type);
981
982         /* Free the node */
983         FreeExprNode (N);
984
985     }
986
987     /* Create a constant node with type size_t and return it */
988     N = AllocExprNode (NT_CONST, type_size_t, RVALUE);
989     N->IVal = Size;
990     return N;
991 }
992
993
994
995 static ExprNode* DoTypeCast (void)
996 /* Handle type casts */
997 {
998     type      TargetType[MAXTYPELEN];
999     ExprNode* Op;
1000     ExprNode* Root;
1001
1002     /* Skip the left paren */
1003     NextToken ();
1004
1005     /* Read the type */
1006     ParseType (TargetType);
1007
1008     /* Closing paren */
1009     ConsumeRParen ();
1010
1011     /* Read the expression we have to cast */
1012     Op = UnaryExpr ();
1013
1014     /* As a minor optimization, check if the type is already correct. If so,
1015      * do nothing.
1016      */
1017     if (TypeCmp (TargetType, Op->Type) >= TC_EQUAL) {
1018
1019         /* Just return the operand as is */
1020         return Op;
1021
1022     } else {
1023
1024         /* Must be casted. Setup the expression tree and return the new node */
1025         Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
1026         SetLeftNode (Root, Op);
1027         return Root;
1028
1029     }
1030 }
1031
1032
1033
1034 static ExprNode* UnaryExpr (void)
1035 {
1036     /* */
1037     if (CurTok.Tok == TOK_INC    || CurTok.Tok == TOK_DEC      ||
1038         CurTok.Tok == TOK_PLUS   || CurTok.Tok == TOK_MINUS    ||
1039         CurTok.Tok == TOK_COMP   || CurTok.Tok == TOK_BOOL_NOT ||
1040         CurTok.Tok == TOK_AND    || CurTok.Tok == TOK_STAR     ||
1041         CurTok.Tok == TOK_SIZEOF || IsTypeExpr ()) {
1042
1043         /* Check the token */
1044         switch (CurTok.Tok) {
1045
1046             case TOK_INC:
1047             case TOK_DEC:
1048                 return DoPreIncDec ();
1049
1050             case TOK_PLUS:
1051             case TOK_MINUS:
1052                 return DoUnaryPlusMinus ();
1053
1054             case TOK_COMP:
1055                 return DoComplement ();
1056
1057             case TOK_BOOL_NOT:
1058                 return DoBoolNot ();
1059
1060             case TOK_AND:
1061                 return DoAddress ();
1062
1063             case TOK_STAR:
1064                 return DoIndirect ();
1065
1066             case TOK_SIZEOF:
1067                 return DoSizeOf ();
1068
1069             default:
1070                 /* Type cast */
1071                 return DoTypeCast ();
1072
1073         }
1074
1075     } else {
1076
1077         /* Call the lower level */
1078         return PostfixExpr ();
1079
1080     }
1081 }
1082
1083
1084
1085 static ExprNode* MultExpr (void)
1086 /* Handle multiplicative expressions: '*' '/' and '%' */
1087 {
1088     /* Get the left leave */
1089     ExprNode* Root = UnaryExpr ();
1090
1091     /* Check if this is for us */
1092     while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV || CurTok.Tok == TOK_MOD) {
1093
1094         switch (CurTok.Tok) {
1095
1096             case TOK_MUL:
1097                 break;
1098
1099             case TOK_DIV:
1100                 break;
1101
1102             case TOK_MOD:
1103                 break;
1104
1105             default:
1106                 Internal ("Unexpected token");
1107         }
1108
1109     }
1110
1111     /* Return the resulting expression */
1112     return Root;
1113 }
1114
1115
1116
1117 static ExprNode* AddExpr (void)
1118 /* Handle additive expressions: '+' and '-' */
1119 {
1120     /* Get the left leave */
1121     ExprNode* Root = MultExpr ();
1122
1123     /* Check if this is for us */
1124     while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) {
1125
1126         switch (CurTok.Tok) {
1127
1128             case TOK_PLUS:
1129                 break;
1130
1131             case TOK_MINUS:
1132                 break;
1133
1134             default:
1135                 Internal ("Unexpected token");
1136         }
1137
1138     }
1139
1140     /* Return the resulting expression */
1141     return Root;
1142 }
1143
1144
1145
1146 static ExprNode* ShiftExpr (void)
1147 /* Handle shift expressions: '<<' and '>>' */
1148 {
1149     /* Get the left leave */
1150     ExprNode* Root = AddExpr ();
1151
1152     /* Check if this is for us */
1153     while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
1154
1155         switch (CurTok.Tok) {
1156
1157             case TOK_SHL:
1158                 break;
1159
1160             case TOK_SHR:
1161                 break;
1162
1163             default:
1164                 Internal ("Unexpected token");
1165         }
1166
1167     }
1168
1169     /* Return the resulting expression */
1170     return Root;
1171 }
1172
1173
1174
1175 static ExprNode* RelationalExpr (void)
1176 /* Handle relational expressions: '<=', '<', '>=' and '>' */
1177 {
1178     /* Get the left leave */
1179     ExprNode* Root = ShiftExpr ();
1180
1181     /* Check if this is for us */
1182     while (CurTok.Tok == TOK_LE || CurTok.Tok == TOK_LT ||
1183            CurTok.Tok == TOK_GE || CurTok.Tok == TOK_GT) {
1184
1185         switch (CurTok.Tok) {
1186
1187             case TOK_LE:
1188                 break;
1189
1190             case TOK_LT:
1191                 break;
1192
1193             case TOK_GE:
1194                 break;
1195
1196             case TOK_GT:
1197                 break;
1198
1199             default:
1200                 Internal ("Unexpected token");
1201         }
1202
1203     }
1204
1205     /* Return the resulting expression */
1206     return Root;
1207 }
1208
1209
1210
1211 static ExprNode* EqualityExpr (void)
1212 /* Handle equality expressions: '==' and '!=' */
1213 {
1214     /* Get the left leave */
1215     ExprNode* Root = RelationalExpr ();
1216
1217     /* Check if this is for us */
1218     while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE) {
1219
1220         switch (CurTok.Tok) {
1221
1222             case TOK_EQ:
1223                 break;
1224
1225             case TOK_NE:
1226                 break;
1227
1228             default:
1229                 Internal ("Unexpected token");
1230         }
1231
1232     }
1233
1234     /* Return the resulting expression */
1235     return Root;
1236 }
1237
1238
1239
1240 static ExprNode* AndExpr (void)
1241 /* Handle and expressions: '&' */
1242 {
1243     /* Get the left leave */
1244     ExprNode* Root = EqualityExpr ();
1245
1246     /* Check if this is for us */
1247     while (CurTok.Tok == TOK_AND) {
1248
1249         ExprNode* Left = Root;
1250         ExprNode* Right;
1251
1252         /* Skip the token */
1253         NextToken ();
1254
1255         /* Get the right operand */
1256         Right = EqualityExpr ();
1257
1258         /* Type check */
1259         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1260
1261             /* Print a diagnostic */
1262             Error (ERR_OP_NOT_ALLOWED);
1263
1264             /* Remove the unneeded nodes */
1265             FreeExprNode (Right);
1266             FreeExprNode (Left);
1267
1268             /* Create something safe */
1269             Root = GetIntNode (0);
1270
1271         } else {
1272
1273             /* Check if both operands are constant */
1274             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1275
1276                 /* Get the constant result */
1277                 int Result = GetBoolRep (Left) & GetBoolRep (Right);
1278
1279                 /* Remove the unneeded nodes */
1280                 FreeExprNode (Right);
1281                 FreeExprNode (Left);
1282
1283                 /* Create a constant result */
1284                 Root = GetIntNode (Result);
1285
1286             } else {
1287
1288                 /* Make an operator node */
1289                 Root = AllocExprNode (NT_AND, type_int, RVALUE);
1290                 SetRightNode (Root, Right);
1291                 SetLeftNode (Root, Left);
1292
1293             }
1294         }
1295     }
1296
1297     /* Return the resulting expression */
1298     return Root;
1299 }
1300
1301
1302
1303 static ExprNode* XorExpr (void)
1304 /* Handle xor expressions: '^' */
1305 {
1306     /* Get the left leave */
1307     ExprNode* Root = AndExpr ();
1308
1309     /* Check if this is for us */
1310     while (CurTok.Tok == TOK_XOR) {
1311
1312         ExprNode* Left = Root;
1313         ExprNode* Right;
1314
1315         /* Skip the token */
1316         NextToken ();
1317
1318         /* Get the right operand */
1319         Right = AndExpr ();
1320
1321         /* Type check */
1322         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1323
1324             /* Print a diagnostic */
1325             Error (ERR_OP_NOT_ALLOWED);
1326
1327             /* Remove the unneeded nodes */
1328             FreeExprNode (Right);
1329             FreeExprNode (Left);
1330
1331             /* Create something safe */
1332             Root = GetIntNode (0);
1333
1334         } else {
1335
1336             /* Check if both operands are constant */
1337             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1338
1339                 /* Get the constant result */
1340                 int Result = GetBoolRep (Left) ^ GetBoolRep (Right);
1341
1342                 /* Remove the unneeded nodes */
1343                 FreeExprNode (Right);
1344                 FreeExprNode (Left);
1345
1346                 /* Create a constant result */
1347                 Root = GetIntNode (Result);
1348
1349             } else {
1350
1351                 /* Make an operator node */
1352                 Root = AllocExprNode (NT_XOR, type_int, RVALUE);
1353                 SetRightNode (Root, Right);
1354                 SetLeftNode (Root, Left);
1355
1356             }
1357         }
1358     }
1359
1360     /* Return the resulting expression */
1361     return Root;
1362 }
1363
1364
1365
1366 static ExprNode* OrExpr (void)
1367 /* Handle or expressions: '|' */
1368 {
1369     /* Get the left leave */
1370     ExprNode* Root = XorExpr ();
1371
1372     /* Check if this is for us */
1373     while (CurTok.Tok == TOK_OR) {
1374
1375         ExprNode* Left = Root;
1376         ExprNode* Right;
1377
1378         /* Skip the token */
1379         NextToken ();
1380
1381         /* Get the right operand */
1382         Right = XorExpr ();
1383
1384         /* Type check */
1385         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1386
1387             /* Print a diagnostic */
1388             Error (ERR_OP_NOT_ALLOWED);
1389
1390             /* Remove the unneeded nodes */
1391             FreeExprNode (Right);
1392             FreeExprNode (Left);
1393
1394             /* Create something safe */
1395             Root = GetIntNode (0);
1396
1397         } else {
1398
1399             /* Check if both operands are constant */
1400             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1401
1402                 /* Get the constant result */
1403                 int Result = GetBoolRep (Left) | GetBoolRep (Right);
1404
1405                 /* Remove the unneeded nodes */
1406                 FreeExprNode (Right);
1407                 FreeExprNode (Left);
1408
1409                 /* Create a constant result */
1410                 Root = GetIntNode (Result);
1411
1412             } else {
1413
1414                 /* Make an operator node */
1415                 Root = AllocExprNode (NT_OR, type_int, RVALUE);
1416                 SetRightNode (Root, Right);
1417                 SetLeftNode (Root, Left);
1418
1419             }
1420         }
1421     }
1422
1423     /* Return the resulting expression */
1424     return Root;
1425 }
1426
1427
1428
1429 static ExprNode* BoolAndExpr (void)
1430 /* Handle boolean and expressions: '&&' */
1431 {
1432     /* Get the left leave */
1433     ExprNode* Root = OrExpr ();
1434
1435     /* Check if this is for us */
1436     while (CurTok.Tok == TOK_BOOL_AND) {
1437
1438         ExprNode* Left = Root;
1439         ExprNode* Right;
1440
1441         /* Skip the token */
1442         NextToken ();
1443
1444         /* Get the right operand */
1445         Right = OrExpr ();
1446
1447         /* Check if both operands are constant */
1448         if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1449
1450             /* Get the constant result */
1451             int Result = GetBoolRep (Left) && GetBoolRep (Right);
1452
1453             /* Remove the unneeded nodes */
1454             FreeExprNode (Right);
1455             FreeExprNode (Left);
1456
1457             /* Create a constant result */
1458             Root = GetIntNode (Result);
1459
1460         } else {
1461
1462             /* Make an operator node */
1463             Root = AllocExprNode (NT_BOOL_AND, type_int, RVALUE);
1464             SetRightNode (Root, Right);
1465             SetLeftNode (Root, Left);
1466
1467         }
1468
1469     }
1470
1471     /* Return the resulting expression */
1472     return Root;
1473 }
1474
1475
1476
1477 static ExprNode* BoolOrExpr (void)
1478 /* Handle boolean or expressions: '||' */
1479 {
1480     /* Get the left leave */
1481     ExprNode* Root = BoolAndExpr ();
1482
1483     /* Check if this is for us */
1484     while (CurTok.Tok == TOK_BOOL_OR) {
1485
1486         ExprNode* Left = Root;
1487         ExprNode* Right;
1488
1489         /* Skip the token */
1490         NextToken ();
1491
1492         /* Get the right operand */
1493         Right = BoolAndExpr ();
1494
1495         /* Check if both operands are constant */
1496         if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1497
1498             /* Get the constant result */
1499             int Result = GetBoolRep (Left) && GetBoolRep (Right);
1500
1501             /* Remove the unneeded nodes */
1502             FreeExprNode (Right);
1503             FreeExprNode (Left);
1504
1505             /* Create a constant result */
1506             Root = GetIntNode (Result);
1507
1508         } else {
1509
1510             /* Make an operator node */
1511             Root = AllocExprNode (NT_BOOL_OR, type_int, RVALUE);
1512             SetRightNode (Root, Right);
1513             SetLeftNode (Root, Left);
1514
1515         }
1516
1517     }
1518
1519     /* Return the resulting expression */
1520     return Root;
1521 }
1522
1523
1524
1525 static ExprNode* ConditionalExpr (void)
1526 /* Handle the ternary operator: ':?' */
1527 {
1528     /* Get the left leave */
1529     ExprNode* Cond = BoolOrExpr ();
1530
1531     /* Check if this is for us */
1532     if (CurTok.Tok == TOK_QUEST) {
1533
1534         ExprNode* Expr1;
1535         ExprNode* Expr2;
1536         ExprNode* Root;
1537         type*     Type;
1538
1539
1540         /* Skip the token */
1541         NextToken ();
1542
1543         /* Get the first expression */
1544         Expr1 = Expression ();
1545
1546         /* Colon must follow */
1547         ConsumeColon ();
1548
1549         /* Get the second expression */
1550         Expr2 = ConditionalExpr ();
1551
1552         /* Get the common type of the two expressions */
1553         Type = CommonType (Expr1->Type, Expr2->Type);
1554
1555         /* Create a new ternary token node */
1556         Root = AllocExprNode (NT_TERNARY, Type, RVALUE);
1557         AppendItem (Root, Cond);
1558         AppendItem (Root, Expr1);
1559         AppendItem (Root, Expr2);
1560
1561         /* Return the result */
1562         return Root;
1563
1564     } else {
1565
1566         /* Just return the lower level expression */
1567         return Cond;
1568
1569     }
1570 }
1571
1572
1573
1574