]> git.sur5r.net Git - cc65/blob - src/cc65/parser.c
cleanup
[cc65] / src / cc65 / parser.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 parser.c                                  */
4 /*                                                                           */
5 /*                             Expression parser                             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2001 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 ("String literal 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         ResetLiteralPoolOffs (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 ("Preprocessor expression 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 ("Cannot use a label in an expression");
270                 return GetIntNode (0);
271             } else if (Sym->Flags & SC_TYPE) {
272                 /* Cannot use type symbols */
273                 Error ("Cannot use a type in an expression");
274                 /* Assume an int type to make lval valid */
275                 return GetIntNode (0);
276             }
277
278             /* Handle constants including enum values */
279             if ((Sym->Flags & SC_CONST) == SC_CONST) {
280
281                 N = AllocExprNode (NT_CONST, Sym->Type, RVALUE);
282                 N->IVal = Sym->V.ConstVal;
283
284             } else {
285
286                 /* All symbols besides functions and arrays are lvalues */
287                 int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type));
288
289                 /* Create the node */
290                 N = AllocExprNode (NT_SYM, Sym->Type, LVal);
291
292                 /* Set the symbol pointer */
293                 SetNodeSym (N, Sym);
294             }
295
296             /* The symbol is referenced now */
297             Sym->Flags |= SC_REF;
298
299         } else {
300
301             /* We did not find the symbol. Remember the name, then skip it */
302             strcpy (Ident, CurTok.Ident);
303             NextToken ();
304
305             /* IDENT is either an auto-declared function or an undefined
306              * variable.
307              */
308             if (CurTok.Tok == TOK_LPAREN) {
309
310                 /* Warn about the use of a function without prototype */
311                 Warning ("Function call without a prototype");
312
313                 /* Declare a function returning int. For that purpose, prepare
314                  * a function signature for a function having an empty param
315                  * list and returning int.
316                  */
317                 Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
318                 N   = AllocExprNode (NT_SYM, Sym->Type, RVALUE);
319                 SetNodeSym (N, Sym);
320
321             } else {
322
323                 /* Print an error about an undeclared variable */
324                 Error ("Undefined symbiol: `%s'", Ident);
325
326                 /* Undeclared Variable */
327                 Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
328                 N   = AllocExprNode (NT_SYM, Sym->Type, LVALUE);
329                 SetNodeSym (N, Sym);
330
331             }
332
333         }
334
335     } else if (CurTok.Tok == TOK_SCONST) {
336
337         /* String literal */
338         N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (CurTok.IVal))), RVALUE);
339         N->IVal = CurTok.IVal;
340
341     } else if (CurTok.Tok == TOK_ASM) {
342
343         /* ASM statement? */
344         N = DoAsm ();
345
346     } else if (CurTok.Tok == TOK_A) {
347
348         /* A register */
349         N = AllocExprNode (NT_REG_A, type_uchar, LVALUE);
350
351     } else if (CurTok.Tok == TOK_X) {
352
353         /* X register */
354         N = AllocExprNode (NT_REG_X, type_uchar, LVALUE);
355
356     } else if (CurTok.Tok == TOK_Y) {
357
358         /* Y register */
359         N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE);
360
361     } else if (CurTok.Tok == TOK_AX) {
362
363         /* AX pseudo register */
364         N = AllocExprNode (NT_REG_AX, type_uint, LVALUE);
365
366     } else if (CurTok.Tok == TOK_EAX) {
367
368         /* EAX pseudo register */
369         N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE);
370
371     } else {
372
373         /* Illegal primary. */
374         Error ("Expression expected");
375         N = GetIntNode (0);
376
377     }
378
379     /* Return the new node */
380     return N;
381 }
382
383
384
385 static ExprNode* DoArray (ExprNode* Left)
386 /* Handle arrays */
387 {
388     ExprNode* Right;
389     ExprNode* Root;
390     type*     ElementType;
391
392
393     /* Skip the bracket */
394     NextToken ();
395
396     /* Get the index */
397     Right = Expression ();
398
399     /* Check the types. As special "C" feature, accept a reversal of base and
400      * index types: char C = 3["abcdefg"] is legal C!
401      */
402     if (IsClassPtr (Left->Type)) {
403         /* Right side must be some sort of integer */
404         if (!IsClassInt (Right->Type)) {
405             /* Print an error */
406             Error ("Invalid subscript");
407             /* To avoid problems later, create a new, legal subscript
408              * expression
409              */
410             Right = GetIntNode (0);
411         }
412     } else if (IsClassPtr (Right->Type)) {
413
414         ExprNode* Tmp;
415
416         /* Left side must be some sort of integer */
417         if (!IsClassInt (Left->Type)) {
418             /* Print an error */
419             Error ("Invalid subscript");
420             /* To avoid problems later, create a new, legal subscript
421              * expression
422              */
423             Left = GetIntNode (0);
424         }
425
426         /* Swap the expression to it's normal form */
427         Tmp   = Right;
428         Right = Left;
429         Left  = Tmp;
430
431     } else {
432         /* Invalid array expression. Skip the closing bracket, then return
433          * an integer instead of the array expression to be safe later.
434          */
435         Error ("Invalid subscript");
436         ConsumeRBrack ();
437         return GetIntNode (0);
438     }
439
440     /* Skip the right bracket */
441     ConsumeRBrack ();
442
443     /* Get the type of the array elements */
444     ElementType = Indirect (Left->Type);
445
446     /* Allocate the branch node for the array expression */
447     Root = AllocExprNode (NT_ARRAY_SUBSCRIPT,
448                           ElementType,
449                           IsTypeArray (ElementType)? RVALUE : LVALUE);
450
451     /* Setup the branches */
452     SetLeftNode (Root, Left);
453     SetRightNode (Root, Right);
454
455     /* ...and return it */
456     return Root;
457 }
458
459
460
461 static ExprNode* DoStruct (ExprNode* Left)
462 /* Process struct field access */
463 {
464     nodetype_t  NT;
465     ident       Ident;
466     type*       StructType;
467     ExprNode*   Right;
468     ExprNode*   Root;
469     SymEntry*   Field;
470
471
472     /* Type check */
473     StructType = Left->Type;
474     if (CurTok.Tok == TOK_PTR_REF) {
475         NT = NT_STRUCTPTR_ACCESS;
476         if (!IsTypePtr (StructType)) {
477             Error ("Struct pointer expected");
478             return GetIntNode (0);
479         }
480         StructType = Indirect (StructType);
481     } else {
482         NT = NT_STRUCT_ACCESS;
483     }
484     if (!IsClassStruct (StructType)) {
485         Error ("Struct expected");
486         return GetIntNode (0);
487     }
488
489     /* Skip the token and check for an identifier */
490     NextToken ();
491     if (CurTok.Tok != TOK_IDENT) {
492         /* Print an error */
493         Error ("Identifier expected");
494         /* Return an integer expression instead */
495         return GetIntNode (0);
496     }
497
498     /* Get the symbol table entry and check for a struct field */
499     strcpy (Ident, CurTok.Ident);
500     NextToken ();
501     Field = FindStructField (StructType, Ident);
502     if (Field == 0) {
503         /* Struct field not found */
504         Error ("Struct/union has no field named `%s'", Ident);
505         /* Return an integer expression instead */
506         return GetIntNode (0);
507     }
508
509     /* Allocate and set up the right (== field) node */
510     Right = AllocExprNode (NT_SYM, Field->Type, RVALUE);
511     SetNodeSym (Right, Field);
512
513     /* Allocate the branch node for the resulting expression */
514     Root = AllocExprNode (NT, Right->Type,
515                           IsTypeArray (Right->Type)? RVALUE : LVALUE);
516
517     /* Setup the branches */
518     SetLeftNode (Root, Left);
519     SetRightNode (Root, Right);
520
521     /* ...and return it */
522     return Root;
523 }
524
525
526
527 static ExprNode* DoFunctionCall (ExprNode* Left)
528 /* Process a function call */
529 {
530     type*       ResultType;     /* Type of function result */
531     FuncDesc*   Func;           /* Function descriptor */
532     ExprNode*   Root;           /* Function call node */
533     int         Ellipsis;       /* True if we have an open param list */
534     SymEntry*   Param;          /* Current formal parameter */
535     unsigned    ParamCount;     /* Actual parameter count */
536     unsigned    ParamSize;      /* Number of parameter bytes */
537
538
539     /* Type check */
540     if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) {
541
542         /* Call to non function */
543         Error ("Illegal function call");
544
545         /* Free the old tree */
546         FreeExprTree (Left);
547
548         /* Return something safe */
549         return GetIntNode (0);
550     }
551
552     /* Get the type of the function result */
553     ResultType = Left->Type;
554     if (IsTypeFuncPtr (Left->Type)) {
555         ++ResultType;
556     }
557     ResultType += DECODE_SIZE + 1;      /* Set to result type */
558
559     /* Skip the opening parenthesis */
560     NextToken ();
561
562     /* Allocate the function call node */
563     Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE);
564
565     /* Get a pointer to the function descriptor from the type string */
566     Func = GetFuncDesc (Left->Type);
567
568     /* Initialize vars to keep gcc silent */
569     Param = 0;
570
571     /* Parse the parameter list */
572     ParamSize  = 0;
573     ParamCount = 0;
574     Ellipsis   = 0;
575     while (CurTok.Tok != TOK_RPAREN) {
576
577         /* Count arguments */
578         ++ParamCount;
579
580         /* Fetch the pointer to the next argument, check for too many args */
581         if (ParamCount <= Func->ParamCount) {
582             if (ParamCount == 1) {
583                 /* First argument */
584                 Param = Func->SymTab->SymHead;
585             } else {
586                 /* Next argument */
587                 Param = Param->NextSym;
588                 CHECK ((Param->Flags & SC_PARAM) != 0);
589             }
590         } else if (!Ellipsis) {
591             /* Too many arguments. Do we have an open param list? */
592             if ((Func->Flags & FD_VARIADIC) == 0) {
593                 /* End of param list reached, no ellipsis */
594                 Error ("Too many function arguments");
595             }
596             /* Assume an ellipsis even in case of errors to avoid an error
597              * message for each other argument.
598              */
599             Ellipsis = 1;
600         }
601
602         /* Get the parameter value expression tree and add it to the parameter
603          * list.
604          */
605         AppendItem (Root, AssignExpr ());
606
607         /* Check for end of argument list */
608         if (CurTok.Tok != TOK_COMMA) {
609             break;
610         }
611         NextToken ();
612     }
613
614     /* We need the closing bracket here */
615     ConsumeRParen ();
616
617     /* Check if we had enough parameters */
618     if (ParamCount < Func->ParamCount) {
619         Error ("Too few function arguments");
620     }
621
622     /* Return the function call node */
623     return Root;
624 }
625
626
627
628 static ExprNode* DoPostIncDec (ExprNode* Left)
629 /* Handle postincrement and postdecrement */
630 {
631     ExprNode* Root;
632
633     /* Determine the type of the node */
634     nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_POST_INC : NT_POST_DEC;
635
636     /* Skip the operator token */
637     NextToken ();
638
639     /* The operand must be an lvalue */
640     if (Left->LValue == 0) {
641
642         /* Print a diagnostics */
643         Error ("lvalue expected");
644
645         /* It is safe to return the operand expression and probably better
646          * than returning an int, since the operand expression already has
647          * the correct type as expected by the program at this place, and
648          * it is even an rvalue.
649          */
650         return Left;
651     }
652
653     /* Setup the expression tree */
654     Root = AllocExprNode (NT, Left->Type, RVALUE);
655     SetLeftNode (Root, Left);
656
657     /* Return the new node */
658     return Root;
659 }
660
661
662
663 static ExprNode* PostfixExpr (void)
664 {
665     /* Get the lower level expression */
666     ExprNode* Root = Primary ();
667
668     /* */
669     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN  ||
670            CurTok.Tok == TOK_DOT    || CurTok.Tok == TOK_PTR_REF ||
671            CurTok.Tok == TOK_INC    || CurTok.Tok == TOK_DEC) {
672
673         /* This is for us */
674         switch (CurTok.Tok) {
675
676             case TOK_LBRACK:
677                 Root = DoArray (Root);
678                 break;
679
680             case TOK_LPAREN:
681                 Root = DoFunctionCall (Root);
682                 break;
683
684             case TOK_DOT:
685             case TOK_PTR_REF:
686                 Root = DoStruct (Root);
687                 break;
688
689             case TOK_INC:
690             case TOK_DEC:
691                 Root = DoPostIncDec (Root);
692                 break;
693
694             default:
695                 Internal ("Unexpected token");
696
697         }
698     }
699
700     /* Return the result */
701     return Root;
702 }
703
704
705
706 static ExprNode* DoPreIncDec (void)
707 /* Handle preincrement and predecrement */
708 {
709     ExprNode* Op;
710     ExprNode* Root;
711
712     /* Determine the type of the node */
713     nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_PRE_INC : NT_PRE_DEC;
714
715     /* Skip the operator token */
716     NextToken ();
717
718     /* Get the expression to increment or decrement */
719     Op = UnaryExpr ();
720
721     /* The operand must be an lvalue */
722     if (Op->LValue == 0) {
723
724         /* Print a diagnostics */
725         Error ("lvalue expected");
726
727         /* It is safe to return the operand expression and probably better
728          * than returning an int, since the operand expression already has
729          * the correct type as expected by the program at this place, and
730          * it is even an rvalue.
731          */
732         return Op;
733     }
734
735     /* Setup the expression tree */
736     Root = AllocExprNode (NT, Op->Type, RVALUE);
737     SetLeftNode (Root, Op);
738
739     /* Return the new node */
740     return Root;
741 }
742
743
744
745 static ExprNode* DoUnaryPlusMinus (void)
746 /* Handle unary +/- */
747 {
748     ExprNode* Op;
749     ExprNode* Root;
750
751     /* Remember the current token for later, then skip it */
752     token_t Tok = CurTok.Tok;
753     NextToken ();
754
755     /* Get the operand */
756     Op = UnaryExpr ();
757
758     /* Type check */
759     if (!IsClassInt (Op->Type) && !IsClassFloat (Op->Type)) {
760
761         /* Output diagnostic */
762         Error ("Syntax error");
763
764         /* Free the errorneous node */
765         FreeExprTree (Op);
766
767         /* Return something that makes sense later */
768         return GetIntNode (0);
769     }
770
771     /* In case of PLUS, we must do nothing */
772     if (Tok == TOK_PLUS) {
773
774         /* Return the operand unchanged */
775         return Op;
776
777     } else if (Op->NT == NT_CONST) {
778
779         /* The value is constant, change it according to the insn */
780         if (IsClassInt (Op->Type)) {
781             /* Integer */
782             Op->IVal = -Op->IVal;
783         } else {
784             /* Float */
785             Op->FVal = -Op->FVal;
786         }
787
788         /* Return the operand itself */
789         return Op;
790
791     } else {
792
793         /* Non constant value, setup the expression tree */
794         Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
795         SetLeftNode (Root, Op);
796
797     }
798
799     /* Return the new node */
800     return Root;
801 }
802
803
804
805 static ExprNode* DoComplement (void)
806 /* Handle ~ */
807 {
808     ExprNode* Op;
809     ExprNode* Root;
810
811     /* Skip the operator token */
812     NextToken ();
813
814     /* Get the operand */
815     Op = UnaryExpr ();
816
817     /* Type check */
818     if (!IsClassInt (Op->Type)) {
819
820         /* Display diagnostic */
821         Error ("Operation not allowed on this type");
822
823         /* Free the errorneous node */
824         FreeExprTree (Op);
825
826         /* Return something that makes sense later */
827         return GetIntNode (0);
828     }
829
830     /* If the operand is constant, handle the operation directly */
831     if (Op->NT == NT_CONST) {
832
833         /* Change the value and return the operand node */
834         Op->IVal = ~Op->IVal;
835         return Op;
836
837     } else {
838
839         /* Setup the expression tree and return the new node */
840         Root = AllocExprNode (NT_COMPLEMENT, Op->Type, RVALUE);
841         SetLeftNode (Root, Op);
842         return Root;
843     }
844 }
845
846
847
848 static ExprNode* DoBoolNot (void)
849 /* Handle ! */
850 {
851     ExprNode* Op;
852     ExprNode* Root;
853
854     /* Skip the operator token */
855     NextToken ();
856
857     /* Get the operand */
858     Op = UnaryExpr ();
859
860     /* The boolean NOT operator eats anything - no need for a type check. */
861
862     /* Setup the expression tree and return the new node */
863     Root = AllocExprNode (NT_BOOL_NOT, type_int, RVALUE);
864     SetLeftNode (Root, Op);
865     return Root;
866 }
867
868
869
870 static ExprNode* DoAddress (void)
871 /* Handle the address operator & */
872 {
873     ExprNode* Op;
874
875     /* Skip the operator */
876     NextToken ();
877
878     /* Get the operand */
879     Op = UnaryExpr ();
880
881     /* Accept using the address operator with arrays. This is harmless, it
882      * will just be as using the array without the operator.
883      */
884     if (IsTypeArray (Op->Type)) {
885         return Op;
886     }
887
888     /* We cannot operate on rvalues */
889     if (Op->LValue == 0) {
890
891         ExprNode* Root;
892
893         /* Print diagnostics */
894         Error ("Cannot take address of rvalue");
895
896         /* Free the problematic tree */
897         FreeExprTree (Op);
898
899         /* Return something that is safe later */
900         Root = AllocExprNode (NT_CONST, PointerTo (type_void), 0);
901         return Root;
902
903     }
904
905     /* Create the operator node and return it */
906     return AllocExprNode (NT_ADDRESS, PointerTo (Op->Type), RVALUE);
907 }
908
909
910
911 static ExprNode* DoIndirect (void)
912 /* Handle the indirection operaror * */
913 {
914     ExprNode* Op;
915     type*     ResultType;
916     int       LVal;
917
918     /* Skip the operator */
919     NextToken ();
920
921     /* Get the operand */
922     Op = UnaryExpr ();
923
924     /* Type check */
925     if (!IsClassPtr (Op->Type)) {
926
927         /* Print diagnostics */
928         Error ("Illegal indirection");
929
930         /* Free the problematic tree */
931         FreeExprTree (Op);
932
933         /* Return something that is safe later ### */
934         return GetIntNode (0);
935
936     }
937
938     /* Get the type of the result */
939     ResultType = Indirect (Op->Type);
940
941     /* The result is an lvalue if it is not an array */
942     LVal = IsTypeArray (ResultType)? RVALUE : LVALUE;
943
944     /* Create the operator node and return it */
945     return AllocExprNode (NT_INDIRECT, ResultType, LVal);
946 }
947
948
949
950 static ExprNode* DoSizeOf (void)
951 /* Handle the sizeof operator */
952 {
953     ExprNode*     N;
954     unsigned long Size;
955
956     /* Skip the left paren */
957     NextToken ();
958
959     /* A type or an actual variable access may follow */
960     if (IsTypeExpr ()) {
961
962         type    Type[MAXTYPELEN];
963
964         /* A type in parenthesis. Skip the left paren. */
965         NextToken ();
966
967         /* Read the type and calculate the size. */
968         Size = SizeOf (ParseType (Type));
969
970         /* Closing paren must follow */
971         ConsumeRParen ();
972
973     } else {
974
975         /* Some other entity */
976         N = UnaryExpr ();
977
978         /* Get the size */
979         Size = SizeOf (N->Type);
980
981         /* Free the node */
982         FreeExprTree (N);
983
984     }
985
986     /* Create a constant node with type size_t and return it */
987     N = AllocExprNode (NT_CONST, type_size_t, RVALUE);
988     N->IVal = Size;
989     return N;
990 }
991
992
993
994 static ExprNode* DoTypeCast (void)
995 /* Handle type casts */
996 {
997     type      TargetType[MAXTYPELEN];
998     ExprNode* Op;
999     ExprNode* Root;
1000
1001     /* Skip the left paren */
1002     NextToken ();
1003
1004     /* Read the type */
1005     ParseType (TargetType);
1006
1007     /* Closing paren */
1008     ConsumeRParen ();
1009
1010     /* Read the expression we have to cast */
1011     Op = UnaryExpr ();
1012
1013     /* As a minor optimization, check if the type is already correct. If so,
1014      * do nothing.
1015      */
1016     if (TypeCmp (TargetType, Op->Type) >= TC_EQUAL) {
1017
1018         /* Just return the operand as is */
1019         return Op;
1020
1021     } else {
1022
1023         /* Must be casted. Setup the expression tree and return the new node */
1024         Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
1025         SetLeftNode (Root, Op);
1026         return Root;
1027
1028     }
1029 }
1030
1031
1032
1033 static ExprNode* UnaryExpr (void)
1034 {
1035     /* */
1036     if (CurTok.Tok == TOK_INC    || CurTok.Tok == TOK_DEC      ||
1037         CurTok.Tok == TOK_PLUS   || CurTok.Tok == TOK_MINUS    ||
1038         CurTok.Tok == TOK_COMP   || CurTok.Tok == TOK_BOOL_NOT ||
1039         CurTok.Tok == TOK_AND    || CurTok.Tok == TOK_STAR     ||
1040         CurTok.Tok == TOK_SIZEOF || IsTypeExpr ()) {
1041
1042         /* Check the token */
1043         switch (CurTok.Tok) {
1044
1045             case TOK_INC:
1046             case TOK_DEC:
1047                 return DoPreIncDec ();
1048
1049             case TOK_PLUS:
1050             case TOK_MINUS:
1051                 return DoUnaryPlusMinus ();
1052
1053             case TOK_COMP:
1054                 return DoComplement ();
1055
1056             case TOK_BOOL_NOT:
1057                 return DoBoolNot ();
1058
1059             case TOK_AND:
1060                 return DoAddress ();
1061
1062             case TOK_STAR:
1063                 return DoIndirect ();
1064
1065             case TOK_SIZEOF:
1066                 return DoSizeOf ();
1067
1068             default:
1069                 /* Type cast */
1070                 return DoTypeCast ();
1071
1072         }
1073
1074     } else {
1075
1076         /* Call the lower level */
1077         return PostfixExpr ();
1078
1079     }
1080 }
1081
1082
1083
1084 static ExprNode* DoMul (ExprNode* Left)
1085 /* Handle multiplication */
1086 {
1087     type      TargetType[MAXTYPELEN];
1088     ExprNode* Right;
1089     ExprNode* Root;
1090
1091     /* Check the type of the left operand */
1092     if (!IsClassInt (Left->Type) && !IsClassFloat (Left->Type)) {
1093         Error ("Invalid left operand to binary operator `*'");
1094         FreeExprTree (Left);
1095         Left = GetIntNode (0);
1096     }
1097
1098     /* Skip the operator token */
1099     NextToken ();
1100
1101     /* Read the right expression */
1102     Right = UnaryExpr ();
1103
1104     /* Check the type of the right operand */
1105     if (!IsClassInt (Right->Type) && !IsClassFloat (Right->Type)) {
1106         Error ("Invalid right operand to binary operator `*'");
1107         FreeExprTree (Right);
1108         Right = GetIntNode (0);
1109     }
1110
1111     /* Make the root node */
1112     Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
1113     SetLeftNode (Root, Left);
1114     SetRightNode (Root, Right);
1115
1116     return Root;
1117 }
1118
1119
1120
1121 static ExprNode* MultExpr (void)
1122 /* Handle multiplicative expressions: '*' '/' and '%' */
1123 {
1124     /* Get the left leave */
1125     ExprNode* Root = UnaryExpr ();
1126
1127     /* Check if this is for us */
1128     while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV || CurTok.Tok == TOK_MOD) {
1129
1130         switch (CurTok.Tok) {
1131
1132             case TOK_MUL:
1133                 Root = DoMul (Root);
1134                 break;
1135
1136             case TOK_DIV:
1137                 break;
1138
1139             case TOK_MOD:
1140                 break;
1141
1142             default:
1143                 Internal ("Unexpected token");
1144         }
1145
1146     }
1147
1148     /* Return the resulting expression */
1149     return Root;
1150 }
1151
1152
1153
1154 static ExprNode* AddExpr (void)
1155 /* Handle additive expressions: '+' and '-' */
1156 {
1157     /* Get the left leave */
1158     ExprNode* Root = MultExpr ();
1159
1160     /* Check if this is for us */
1161     while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) {
1162
1163         switch (CurTok.Tok) {
1164
1165             case TOK_PLUS:
1166                 break;
1167
1168             case TOK_MINUS:
1169                 break;
1170
1171             default:
1172                 Internal ("Unexpected token");
1173         }
1174
1175     }
1176
1177     /* Return the resulting expression */
1178     return Root;
1179 }
1180
1181
1182
1183 static ExprNode* ShiftExpr (void)
1184 /* Handle shift expressions: '<<' and '>>' */
1185 {
1186     /* Get the left leave */
1187     ExprNode* Root = AddExpr ();
1188
1189     /* Check if this is for us */
1190     while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
1191
1192         switch (CurTok.Tok) {
1193
1194             case TOK_SHL:
1195                 break;
1196
1197             case TOK_SHR:
1198                 break;
1199
1200             default:
1201                 Internal ("Unexpected token");
1202         }
1203
1204     }
1205
1206     /* Return the resulting expression */
1207     return Root;
1208 }
1209
1210
1211
1212 static ExprNode* RelationalExpr (void)
1213 /* Handle relational expressions: '<=', '<', '>=' and '>' */
1214 {
1215     /* Get the left leave */
1216     ExprNode* Root = ShiftExpr ();
1217
1218     /* Check if this is for us */
1219     while (CurTok.Tok == TOK_LE || CurTok.Tok == TOK_LT ||
1220            CurTok.Tok == TOK_GE || CurTok.Tok == TOK_GT) {
1221
1222         switch (CurTok.Tok) {
1223
1224             case TOK_LE:
1225                 break;
1226
1227             case TOK_LT:
1228                 break;
1229
1230             case TOK_GE:
1231                 break;
1232
1233             case TOK_GT:
1234                 break;
1235
1236             default:
1237                 Internal ("Unexpected token");
1238         }
1239
1240     }
1241
1242     /* Return the resulting expression */
1243     return Root;
1244 }
1245
1246
1247
1248 static ExprNode* EqualityExpr (void)
1249 /* Handle equality expressions: '==' and '!=' */
1250 {
1251     /* Get the left leave */
1252     ExprNode* Root = RelationalExpr ();
1253
1254     /* Check if this is for us */
1255     while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE) {
1256
1257         switch (CurTok.Tok) {
1258
1259             case TOK_EQ:
1260                 break;
1261
1262             case TOK_NE:
1263                 break;
1264
1265             default:
1266                 Internal ("Unexpected token");
1267         }
1268
1269     }
1270
1271     /* Return the resulting expression */
1272     return Root;
1273 }
1274
1275
1276
1277 static ExprNode* AndExpr (void)
1278 /* Handle and expressions: '&' */
1279 {
1280     /* Get the left leave */
1281     ExprNode* Root = EqualityExpr ();
1282
1283     /* Check if this is for us */
1284     while (CurTok.Tok == TOK_AND) {
1285
1286         ExprNode* Left = Root;
1287         ExprNode* Right;
1288
1289         /* Skip the token */
1290         NextToken ();
1291
1292         /* Get the right operand */
1293         Right = EqualityExpr ();
1294
1295         /* Type check */
1296         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1297
1298             /* Print a diagnostic */
1299             Error ("Operation not allowed for these types");
1300
1301             /* Remove the unneeded nodes */
1302             FreeExprTree (Right);
1303             FreeExprTree (Left);
1304
1305             /* Create something safe */
1306             Root = GetIntNode (0);
1307
1308         } else {
1309
1310             /* Check if both operands are constant */
1311             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1312
1313                 /* Get the constant result */
1314                 int Result = GetBoolRep (Left) & GetBoolRep (Right);
1315
1316                 /* Remove the unneeded nodes */
1317                 FreeExprTree (Right);
1318                 FreeExprTree (Left);
1319
1320                 /* Create a constant result */
1321                 Root = GetIntNode (Result);
1322
1323             } else {
1324
1325                 /* Make an operator node */
1326                 Root = AllocExprNode (NT_AND, type_int, RVALUE);
1327                 SetRightNode (Root, Right);
1328                 SetLeftNode (Root, Left);
1329
1330             }
1331         }
1332     }
1333
1334     /* Return the resulting expression */
1335     return Root;
1336 }
1337
1338
1339
1340 static ExprNode* XorExpr (void)
1341 /* Handle xor expressions: '^' */
1342 {
1343     /* Get the left leave */
1344     ExprNode* Root = AndExpr ();
1345
1346     /* Check if this is for us */
1347     while (CurTok.Tok == TOK_XOR) {
1348
1349         ExprNode* Left = Root;
1350         ExprNode* Right;
1351
1352         /* Skip the token */
1353         NextToken ();
1354
1355         /* Get the right operand */
1356         Right = AndExpr ();
1357
1358         /* Type check */
1359         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1360
1361             /* Print a diagnostic */
1362             Error ("Operation not allowed for these types");
1363
1364             /* Remove the unneeded nodes */
1365             FreeExprTree (Right);
1366             FreeExprTree (Left);
1367
1368             /* Create something safe */
1369             Root = GetIntNode (0);
1370
1371         } else {
1372
1373             /* Check if both operands are constant */
1374             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1375
1376                 /* Get the constant result */
1377                 int Result = GetBoolRep (Left) ^ GetBoolRep (Right);
1378
1379                 /* Remove the unneeded nodes */
1380                 FreeExprTree (Right);
1381                 FreeExprTree (Left);
1382
1383                 /* Create a constant result */
1384                 Root = GetIntNode (Result);
1385
1386             } else {
1387
1388                 /* Make an operator node */
1389                 Root = AllocExprNode (NT_XOR, type_int, RVALUE);
1390                 SetRightNode (Root, Right);
1391                 SetLeftNode (Root, Left);
1392
1393             }
1394         }
1395     }
1396
1397     /* Return the resulting expression */
1398     return Root;
1399 }
1400
1401
1402
1403 static ExprNode* OrExpr (void)
1404 /* Handle or expressions: '|' */
1405 {
1406     /* Get the left leave */
1407     ExprNode* Root = XorExpr ();
1408
1409     /* Check if this is for us */
1410     while (CurTok.Tok == TOK_OR) {
1411
1412         ExprNode* Left = Root;
1413         ExprNode* Right;
1414
1415         /* Skip the token */
1416         NextToken ();
1417
1418         /* Get the right operand */
1419         Right = XorExpr ();
1420
1421         /* Type check */
1422         if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1423
1424             /* Print a diagnostic */
1425             Error ("Operation not allowed for these types");
1426
1427             /* Remove the unneeded nodes */
1428             FreeExprTree (Right);
1429             FreeExprTree (Left);
1430
1431             /* Create something safe */
1432             Root = GetIntNode (0);
1433
1434         } else {
1435
1436             /* Check if both operands are constant */
1437             if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1438
1439                 /* Get the constant result */
1440                 int Result = GetBoolRep (Left) | GetBoolRep (Right);
1441
1442                 /* Remove the unneeded nodes */
1443                 FreeExprTree (Right);
1444                 FreeExprTree (Left);
1445
1446                 /* Create a constant result */
1447                 Root = GetIntNode (Result);
1448
1449             } else {
1450
1451                 /* Make an operator node */
1452                 Root = AllocExprNode (NT_OR, type_int, RVALUE);
1453                 SetRightNode (Root, Right);
1454                 SetLeftNode (Root, Left);
1455
1456             }
1457         }
1458     }
1459
1460     /* Return the resulting expression */
1461     return Root;
1462 }
1463
1464
1465
1466 static ExprNode* BoolAndExpr (void)
1467 /* Handle boolean and expressions: '&&' */
1468 {
1469     /* Get the left leave */
1470     ExprNode* Root = OrExpr ();
1471
1472     /* Check if this is for us */
1473     while (CurTok.Tok == TOK_BOOL_AND) {
1474
1475         ExprNode* Left = Root;
1476         ExprNode* Right;
1477
1478         /* Skip the token */
1479         NextToken ();
1480
1481         /* Get the right operand */
1482         Right = OrExpr ();
1483
1484         /* Check if both operands are constant */
1485         if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1486
1487             /* Get the constant result */
1488             int Result = GetBoolRep (Left) && GetBoolRep (Right);
1489
1490             /* Remove the unneeded nodes */
1491             FreeExprTree (Right);
1492             FreeExprTree (Left);
1493
1494             /* Create a constant result */
1495             Root = GetIntNode (Result);
1496
1497         } else {
1498
1499             /* Make an operator node */
1500             Root = AllocExprNode (NT_BOOL_AND, type_int, RVALUE);
1501             SetRightNode (Root, Right);
1502             SetLeftNode (Root, Left);
1503
1504         }
1505
1506     }
1507
1508     /* Return the resulting expression */
1509     return Root;
1510 }
1511
1512
1513
1514 static ExprNode* BoolOrExpr (void)
1515 /* Handle boolean or expressions: '||' */
1516 {
1517     /* Get the left leave */
1518     ExprNode* Root = BoolAndExpr ();
1519
1520     /* Check if this is for us */
1521     while (CurTok.Tok == TOK_BOOL_OR) {
1522
1523         ExprNode* Left = Root;
1524         ExprNode* Right;
1525
1526         /* Skip the token */
1527         NextToken ();
1528
1529         /* Get the right operand */
1530         Right = BoolAndExpr ();
1531
1532         /* Check if both operands are constant */
1533         if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1534
1535             /* Get the constant result */
1536             int Result = GetBoolRep (Left) && GetBoolRep (Right);
1537
1538             /* Remove the unneeded nodes */
1539             FreeExprTree (Right);
1540             FreeExprTree (Left);
1541
1542             /* Create a constant result */
1543             Root = GetIntNode (Result);
1544
1545         } else {
1546
1547             /* Make an operator node */
1548             Root = AllocExprNode (NT_BOOL_OR, type_int, RVALUE);
1549             SetRightNode (Root, Right);
1550             SetLeftNode (Root, Left);
1551
1552         }
1553
1554     }
1555
1556     /* Return the resulting expression */
1557     return Root;
1558 }
1559
1560
1561
1562 static ExprNode* ConditionalExpr (void)
1563 /* Handle the ternary operator: ':?' */
1564 {
1565     /* Get the left leave */
1566     ExprNode* Cond = BoolOrExpr ();
1567
1568     /* Check if this is for us */
1569     if (CurTok.Tok == TOK_QUEST) {
1570
1571         ExprNode* Expr1;
1572         ExprNode* Expr2;
1573         ExprNode* Root;
1574         type*     Type;
1575
1576
1577         /* Skip the token */
1578         NextToken ();
1579
1580         /* Get the first expression */
1581         Expr1 = Expression ();
1582
1583         /* Colon must follow */
1584         ConsumeColon ();
1585
1586         /* Get the second expression */
1587         Expr2 = ConditionalExpr ();
1588
1589         /* Get the common type of the two expressions */
1590         Type = CommonType (Expr1->Type, Expr2->Type);
1591
1592         /* Create a new ternary token node */
1593         Root = AllocExprNode (NT_TERNARY, Type, RVALUE);
1594         AppendItem (Root, Cond);
1595         AppendItem (Root, Expr1);
1596         AppendItem (Root, Expr2);
1597
1598         /* Return the result */
1599         return Root;
1600
1601     } else {
1602
1603         /* Just return the lower level expression */
1604         return Cond;
1605
1606     }
1607 }
1608
1609
1610
1611