X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fgoto.c;h=08a7033c38dc3da200810884057a82a5f002abfc;hb=a9cbb5305c3863b3385c54d7112bd587e8d075c4;hp=5d6290004f674781b683eb77ccfb8214e7747c40;hpb=9cc25f13b6aabc4fd299c54c9c38c5825689eb47;p=cc65 diff --git a/src/cc65/goto.c b/src/cc65/goto.c index 5d6290004..08a7033c3 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -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 */ /* */ /* */ /* */ @@ -33,42 +33,126 @@ +#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_IDENT) { - - Error (ERR_IDENT_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 (); + ConsumeLBrack (); + + /* Find array size */ + if (!IsTypeArray (arr->Type) || SizeOf (arr->Type) == 0 || + SizeOf (GetElementType(arr->Type)) != 2) + Error ("Expected array"); + if (GetElementCount (arr->Type) > 127) + Error ("Only arrays with <= 127 labels are supported, got %lu", + GetElementCount (arr->Type)); + + 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 +164,12 @@ void DoLabel (void) SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF); /* Emit the jump label */ - g_defloclabel (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 (); } - - -