1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-18 07:29:36 +00:00

Use one function exit point

git-svn-id: svn://svn.cc65.org/cc65/trunk@674 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-03-26 20:07:05 +00:00
parent b0f3e85d44
commit c3ec23aed0
4 changed files with 139 additions and 132 deletions

View File

@ -64,9 +64,9 @@ 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 */
int TopLevelSP; /* SP at function top level */
};
/* Pointer to current function */
@ -90,9 +90,9 @@ static Function* NewFunction (struct SymEntry* Sym)
F->FuncEntry = Sym;
F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
F->Desc = (FuncDesc*) DecodePtr (Sym->Type + 1);
F->EntryCode = 0;
F->Reserved = 0;
F->RetLab = GetLabel ();
F->TopLevelSP = 0;
/* Return the new structure */
return F;
@ -156,14 +156,6 @@ int IsVariadic (const Function* F)
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 */
{
@ -172,6 +164,14 @@ unsigned GetRetLab (const Function* F)
int GetTopLevelSP (const Function* F)
/* Get the value of the stack pointer on function top level */
{
return F->TopLevelSP;
}
int ReserveLocalSpace (Function* F, unsigned Size)
/* Reserve (but don't allocate) the given local space and return the stack
* offset.
@ -215,7 +215,8 @@ void AllocLocalSpace (Function* F)
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
int isbrk;
int HadReturn;
int IsVoidFunc;
unsigned Flags;
/* Get the function descriptor from the function entry */
@ -244,11 +245,6 @@ void NewFunc (SymEntry* Func)
/* Function body now defined */
Func->Flags |= SC_DEF;
/* Need a starting curly brace */
if (curtok != TOK_LCURLY) {
Error ("`{' expected");
}
/* Setup register variables */
InitRegVars ();
@ -264,7 +260,7 @@ void NewFunc (SymEntry* Func)
/* Fastcall functions may never have an ellipsis or the compiler is buggy */
CHECK ((D->Flags & FD_VARIADIC) == 0);
/* Get a pointer to the last parameter entry */
LastParam = D->SymTab->SymTail;
@ -286,31 +282,57 @@ void NewFunc (SymEntry* Func)
/* 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 */
/* Setup the stack */
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);
/* Need a starting curly brace */
ConsumeLCurly ();
/* Parse local variable declarations if any */
DeclareLocals ();
/* Remember the current stack pointer. All variables allocated elsewhere
* must be dropped when doing a return from an inner block.
*/
CurrentFunc->TopLevelSP = oursp;
/* Now process statements in this block */
HadReturn = 0;
while (curtok != TOK_RCURLY) {
if (curtok != TOK_CEOF) {
HadReturn = Statement ();
} else {
break;
}
#endif
RestoreRegVars (0);
Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG;
g_leave (Flags, 0);
}
/* If the function has a return type but no return statement, flag
* a warning
*/
IsVoidFunc = HasVoidReturn (CurrentFunc);
#if 0
/* Does not work reliably */
if (!IsVoidFunc && !HadReturn) {
Warning ("Function `%s' should return a value", Func->Name);
}
#endif
/* Output the function exit code label */
g_defloclabel (GetRetLab (CurrentFunc));
/* Restore the register variables */
RestoreRegVars (!IsVoidFunc);
/* Generate the exit code */
Flags = IsVoidFunc? CF_NONE : CF_REG;
g_leave (Flags, 0);
/* Eat the closing brace */
ConsumeRCurly ();
/* Emit references to imports/exports */
EmitExternals ();
/* Dump literal data created by the function */
DumpLiteralPool ();

View File

@ -76,12 +76,12 @@ int HasVoidReturn (const Function* F);
int IsVariadic (const Function* F);
/* Return true if this is a variadic function */
void RememberEntry (Function* F);
/* Remember the current output position for local space creation later */
unsigned GetRetLab (const Function* F);
/* Return the return jump label */
int GetTopLevelSP (const Function* F);
/* Get the value of the stack pointer on function top level */
int ReserveLocalSpace (Function* F, unsigned Size);
/* Reserve (but don't allocate) the given local space and return the stack
* offset.

View File

@ -51,11 +51,6 @@
static int statement (void);
/* Forward decl */
static int doif (void)
/* Handle 'if' statement here */
{
@ -71,7 +66,7 @@ static int doif (void)
test (flab1, 0);
/* Parse the if body */
gotbreak = statement ();
gotbreak = Statement ();
/* Else clause present? */
if (curtok != TOK_ELSE) {
@ -99,7 +94,7 @@ static int doif (void)
flab2 = 0;
}
g_defloclabel (flab1);
gotbreak &= statement ();
gotbreak &= Statement ();
/* Generate the label for the else clause */
if (flab2) {
@ -142,7 +137,7 @@ static void dowhile (char wtype)
g_truejump (CF_NONE, loop);
} else {
/* There is code inside the while loop */
statement ();
Statement ();
g_jump (loop);
g_defloclabel (lab);
}
@ -150,7 +145,7 @@ static void dowhile (char wtype)
} else {
/* Do loop */
statement ();
Statement ();
Consume (TOK_WHILE, "`while' expected");
test (loop, 1);
ConsumeSemi ();
@ -162,36 +157,33 @@ static void dowhile (char wtype)
static void doreturn (void)
static void DoReturn (void)
/* Handle 'return' statement here */
{
struct expent lval;
unsigned Flags = 0; /* Code generator flags */
int HaveVal = 0; /* Do we have a return value in ax? */
NextToken ();
if (curtok != TOK_SEMI) {
if (HasVoidReturn (CurrentFunc)) {
Error ("Returning a value in function with return type void");
}
if (evalexpr (CF_NONE, hie0, &lval) == 0) {
/* Constant value */
Flags = CF_CONST;
} else {
/* Value in the primary register */
HaveVal = 1;
}
/* Evaluate the return expression. Result will be in primary */
expression (&lval);
/* Convert the return value to the type of the function result */
if (!HasVoidReturn (CurrentFunc)) {
Flags |= (assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST) | CF_REG;
assignadjust (GetReturnType (CurrentFunc), &lval);
}
} else if (!HasVoidReturn (CurrentFunc)) {
Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
}
RestoreRegVars (HaveVal);
g_leave (Flags, lval.e_const);
/* Cleanup the stack in case we're inside a block with locals */
g_space (oursp - GetTopLevelSP (CurrentFunc));
/* Output a jump to the function exit code */
g_jump (GetRetLab (CurrentFunc));
}
@ -414,7 +406,7 @@ static void cascadeswitch (struct expent* eval)
/* Parse statements */
if (curtok != TOK_RCURLY) {
HaveBreak = statement ();
HaveBreak = Statement ();
}
}
@ -503,7 +495,7 @@ static void tableswitch (struct expent* eval)
HaveBreak = 0;
}
if (curtok != TOK_RCURLY) {
HaveBreak = statement ();
HaveBreak = Statement ();
}
}
@ -615,7 +607,7 @@ static void dofor (void)
ConsumeRParen ();
g_jump (loop);
g_defloclabel (lstat);
statement ();
Statement ();
g_jump (linc);
g_defloclabel (lab);
DelLoop ();
@ -623,9 +615,58 @@ static void dofor (void)
static int statement (void)
/* Statement parser. Called whenever syntax requires a statement.
* This routine performs that statement and returns 1 if it is a branch,
static int CompoundStatement (void)
/* Compound statement. Allow any number of statements inside braces. */
{
int isbrk;
int oldsp;
/* eat LCURLY */
NextToken ();
/* Remember the stack at block entry */
oldsp = oursp;
/* Enter a new lexical level */
EnterBlockLevel ();
/* Parse local variable declarations if any */
DeclareLocals ();
/* Now process statements in this block */
isbrk = 0;
while (curtok != TOK_RCURLY) {
if (curtok != TOK_CEOF) {
isbrk = Statement ();
} else {
break;
}
}
/* Emit references to imports/exports for this block */
EmitExternals ();
/* Clean up the stack. */
if (isbrk) {
oursp = oldsp;
} else {
g_space (oursp - oldsp);
oursp = oldsp;
}
/* Leave the lexical level */
LeaveBlockLevel ();
/* Eat closing brace */
ConsumeRCurly ();
return isbrk;
}
int Statement (void)
/* Statement parser. Returns 1 if the statement does a return/break, returns
* 0 otherwise
*/
{
@ -642,10 +683,10 @@ static int statement (void)
switch (curtok) {
case TOK_LCURLY:
return compound ();
return CompoundStatement ();
case TOK_IF:
return doif ();
return doif ();
case TOK_WHILE:
dowhile ('w');
@ -660,7 +701,7 @@ static int statement (void)
break;
case TOK_RETURN:
doreturn ();
DoReturn ();
ConsumeSemi ();
return 1;
@ -704,61 +745,3 @@ static int statement (void)
int compound (void)
/* Compound statement. Allow any number of statements, inside braces. */
{
static unsigned CurrentLevel = 0;
int isbrk;
int oldsp;
/* eat LCURLY */
NextToken ();
/* Remember the stack at block entry */
oldsp = oursp;
/* If we're not on function level, enter a new lexical level */
if (CurrentLevel++ > 0) {
/* A nested block */
EnterBlockLevel ();
}
/* Parse local variable declarations if any */
DeclareLocals ();
/* Now process statements in the function body */
isbrk = 0;
while (curtok != TOK_RCURLY) {
if (curtok == TOK_CEOF)
break;
else {
isbrk = statement ();
}
}
/* Emit references to imports/exports for this block */
EmitExternals ();
/* If this is not the top level compound statement, clean up the stack.
* For a top level statement this will be done by the function exit code.
*/
if (--CurrentLevel != 0) {
/* Some sort of nested block */
LeaveBlockLevel ();
if (isbrk) {
oursp = oldsp;
} else {
g_space (oursp - oldsp);
oursp = oldsp;
}
}
/* Eat closing brace */
ConsumeRCurly ();
return isbrk;
}

View File

@ -17,8 +17,10 @@
int compound ();
/* Compound statement. Allow any number of statements, inside braces. */
int Statement (void);
/* Statement parser. Returns 1 if the statement does a return/break, returns
* 0 otherwise
*/