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 */
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;
-void RememberEntry (Function* F)
-/* Remember the current output position for local space creation later */
+unsigned GetRetLab (const Function* F)
+/* Return the return jump label */
{
- F->EntryCode = GetCodePos ();
+ return F->RetLab;
}
-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 */
{
- return F->RetLab;
+ return F->TopLevelSP;
}
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 */
/* Function body now defined */
Func->Flags |= SC_DEF;
- /* Need a starting curly brace */
- if (curtok != TOK_LCURLY) {
- Error ("`{' expected");
- }
-
/* Setup register variables */
InitRegVars ();
/* 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;
/* 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 ();
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.
-static int statement (void);
-/* Forward decl */
-
-
-
static int doif (void)
/* Handle 'if' statement here */
{
test (flab1, 0);
/* Parse the if body */
- gotbreak = statement ();
+ gotbreak = Statement ();
/* Else clause present? */
if (curtok != TOK_ELSE) {
flab2 = 0;
}
g_defloclabel (flab1);
- gotbreak &= statement ();
+ gotbreak &= Statement ();
/* Generate the label for the else clause */
if (flab2) {
g_truejump (CF_NONE, loop);
} else {
/* There is code inside the while loop */
- statement ();
+ Statement ();
g_jump (loop);
g_defloclabel (lab);
}
} else {
/* Do loop */
- statement ();
+ Statement ();
Consume (TOK_WHILE, "`while' expected");
test (loop, 1);
ConsumeSemi ();
-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));
}
/* Parse statements */
if (curtok != TOK_RCURLY) {
- HaveBreak = statement ();
+ HaveBreak = Statement ();
}
}
HaveBreak = 0;
}
if (curtok != TOK_RCURLY) {
- HaveBreak = statement ();
+ HaveBreak = Statement ();
}
}
ConsumeRParen ();
g_jump (loop);
g_defloclabel (lstat);
- statement ();
+ Statement ();
g_jump (linc);
g_defloclabel (lab);
DelLoop ();
-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
*/
{
switch (curtok) {
case TOK_LCURLY:
- return compound ();
+ return CompoundStatement ();
case TOK_IF:
- return doif ();
+ return doif ();
case TOK_WHILE:
dowhile ('w');
break;
case TOK_RETURN:
- doreturn ();
+ DoReturn ();
ConsumeSemi ();
return 1;
-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;
-}
-
-
-
-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
+ */