static void DoConversion (ExprDesc* Expr, const Type* NewType) /* Emit code to convert the given expression to a new type. */ { Type* OldType; unsigned OldSize; unsigned NewSize; /* Remember the old type */ OldType = Expr->Type; /* If we're converting to void, we're done. Note: This does also cover a * conversion void -> void. */ if (IsTypeVoid (NewType)) { ED_MakeRVal (Expr); /* Never an lvalue */ goto ExitPoint; } /* Don't allow casts from void to something else. */ if (IsTypeVoid (OldType)) { Error ("Cannot convert from `void' to something else"); goto ExitPoint; } /* Get the sizes of the types. Since we've excluded void types, checking * for known sizes makes sense here. */ OldSize = CheckedSizeOf (OldType); NewSize = CheckedSizeOf (NewType); /* lvalue? */ if (ED_IsLVal (Expr)) { /* We have an lvalue. If the new size is smaller than the new one, * we don't need to do anything. The compiler will generate code * to load only the portion of the value that is actually needed. * This works only on a little endian architecture, but that's * what we support. * If both sizes are equal, do also leave the value alone. * If the new size is larger, we must convert the value. */ if (NewSize > OldSize) { /* Load the value into the primary */ LoadExpr (CF_NONE, Expr); /* Emit typecast code */ g_typecast (TypeOf (NewType), TypeOf (OldType) | CF_FORCECHAR); /* Value is now in primary and an rvalue */ ED_MakeRValExpr (Expr); } } else if (ED_IsLocAbs (Expr)) { /* A cast of a constant numeric value to another type. Be sure * to handle sign extension correctly. */ /* Get the current and new size of the value */ unsigned OldBits = OldSize * 8; unsigned NewBits = NewSize * 8; /* Check if the new datatype will have a smaller range. If it * has a larger range, things are ok, since the value is * internally already represented by a long. */ if (NewBits <= OldBits) { /* Cut the value to the new size */ Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits)); /* If the new type is signed, sign extend the value */ if (IsSignSigned (NewType)) { if (Expr->IVal & (0x01UL << (NewBits-1))) { /* Beware: Use the safe shift routine here. */ Expr->IVal |= shl_l (~0UL, NewBits); } } } } else {
int Statement (int* PendingToken) /* Statement parser. Returns 1 if the statement does a return/break, returns ** 0 otherwise. If the PendingToken pointer is not NULL, the function will ** not skip the terminating token of the statement (closing brace or ** semicolon), but store true if there is a pending token, and false if there ** is none. The token is always checked, so there is no need for the caller to ** check this token, it must be skipped, however. If the argument pointer is ** NULL, the function will skip the token. */ { ExprDesc Expr; int GotBreak; CodeMark Start, End; /* Assume no pending token */ if (PendingToken) { *PendingToken = 0; } /* Check for a label. A label is always part of a statement, it does not ** replace one. */ while (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) { /* Handle the label */ DoLabel (); if (CheckLabelWithoutStatement ()) { return 0; } } switch (CurTok.Tok) { case TOK_LCURLY: NextToken (); GotBreak = CompoundStatement (); CheckTok (TOK_RCURLY, "`{' expected", PendingToken); return GotBreak; case TOK_IF: return IfStatement (); case TOK_WHILE: WhileStatement (); break; case TOK_DO: DoStatement (); break; case TOK_SWITCH: SwitchStatement (); break; case TOK_RETURN: ReturnStatement (); CheckSemi (PendingToken); return 1; case TOK_BREAK: BreakStatement (); CheckSemi (PendingToken); return 1; case TOK_CONTINUE: ContinueStatement (); CheckSemi (PendingToken); return 1; case TOK_FOR: ForStatement (); break; case TOK_GOTO: GotoStatement (); CheckSemi (PendingToken); return 1; case TOK_SEMI: /* Ignore it */ CheckSemi (PendingToken); break; case TOK_PRAGMA: DoPragma (); break; case TOK_CASE: CaseLabel (); CheckLabelWithoutStatement (); break; case TOK_DEFAULT: DefaultLabel (); CheckLabelWithoutStatement (); break; default: /* Remember the current code position */ GetCodePos (&Start); /* Actual statement */ ExprWithCheck (hie0, &Expr); /* Load the result only if it is an lvalue and the type is ** marked as volatile. Otherwise the load is useless. */ if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) { LoadExpr (CF_NONE, &Expr); } /* If the statement didn't generate code, and is not of type ** void, emit a warning. */ GetCodePos (&End); if (CodeRangeIsEmpty (&Start, &End) && !IsTypeVoid (Expr.Type) && IS_Get (&WarnNoEffect)) { Warning ("Statement has no effect"); } CheckSemi (PendingToken); } return 0; }
void LoadExpr (unsigned Flags, struct ExprDesc* Expr) /* Load an expression into the primary register if it is not already there. */ { if (ED_IsLVal (Expr)) { /* Dereferenced lvalue. If this is a bit field its type is unsigned. * But if the field is completely contained in the lower byte, we will * throw away the high byte anyway and may therefore load just the * low byte. */ if (ED_IsBitField (Expr)) { Flags |= (Expr->BitOffs + Expr->BitWidth <= CHAR_BITS)? CF_CHAR : CF_INT; Flags |= CF_UNSIGNED; } else { Flags |= TypeOf (Expr->Type); } if (ED_NeedsTest (Expr)) { Flags |= CF_TEST; } switch (ED_GetLoc (Expr)) { case E_LOC_ABS: /* Absolute: numeric address or const */ g_getstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0); break; case E_LOC_GLOBAL: /* Global variable */ g_getstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal); break; case E_LOC_STATIC: case E_LOC_LITERAL: /* Static variable or literal in the literal pool */ g_getstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal); break; case E_LOC_REGISTER: /* Register variable */ g_getstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal); break; case E_LOC_STACK: /* Value on the stack */ g_getlocal (Flags, Expr->IVal); break; case E_LOC_PRIMARY: /* The primary register - just test if necessary */ if (Flags & CF_TEST) { g_test (Flags); } break; case E_LOC_EXPR: /* Reference to address in primary with offset in Expr */ g_getind (Flags, Expr->IVal); break; default: Internal ("Invalid location in LoadExpr: 0x%04X", ED_GetLoc (Expr)); } /* Handle bit fields. The actual type may have been casted or * converted, so be sure to always use unsigned ints for the * operations. */ if (ED_IsBitField (Expr)) { unsigned F = CF_INT | CF_UNSIGNED | CF_CONST | (Flags & CF_TEST); /* Shift right by the bit offset */ g_asr (F, Expr->BitOffs); /* And by the width if the field doesn't end on an int boundary */ if (Expr->BitOffs + Expr->BitWidth != CHAR_BITS && Expr->BitOffs + Expr->BitWidth != INT_BITS) { g_and (F, (0x0001U << Expr->BitWidth) - 1U); } } /* Expression was tested */ ED_TestDone (Expr); } else { /* An rvalue */ if (ED_IsLocExpr (Expr)) { if (Expr->IVal != 0) { /* We have an expression in the primary plus a constant * offset. Adjust the value in the primary accordingly. */ Flags |= TypeOf (Expr->Type); g_inc (Flags | CF_CONST, Expr->IVal); } } else { /* Constant of some sort, load it into the primary */ LoadConstant (Flags, Expr); } /* Are we testing this value? */ if (ED_NeedsTest (Expr)) { /* Yes, force a test */ Flags |= TypeOf (Expr->Type); g_test (Flags); ED_TestDone (Expr); } } }