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* Expr1 (void);
71 ExprNode* Expr0 (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_LPAREN && (
89 (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) ||
90 (nxttok == TOK_CONST) ||
91 (nxttok == TOK_IDENT &&
92 (Entry = FindSym (NextTok.Ident)) != 0 &&
99 /*****************************************************************************/
100 /* Expression node helper functions */
101 /*****************************************************************************/
105 static ExprNode* GetIntNode (int Value)
106 /* Allocate a new expression node from the tree, make it a valid integer
107 * node and return it. Often used if an error occurs to get a safe expression
111 ExprNode* N = AllocExprNode (NT_CONST, type_int, RVALUE);
118 /*****************************************************************************/
120 /*****************************************************************************/
124 ExprNode* DoAsm (void)
125 /* This function parses ASM statements. The syntax of the ASM directive
126 * looks like the one defined for C++ (C has no ASM directive), that is,
127 * a string literal in parenthesis.
136 /* Need left parenthesis */
139 /* Create a new expression node and assign a void type */
140 N = AllocExprNode (NT_ASM, type_void, RVALUE);
143 if (curtok != TOK_SCONST) {
146 Error (ERR_STRLIT_EXPECTED);
148 /* To be on the safe side later, insert an empty asm string */
149 AppendItem (N, xstrdup (""));
153 /* Insert a copy of the string into the expression node */
154 AppendItem (N, xstrdup (GetLiteral (curval)));
156 /* Reset the string pointer, effectivly clearing the string from the
157 * string table. Since we're working with one token lookahead, this
158 * will fail if the next token is also a string token, but that's a
159 * syntax error anyway, because we expect a right paren.
161 ResetLiteralOffs (curval);
164 /* Skip the string token */
167 /* Closing paren needed */
170 /* Return the created node */
176 static ExprNode* Primary (void)
177 /* Evaluate a primary expression */
181 /* Process a parenthesized subexpression. In this case we don't need to
182 * allocate a new node ourselves.
184 if (curtok == TOK_LPAREN) {
191 /* Check for an integer or character constant */
192 if (curtok == TOK_ICONST || curtok == TOK_CCONST) {
194 /* Create the new node */
195 N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
196 N->V.I = CurTok.IVal;
198 /* Skip the token and return the result */
203 /* Check for a float constant */
204 if (curtok == TOK_FCONST) {
206 /* Create the new node */
207 N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE);
208 N->V.F = CurTok.FVal;
210 /* Skip the token and return the result */
215 /* All others may only be used if the expression evaluation is not called
216 * recursively by the preprocessor.
219 /* Illegal expression in PP mode */
220 Error (ERR_CPP_EXPR_EXPECTED);
222 /* Skip the token for error recovery */
225 /* Return an integer constant */
226 return GetIntNode (0);
230 if (curtok == TOK_IDENT) {
236 /* Get a pointer to the symbol table entry */
237 Sym = FindSym (CurTok.Ident);
239 /* Is the symbol known? */
242 /* We found the symbol - skip the name token */
245 /* Check for illegal symbol types */
246 if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
247 /* Cannot use labels in expressions */
248 Error (ERR_SYMBOL_KIND);
249 return GetIntNode (0);
250 } else if (Sym->Flags & SC_TYPE) {
251 /* Cannot use type symbols */
252 Error (ERR_VAR_IDENT_EXPECTED);
253 /* Assume an int type to make lval valid */
254 return GetIntNode (0);
257 /* Handle enum values as constant integers */
258 if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
260 N = GetIntNode (Sym->V.EnumVal);
264 /* All symbols besides functions and arrays are lvalues */
265 int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type));
267 /* Create the node */
268 N = AllocExprNode (NT_SYM, Sym->Type, LVal);
270 /* Set the symbol pointer */
274 /* The symbol is referenced now */
275 Sym->Flags |= SC_REF;
279 /* We did not find the symbol. Remember the name, then skip it */
280 strcpy (Ident, CurTok.Ident);
283 /* IDENT is either an auto-declared function or an undefined
286 if (curtok == TOK_LPAREN) {
288 /* Warn about the use of a function without prototype */
289 Warning (WARN_FUNC_WITHOUT_PROTO);
291 /* Declare a function returning int. For that purpose, prepare
292 * a function signature for a function having an empty param
293 * list and returning int.
295 Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
296 N = AllocExprNode (NT_SYM, Sym->Type, RVALUE);
301 /* Print an error about an undeclared variable */
302 Error (ERR_UNDEFINED_SYMBOL, Ident);
304 /* Undeclared Variable */
305 Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
306 N = AllocExprNode (NT_SYM, Sym->Type, LVALUE);
313 } else if (curtok == TOK_SCONST) {
316 N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (curval))), RVALUE);
319 } else if (curtok == TOK_ASM) {
324 } else if (curtok == TOK_A) {
327 N = AllocExprNode (NT_REG_A, type_uchar, LVALUE);
329 } else if (curtok == TOK_X) {
332 N = AllocExprNode (NT_REG_X, type_uchar, LVALUE);
334 } else if (curtok == TOK_Y) {
337 N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE);
339 } else if (curtok == TOK_AX) {
341 /* AX pseudo register */
342 N = AllocExprNode (NT_REG_AX, type_uint, LVALUE);
344 } else if (curtok == TOK_EAX) {
346 /* EAX pseudo register */
347 N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE);
351 /* Illegal primary. */
352 Error (ERR_EXPR_EXPECTED);
357 /* Return the new node */
363 static ExprNode* DoArray (ExprNode* Left)
371 /* Skip the bracket */
377 /* Check the types. As special "C" feature, accept a reversal of base and
379 * char C = 3["abcdefg"];
382 if (IsClassPtr (Left->Type)) {
383 /* Right side must be some sort of integer */
384 if (!IsClassInt (Right->Type)) {
386 Error (ERR_CANNOT_SUBSCRIPT);
387 /* To avoid problems later, create a new, legal subscript
390 Right = GetIntNode (0);
392 } else if (IsClassPtr (Right->Type)) {
396 /* Left side must be some sort of integer */
397 if (!IsClassInt (Right->Type)) {
399 Error (ERR_CANNOT_SUBSCRIPT);
400 /* To avoid problems later, create a new, legal subscript
403 Left = GetIntNode (0);
406 /* Swap the expression to it's normal form */
412 /* Invalid array expression. Skip the closing bracket, then return
413 * an integer instead of the array expression to be safe later.
415 Error (ERR_CANNOT_SUBSCRIPT);
417 return GetIntNode (0);
420 /* Skip the right bracket */
423 /* Get the type of the array elements */
424 ElementType = Indirect (Left->Type);
426 /* Allocate the branch node for the array expression */
427 Root = AllocExprNode (NT_ARRAY_SUBSCRIPT,
429 IsTypeArray (ElementType)? RVALUE : LVALUE);
431 /* Setup the branches */
432 SetLeftNode (Root, Left);
433 SetRightNode (Root, Right);
435 /* ...and return it */
441 static ExprNode* DoStruct (ExprNode* Left)
442 /* Process struct field access */
453 StructType = Left->Type;
454 if (curtok == TOK_PTR_REF) {
455 NT = NT_STRUCTPTR_ACCESS;
456 if (!IsTypePtr (StructType)) {
457 Error (ERR_STRUCT_PTR_EXPECTED);
458 return GetIntNode (0);
460 StructType = Indirect (StructType);
462 NT = NT_STRUCT_ACCESS;
464 if (!IsClassStruct (StructType)) {
465 Error (ERR_STRUCT_EXPECTED);
466 return GetIntNode (0);
469 /* Skip the token and check for an identifier */
471 if (curtok != TOK_IDENT) {
473 Error (ERR_IDENT_EXPECTED);
474 /* Return an integer expression instead */
475 return GetIntNode (0);
478 /* Get the symbol table entry and check for a struct field */
479 strcpy (Ident, CurTok.Ident);
481 Field = FindStructField (StructType, Ident);
483 /* Struct field not found */
484 Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
485 /* Return an integer expression instead */
486 return GetIntNode (0);
489 /* Allocate and set up the right (== field) node */
490 Right = AllocExprNode (NT_SYM, Field->Type, RVALUE);
491 SetNodeSym (Right, Field);
493 /* Allocate the branch node for the resulting expression */
494 Root = AllocExprNode (NT, Right->Type,
495 IsTypeArray (Right->Type)? RVALUE : LVALUE);
497 /* Setup the branches */
498 SetLeftNode (Root, Left);
499 SetRightNode (Root, Right);
501 /* ...and return it */
507 static ExprNode* DoFunctionCall (ExprNode* Left)
508 /* Process a function call */
510 type* ResultType; /* Type of function result */
511 FuncDesc* Func; /* Function descriptor */
512 ExprNode* Root; /* Function call node */
513 int Ellipsis; /* True if we have an open param list */
514 SymEntry* Param; /* Current formal parameter */
515 unsigned ParamCount; /* Actual parameter count */
516 unsigned ParamSize; /* Number of parameter bytes */
520 if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) {
522 /* Call to non function */
523 Error (ERR_ILLEGAL_FUNC_CALL);
525 /* Free the old node */
528 /* Return something safe */
529 return GetIntNode (0);
532 /* Get the type of the function result */
533 ResultType = Left->Type;
534 if (IsTypeFuncPtr (Left->Type)) {
537 ResultType += DECODE_SIZE + 1; /* Set to result type */
539 /* Skip the opening parenthesis */
542 /* Allocate the function call node */
543 Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE);
545 /* Get a pointer to the function descriptor from the type string */
546 Func = GetFuncDesc (Left->Type);
548 /* Initialize vars to keep gcc silent */
551 /* Parse the parameter list */
555 while (curtok != TOK_RPAREN) {
557 /* Count arguments */
560 /* Fetch the pointer to the next argument, check for too many args */
561 if (ParamCount <= Func->ParamCount) {
562 if (ParamCount == 1) {
564 Param = Func->SymTab->SymHead;
567 Param = Param->NextSym;
568 CHECK ((Param->Flags & SC_PARAM) != 0);
570 } else if (!Ellipsis) {
571 /* Too many arguments. Do we have an open param list? */
572 if ((Func->Flags & FD_ELLIPSIS) == 0) {
573 /* End of param list reached, no ellipsis */
574 Error (ERR_TOO_MANY_FUNC_ARGS);
576 /* Assume an ellipsis even in case of errors to avoid an error
577 * message for each other argument.
582 /* Get the parameter value expression tree and add it to the parameter
583 * list. (### check expr level)
585 AppendItem (Root, Expr1 ());
587 /* Check for end of argument list */
588 if (curtok != TOK_COMMA) {
594 /* We need the closing bracket here */
597 /* Check if we had enough parameters */
598 if (ParamCount < Func->ParamCount) {
599 Error (ERR_TOO_FEW_FUNC_ARGS);
602 /* Return the function call node */
608 static ExprNode* PostfixExpr (void)
610 /* Get the lower level expression */
611 ExprNode* Root = Primary ();
614 while (curtok == TOK_LBRACK || curtok == TOK_LPAREN ||
615 curtok == TOK_DOT || curtok == TOK_PTR_REF ||
616 curtok == TOK_INC || curtok == TOK_DEC) {
622 Root = DoArray (Root);
626 Root = DoFunctionCall (Root);
631 Root = DoStruct (Root);
641 Internal ("Unexpected token");
646 /* Return the result */
652 static ExprNode* DoPreIncDec (void)
653 /* Handle preincrement and predecrement */
658 /* Determine the type of the node */
659 nodetype_t NT = (curtok == TOK_INC)? NT_PRE_INC : NT_PRE_DEC;
661 /* Skip the operator token */
664 /* Get the expression to increment or decrement */
667 /* The operand must be an lvalue */
668 if (Op->LValue == 0) {
670 /* Print a diagnostics */
671 Error (ERR_LVALUE_EXPECTED);
673 /* It is safe to return the operand expression and probably better
674 * than returning an int, since the operand expression already has
675 * the correct type as expected by the program at this place, and
676 * it is even an rvalue.
681 /* Setup the expression tree */
682 Root = AllocExprNode (NT, Op->Type, RVALUE);
683 SetLeftNode (Root, Op);
685 /* Return the new node */
691 static ExprNode* DoUnaryPlusMinus (void)
692 /* Handle unary +/- */
697 /* Remember the current token for later, then skip it */
698 token_t Tok = curtok;
701 /* Get the operand */
705 if (!IsClassInt (Op->Type) && !IsClassFloat (Op->Type)) {
707 /* Display diagnostic */
710 /* Free the errorneous node */
713 /* Return something that makes sense later */
714 return GetIntNode (0);
717 /* In case of PLUS, we must do nothing */
718 if (Tok == TOK_PLUS) {
720 /* Use the operand unchanged */
725 /* Setup the expression tree */
726 Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
727 SetLeftNode (Root, Op);
731 /* Return the new node */
737 static ExprNode* UnaryExpr (void)
740 if (curtok == TOK_INC || curtok == TOK_DEC ||
741 curtok == TOK_PLUS || curtok == TOK_MINUS ||
742 curtok == TOK_AND || curtok == TOK_STAR ||
743 curtok == TOK_COMP || curtok == TOK_BOOL_NOT ||
744 curtok == TOK_SIZEOF || IsTypeExpr ()) {
746 /* Check the token */
751 return DoPreIncDec ();
755 return DoUnaryPlusMinus ();
779 /* Call the lower level */
780 return PostfixExpr ();