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