static Function* NewFunction (struct SymEntry* Sym) /* Create a new function activation structure and return it */ { /* Allocate a new structure */ Function* F = (Function*) xmalloc (sizeof (Function)); /* Initialize the fields */ F->FuncEntry = Sym; F->ReturnType = GetFuncReturn (Sym->Type); F->Desc = GetFuncDesc (Sym->Type); F->Reserved = 0; F->RetLab = GetLocalLabel (); F->TopLevelSP = 0; F->RegOffs = RegisterSpace; F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE; /* Return the new structure */ return F; }
CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func) /* Create a new code segment, initialize and return it */ { unsigned I; const Type* RetType; /* Allocate memory */ CodeSeg* S = xmalloc (sizeof (CodeSeg)); /* Initialize the fields */ S->SegName = xstrdup (SegName); S->Func = Func; InitCollection (&S->Entries); InitCollection (&S->Labels); for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) { S->LabelHash[I] = 0; } /* If we have a function given, get the return type of the function. * Assume ANY return type besides void will use the A and X registers. */ if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) { if (SizeOf (RetType) == SizeOf (type_long)) { S->ExitRegs = REG_EAX; } else { S->ExitRegs = REG_AX; } } else { S->ExitRegs = REG_NONE; } /* Copy the global optimization settings */ S->Optimize = (unsigned char) IS_Get (&Optimize); S->CodeSizeFactor = (unsigned) IS_Get (&CodeSizeFactor); /* Return the new struct */ return S; }
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; }
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 {