Beispiel #1
0
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 {
Beispiel #2
0
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;
}
Beispiel #3
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);
        }
    }

}