X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fswstmt.c;h=5c50f5e6aae7bac66c540c685277db1ddc48b2cd;hb=60bf40f6dbec6618c0e1c659dfe030c9a7d27480;hp=c1317449fedc55487cf660f0869a32c56844d846;hpb=f0ed4af252bba877085d900da82bcf448426d674;p=cc65 diff --git a/src/cc65/swstmt.c b/src/cc65/swstmt.c index c1317449f..5c50f5e6a 100644 --- a/src/cc65/swstmt.c +++ b/src/cc65/swstmt.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ +/* (C) 1998-2003 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@cc65.org */ @@ -73,7 +73,9 @@ void SwitchStatement (void) unsigned ExitLabel; /* Exit label */ unsigned CaseLabel; /* Label for case */ unsigned DefaultLabel; /* Label for the default branch */ - long Val; /* Case label value */ + unsigned SwitchCodeLabel; /* Label for the switch code */ + long Val; /* Case label value */ + int HaveBreak = 0; /* True if the last statement had a break */ /* Eat the "switch" token */ @@ -84,12 +86,26 @@ void SwitchStatement (void) intexpr (&SwitchExpr); ConsumeRParen (); + /* Add a jump to the switch code. This jump is usually unnecessary, + * because the switch code will moved up just behind the switch + * expression. However, in rare cases, there's a label at the end of + * the switch expression. This label will not get moved, so the code + * jumps around the switch code, and after moving the switch code, + * things look really weird. If we add a jump here, we will never have + * a label attached to the current code position, and the jump itself + * will get removed by the optimizer if it is unnecessary. + */ + SwitchCodeLabel = GetLocalLabel (); + g_jump (SwitchCodeLabel); + + /* Remember the current code position. We will move the switch code + * to this position later. + */ + CaseCodeStart = GetCodePos(); + /* Opening curly brace */ ConsumeLCurly (); - /* Remember the current code position */ - CaseCodeStart = GetCodePos(); - /* Get the unqualified type of the switch expression */ SwitchExprType = UnqualifiedType (SwitchExpr.Type[0]); @@ -101,7 +117,7 @@ void SwitchStatement (void) ExitLabel = GetLocalLabel (); /* Create a loop so we may use break. */ - AddLoop (oursp, 0, ExitLabel, 0, 0); + AddLoop (oursp, ExitLabel, 0); /* Create the collection for the case node tree */ Nodes = NewCollection (); @@ -121,9 +137,9 @@ void SwitchStatement (void) NextToken (); /* Read the selector expression */ - constexpr (&CaseExpr); + ConstExpr (&CaseExpr); if (!IsClassInt (CaseExpr.Type)) { - Error ("Switch quantity not an integer"); + Error ("Switch quantity not an integer"); } /* Check the range of the expression */ @@ -142,14 +158,14 @@ void SwitchStatement (void) Error ("Range error"); } break; - + case T_SHORT: case T_INT: if (Val < -32768 || Val > 32767) { Error ("Range error"); } break; - + case T_USHORT: case T_UINT: if (Val < 0 || Val > 65535) { @@ -166,7 +182,7 @@ void SwitchStatement (void) } /* Insert the case selector into the selector table */ - CaseLabel = InsertCaseValue (Nodes, Val, Depth); + CaseLabel = InsertCaseValue (Nodes, Val, Depth); /* Define this label */ g_defcodelabel (CaseLabel); @@ -200,7 +216,7 @@ void SwitchStatement (void) /* Parse statements */ if (CurTok.Tok != TOK_RCURLY) { - Statement (0); + HaveBreak = Statement (0); } } @@ -211,8 +227,24 @@ void SwitchStatement (void) } else { + CodeMark SwitchCodeStart; + + /* If the last statement did not have a break, we may have an open + * label (maybe from an if or similar). Emitting code and then moving + * this code to the top will also move the label to the top which is + * wrong. So if the last statement did not have a break (which would + * carry the label), add a jump to the exit. If it is useless, the + * optimizer will remove it later. + */ + if (!HaveBreak) { + g_jump (ExitLabel); + } + /* Remember the current position */ - CodeMark SwitchCodeStart = GetCodePos(); + SwitchCodeStart = GetCodePos(); + + /* Output the switch code label */ + g_defcodelabel (SwitchCodeLabel); /* Generate code */ g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);