]> git.sur5r.net Git - cc65/blob - src/cc65/parser.c
The check for illegal storage classes on globals was wrong
[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 */
83 {
84     SymEntry* Entry;
85
86     return CurTok.Tok == TOK_LPAREN && (
87             (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) ||
88             (nxttok == TOK_CONST)                               ||
89             (nxttok  == TOK_IDENT                               &&
90             (Entry = FindSym (NextTok.Ident)) != 0              &&
91             IsTypeDef (Entry))
92            );
93 }
94
95
96
97 static int GetBoolRep (const ExprNode* N)
98 /* Get the boolean representation of a constant expression node */
99 {
100     if (IsClassInt (N->Type)) {
101         /* An integer constant */
102         return (N->IVal != 0);
103     } else if (IsClassFloat (N->Type)) {
104         /* A float constant */
105         return (N->FVal != 0.0);
106     } else if (IsTypeArray (N->Type) && IsTypeChar (Indirect (N->Type))) {
107         /* A string constant - useless but allowed */
108         return 1;
109     } else {
110         Internal ("GetBoolRep: Unknown type");
111         /* NOTREACHED */
112         return 0;
113     }
114 }
115
116
117
118 /*****************************************************************************/
119 /*                     Expression node helper functions                      */
120 /*****************************************************************************/
121
122
123
124 static ExprNode* GetIntNode (int Value)
125 /* Allocate a new expression node from the tree, make it a valid integer
126  * node and return it. Often used if an error occurs to get a safe expression
127  * tree.
128  */
129 {
130     ExprNode* N = AllocExprNode (NT_CONST, type_int, RVALUE);
131     N->IVal = Value;
132     return N;
133 }
134
135
136
137 /*****************************************************************************/
138 /*                                   Code                                    */
139 /*****************************************************************************/
140
141
142
143 ExprNode* DoAsm (void)
144 /* This function parses ASM statements. The syntax of the ASM directive
145  * looks like the one defined for C++ (C has no ASM directive), that is,
146  * a string literal in parenthesis.
147  */
148 {
149     ExprNode* N;
150
151
152     /* Skip the ASM */
153     NextToken ();
154
155     /* Need left parenthesis */
156     ConsumeLParen ();
157
158     /* Create a new expression node and assign a void type */
159     N = AllocExprNode (NT_ASM, type_void, RVALUE);
160
161     /* String literal */
162     if (CurTok.Tok != TOK_SCONST) {
163
164         /* Print an error */
165         Error ("String literal expected");
166
167         /* To be on the safe side later, insert an empty asm string */
168         AppendItem (N, xstrdup (""));
169
170     } else {
171
172         /* Insert a copy of the string into the expression node */
173         AppendItem (N, xstrdup (GetLiteral (CurTok.IVal)));
174
175         /* Reset the string pointer, effectivly clearing the string from the
176          * string table. Since we're working with one token lookahead, this
177          * will fail if the next token is also a string token, but that's a
178          * syntax error anyway, because we expect a right paren.
179          */
180         ResetLiteralPoolOffs (CurTok.IVal);
181     }
182
183     /* Skip the string token */
184     NextToken ();
185
186     /* Closing paren needed */
187     ConsumeRParen ();
188
189     /* Return the created node */
190     return N;
191 }
192
193
194
195 static ExprNode* Primary (void)
196 /* Evaluate a primary expression */
197 {
198     ExprNode* N;
199
200     /* Process a parenthesized subexpression. In this case we don't need to
201      * allocate a new node ourselves.
202      */
203     if (CurTok.Tok == TOK_LPAREN) {
204         NextToken ();
205         N = Expression ();
206         ConsumeRParen ();
207         return N;
208     }
209
210     /* Check for an integer or character constant */
211     if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
212
213         /* Create the new node */
214         N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
215         N->IVal = CurTok.IVal;
216
217         /* Skip the token and return the result */
218         NextToken ();
219         return N;
220     }
221
222     /* Check for a float constant */
223     if (CurTok.Tok == TOK_FCONST) {
224
225         /* Create the new node */
226         N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
227         N->FVal = CurTok.FVal;
228
229         /* Skip the token and return the result */
230         NextToken ();
231         return N;
232     }
233
234     /* All others may only be used if the expression evaluation is not called
235      * recursively by the preprocessor.
236      */
237     if (Preprocessing) {
238         /* Illegal expression in PP mode */
239         Error ("Preprocessor expression expected");
240
241         /* Skip the token for error recovery */
242         NextToken ();
243
244         /* Return an integer constant */
245         return GetIntNode (0);
246     }
247
248     /* Identifier? */
249     if (CurTok.Tok == TOK_IDENT) {
250
251         /* Identifier */
252         SymEntry* Sym;
253         ident Ident;
254
255         /* Get a pointer to the symbol table entry */
256         Sym = FindSym (CurTok.Ident);
257
258         /* Is the symbol known? */
259         if (Sym) {
260
261             /* We found the symbol - skip the name token */
262             NextToken ();
263
264             /* Check for illegal symbol types */
265             if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
266                 /* Cannot use labels in expressions */
267                 Error ("Cannot use a label in an expression");
268                 return GetIntNode (0);
269             } else if (Sym->Flags & SC_TYPE) {
270                 /* Cannot use type symbols */
271                 Error ("Cannot use a type in an expression");
272                 /* Assume an int type to make lval valid */
273                 return GetIntNode (0);
274             }
275
276             /* Handle constants including enum values */
277             if ((Sym->Flags & SC_CONST) == SC_CONST) {
278
279                 N = AllocExprNode (NT_CONST, Sym->Type, RVALUE);
280                 N->IVal = Sym->V.ConstVal;
281
282             } else {
283
284                 /* All symbols besides functions and arrays are lvalues */
285                 int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type));
286
287                 /* Create the node */
288                 N = AllocExprNode (NT_SYM, Sym->Type, LVal);
289
290                 /* Set the symbol pointer */
291                 SetNodeSym (N, Sym);
292             }
293
294             /* The symbol is referenced now */
295             Sym->Flags |= SC_REF;
296
297         } else {
298
299             /* We did not find the symbol. Remember the name, then skip it */
300             strcpy (Ident, CurTok.Ident);
301             NextToken ();
302
303             /* IDENT is either an auto-declared function or an undefined
304              * variable.
305              */
306             if (CurTok.Tok == TOK_LPAREN) {
307
308                 /* Warn about the use of a function without prototype */
309                 Warning ("Function call without a prototype");
310
311                 /* Declare a function returning int. For that purpose, prepare
312                  * a function signature for a function having an empty param
313                  * list and returning int.
314                  */
315                 Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
316                 N   = AllocExprNode (NT_SYM, Sym->Type, RVALUE);
317                 SetNodeSym (N, Sym);
318
319             } else {
320
321                 /* Print an error about an undeclared variable */
322                 Error ("Undefined symbiol: `%s'", Ident);
323
324                 /* Undeclared Variable */
325                 Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
326                 N   = AllocExprNode (NT_SYM, Sym->Type, LVALUE);
327                 SetNodeSym (N, Sym);
328
329             }
330
331         }
332
333     } else if (CurTok.Tok == TOK_SCONST) {
334
335         /* String literal */
336         N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (CurTok.IVal))), RVALUE);
337         N->IVal = CurTok.IVal;
338
339     } else if (CurTok.Tok == TOK_ASM) {
340
341         /* ASM statement? */
342         N = DoAsm ();
343
344     } else if (CurTok.Tok == TOK_A) {
345
346         /* A register */
347         N = AllocExprNode (NT_REG_A, type_uchar, LVALUE);
348
349     } else if (CurTok.Tok == TOK_X) {
350
351         /* X register */
352         N = AllocExprNode (NT_REG_X, type_uchar, LVALUE);
353
354     } else if (CurTok.Tok == TOK_Y) {
355
356         /* Y register */
357         N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE);
358
359     } else if (CurTok.Tok == TOK_AX) {
360
361         /* AX pseudo register */
362         N = AllocExprNode (NT_REG_AX, type_uint, LVALUE);
363
364     } else if (CurTok.Tok == TOK_EAX) {
365
366         /* EAX pseudo register */
367         N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE);
368
369     } else {
370
371         /* Illegal primary. */
372         Error ("Expression expected");
373         N = GetIntNode (0);
374
375     }
376
377     /* Return the new node */
378     return N;
379 }
380
381
382
383 static ExprNode* DoArray (ExprNode* Left)
384 /* Handle arrays */
385 {
386     ExprNode* Right;
387     ExprNode* Root;
388     type*     ElementType;
389
390
391     /* Skip the bracket */
392     NextToken ();
393
394     /* Get the index */
395     Right = Expression ();
396
397     /* Check the types. As special "C" feature, accept a reversal of base and
398      * index types: char C = 3["abcdefg"] is legal C!
399      */
400     if (IsClassPtr (Left->Type)) {
401         /* Right side must be some sort of integer */
402         if (!IsClassInt (Right->Type)) {
403             /* Print an error */
404             Error ("Invalid subscript");
405             /* To avoid problems later, create a new, legal subscript
406              * expression
407              */
408             Right = GetIntNode (0);
409         }
410     } else if (IsClassPtr (Right->Type)) {
411
412         ExprNode* Tmp;
413
414         /* Left side must be some sort of integer */
415         if (!IsClassInt (Left->Type)) {
416             /* Print an error */
417             Error ("Invalid subscript");
418             /* To avoid problems later, create a new, legal subscript
419              * expression
420              */
421             Left = GetIntNode (0);
422         }
423
424         /* Swap the expression to it's normal form */
425         Tmp   = Right;
426         Right = Left;
427         Left  = Tmp;
428
429     } else {
430         /* Invalid array expression. Skip the closing bracket, then return
431          * an integer instead of the array expression to be safe later.
432          */
433         Error ("Invalid subscript");
434         ConsumeRBrack ();
435         return GetIntNode (0);
436     }
437
438     /* Skip the right bracket */
439     ConsumeRBrack ();
440
441     /* Get the type of the array elements */
442     ElementType = Indirect (Left->Type);
443
444     /* Allocate the branch node for the array expression */
445     Root = AllocExprNode (NT_ARRAY_SUBSCRIPT,
446                           ElementType,
447                           IsTypeArray (ElementType)? RVALUE : LVALUE);
448
449     /* Setup the branches */
450     SetLeftNode (Root, Left);
451     SetRightNode (Root, Right);
452
453     /* ...and return it */
454     return Root;
455 }
456
457
458
459 static ExprNode* DoStruct (ExprNode* Left)
460 /* Process struct field access */
461 {
462     nodetype_t  NT;
463     ident       Ident;
464     type*       StructType;
465     ExprNode*   Right;
466     ExprNode*   Root;
467     SymEntry*   Field;
468
469
470     /* Type check */
471     StructType = Left->Type;
472     if (CurTok.Tok == TOK_PTR_REF) {
473         NT = NT_STRUCTPTR_ACCESS;
474         if (!IsTypePtr (StructType)) {
475             Error ("Struct pointer expected");
476             return GetIntNode (0);
477         }
478         StructType = Indirect (StructType);
479     } else {
480         NT = NT_STRUCT_ACCESS;
481     }
482     if (!IsClassStruct (StructType)) {
483         Error ("Struct expected");
484         return GetIntNode (0);
485     }
486
487     /* Skip the token and check for an identifier */
488     NextToken ();
489     if (CurTok.Tok != TOK_IDENT) {
490         /* Print an error */
491         Error ("Identifier expected");
492         /* Return an integer expression instead */
493         return GetIntNode (0);
494     }
495
496     /* Get the symbol table entry and check for a struct field */
497     strcpy (Ident, CurTok.Ident);
498     NextToken ();
499     Field = FindStructField (StructType, Ident);
500     if (Field == 0) {
501         /* Struct field not found */
502         Error ("Struct/union has no field named `%s'", Ident);
503         /* Return an integer expression instead */
504         return GetIntNode (0);
505     }
506
507     /* Allocate and set up the right (== field) node */
508     Right = AllocExprNode (NT_SYM, Field->Type, RVALUE);
509     SetNodeSym (Right, Field);
510
511     /* Allocate the branch node for the resulting expression */
512     Root = AllocExprNode (NT, Right->Type,
513                           IsTypeArray (Right->Type)? RVALUE : LVALUE);
514
515     /* Setup the branches */
516     SetLeftNode (Root, Left);
517     SetRightNode (Root, Right);
518
519     /* ...and return it */
520     return Root;
521 }
522
523
524
525 static ExprNode* DoFunctionCall (ExprNode* Left)
526 /* Process a function call */
527 {
528     type*       ResultType;     /* Type of function result */
529     FuncDesc*   Func;           /* Function descriptor */
530     ExprNode*   Root;           /* Function call node */
531     int         Ellipsis;       /* True if we have an open param list */
532     SymEntry*   Param;          /* Current formal parameter */
533     unsigned    ParamCount;     /* Actual parameter count */
534     unsigned    ParamSize;      /* Number of parameter bytes */
535
536
537     /* Type check */
538     if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) {
539
540         /* Call to non function */
541         Error ("Illegal function call");
542
543         /* Free the old tree */
544         FreeExprTree (Left);
545
546         /* Return something safe */
547         return GetIntNode (0);
548     }
549
550     /* Get the type of the function result */
551     ResultType = Left->Type;
552     if (IsTypeFuncPtr (Left->Type)) {
553         ++ResultType;
554     }
555     ResultType += DECODE_SIZE + 1;      /* Set to result type */
556
557     /* Skip the opening parenthesis */
558     NextToken ();
559
560     /* Allocate the function call node */
561     Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE);
562
563     /* Get a pointer to the function descriptor from the type string */
564     Func = GetFuncDesc (Left->Type);
565
566     /* Initialize vars to keep gcc silent */
567     Param = 0;
568
569     /* Parse the parameter list */
570     ParamSize  = 0;
571     ParamCount = 0;
572     Ellipsis   = 0;
573     while (CurTok.Tok != TOK_RPAREN) {
574
575         /* Count arguments */
576         ++ParamCount;
577
578         /* Fetch the pointer to the next argument, check for too many args */
579         if (ParamCount <= Func->ParamCount) {
580             if (ParamCount == 1) {
581                 /* First argument */
582                 Param = Func->SymTab->SymHead;
583             } else {
584                 /* Next argument */
585                 Param = Param->NextSym;
586                 CHECK ((Param->Flags & SC_PARAM) != 0);
587             }
588         } else if (!Ellipsis) {
589             /* Too many arguments. Do we have an open param list? */
590             if ((Func->Flags & FD_VARIADIC) == 0) {
591                 /* End of param list reached, no ellipsis */
592                 Error ("Too many function arguments");
593             }
594             /* Assume an ellipsis even in case of errors to avoid an error
595              * message for each other argument.
596              */
597             Ellipsis = 1;
598         }
599
600         /* Get the parameter value expression tree and add it to the parameter
601          * list.
602          */
603         AppendItem (Root, AssignExpr ());
604
605         /* Check for end of argument list */
606         if (CurTok.Tok != TOK_COMMA) {
607             break;
608         }
609         NextToken ();
610     }
611
612     /* We need the closing bracket here */
613     ConsumeRParen ();
614
615     /* Check if we had enough parameters */
616     if (ParamCount < Func->ParamCount) {
617         Error ("Too few function arguments");
618     }
619
620     /* Return the function call node */
621     return Root;
622 }
623
624
625
626 static ExprNode* DoPostIncDec (ExprNode* Left)
627 /* Handle postincrement and postdecrement */
628 {
629     ExprNode* Root;
630
631     /* Determine the type of the node */
632     nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_POST_INC : NT_POST_DEC;
633
634     /* Skip the operator token */
635     NextToken ();
636
637     /* The operand must be an lvalue */
638     if (Left->LValue == 0) {
639
640         /* Print a diagnostics */
641         Error ("lvalue expected");
642
643         /* It is safe to return the operand expression and probably better
644          * than returning an int, since the operand expression already has
645          * the correct type as expected by the program at this place, and
646          * it is even an rvalue.
647          */
648         return Left;
649     }
650
651     /* Setup the expression tree */
652     Root = AllocExprNode (NT, Left->Type, RVALUE);
653     SetLeftNode (Root, Left);
654
655     /* Return the new node */
656     return Root;
657 }
658
659
660
661 static ExprNode* PostfixExpr (void)
662 /* Handle a postfix expression */
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 operator * */
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_TYPECAST, 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