1 /*****************************************************************************/
5 /* Expression parser */
9 /* (C) 2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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. */
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: */
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 */
32 /*****************************************************************************/
63 /*****************************************************************************/
65 /*****************************************************************************/
69 static ExprNode* UnaryExpr (void);
70 ExprNode* AssignExpr (void);
71 ExprNode* Expression (void);
75 /*****************************************************************************/
76 /* Helper functions */
77 /*****************************************************************************/
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).
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 &&
99 static int GetBoolRep (const ExprNode* N)
100 /* Get the boolean representation of a constant expression node */
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 */
112 Internal ("GetBoolRep: Unknown type");
120 /*****************************************************************************/
121 /* Expression node helper functions */
122 /*****************************************************************************/
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
132 ExprNode* N = AllocExprNode (NT_CONST, type_int, RVALUE);
139 /*****************************************************************************/
141 /*****************************************************************************/
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.
157 /* Need left parenthesis */
160 /* Create a new expression node and assign a void type */
161 N = AllocExprNode (NT_ASM, type_void, RVALUE);
164 if (CurTok.Tok != TOK_SCONST) {
167 Error (ERR_STRLIT_EXPECTED);
169 /* To be on the safe side later, insert an empty asm string */
170 AppendItem (N, xstrdup (""));
174 /* Insert a copy of the string into the expression node */
175 AppendItem (N, xstrdup (GetLiteral (CurTok.IVal)));
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.
182 ResetLiteralOffs (CurTok.IVal);
185 /* Skip the string token */
188 /* Closing paren needed */
191 /* Return the created node */
197 static ExprNode* Primary (void)
198 /* Evaluate a primary expression */
202 /* Process a parenthesized subexpression. In this case we don't need to
203 * allocate a new node ourselves.
205 if (CurTok.Tok == TOK_LPAREN) {
212 /* Check for an integer or character constant */
213 if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
215 /* Create the new node */
216 N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
217 N->IVal = CurTok.IVal;
219 /* Skip the token and return the result */
224 /* Check for a float constant */
225 if (CurTok.Tok == TOK_FCONST) {
227 /* Create the new node */
228 N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
229 N->FVal = CurTok.FVal;
231 /* Skip the token and return the result */
236 /* All others may only be used if the expression evaluation is not called
237 * recursively by the preprocessor.
240 /* Illegal expression in PP mode */
241 Error (ERR_CPP_EXPR_EXPECTED);
243 /* Skip the token for error recovery */
246 /* Return an integer constant */
247 return GetIntNode (0);
251 if (CurTok.Tok == TOK_IDENT) {
257 /* Get a pointer to the symbol table entry */
258 Sym = FindSym (CurTok.Ident);
260 /* Is the symbol known? */
263 /* We found the symbol - skip the name token */
266 /* Check for illegal symbol types */
267 if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
268 /* Cannot use labels in expressions */
269 Error (ERR_SYMBOL_KIND);
270 return GetIntNode (0);
271 } else if (Sym->Flags & SC_TYPE) {
272 /* Cannot use type symbols */
273 Error (ERR_VAR_IDENT_EXPECTED);
274 /* Assume an int type to make lval valid */
275 return GetIntNode (0);
278 /* Handle enum values as constant integers */
279 if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
281 N = GetIntNode (Sym->V.EnumVal);
285 /* All symbols besides functions and arrays are lvalues */
286 int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type));
288 /* Create the node */
289 N = AllocExprNode (NT_SYM, Sym->Type, LVal);
291 /* Set the symbol pointer */
295 /* The symbol is referenced now */
296 Sym->Flags |= SC_REF;
300 /* We did not find the symbol. Remember the name, then skip it */
301 strcpy (Ident, CurTok.Ident);
304 /* IDENT is either an auto-declared function or an undefined
307 if (CurTok.Tok == TOK_LPAREN) {
309 /* Warn about the use of a function without prototype */
310 Warning (WARN_FUNC_WITHOUT_PROTO);
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.
316 Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
317 N = AllocExprNode (NT_SYM, Sym->Type, RVALUE);
322 /* Print an error about an undeclared variable */
323 Error (ERR_UNDEFINED_SYMBOL, Ident);
325 /* Undeclared Variable */
326 Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
327 N = AllocExprNode (NT_SYM, Sym->Type, LVALUE);
334 } else if (CurTok.Tok == TOK_SCONST) {
337 N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (CurTok.IVal))), RVALUE);
338 N->IVal = CurTok.IVal;
340 } else if (CurTok.Tok == TOK_ASM) {
345 } else if (CurTok.Tok == TOK_A) {
348 N = AllocExprNode (NT_REG_A, type_uchar, LVALUE);
350 } else if (CurTok.Tok == TOK_X) {
353 N = AllocExprNode (NT_REG_X, type_uchar, LVALUE);
355 } else if (CurTok.Tok == TOK_Y) {
358 N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE);
360 } else if (CurTok.Tok == TOK_AX) {
362 /* AX pseudo register */
363 N = AllocExprNode (NT_REG_AX, type_uint, LVALUE);
365 } else if (CurTok.Tok == TOK_EAX) {
367 /* EAX pseudo register */
368 N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE);
372 /* Illegal primary. */
373 Error (ERR_EXPR_EXPECTED);
378 /* Return the new node */
384 static ExprNode* DoArray (ExprNode* Left)
392 /* Skip the bracket */
396 Right = Expression ();
398 /* Check the types. As special "C" feature, accept a reversal of base and
400 * char C = 3["abcdefg"];
403 if (IsClassPtr (Left->Type)) {
404 /* Right side must be some sort of integer */
405 if (!IsClassInt (Right->Type)) {
407 Error (ERR_CANNOT_SUBSCRIPT);
408 /* To avoid problems later, create a new, legal subscript
411 Right = GetIntNode (0);
413 } else if (IsClassPtr (Right->Type)) {
417 /* Left side must be some sort of integer */
418 if (!IsClassInt (Right->Type)) {
420 Error (ERR_CANNOT_SUBSCRIPT);
421 /* To avoid problems later, create a new, legal subscript
424 Left = GetIntNode (0);
427 /* Swap the expression to it's normal form */
433 /* Invalid array expression. Skip the closing bracket, then return
434 * an integer instead of the array expression to be safe later.
436 Error (ERR_CANNOT_SUBSCRIPT);
438 return GetIntNode (0);
441 /* Skip the right bracket */
444 /* Get the type of the array elements */
445 ElementType = Indirect (Left->Type);
447 /* Allocate the branch node for the array expression */
448 Root = AllocExprNode (NT_ARRAY_SUBSCRIPT,
450 IsTypeArray (ElementType)? RVALUE : LVALUE);
452 /* Setup the branches */
453 SetLeftNode (Root, Left);
454 SetRightNode (Root, Right);
456 /* ...and return it */
462 static ExprNode* DoStruct (ExprNode* Left)
463 /* Process struct field access */
474 StructType = Left->Type;
475 if (CurTok.Tok == TOK_PTR_REF) {
476 NT = NT_STRUCTPTR_ACCESS;
477 if (!IsTypePtr (StructType)) {
478 Error (ERR_STRUCT_PTR_EXPECTED);
479 return GetIntNode (0);
481 StructType = Indirect (StructType);
483 NT = NT_STRUCT_ACCESS;
485 if (!IsClassStruct (StructType)) {
486 Error (ERR_STRUCT_EXPECTED);
487 return GetIntNode (0);
490 /* Skip the token and check for an identifier */
492 if (CurTok.Tok != TOK_IDENT) {
494 Error (ERR_IDENT_EXPECTED);
495 /* Return an integer expression instead */
496 return GetIntNode (0);
499 /* Get the symbol table entry and check for a struct field */
500 strcpy (Ident, CurTok.Ident);
502 Field = FindStructField (StructType, Ident);
504 /* Struct field not found */
505 Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
506 /* Return an integer expression instead */
507 return GetIntNode (0);
510 /* Allocate and set up the right (== field) node */
511 Right = AllocExprNode (NT_SYM, Field->Type, RVALUE);
512 SetNodeSym (Right, Field);
514 /* Allocate the branch node for the resulting expression */
515 Root = AllocExprNode (NT, Right->Type,
516 IsTypeArray (Right->Type)? RVALUE : LVALUE);
518 /* Setup the branches */
519 SetLeftNode (Root, Left);
520 SetRightNode (Root, Right);
522 /* ...and return it */
528 static ExprNode* DoFunctionCall (ExprNode* Left)
529 /* Process a function call */
531 type* ResultType; /* Type of function result */
532 FuncDesc* Func; /* Function descriptor */
533 ExprNode* Root; /* Function call node */
534 int Ellipsis; /* True if we have an open param list */
535 SymEntry* Param; /* Current formal parameter */
536 unsigned ParamCount; /* Actual parameter count */
537 unsigned ParamSize; /* Number of parameter bytes */
541 if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) {
543 /* Call to non function */
544 Error (ERR_ILLEGAL_FUNC_CALL);
546 /* Free the old tree */
549 /* Return something safe */
550 return GetIntNode (0);
553 /* Get the type of the function result */
554 ResultType = Left->Type;
555 if (IsTypeFuncPtr (Left->Type)) {
558 ResultType += DECODE_SIZE + 1; /* Set to result type */
560 /* Skip the opening parenthesis */
563 /* Allocate the function call node */
564 Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE);
566 /* Get a pointer to the function descriptor from the type string */
567 Func = GetFuncDesc (Left->Type);
569 /* Initialize vars to keep gcc silent */
572 /* Parse the parameter list */
576 while (CurTok.Tok != TOK_RPAREN) {
578 /* Count arguments */
581 /* Fetch the pointer to the next argument, check for too many args */
582 if (ParamCount <= Func->ParamCount) {
583 if (ParamCount == 1) {
585 Param = Func->SymTab->SymHead;
588 Param = Param->NextSym;
589 CHECK ((Param->Flags & SC_PARAM) != 0);
591 } else if (!Ellipsis) {
592 /* Too many arguments. Do we have an open param list? */
593 if ((Func->Flags & FD_ELLIPSIS) == 0) {
594 /* End of param list reached, no ellipsis */
595 Error (ERR_TOO_MANY_FUNC_ARGS);
597 /* Assume an ellipsis even in case of errors to avoid an error
598 * message for each other argument.
603 /* Get the parameter value expression tree and add it to the parameter
606 AppendItem (Root, AssignExpr ());
608 /* Check for end of argument list */
609 if (CurTok.Tok != TOK_COMMA) {
615 /* We need the closing bracket here */
618 /* Check if we had enough parameters */
619 if (ParamCount < Func->ParamCount) {
620 Error (ERR_TOO_FEW_FUNC_ARGS);
623 /* Return the function call node */
629 static ExprNode* DoPostIncDec (ExprNode* Left)
630 /* Handle postincrement and postdecrement */
634 /* Determine the type of the node */
635 nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_POST_INC : NT_POST_DEC;
637 /* Skip the operator token */
640 /* The operand must be an lvalue */
641 if (Left->LValue == 0) {
643 /* Print a diagnostics */
644 Error (ERR_LVALUE_EXPECTED);
646 /* It is safe to return the operand expression and probably better
647 * than returning an int, since the operand expression already has
648 * the correct type as expected by the program at this place, and
649 * it is even an rvalue.
654 /* Setup the expression tree */
655 Root = AllocExprNode (NT, Left->Type, RVALUE);
656 SetLeftNode (Root, Left);
658 /* Return the new node */
664 static ExprNode* PostfixExpr (void)
666 /* Get the lower level expression */
667 ExprNode* Root = Primary ();
670 while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN ||
671 CurTok.Tok == TOK_DOT || CurTok.Tok == TOK_PTR_REF ||
672 CurTok.Tok == TOK_INC || CurTok.Tok == TOK_DEC) {
675 switch (CurTok.Tok) {
678 Root = DoArray (Root);
682 Root = DoFunctionCall (Root);
687 Root = DoStruct (Root);
692 Root = DoPostIncDec (Root);
696 Internal ("Unexpected token");
701 /* Return the result */
707 static ExprNode* DoPreIncDec (void)
708 /* Handle preincrement and predecrement */
713 /* Determine the type of the node */
714 nodetype_t NT = (CurTok.Tok == TOK_INC)? NT_PRE_INC : NT_PRE_DEC;
716 /* Skip the operator token */
719 /* Get the expression to increment or decrement */
722 /* The operand must be an lvalue */
723 if (Op->LValue == 0) {
725 /* Print a diagnostics */
726 Error (ERR_LVALUE_EXPECTED);
728 /* It is safe to return the operand expression and probably better
729 * than returning an int, since the operand expression already has
730 * the correct type as expected by the program at this place, and
731 * it is even an rvalue.
736 /* Setup the expression tree */
737 Root = AllocExprNode (NT, Op->Type, RVALUE);
738 SetLeftNode (Root, Op);
740 /* Return the new node */
746 static ExprNode* DoUnaryPlusMinus (void)
747 /* Handle unary +/- */
752 /* Remember the current token for later, then skip it */
753 token_t Tok = CurTok.Tok;
756 /* Get the operand */
760 if (!IsClassInt (Op->Type) && !IsClassFloat (Op->Type)) {
762 /* Output diagnostic */
765 /* Free the errorneous node */
768 /* Return something that makes sense later */
769 return GetIntNode (0);
772 /* In case of PLUS, we must do nothing */
773 if (Tok == TOK_PLUS) {
775 /* Return the operand unchanged */
778 } else if (Op->NT == NT_CONST) {
780 /* The value is constant, change it according to the insn */
781 if (IsClassInt (Op->Type)) {
783 Op->IVal = -Op->IVal;
786 Op->FVal = -Op->FVal;
789 /* Return the operand itself */
794 /* Non constant value, setup the expression tree */
795 Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
796 SetLeftNode (Root, Op);
800 /* Return the new node */
806 static ExprNode* DoComplement (void)
812 /* Skip the operator token */
815 /* Get the operand */
819 if (!IsClassInt (Op->Type)) {
821 /* Display diagnostic */
822 Error (ERR_OP_NOT_ALLOWED);
824 /* Free the errorneous node */
827 /* Return something that makes sense later */
828 return GetIntNode (0);
831 /* If the operand is constant, handle the operation directly */
832 if (Op->NT == NT_CONST) {
834 /* Change the value and return the operand node */
835 Op->IVal = ~Op->IVal;
840 /* Setup the expression tree and return the new node */
841 Root = AllocExprNode (NT_COMPLEMENT, Op->Type, RVALUE);
842 SetLeftNode (Root, Op);
849 static ExprNode* DoBoolNot (void)
855 /* Skip the operator token */
858 /* Get the operand */
861 /* The boolean NOT operator eats anything - no need for a type check. */
863 /* Setup the expression tree and return the new node */
864 Root = AllocExprNode (NT_BOOL_NOT, type_int, RVALUE);
865 SetLeftNode (Root, Op);
871 static ExprNode* DoAddress (void)
872 /* Handle the address operator & */
876 /* Skip the operator */
879 /* Get the operand */
882 /* Accept using the address operator with arrays. This is harmless, it
883 * will just be as using the array without the operator.
885 if (IsTypeArray (Op->Type)) {
889 /* We cannot operate on rvalues */
890 if (Op->LValue == 0) {
894 /* Print diagnostics */
895 Error (ERR_ILLEGAL_ADDRESS);
897 /* Free the problematic tree */
900 /* Return something that is safe later */
901 Root = AllocExprNode (NT_CONST, PointerTo (type_void), 0);
906 /* Create the operator node and return it */
907 return AllocExprNode (NT_ADDRESS, PointerTo (Op->Type), RVALUE);
912 static ExprNode* DoIndirect (void)
913 /* Handle the indirection operaror * */
919 /* Skip the operator */
922 /* Get the operand */
926 if (!IsClassPtr (Op->Type)) {
928 /* Print diagnostics */
929 Error (ERR_ILLEGAL_INDIRECT);
931 /* Free the problematic tree */
934 /* Return something that is safe later ### */
935 return GetIntNode (0);
939 /* Get the type of the result */
940 ResultType = Indirect (Op->Type);
942 /* The result is an lvalue if it is not an array */
943 LVal = IsTypeArray (ResultType)? RVALUE : LVALUE;
945 /* Create the operator node and return it */
946 return AllocExprNode (NT_INDIRECT, ResultType, LVal);
951 static ExprNode* DoSizeOf (void)
952 /* Handle the sizeof operator */
957 /* Skip the left paren */
960 /* A type or an actual variable access may follow */
963 type Type[MAXTYPELEN];
965 /* A type in parenthesis. Skip the left paren. */
968 /* Read the type and calculate the size. */
969 Size = SizeOf (ParseType (Type));
971 /* Closing paren must follow */
976 /* Some other entity */
980 Size = SizeOf (N->Type);
987 /* Create a constant node with type size_t and return it */
988 N = AllocExprNode (NT_CONST, type_size_t, RVALUE);
995 static ExprNode* DoTypeCast (void)
996 /* Handle type casts */
998 type TargetType[MAXTYPELEN];
1002 /* Skip the left paren */
1006 ParseType (TargetType);
1011 /* Read the expression we have to cast */
1014 /* As a minor optimization, check if the type is already correct. If so,
1017 if (TypeCmp (TargetType, Op->Type) >= TC_EQUAL) {
1019 /* Just return the operand as is */
1024 /* Must be casted. Setup the expression tree and return the new node */
1025 Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
1026 SetLeftNode (Root, Op);
1034 static ExprNode* UnaryExpr (void)
1037 if (CurTok.Tok == TOK_INC || CurTok.Tok == TOK_DEC ||
1038 CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS ||
1039 CurTok.Tok == TOK_COMP || CurTok.Tok == TOK_BOOL_NOT ||
1040 CurTok.Tok == TOK_AND || CurTok.Tok == TOK_STAR ||
1041 CurTok.Tok == TOK_SIZEOF || IsTypeExpr ()) {
1043 /* Check the token */
1044 switch (CurTok.Tok) {
1048 return DoPreIncDec ();
1052 return DoUnaryPlusMinus ();
1055 return DoComplement ();
1058 return DoBoolNot ();
1061 return DoAddress ();
1064 return DoIndirect ();
1071 return DoTypeCast ();
1077 /* Call the lower level */
1078 return PostfixExpr ();
1085 static ExprNode* DoMul (ExprNode* Left)
1086 /* Handle multiplication */
1088 type TargetType[MAXTYPELEN];
1092 /* Check the type of the left operand */
1093 if (!IsClassInt (Left->Type) && !IsClassFloat (Left->Type)) {
1094 MError ("Invalid left operand to binary operator `*'");
1095 FreeExprTree (Left);
1096 Left = GetIntNode (0);
1099 /* Skip the operator token */
1102 /* Read the right expression */
1103 Right = UnaryExpr ();
1105 /* Check the type of the right operand */
1106 if (!IsClassInt (Right->Type) && !IsClassFloat (Right->Type)) {
1107 MError ("Invalid right operand to binary operator `*'");
1108 FreeExprTree (Right);
1109 Right = GetIntNode (0);
1112 /* Do minor optimizations ### */
1114 /* Make the root node */
1115 Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
1116 SetLeftNode (Root, Left);
1117 SetRightNode (Root, Right);
1124 static ExprNode* MultExpr (void)
1125 /* Handle multiplicative expressions: '*' '/' and '%' */
1127 /* Get the left leave */
1128 ExprNode* Root = UnaryExpr ();
1130 /* Check if this is for us */
1131 while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV || CurTok.Tok == TOK_MOD) {
1133 switch (CurTok.Tok) {
1136 Root = DoMul (Root);
1146 Internal ("Unexpected token");
1151 /* Return the resulting expression */
1157 static ExprNode* AddExpr (void)
1158 /* Handle additive expressions: '+' and '-' */
1160 /* Get the left leave */
1161 ExprNode* Root = MultExpr ();
1163 /* Check if this is for us */
1164 while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) {
1166 switch (CurTok.Tok) {
1175 Internal ("Unexpected token");
1180 /* Return the resulting expression */
1186 static ExprNode* ShiftExpr (void)
1187 /* Handle shift expressions: '<<' and '>>' */
1189 /* Get the left leave */
1190 ExprNode* Root = AddExpr ();
1192 /* Check if this is for us */
1193 while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
1195 switch (CurTok.Tok) {
1204 Internal ("Unexpected token");
1209 /* Return the resulting expression */
1215 static ExprNode* RelationalExpr (void)
1216 /* Handle relational expressions: '<=', '<', '>=' and '>' */
1218 /* Get the left leave */
1219 ExprNode* Root = ShiftExpr ();
1221 /* Check if this is for us */
1222 while (CurTok.Tok == TOK_LE || CurTok.Tok == TOK_LT ||
1223 CurTok.Tok == TOK_GE || CurTok.Tok == TOK_GT) {
1225 switch (CurTok.Tok) {
1240 Internal ("Unexpected token");
1245 /* Return the resulting expression */
1251 static ExprNode* EqualityExpr (void)
1252 /* Handle equality expressions: '==' and '!=' */
1254 /* Get the left leave */
1255 ExprNode* Root = RelationalExpr ();
1257 /* Check if this is for us */
1258 while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE) {
1260 switch (CurTok.Tok) {
1269 Internal ("Unexpected token");
1274 /* Return the resulting expression */
1280 static ExprNode* AndExpr (void)
1281 /* Handle and expressions: '&' */
1283 /* Get the left leave */
1284 ExprNode* Root = EqualityExpr ();
1286 /* Check if this is for us */
1287 while (CurTok.Tok == TOK_AND) {
1289 ExprNode* Left = Root;
1292 /* Skip the token */
1295 /* Get the right operand */
1296 Right = EqualityExpr ();
1299 if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1301 /* Print a diagnostic */
1302 Error (ERR_OP_NOT_ALLOWED);
1304 /* Remove the unneeded nodes */
1305 FreeExprTree (Right);
1306 FreeExprTree (Left);
1308 /* Create something safe */
1309 Root = GetIntNode (0);
1313 /* Check if both operands are constant */
1314 if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1316 /* Get the constant result */
1317 int Result = GetBoolRep (Left) & GetBoolRep (Right);
1319 /* Remove the unneeded nodes */
1320 FreeExprTree (Right);
1321 FreeExprTree (Left);
1323 /* Create a constant result */
1324 Root = GetIntNode (Result);
1328 /* Make an operator node */
1329 Root = AllocExprNode (NT_AND, type_int, RVALUE);
1330 SetRightNode (Root, Right);
1331 SetLeftNode (Root, Left);
1337 /* Return the resulting expression */
1343 static ExprNode* XorExpr (void)
1344 /* Handle xor expressions: '^' */
1346 /* Get the left leave */
1347 ExprNode* Root = AndExpr ();
1349 /* Check if this is for us */
1350 while (CurTok.Tok == TOK_XOR) {
1352 ExprNode* Left = Root;
1355 /* Skip the token */
1358 /* Get the right operand */
1362 if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1364 /* Print a diagnostic */
1365 Error (ERR_OP_NOT_ALLOWED);
1367 /* Remove the unneeded nodes */
1368 FreeExprTree (Right);
1369 FreeExprTree (Left);
1371 /* Create something safe */
1372 Root = GetIntNode (0);
1376 /* Check if both operands are constant */
1377 if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1379 /* Get the constant result */
1380 int Result = GetBoolRep (Left) ^ GetBoolRep (Right);
1382 /* Remove the unneeded nodes */
1383 FreeExprTree (Right);
1384 FreeExprTree (Left);
1386 /* Create a constant result */
1387 Root = GetIntNode (Result);
1391 /* Make an operator node */
1392 Root = AllocExprNode (NT_XOR, type_int, RVALUE);
1393 SetRightNode (Root, Right);
1394 SetLeftNode (Root, Left);
1400 /* Return the resulting expression */
1406 static ExprNode* OrExpr (void)
1407 /* Handle or expressions: '|' */
1409 /* Get the left leave */
1410 ExprNode* Root = XorExpr ();
1412 /* Check if this is for us */
1413 while (CurTok.Tok == TOK_OR) {
1415 ExprNode* Left = Root;
1418 /* Skip the token */
1421 /* Get the right operand */
1425 if (!IsClassInt (Left->Type) || !IsClassInt (Right->Type)) {
1427 /* Print a diagnostic */
1428 Error (ERR_OP_NOT_ALLOWED);
1430 /* Remove the unneeded nodes */
1431 FreeExprTree (Right);
1432 FreeExprTree (Left);
1434 /* Create something safe */
1435 Root = GetIntNode (0);
1439 /* Check if both operands are constant */
1440 if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1442 /* Get the constant result */
1443 int Result = GetBoolRep (Left) | GetBoolRep (Right);
1445 /* Remove the unneeded nodes */
1446 FreeExprTree (Right);
1447 FreeExprTree (Left);
1449 /* Create a constant result */
1450 Root = GetIntNode (Result);
1454 /* Make an operator node */
1455 Root = AllocExprNode (NT_OR, type_int, RVALUE);
1456 SetRightNode (Root, Right);
1457 SetLeftNode (Root, Left);
1463 /* Return the resulting expression */
1469 static ExprNode* BoolAndExpr (void)
1470 /* Handle boolean and expressions: '&&' */
1472 /* Get the left leave */
1473 ExprNode* Root = OrExpr ();
1475 /* Check if this is for us */
1476 while (CurTok.Tok == TOK_BOOL_AND) {
1478 ExprNode* Left = Root;
1481 /* Skip the token */
1484 /* Get the right operand */
1487 /* Check if both operands are constant */
1488 if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1490 /* Get the constant result */
1491 int Result = GetBoolRep (Left) && GetBoolRep (Right);
1493 /* Remove the unneeded nodes */
1494 FreeExprTree (Right);
1495 FreeExprTree (Left);
1497 /* Create a constant result */
1498 Root = GetIntNode (Result);
1502 /* Make an operator node */
1503 Root = AllocExprNode (NT_BOOL_AND, type_int, RVALUE);
1504 SetRightNode (Root, Right);
1505 SetLeftNode (Root, Left);
1511 /* Return the resulting expression */
1517 static ExprNode* BoolOrExpr (void)
1518 /* Handle boolean or expressions: '||' */
1520 /* Get the left leave */
1521 ExprNode* Root = BoolAndExpr ();
1523 /* Check if this is for us */
1524 while (CurTok.Tok == TOK_BOOL_OR) {
1526 ExprNode* Left = Root;
1529 /* Skip the token */
1532 /* Get the right operand */
1533 Right = BoolAndExpr ();
1535 /* Check if both operands are constant */
1536 if (Left->NT == NT_CONST && Right->NT == NT_CONST) {
1538 /* Get the constant result */
1539 int Result = GetBoolRep (Left) && GetBoolRep (Right);
1541 /* Remove the unneeded nodes */
1542 FreeExprTree (Right);
1543 FreeExprTree (Left);
1545 /* Create a constant result */
1546 Root = GetIntNode (Result);
1550 /* Make an operator node */
1551 Root = AllocExprNode (NT_BOOL_OR, type_int, RVALUE);
1552 SetRightNode (Root, Right);
1553 SetLeftNode (Root, Left);
1559 /* Return the resulting expression */
1565 static ExprNode* ConditionalExpr (void)
1566 /* Handle the ternary operator: ':?' */
1568 /* Get the left leave */
1569 ExprNode* Cond = BoolOrExpr ();
1571 /* Check if this is for us */
1572 if (CurTok.Tok == TOK_QUEST) {
1580 /* Skip the token */
1583 /* Get the first expression */
1584 Expr1 = Expression ();
1586 /* Colon must follow */
1589 /* Get the second expression */
1590 Expr2 = ConditionalExpr ();
1592 /* Get the common type of the two expressions */
1593 Type = CommonType (Expr1->Type, Expr2->Type);
1595 /* Create a new ternary token node */
1596 Root = AllocExprNode (NT_TERNARY, Type, RVALUE);
1597 AppendItem (Root, Cond);
1598 AppendItem (Root, Expr1);
1599 AppendItem (Root, Expr2);
1601 /* Return the result */
1606 /* Just return the lower level expression */