X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Ffunction.c;h=8944d10077583c722124f0b19c75a8c5cf5f0921;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=6de9ba7b15f9a276bcf96b9fb9f53beb050ac30a;hpb=d0ea9f34b6ea2e460b7fbfe15f629f4fc944eb35;p=cc65 diff --git a/src/cc65/function.c b/src/cc65/function.c index 6de9ba7b1..8944d1007 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000-2004 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2000-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -48,6 +48,8 @@ #include "locals.h" #include "scanner.h" #include "segments.h" +#include "stackptr.h" +#include "standard.h" #include "stmt.h" #include "symtab.h" #include "function.h" @@ -60,15 +62,24 @@ +/* Enumeration for function flags */ +typedef enum { + FF_NONE = 0x0000, + FF_HAS_RETURN = 0x0001, /* Function has a return statement */ + FF_IS_MAIN = 0x0002, /* This is the main function */ + FF_VOID_RETURN = 0x0004, /* Function returning void */ +} funcflags_t; + /* Structure that holds all data needed for function activation */ struct Function { struct SymEntry* FuncEntry; /* Symbol table entry */ - type* ReturnType; /* Function return type */ + Type* ReturnType; /* Function return type */ struct FuncDesc* Desc; /* Function descriptor */ - int Reserved; /* Reserved local space */ - unsigned RetLab; /* Return code label */ - int TopLevelSP; /* SP at function top level */ + int Reserved; /* Reserved local space */ + unsigned RetLab; /* Return code label */ + int TopLevelSP; /* SP at function top level */ unsigned RegOffs; /* Register variable space offset */ + funcflags_t Flags; /* Function flags */ }; /* Pointer to current function */ @@ -77,7 +88,7 @@ Function* CurrentFunc = 0; /*****************************************************************************/ -/* Subroutines working with struct Function */ +/* Subroutines working with struct Function */ /*****************************************************************************/ @@ -91,11 +102,12 @@ static Function* NewFunction (struct SymEntry* Sym) /* Initialize the fields */ F->FuncEntry = Sym; F->ReturnType = GetFuncReturn (Sym->Type); - F->Desc = (FuncDesc*) DecodePtr (Sym->Type + 1); + 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; @@ -135,7 +147,7 @@ unsigned F_GetParamSize (const Function* F) -type* F_GetReturnType (Function* F) +Type* F_GetReturnType (Function* F) /* Get the return type for the function */ { return F->ReturnType; @@ -146,7 +158,31 @@ type* F_GetReturnType (Function* F) int F_HasVoidReturn (const Function* F) /* Return true if the function does not have a return value */ { - return IsTypeVoid (F->ReturnType); + return (F->Flags & FF_VOID_RETURN) != 0; +} + + + +void F_ReturnFound (Function* F) +/* Mark the function as having a return statement */ +{ + F->Flags |= FF_HAS_RETURN; +} + + + +int F_HasReturn (const Function* F) +/* Return true if the function contains a return statement*/ +{ + return (F->Flags & FF_HAS_RETURN) != 0; +} + + + +int F_IsMainFunc (const Function* F) +/* Return true if this is the main function */ +{ + return (F->Flags & FF_IS_MAIN) != 0; } @@ -197,7 +233,7 @@ int F_ReserveLocalSpace (Function* F, unsigned Size) */ { F->Reserved += Size; - return oursp - F->Reserved; + return StackPtr - F->Reserved; } @@ -213,7 +249,7 @@ void F_AllocLocalSpace (Function* F) g_space (F->Reserved); /* Correct the stack pointer */ - oursp -= F->Reserved; + StackPtr -= F->Reserved; /* Nothing more reserved */ F->Reserved = 0; @@ -222,7 +258,7 @@ void F_AllocLocalSpace (Function* F) -int F_AllocRegVar (Function* F, const type* Type) +int F_AllocRegVar (Function* F, const Type* Type) /* Allocate a register variable for the given variable type. If the allocation * was successful, return the offset of the register variable in the register * bank (zero page storage). If there is no register space left, return -1. @@ -323,7 +359,7 @@ static void F_RestoreRegVars (Function* F) } - + /*****************************************************************************/ /* code */ /*****************************************************************************/ @@ -333,7 +369,6 @@ static void F_RestoreRegVars (Function* F) void NewFunc (SymEntry* Func) /* Parse argument declarations and function body. */ { - int HadReturn; SymEntry* Param; /* Get the function descriptor from the function entry */ @@ -345,33 +380,53 @@ void NewFunc (SymEntry* Func) /* Reenter the lexical level */ ReenterFunctionLevel (D); + /* Check if the function header contains unnamed parameters. These are + * only allowed in cc65 mode. + */ + if ((D->Flags & FD_UNNAMED_PARAMS) != 0 && (IS_Get (&Standard) != STD_CC65)) { + Error ("Parameter name omitted"); + } + /* Declare two special functions symbols: __fixargs__ and __argsize__. * The latter is different depending on the type of the function (variadic * or not). */ AddConstSym ("__fixargs__", type_uint, SC_DEF | SC_CONST, D->ParamSize); if (D->Flags & FD_VARIADIC) { - /* Variadic function. The variable must be const. */ - static const type T [] = { T_UCHAR | T_QUAL_CONST, T_END }; - AddLocalSym ("__argsize__", T, SC_DEF | SC_REF | SC_AUTO, 0); + /* Variadic function. The variable must be const. */ + static const Type T[] = { TYPE(T_UCHAR | T_QUAL_CONST), TYPE(T_END) }; + AddLocalSym ("__argsize__", T, SC_DEF | SC_REF | SC_AUTO, 0); } else { - /* Non variadic */ + /* Non variadic */ AddConstSym ("__argsize__", type_uchar, SC_DEF | SC_CONST, D->ParamSize); } /* Function body now defined */ Func->Flags |= SC_DEF; - /* Allocate code and data segments for this function */ - Func->V.F.Seg = PushSegments (Func); - /* Special handling for main() */ if (strcmp (Func->Name, "main") == 0) { + + /* Mark this as the main function */ + CurrentFunc->Flags |= FF_IS_MAIN; + /* Main cannot be a fastcall function */ - if (IsFastCallFunc (Func->Type)) { + if (IsQualFastcall (Func->Type)) { Error ("`main' cannot be declared as __fastcall__"); } + /* If cc65 extensions aren't enabled, don't allow a main function that + * doesn't return an int. + */ + if (IS_Get (&Standard) != STD_CC65 && CurrentFunc->ReturnType[0].C != T_INT) { + Error ("`main' must always return an int"); + } + + /* Add a forced import of a symbol that is contained in the startup + * code. This will force the startup code to be linked in. + */ + g_importstartup (); + /* If main() takes parameters, generate a forced import to a function * that will setup these parameters. This way, programs that do not * need the additional code will not get it. @@ -381,16 +436,22 @@ void NewFunc (SymEntry* Func) } } + /* Allocate code and data segments for this function */ + Func->V.F.Seg = PushSegments (Func); + + /* Allocate a new literal pool */ + PushLiteralPool (Func); + /* If this is a fastcall function, push the last parameter onto the stack */ - if (IsFastCallFunc (Func->Type) && D->ParamCount > 0) { + if (IsQualFastcall (Func->Type) && D->ParamCount > 0) { - unsigned Flags; + unsigned Flags; - /* Fastcall functions may never have an ellipsis or the compiler is buggy */ - CHECK ((D->Flags & FD_VARIADIC) == 0); + /* Fastcall functions may never have an ellipsis or the compiler is buggy */ + CHECK ((D->Flags & FD_VARIADIC) == 0); - /* Generate the push */ - if (IsTypeFunc (D->LastParam->Type)) { + /* Generate the push */ + if (IsTypeFunc (D->LastParam->Type)) { /* Pointer to function */ Flags = CF_PTR; } else { @@ -408,7 +469,7 @@ void NewFunc (SymEntry* Func) } /* Setup the stack */ - oursp = 0; + StackPtr = 0; /* Walk through the parameter list and allocate register variable space * for parameters declared as register. Generate code to swap the contents @@ -433,7 +494,6 @@ void NewFunc (SymEntry* Func) /* Generate swap code */ g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type)); - } } @@ -450,16 +510,18 @@ void NewFunc (SymEntry* Func) /* Remember the current stack pointer. All variables allocated elsewhere * must be dropped when doing a return from an inner block. */ - CurrentFunc->TopLevelSP = oursp; + CurrentFunc->TopLevelSP = StackPtr; /* Now process statements in this block */ - HadReturn = 0; - while (CurTok.Tok != TOK_RCURLY) { - if (CurTok.Tok != TOK_CEOF) { - HadReturn = Statement (0); - } else { - break; - } + while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) { + Statement (0); + } + + /* If this is not a void function, output a warning if we didn't see a + * return statement. + */ + if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc)) { + Warning ("Control reaches end of non-void function"); } /* Output the function exit code label */ @@ -480,6 +542,9 @@ void NewFunc (SymEntry* Func) /* Eat the closing brace */ ConsumeRCurly (); + /* Restore the old literal pool, remembering the one for the function */ + Func->V.F.LitPool = PopLiteralPool (); + /* Switch back to the old segments */ PopSegments ();