diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 01dd4b471..5a459bebc 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -499,7 +499,7 @@ static unsigned OptSub2 (CodeSeg* S) CodeEntry* E = GetCodeEntry (S, I); /* Check for the sequence */ - if (E->OPC == OPC_LDA && + if (E->OPC == OPC_LDA && GetCodeEntries (S, L, I+1, 5) && L[0]->OPC == OPC_SEC && !CodeEntryHasLabel (L[0]) && @@ -527,8 +527,15 @@ static unsigned OptSub2 (CodeSeg* S) MoveCodeEntry (S, I, I+3); ReplaceOPC (E, OPC_SBC); + /* If the sequence head had a label, move this label back to the + * head. + */ + if (CodeEntryHasLabel (E)) { + MoveCodeLabels (S, E, L[0]); + } + /* Remember, we had changes */ - ++Changes; + ++Changes; } @@ -765,6 +772,13 @@ static unsigned OptCmp3 (CodeSeg* S) ReplaceOPC (L[0], OPC_LDA); ReplaceOPC (L[1], OPC_CMP); + /* Beware: If the first LDA instruction had a label, we have + * to move this label to the top of the sequence again. + */ + if (CodeEntryHasLabel (E)) { + MoveCodeLabels (S, E, L[0]); + } + } ++Changes; diff --git a/src/cc65/function.c b/src/cc65/function.c index bcddf88d2..06786e6e8 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -296,7 +296,7 @@ void NewFunc (SymEntry* Func) HadReturn = 0; while (CurTok.Tok != TOK_RCURLY) { if (CurTok.Tok != TOK_CEOF) { - HadReturn = Statement (); + HadReturn = Statement (0); } else { break; } diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 1cb03576a..0de58c6d2 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -46,11 +46,48 @@ /*****************************************************************************/ -/* Forwards */ +/* Helper functions */ /*****************************************************************************/ +static void CheckTok (token_t Tok, const char* Msg, int* PendingToken) +/* Helper function for Statement. Will check for Tok and print Msg if not + * found. If PendingToken is NULL, it will the skip the token, otherwise + * it will store one to PendingToken. + */ +{ + if (CurTok.Tok != Tok) { + Error (Msg); + } else if (PendingToken) { + *PendingToken = 1; + } else { + NextToken (); + } +} + + + +static void CheckSemi (int* PendingToken) +/* Helper function for Statement. Will call CheckTok with the parameters + * for a semicolon. + */ +{ + CheckTok (TOK_SEMI, "`;' expected", PendingToken); +} + + + +static void SkipPending (int PendingToken) +/* Skip the pending token if we have one */ +{ + if (PendingToken) { + NextToken (); + } +} + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ @@ -71,12 +108,13 @@ static int IfStatement (void) test (Label1, 0); /* Parse the if body */ - GotBreak = Statement (); + GotBreak = Statement (0); /* Else clause present? */ if (CurTok.Tok != TOK_ELSE) { g_defcodelabel (Label1); + /* Since there's no else clause, we're not sure, if the a break * statement is really executed. */ @@ -95,7 +133,7 @@ static int IfStatement (void) g_defcodelabel (Label1); /* Total break only if both branches had a break. */ - GotBreak &= Statement (); + GotBreak &= Statement (0); /* Generate the label for the else clause */ g_defcodelabel (Label2); @@ -124,7 +162,7 @@ static void DoStatement (void) g_defcodelabel (loop); /* Parse the loop body */ - Statement (); + Statement (0); /* Parse the end condition */ Consume (TOK_WHILE, "`while' expected"); @@ -143,6 +181,8 @@ static void DoStatement (void) static void WhileStatement (void) /* Handle the 'while' statement */ { + int PendingToken; + /* Get the loop control labels */ unsigned loop = GetLocalLabel (); unsigned lab = GetLocalLabel (); @@ -172,9 +212,10 @@ static void WhileStatement (void) NextToken (); } else { /* There is code inside the while loop, parse the body */ - Statement (); + Statement (&PendingToken); g_jump (loop); g_defcodelabel (lab); + SkipPending (PendingToken); } /* Remove the loop from the loop stack */ @@ -432,7 +473,7 @@ static void CascadeSwitch (struct expent* eval) /* Parse statements */ if (CurTok.Tok != TOK_RCURLY) { - HaveBreak = Statement (); + HaveBreak = Statement (0); } } @@ -521,7 +562,7 @@ static void TableSwitch (struct expent* eval) HaveBreak = 0; } if (CurTok.Tok != TOK_RCURLY) { - HaveBreak = Statement (); + HaveBreak = Statement (0); } } @@ -600,6 +641,7 @@ static void ForStatement (void) struct expent lval1; struct expent lval2; struct expent lval3; + int PendingToken; /* Get several local labels needed later */ unsigned TestLabel = GetLocalLabel (); @@ -651,10 +693,13 @@ static void ForStatement (void) /* Loop body */ g_defcodelabel (lstat); - Statement (); + Statement (&PendingToken); /* Jump back to the increment expression */ g_jump (IncLabel); + + /* Skip a pending token if we have one */ + SkipPending (PendingToken); /* Declare the break label */ g_defcodelabel (lab); @@ -678,9 +723,6 @@ static int CompoundStatement (void) /* Enter a new lexical level */ EnterBlockLevel (); - /* Skip the rcurly */ - NextToken (); - /* Parse local variable declarations if any */ DeclareLocals (); @@ -688,7 +730,7 @@ static int CompoundStatement (void) GotBreak = 0; while (CurTok.Tok != TOK_RCURLY) { if (CurTok.Tok != TOK_CEOF) { - GotBreak = Statement (); + GotBreak = Statement (0); } else { break; } @@ -700,9 +742,6 @@ static int CompoundStatement (void) } oursp = OldStack; - /* Skip the closing brace */ - ConsumeRCurly (); - /* Emit references to imports/exports for this block */ EmitExternals (); @@ -714,12 +753,23 @@ static int CompoundStatement (void) -int Statement (void) +int Statement (int* PendingToken) /* Statement parser. Returns 1 if the statement does a return/break, returns - * 0 otherwise + * 0 otherwise. If the PendingToken pointer is not NULL, the function will + * not skip the terminating token of the statement (closing brace or + * semicolon), but store true if there is a pending token, and false if there + * is none. The token is always checked, so there is no need for the caller to + * check this token, it must be skipped, however. If the argument pointer is + * NULL, the function will skip the token. */ { struct expent lval; + int GotBreak; + + /* Assume no pending token */ + if (PendingToken) { + *PendingToken = 0; + } /* Check for a label */ if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) { @@ -732,7 +782,10 @@ int Statement (void) switch (CurTok.Tok) { case TOK_LCURLY: - return CompoundStatement (); + NextToken (); + GotBreak = CompoundStatement (); + CheckTok (TOK_RCURLY, "`{' expected", PendingToken); + return GotBreak; case TOK_IF: return IfStatement (); @@ -751,17 +804,17 @@ int Statement (void) case TOK_RETURN: ReturnStatement (); - ConsumeSemi (); + CheckSemi (PendingToken); return 1; case TOK_BREAK: BreakStatement (); - ConsumeSemi (); + CheckSemi (PendingToken); return 1; case TOK_CONTINUE: ContinueStatement (); - ConsumeSemi (); + CheckSemi (PendingToken); return 1; case TOK_FOR: @@ -770,7 +823,7 @@ int Statement (void) case TOK_GOTO: GotoStatement (); - ConsumeSemi (); + CheckSemi (PendingToken); return 1; case TOK_SEMI: @@ -785,7 +838,7 @@ int Statement (void) default: /* Actual statement */ expression (&lval); - ConsumeSemi (); + CheckSemi (PendingToken); } } return 0; diff --git a/src/cc65/stmt.h b/src/cc65/stmt.h index 258af0707..a5d3abbd4 100644 --- a/src/cc65/stmt.h +++ b/src/cc65/stmt.h @@ -17,9 +17,14 @@ -int Statement (void); +int Statement (int* PendingToken); /* Statement parser. Returns 1 if the statement does a return/break, returns - * 0 otherwise + * 0 otherwise. If the PendingToken pointer is not NULL, the function will + * not skip the terminating token of the statement (closing brace or + * semicolon), but store true if there is a pending token, and false if there + * is none. The token is always checked, so there is no need for the caller to + * check this token, it must be skipped, however. If the argument pointer is + * NULL, the function will skip the token. */