X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fgoto.c;h=10293642f6ba11b45e97d0a663b47f8ea2306524;hb=214c90f957f96b094cf88db858d0a0a17747d0de;hp=6e282c636adad4ec08adca9da0cabfb78dad94de;hpb=0b186407f1117529f0f6902569f9d24bc8b1b979;p=cc65 diff --git a/src/cc65/goto.c b/src/cc65/goto.c index 6e282c636..10293642f 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -33,9 +33,17 @@ +#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" @@ -54,21 +62,99 @@ void GotoStatement (void) NextToken (); /* Label name must follow */ - if (CurTok.Tok != TOK_IDENT) { - - Error ("Label name expected"); - - } else { + 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); + SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF | SC_GOTO); /* Jump to the label */ - g_jump (Entry->V.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; + + 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 || + !(arr->Flags & SC_STATIC) || + SizeOf (GetElementType(arr->Type)) != 2) { + Error ("Expected a static array"); + } else if (GetElementCount (arr->Type) > 127) { + Error ("Only arrays with <= 127 labels are supported, got %lu", + GetElementCount (arr->Type)); + } + + 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 needed only so the optimizer does not remove the labels. + */ + E = CS_GetEntry (CS->Code, CS_GetEntryCount (CS->Code) - 1); + tab = GetLabelSymTab (); + if (tab) { + cur = tab->SymHead; + while (cur) { + if ((cur->Flags & SC_GOTO_IND) != 0) { + cur->V.L.IndJumpFrom = E; + } + cur = cur->NextSym; + } + } + } else { + /* It was not TOK_IDENT, or we couldn't find the symbol */ + Error ("Array name expected"); + } + } else { + Error ("Label name expected"); } - - /* Eat the label name */ - NextToken (); } @@ -80,7 +166,11 @@ 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 ();