X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=343ecdfed4eb048acab1813cef404fc9205623d1;hb=77bfcc1ff0a88e0430f077d22b6fad07c7d0c86b;hp=7f30bb11bdb24f719b8f57b4899c41b107a12b29;hpb=0c20177fce7256c342f55166594b4693d4e3e796;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 7f30bb11b..343ecdfed 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -486,6 +486,12 @@ static void FunctionCall (ExprDesc* Expr) } } else { + /* Check function attributes */ + if (Expr->Sym && SymHasAttr (Expr->Sym, atNoReturn)) { + /* For now, handle as if a return statement was encountered */ + F_ReturnFound (CurrentFunc); + } + /* Check for known standard functions and inline them */ if (Expr->Name != 0) { int StdFunc = FindStdFunc ((const char*) Expr->Name); @@ -547,7 +553,7 @@ static void FunctionCall (ExprDesc* Expr) /* If we have a pointer on stack, remove it */ if (PtrOnStack) { - g_space (- (int) sizeofarg (CF_PTR)); + g_drop (SIZEOF_PTR); pop (CF_PTR); } @@ -740,11 +746,13 @@ static void Primary (ExprDesc* E) break; case TOK_SCONST: + case TOK_WCSCONST: /* String literal */ - E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); + E->LVal = UseLiteral (CurTok.SVal); + E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal)); E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; - E->IVal = CurTok.IVal; - E->Name = LiteralPoolLabel; + E->IVal = 0; + E->Name = GetLiteralLabel (CurTok.SVal); NextToken (); break; @@ -796,6 +804,7 @@ static void ArrayRef (ExprDesc* Expr) ExprDesc Subscript; CodeMark Mark1; CodeMark Mark2; + TypeCode Qualifiers; Type* ElementType; Type* tptr1; @@ -828,7 +837,7 @@ static void ArrayRef (ExprDesc* Expr) } /* TOS now contains ptr to array elements. Get the subscript. */ - ExprWithCheck (hie0, &Subscript); + MarkedExprWithCheck (hie0, &Subscript); /* Check the types of array and subscript. We can either have a * pointer/array to the left, in which case the subscript must be of an @@ -837,12 +846,16 @@ static void ArrayRef (ExprDesc* Expr) * Since we do the necessary checking here, we can rely later on the * correct types. */ + Qualifiers = T_QUAL_NONE; if (IsClassPtr (Expr->Type)) { if (!IsClassInt (Subscript.Type)) { Error ("Array subscript is not an integer"); /* To avoid any compiler errors, make the expression a valid int */ ED_MakeConstAbsInt (&Subscript, 0); } + if (IsTypeArray (Expr->Type)) { + Qualifiers = GetQualifier (Expr->Type); + } ElementType = Indirect (Expr->Type); } else if (IsClassInt (Expr->Type)) { if (!IsClassPtr (Subscript.Type)) { @@ -851,6 +864,8 @@ static void ArrayRef (ExprDesc* Expr) * address 0. */ ED_MakeConstAbs (&Subscript, 0, GetCharArrayType (1)); + } else if (IsTypeArray (Subscript.Type)) { + Qualifiers = GetQualifier (Subscript.Type); } ElementType = Indirect (Subscript.Type); } else { @@ -863,6 +878,14 @@ static void ArrayRef (ExprDesc* Expr) ElementType = Indirect (Expr->Type); } + /* The element type has the combined qualifiers from itself and the array, + * it is a member of (if any). + */ + if (GetQualifier (ElementType) != (GetQualifier (ElementType) | Qualifiers)) { + ElementType = TypeDup (ElementType); + ElementType->C |= Qualifiers; + } + /* If the subscript is a bit-field, load it and make it an rvalue */ if (ED_IsBitField (&Subscript)) { LoadExpr (CF_NONE, &Subscript); @@ -870,7 +893,7 @@ static void ArrayRef (ExprDesc* Expr) } /* Check if the subscript is constant absolute value */ - if (ED_IsConstAbs (&Subscript)) { + if (ED_IsConstAbs (&Subscript) && ED_CodeRangeIsEmpty (&Subscript)) { /* The array subscript is a numeric constant. If we had pushed the * array base address onto the stack before, we can remove this value, @@ -1069,12 +1092,14 @@ static void StructRef (ExprDesc* Expr) { ident Ident; SymEntry* Field; + TypeCode Q; /* Skip the token and check for an identifier */ NextToken (); if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1084,7 +1109,8 @@ static void StructRef (ExprDesc* Expr) Field = FindStructField (Expr->Type, Ident); if (Field == 0) { Error ("Struct/union has no field named `%s'", Ident); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1103,8 +1129,18 @@ static void StructRef (ExprDesc* Expr) /* Set the struct field offset */ Expr->IVal += Field->V.Offs; - /* The type is now the type of the field */ - Expr->Type = Field->Type; + /* The type is the type of the field plus any qualifiers from the struct */ + if (IsClassStruct (Expr->Type)) { + Q = GetQualifier (Expr->Type); + } else { + Q = GetQualifier (Indirect (Expr->Type)); + } + if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) { + Expr->Type = Field->Type; + } else { + Expr->Type = TypeDup (Field->Type); + Expr->Type->C |= Q; + } /* An struct member is actually a variable. So the rules for variables * with respect to the reference type apply: If it's an array, it is @@ -1591,9 +1627,12 @@ void hie10 (ExprDesc* Expr) ED_MakeRValExpr (Expr); } /* If the expression is already a pointer to function, the - * additional dereferencing operator must be ignored. + * additional dereferencing operator must be ignored. A function + * itself is represented as "pointer to function", so any number + * of dereference operators is legal, since the result will + * always be converted to "pointer to function". */ - if (IsTypeFuncPtr (Expr->Type)) { + if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) { /* Expression not storable */ ED_MakeRVal (Expr); } else { @@ -1721,7 +1760,14 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); + MarkedExprWithCheck (hienext, &Expr2); + + /* Check for a constant expression */ + rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)); + if (!rconst) { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + } /* Check the type of the rhs */ if (!IsClassInt (Expr2.Type)) { @@ -1889,7 +1935,14 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); + MarkedExprWithCheck (hienext, &Expr2); + + /* Check for a constant expression */ + rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)); + if (!rconst) { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + } /* Make sure, the types are compatible */ if (IsClassInt (Expr->Type)) { @@ -2057,21 +2110,21 @@ static void parseadd (ExprDesc* Expr) /* Both expressions are constants. Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { - /* Left is pointer, right is int, must scale rhs */ + /* Left is pointer, right is int, must scale rhs */ Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst); - /* Result type is a pointer */ + /* Result type is a pointer */ } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { - /* Left is int, right is pointer, must scale lhs */ + /* Left is int, right is pointer, must scale lhs */ Expr->IVal = Expr->IVal * CheckedPSizeOf (rhst) + Expr2.IVal; - /* Result type is a pointer */ - Expr->Type = Expr2.Type; + /* Result type is a pointer */ + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { - /* Integer addition */ - Expr->IVal += Expr2.IVal; - typeadjust (Expr, &Expr2, 1); + /* Integer addition */ + Expr->IVal += Expr2.IVal; + typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ - Error ("Invalid operands for binary operator `+'"); + Error ("Invalid operands for binary operator `+'"); } } else { @@ -2169,7 +2222,10 @@ static void parseadd (ExprDesc* Expr) g_push (TypeOf (Expr->Type), 0); /* --> stack */ /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { + MarkedExprWithCheck (hie9, &Expr2); + + /* Check for a constant rhs expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { /* Right hand side is a constant. Get the rhs type */ rhst = Expr2.Type; @@ -2203,6 +2259,9 @@ static void parseadd (ExprDesc* Expr) } else { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* lhs and rhs are not constant. Get the rhs type. */ rhst = Expr2.Type; @@ -2282,7 +2341,10 @@ static void parsesub (ExprDesc* Expr) g_push (TypeOf (lhst), 0); /* --> stack */ /* Parse the right hand side */ - if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { + MarkedExprWithCheck (hie9, &Expr2); + + /* Check for a constant rhs expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { /* The right hand side is constant. Get the rhs type. */ rhst = Expr2.Type; @@ -2354,38 +2416,41 @@ static void parsesub (ExprDesc* Expr) /* Do the subtraction */ g_dec (flags | CF_CONST, Expr2.IVal); - /* If this was a pointer subtraction, we must scale the result */ - if (rscale != 1) { - g_scale (flags, -rscale); - } + /* If this was a pointer subtraction, we must scale the result */ + if (rscale != 1) { + g_scale (flags, -rscale); + } - /* Result is a rvalue in the primary register */ - ED_MakeRValExpr (Expr); - ED_MarkAsUntested (Expr); + /* Result is a rvalue in the primary register */ + ED_MakeRValExpr (Expr); + ED_MarkAsUntested (Expr); - } + } } else { - /* Right hand side is not constant. Get the rhs type. */ - rhst = Expr2.Type; + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + + /* Right hand side is not constant. Get the rhs type. */ + rhst = Expr2.Type; /* Check for pointer arithmetic */ - if (IsClassPtr (lhst) && IsClassInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - g_scale (CF_INT, CheckedPSizeOf (lhst)); - /* Operate on pointers, result type is a pointer */ - flags = CF_PTR; - } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { - /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { - Error ("Incompatible pointer types"); - } else { - rscale = CheckedPSizeOf (lhst); - } - /* Operate on pointers, result type is an integer */ - flags = CF_PTR; - Expr->Type = type_int; + g_scale (CF_INT, CheckedPSizeOf (lhst)); + /* Operate on pointers, result type is a pointer */ + flags = CF_PTR; + } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { + /* Left is pointer, right is pointer, must scale result */ + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { + Error ("Incompatible pointer types"); + } else { + rscale = CheckedPSizeOf (lhst); + } + /* Operate on pointers, result type is an integer */ + flags = CF_PTR; + Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction. If the left hand side descriptor says that * the lhs is const, we have to remove this mark, since this is no @@ -2816,7 +2881,7 @@ static void hieQuest (ExprDesc* Expr) -static void opeq (const GenDesc* Gen, ExprDesc* Expr) +static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Process "op=" operators. */ { ExprDesc Expr2; @@ -2861,7 +2926,18 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) g_push (flags, 0); /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &Expr2) == 0) { + MarkedExprWithCheck (hie1, &Expr2); + + /* The rhs must be an integer (or a float, but we don't support that yet */ + if (!IsClassInt (Expr2.Type)) { + Error ("Invalid right operand for binary operator `%s'", Op); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ + } + + /* Check for a constant expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { /* The resulting value is a constant. If the generator has the NOPUSH * flag set, don't push the lhs. */ @@ -2897,7 +2973,9 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) Gen->Func (flags | CF_CONST, Expr2.IVal); } } else { - /* rhs is not constant and already in the primary register */ + + /* rhs is not constant. Load into the primary */ + LoadExpr (CF_NONE, &Expr2); if (MustScale) { /* lhs is a pointer, scale rhs */ g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1)); @@ -2919,7 +2997,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) -static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) +static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) /* Process the += and -= operators */ { ExprDesc Expr2; @@ -2931,7 +3009,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) /* We're currently only able to handle some adressing modes */ if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) { /* Use generic routine */ - opeq (Gen, Expr); + opeq (Gen, Expr, Op); return; } @@ -2964,8 +3042,16 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) lflags = 0; rflags = 0; - /* Evaluate the rhs */ + /* Evaluate the rhs. We expect an integer here, since float is not + * supported + */ hie1 (&Expr2); + if (!IsClassInt (Expr2.Type)) { + Error ("Invalid right operand for binary operator `%s'", Op); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ + } if (ED_IsConstAbs (&Expr2)) { /* The resulting value is a constant. Scale it. */ if (MustScale) { @@ -3059,43 +3145,43 @@ void hie1 (ExprDesc* Expr) break; case TOK_PLUS_ASSIGN: - addsubeq (&GenPASGN, Expr); + addsubeq (&GenPASGN, Expr, "+="); break; case TOK_MINUS_ASSIGN: - addsubeq (&GenSASGN, Expr); + addsubeq (&GenSASGN, Expr, "-="); break; case TOK_MUL_ASSIGN: - opeq (&GenMASGN, Expr); + opeq (&GenMASGN, Expr, "*="); break; case TOK_DIV_ASSIGN: - opeq (&GenDASGN, Expr); + opeq (&GenDASGN, Expr, "/="); break; case TOK_MOD_ASSIGN: - opeq (&GenMOASGN, Expr); + opeq (&GenMOASGN, Expr, "%="); break; case TOK_SHL_ASSIGN: - opeq (&GenSLASGN, Expr); + opeq (&GenSLASGN, Expr, "<<="); break; case TOK_SHR_ASSIGN: - opeq (&GenSRASGN, Expr); + opeq (&GenSRASGN, Expr, ">>="); break; case TOK_AND_ASSIGN: - opeq (&GenAASGN, Expr); + opeq (&GenAASGN, Expr, "&="); break; case TOK_XOR_ASSIGN: - opeq (&GenXOASGN, Expr); + opeq (&GenXOASGN, Expr, "^="); break; case TOK_OR_ASSIGN: - opeq (&GenOASGN, Expr); + opeq (&GenOASGN, Expr, "|="); break; default: