]> git.sur5r.net Git - cc65/blobdiff - src/cc65/goto.c
Return after errors, move left bracket consumption down
[cc65] / src / cc65 / goto.c
index fe3e1b8bdae7056c18b55530d382d9f31755e683..fde9df94595bf4ffc652ba2f51cd7b14f2a61703 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                 goto.c                                   */
+/*                                  goto.c                                   */
 /*                                                                           */
-/*             Goto and label handling for the cc65 C compiler              */
+/*              Goto and label handling for the cc65 C compiler              */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
 
 
 
+#include "asmlabel.h"
+#include "codeent.h"
 #include "codegen.h"
+#include "codeseg.h"
+#include "cpu.h"
 #include "error.h"
+#include "exprdesc.h"
+#include "expr.h"
+#include "loadexpr.h"
 #include "scanner.h"
+#include "standard.h"
 #include "symtab.h"
 #include "goto.h"
 
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
 
-void DoGoto (void)
+void GotoStatement (void)
 /* Process a goto statement. */
 {
     /* Eat the "goto" */
     NextToken ();
 
     /* Label name must follow */
-    if (CurTok.Tok != TOK_IDENT) {
-
-               Error ("Label name expected");
-
+    if (CurTok.Tok == TOK_IDENT) {
+
+        /* Add a new label symbol if we don't have one until now */
+        SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF | SC_GOTO);
+
+        /* Jump to the label */
+        g_jump (Entry->V.L.Label);
+
+        /* Eat the label name */
+        NextToken ();
+
+    } else if (CurTok.Tok == TOK_STAR && IS_Get (&Standard) >= STD_CC65) {
+        SymEntry *arr, *idx, *cur;
+        SymTable *tab;
+        ExprDesc desc;
+        CodeEntry *E;
+        unsigned char val;
+        unsigned I;
+
+        NextToken ();
+
+        /* arr[foo], we only support simple foo for now */
+        if (CurTok.Tok == TOK_IDENT &&
+            (arr = FindSym (CurTok.Ident))) {
+            NextToken ();
+
+            /* Find array size */
+            if (!IsTypeArray (arr->Type) || SizeOf (arr->Type) == 0 ||
+                SizeOf (GetElementType(arr->Type)) != 2) {
+                Error ("Expected array");
+                return;
+            }
+            if (GetElementCount (arr->Type) > 127) {
+                Error ("Only arrays with <= 127 labels are supported, got %lu",
+                       GetElementCount (arr->Type));
+                return;
+            }
+
+            ConsumeLBrack ();
+
+            if (CurTok.Tok == TOK_ICONST) {
+                val = CurTok.IVal;
+                NextToken ();
+
+                if (CPUIsets[CPU] & CPU_ISET_65SC02) {
+                    AddCodeLine ("ldx #$%02X", val * 2);
+                    AddCodeLine ("jmp (.loword(%s),x)", arr->AsmName);
+                } else {
+                    AddCodeLine ("ldy #$%02X", val * 2);
+                    AddCodeLine ("lda %s,y", arr->AsmName);
+                    AddCodeLine ("ldx %s+1,y", arr->AsmName);
+                    AddCodeLine ("jmp callax");
+                }
+            } else if (CurTok.Tok == TOK_IDENT &&
+                       (idx = FindSym (CurTok.Ident))) {
+                hie10 (&desc);
+                LoadExpr (CF_NONE, &desc);
+                AddCodeLine ("asl a");
+
+                if (CPUIsets[CPU] & CPU_ISET_65SC02) {
+                    AddCodeLine ("tax");
+                    AddCodeLine ("jmp (.loword(%s),x)", arr->AsmName);
+                } else {
+                    AddCodeLine ("tay");
+                    AddCodeLine ("lda %s,y", arr->AsmName);
+                    AddCodeLine ("ldx %s+1,y", arr->AsmName);
+                    AddCodeLine ("jmp callax");
+                }
+            } else {
+                Error ("Only simple expressions are supported for computed goto");
+            }
+
+            ConsumeRBrack ();
+
+            /* Loop over all target labels, specifying this as a jump point.
+            ** It's not exact - if there's multiple gotos, the last will be used,
+            ** but it's only needed so the optimizer does not remove the labels.
+            */
+            I = CS_GetEntryCount (CS->Code) - 1;
+            E = CS_GetEntry (CS->Code, I);
+
+            tab = GetLabelSymTab ();
+            if (tab) {
+                cur = tab->SymHead;
+                while (cur) {
+                    if ((cur->Flags & (SC_LABEL|SC_GOTO_IND)) == (SC_LABEL|SC_GOTO_IND)) {
+                        cur->V.L.IndJumpFrom = E;
+                    }
+                    cur = cur->NextSym;
+                }
+            }
+        }
     } else {
 
-       /* Add a new label symbol if we don't have one until now */
-       SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
-
-       /* Jump to the label */
-       g_jump (Entry->V.Label);
+        Error ("Label name expected");
     }
-
-    /* Eat the label name */
-    NextToken ();
 }
 
 
@@ -80,12 +169,12 @@ void DoLabel (void)
     SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF);
 
     /* Emit the jump label */
-    g_defcodelabel (Entry->V.Label);
+    CodeLabel* L = CS_AddLabel (CS->Code, LocalLabelName (Entry->V.L.Label));
+    if (Entry->V.L.IndJumpFrom) {
+        CollAppend (&L->JumpFrom, Entry->V.L.IndJumpFrom);
+    }
 
     /* Eat the ident and colon */
     NextToken ();
     NextToken ();
 }
-
-
-