Files
cc65/src/cc65/function.c
cuz c8171988a2 Added new code hints for use at the end of a function
git-svn-id: svn://svn.cc65.org/cc65/trunk@552 b7a2c559-68d2-44c3-8de9-860c34a00d81
2000-12-04 22:28:15 +00:00

277 lines
7.8 KiB
C

/*****************************************************************************/
/* */
/* function.c */
/* */
/* Parse function entry/body/exit */
/* */
/* */
/* */
/* (C) 2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* common */
#include "xmalloc.h"
/* cc65 */
#include "asmcode.h"
#include "asmlabel.h"
#include "codegen.h"
#include "error.h"
#include "funcdesc.h"
#include "litpool.h"
#include "locals.h"
#include "scanner.h"
#include "stmt.h"
#include "symtab.h"
#include "function.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Structure that holds all data needed for function activation */
struct Function {
struct SymEntry* FuncEntry; /* Symbol table entry */
type* ReturnType; /* Function return type */
struct FuncDesc* Desc; /* Function descriptor */
CodeMark EntryCode; /* Backpatch addr for entry code */
int Reserved; /* Reserved local space */
unsigned RetLab; /* Return code label */
};
/* Pointer to current function */
Function* CurrentFunc = 0;
/*****************************************************************************/
/* Subroutines working with struct Function */
/*****************************************************************************/
static Function* NewFunction (struct SymEntry* Sym)
/* Create a new function activation structure and return it */
{
/* Allocate a new structure */
Function* F = xmalloc (sizeof (Function));
/* Initialize the fields */
F->FuncEntry = Sym;
F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
F->Desc = DecodePtr (Sym->Type + 1);
F->EntryCode = 0;
F->Reserved = 0;
F->RetLab = GetLabel ();
/* Return the new structure */
return F;
}
static void FreeFunction (Function* F)
/* Free a function activation structure */
{
xfree (F);
}
const char* GetFuncName (const Function* F)
/* Return the name of the current function */
{
return F->FuncEntry->Name;
}
unsigned GetParamSize (const Function* F)
/* Return the parameter size for the current function */
{
return F->Desc->ParamSize;
}
type* GetReturnType (Function* F)
/* Get the return type for the function */
{
return F->ReturnType;
}
int HasVoidReturn (const Function* F)
/* Return true if the function does not have a return value */
{
return IsTypeVoid (F->ReturnType);
}
void RememberEntry (Function* F)
/* Remember the current output position for local space creation later */
{
F->EntryCode = GetCodePos ();
}
unsigned GetRetLab (const Function* F)
/* Return the return jump label */
{
return F->RetLab;
}
int ReserveLocalSpace (Function* F, unsigned Size)
/* Reserve (but don't allocate) the given local space and return the stack
* offset.
*/
{
F->Reserved += Size;
return oursp - F->Reserved;
}
void AllocLocalSpace (Function* F)
/* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space.
*/
{
if (F->Reserved > 0) {
/* Switch to the code segment */
g_usecode ();
/* Create space on the stack */
g_space (F->Reserved);
/* Correct the stack pointer */
oursp -= F->Reserved;
/* Nothing more reserved */
F->Reserved = 0;
}
}
/*****************************************************************************/
/* code */
/*****************************************************************************/
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
int isbrk;
unsigned Flags;
/* Get the function descriptor from the function entry */
FuncDesc* D = DecodePtr (Func->Type+1);
/* Allocate the function activation record for the function */
CurrentFunc = NewFunction (Func);
/* Reenter the lexical level */
ReenterFunctionLevel (D);
/* Function body now defined */
Func->Flags |= SC_DEF;
/* C functions cannot currently have __fastcall__ calling conventions */
if (IsFastCallFunc (Func->Type)) {
Error ("__fastcall__ is not allowed for C functions");
}
/* Need a starting curly brace */
if (curtok != TOK_LCURLY) {
Error ("`{' expected");
}
/* Setup register variables */
InitRegVars ();
/* Switch to the code segment and define the function name label */
g_usecode ();
g_defgloblabel (Func->Name);
/* Generate function entry code if needed */
g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
/* Remember the current code position. This may be used later to create
* local variable space once we have created the function body itself.
* Currently this is not possible because the stack offsets of all locals
* have to be known in advance.
*/
RememberEntry (CurrentFunc);
/* Parse the function body */
oursp = 0;
isbrk = compound ();
/* If the function did not end with an return statement, create exit code */
if (!isbrk) {
#if 0
/* If the function has a return type, flag an error */
if (!voidfunc) {
Error ("Function `%s' must return a value", Func->Name);
}
#endif
RestoreRegVars (0);
Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG;
g_leave (Flags, 0);
}
/* Dump literal data created by the function */
DumpLiteralPool ();
/* Cleanup register variables */
DoneRegVars ();
/* Leave the lexical level */
LeaveFunctionLevel ();
/* Reset the current function pointer */
FreeFunction (CurrentFunc);
CurrentFunc = 0;
}