mirror of
https://github.com/cc65/cc65.git
synced 2024-12-28 22:30:12 +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:
parent
b0f3e85d44
commit
c3ec23aed0
@ -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 ();
|
||||
|
||||
|
@ -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.
|
||||
|
163
src/cc65/stmt.c
163
src/cc65/stmt.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user