mirror of
https://github.com/cc65/cc65.git
synced 2025-01-03 16:33:19 +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 */
|
struct SymEntry* FuncEntry; /* Symbol table entry */
|
||||||
type* ReturnType; /* Function return type */
|
type* ReturnType; /* Function return type */
|
||||||
struct FuncDesc* Desc; /* Function descriptor */
|
struct FuncDesc* Desc; /* Function descriptor */
|
||||||
CodeMark EntryCode; /* Backpatch addr for entry code */
|
|
||||||
int Reserved; /* Reserved local space */
|
int Reserved; /* Reserved local space */
|
||||||
unsigned RetLab; /* Return code label */
|
unsigned RetLab; /* Return code label */
|
||||||
|
int TopLevelSP; /* SP at function top level */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Pointer to current function */
|
/* Pointer to current function */
|
||||||
@ -90,9 +90,9 @@ static Function* NewFunction (struct SymEntry* Sym)
|
|||||||
F->FuncEntry = Sym;
|
F->FuncEntry = Sym;
|
||||||
F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
|
F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
|
||||||
F->Desc = (FuncDesc*) DecodePtr (Sym->Type + 1);
|
F->Desc = (FuncDesc*) DecodePtr (Sym->Type + 1);
|
||||||
F->EntryCode = 0;
|
|
||||||
F->Reserved = 0;
|
F->Reserved = 0;
|
||||||
F->RetLab = GetLabel ();
|
F->RetLab = GetLabel ();
|
||||||
|
F->TopLevelSP = 0;
|
||||||
|
|
||||||
/* Return the new structure */
|
/* Return the new structure */
|
||||||
return F;
|
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)
|
unsigned GetRetLab (const Function* F)
|
||||||
/* Return the return jump label */
|
/* 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)
|
int ReserveLocalSpace (Function* F, unsigned Size)
|
||||||
/* Reserve (but don't allocate) the given local space and return the stack
|
/* Reserve (but don't allocate) the given local space and return the stack
|
||||||
* offset.
|
* offset.
|
||||||
@ -215,7 +215,8 @@ void AllocLocalSpace (Function* F)
|
|||||||
void NewFunc (SymEntry* Func)
|
void NewFunc (SymEntry* Func)
|
||||||
/* Parse argument declarations and function body. */
|
/* Parse argument declarations and function body. */
|
||||||
{
|
{
|
||||||
int isbrk;
|
int HadReturn;
|
||||||
|
int IsVoidFunc;
|
||||||
unsigned Flags;
|
unsigned Flags;
|
||||||
|
|
||||||
/* Get the function descriptor from the function entry */
|
/* Get the function descriptor from the function entry */
|
||||||
@ -244,11 +245,6 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Function body now defined */
|
/* Function body now defined */
|
||||||
Func->Flags |= SC_DEF;
|
Func->Flags |= SC_DEF;
|
||||||
|
|
||||||
/* Need a starting curly brace */
|
|
||||||
if (curtok != TOK_LCURLY) {
|
|
||||||
Error ("`{' expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup register variables */
|
/* Setup register variables */
|
||||||
InitRegVars ();
|
InitRegVars ();
|
||||||
|
|
||||||
@ -264,7 +260,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
|
|
||||||
/* Fastcall functions may never have an ellipsis or the compiler is buggy */
|
/* Fastcall functions may never have an ellipsis or the compiler is buggy */
|
||||||
CHECK ((D->Flags & FD_VARIADIC) == 0);
|
CHECK ((D->Flags & FD_VARIADIC) == 0);
|
||||||
|
|
||||||
/* Get a pointer to the last parameter entry */
|
/* Get a pointer to the last parameter entry */
|
||||||
LastParam = D->SymTab->SymTail;
|
LastParam = D->SymTab->SymTail;
|
||||||
|
|
||||||
@ -286,31 +282,57 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Generate function entry code if needed */
|
/* Generate function entry code if needed */
|
||||||
g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
|
g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
|
||||||
|
|
||||||
/* Remember the current code position. This may be used later to create
|
/* Setup the stack */
|
||||||
* 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;
|
oursp = 0;
|
||||||
isbrk = compound ();
|
|
||||||
|
|
||||||
/* If the function did not end with an return statement, create exit code */
|
/* Need a starting curly brace */
|
||||||
if (!isbrk) {
|
ConsumeLCurly ();
|
||||||
#if 0
|
|
||||||
/* If the function has a return type, flag an error */
|
/* Parse local variable declarations if any */
|
||||||
if (!voidfunc) {
|
DeclareLocals ();
|
||||||
Error ("Function `%s' must return a value", Func->Name);
|
|
||||||
|
/* 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 */
|
/* Dump literal data created by the function */
|
||||||
DumpLiteralPool ();
|
DumpLiteralPool ();
|
||||||
|
|
||||||
|
@ -76,12 +76,12 @@ int HasVoidReturn (const Function* F);
|
|||||||
int IsVariadic (const Function* F);
|
int IsVariadic (const Function* F);
|
||||||
/* Return true if this is a variadic function */
|
/* 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);
|
unsigned GetRetLab (const Function* F);
|
||||||
/* Return the return jump label */
|
/* 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);
|
int ReserveLocalSpace (Function* F, unsigned Size);
|
||||||
/* Reserve (but don't allocate) the given local space and return the stack
|
/* Reserve (but don't allocate) the given local space and return the stack
|
||||||
* offset.
|
* 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)
|
static int doif (void)
|
||||||
/* Handle 'if' statement here */
|
/* Handle 'if' statement here */
|
||||||
{
|
{
|
||||||
@ -71,7 +66,7 @@ static int doif (void)
|
|||||||
test (flab1, 0);
|
test (flab1, 0);
|
||||||
|
|
||||||
/* Parse the if body */
|
/* Parse the if body */
|
||||||
gotbreak = statement ();
|
gotbreak = Statement ();
|
||||||
|
|
||||||
/* Else clause present? */
|
/* Else clause present? */
|
||||||
if (curtok != TOK_ELSE) {
|
if (curtok != TOK_ELSE) {
|
||||||
@ -99,7 +94,7 @@ static int doif (void)
|
|||||||
flab2 = 0;
|
flab2 = 0;
|
||||||
}
|
}
|
||||||
g_defloclabel (flab1);
|
g_defloclabel (flab1);
|
||||||
gotbreak &= statement ();
|
gotbreak &= Statement ();
|
||||||
|
|
||||||
/* Generate the label for the else clause */
|
/* Generate the label for the else clause */
|
||||||
if (flab2) {
|
if (flab2) {
|
||||||
@ -142,7 +137,7 @@ static void dowhile (char wtype)
|
|||||||
g_truejump (CF_NONE, loop);
|
g_truejump (CF_NONE, loop);
|
||||||
} else {
|
} else {
|
||||||
/* There is code inside the while loop */
|
/* There is code inside the while loop */
|
||||||
statement ();
|
Statement ();
|
||||||
g_jump (loop);
|
g_jump (loop);
|
||||||
g_defloclabel (lab);
|
g_defloclabel (lab);
|
||||||
}
|
}
|
||||||
@ -150,7 +145,7 @@ static void dowhile (char wtype)
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Do loop */
|
/* Do loop */
|
||||||
statement ();
|
Statement ();
|
||||||
Consume (TOK_WHILE, "`while' expected");
|
Consume (TOK_WHILE, "`while' expected");
|
||||||
test (loop, 1);
|
test (loop, 1);
|
||||||
ConsumeSemi ();
|
ConsumeSemi ();
|
||||||
@ -162,36 +157,33 @@ static void dowhile (char wtype)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void doreturn (void)
|
static void DoReturn (void)
|
||||||
/* Handle 'return' statement here */
|
/* Handle 'return' statement here */
|
||||||
{
|
{
|
||||||
struct expent lval;
|
struct expent lval;
|
||||||
unsigned Flags = 0; /* Code generator flags */
|
|
||||||
int HaveVal = 0; /* Do we have a return value in ax? */
|
|
||||||
|
|
||||||
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (curtok != TOK_SEMI) {
|
if (curtok != TOK_SEMI) {
|
||||||
if (HasVoidReturn (CurrentFunc)) {
|
if (HasVoidReturn (CurrentFunc)) {
|
||||||
Error ("Returning a value in function with return type void");
|
Error ("Returning a value in function with return type void");
|
||||||
}
|
}
|
||||||
if (evalexpr (CF_NONE, hie0, &lval) == 0) {
|
|
||||||
/* Constant value */
|
/* Evaluate the return expression. Result will be in primary */
|
||||||
Flags = CF_CONST;
|
expression (&lval);
|
||||||
} else {
|
|
||||||
/* Value in the primary register */
|
|
||||||
HaveVal = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the return value to the type of the function result */
|
/* Convert the return value to the type of the function result */
|
||||||
if (!HasVoidReturn (CurrentFunc)) {
|
if (!HasVoidReturn (CurrentFunc)) {
|
||||||
Flags |= (assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST) | CF_REG;
|
assignadjust (GetReturnType (CurrentFunc), &lval);
|
||||||
}
|
}
|
||||||
} else if (!HasVoidReturn (CurrentFunc)) {
|
} else if (!HasVoidReturn (CurrentFunc)) {
|
||||||
Error ("Function `%s' must return a value", GetFuncName (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 */
|
/* Parse statements */
|
||||||
if (curtok != TOK_RCURLY) {
|
if (curtok != TOK_RCURLY) {
|
||||||
HaveBreak = statement ();
|
HaveBreak = Statement ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +495,7 @@ static void tableswitch (struct expent* eval)
|
|||||||
HaveBreak = 0;
|
HaveBreak = 0;
|
||||||
}
|
}
|
||||||
if (curtok != TOK_RCURLY) {
|
if (curtok != TOK_RCURLY) {
|
||||||
HaveBreak = statement ();
|
HaveBreak = Statement ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,7 +607,7 @@ static void dofor (void)
|
|||||||
ConsumeRParen ();
|
ConsumeRParen ();
|
||||||
g_jump (loop);
|
g_jump (loop);
|
||||||
g_defloclabel (lstat);
|
g_defloclabel (lstat);
|
||||||
statement ();
|
Statement ();
|
||||||
g_jump (linc);
|
g_jump (linc);
|
||||||
g_defloclabel (lab);
|
g_defloclabel (lab);
|
||||||
DelLoop ();
|
DelLoop ();
|
||||||
@ -623,9 +615,58 @@ static void dofor (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int statement (void)
|
static int CompoundStatement (void)
|
||||||
/* Statement parser. Called whenever syntax requires a statement.
|
/* Compound statement. Allow any number of statements inside braces. */
|
||||||
* This routine performs that statement and returns 1 if it is a branch,
|
{
|
||||||
|
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
|
* 0 otherwise
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@ -642,10 +683,10 @@ static int statement (void)
|
|||||||
switch (curtok) {
|
switch (curtok) {
|
||||||
|
|
||||||
case TOK_LCURLY:
|
case TOK_LCURLY:
|
||||||
return compound ();
|
return CompoundStatement ();
|
||||||
|
|
||||||
case TOK_IF:
|
case TOK_IF:
|
||||||
return doif ();
|
return doif ();
|
||||||
|
|
||||||
case TOK_WHILE:
|
case TOK_WHILE:
|
||||||
dowhile ('w');
|
dowhile ('w');
|
||||||
@ -660,7 +701,7 @@ static int statement (void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_RETURN:
|
case TOK_RETURN:
|
||||||
doreturn ();
|
DoReturn ();
|
||||||
ConsumeSemi ();
|
ConsumeSemi ();
|
||||||
return 1;
|
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 ();
|
int Statement (void);
|
||||||
/* Compound statement. Allow any number of statements, inside braces. */
|
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
||||||
|
* 0 otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user