Change FOREACH to FOR (#680)

This commit is contained in:
Rangi
2021-01-01 18:46:26 -05:00
committed by GitHub
parent 10e3f1a02b
commit 7bb6f71f0b
9 changed files with 63 additions and 63 deletions

View File

@@ -73,7 +73,7 @@ bool yywrap(void);
void fstk_RunInclude(char const *path); void fstk_RunInclude(char const *path);
void fstk_RunMacro(char const *macroName, struct MacroArgs *args); void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size); void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size);
void fstk_RunForeach(char const *symName, int32_t start, int32_t stop, int32_t step, void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size); int32_t reptLineNo, char *body, size_t size);
void fstk_Init(char const *mainPath, size_t maxRecursionDepth); void fstk_Init(char const *mainPath, size_t maxRecursionDepth);

View File

@@ -34,9 +34,9 @@ struct Context {
uint32_t uniqueID; uint32_t uniqueID;
struct MacroArgs *macroArgs; /* Macro args are *saved* here */ struct MacroArgs *macroArgs; /* Macro args are *saved* here */
uint32_t nbReptIters; uint32_t nbReptIters;
int32_t foreachValue; int32_t forValue;
int32_t foreachStep; int32_t forStep;
char *foreachName; char *forName;
}; };
static struct Context *contextStack; static struct Context *contextStack;
@@ -220,14 +220,14 @@ bool yywrap(void)
} }
fileInfo->iters[0]++; fileInfo->iters[0]++;
/* If this is a FOREACH, update the symbol value */ /* If this is a FOR, update the symbol value */
if (contextStack->foreachName) { if (contextStack->forName) {
contextStack->foreachValue += contextStack->foreachStep; contextStack->forValue += contextStack->forStep;
struct Symbol *sym = sym_AddSet(contextStack->foreachName, struct Symbol *sym = sym_AddSet(contextStack->forName,
contextStack->foreachValue); contextStack->forValue);
if (sym->type != SYM_SET) if (sym->type != SYM_SET)
fatalerror("Failed to update FOREACH symbol value\n"); fatalerror("Failed to update FOR symbol value\n");
} }
/* If this wasn't the last iteration, wrap instead of popping */ /* If this wasn't the last iteration, wrap instead of popping */
if (fileInfo->iters[0] <= contextStack->nbReptIters) { if (fileInfo->iters[0] <= contextStack->nbReptIters) {
@@ -254,8 +254,8 @@ bool yywrap(void)
/* Free the file stack node */ /* Free the file stack node */
if (!context->fileInfo->referenced) if (!context->fileInfo->referenced)
free(context->fileInfo); free(context->fileInfo);
/* Free the FOREACH symbol name */ /* Free the FOR symbol name */
free(context->foreachName); free(context->forName);
/* Free the entry and make its parent the current entry */ /* Free the entry and make its parent the current entry */
free(context); free(context);
@@ -281,7 +281,7 @@ static void newContext(struct FileStackNode *fileInfo)
fileInfo->referenced = false; fileInfo->referenced = false;
fileInfo->lineNo = lexer_GetLineNo(); fileInfo->lineNo = lexer_GetLineNo();
context->fileInfo = fileInfo; context->fileInfo = fileInfo;
context->foreachName = NULL; context->forName = NULL;
/* /*
* Link new entry to its parent so it's reachable later * Link new entry to its parent so it's reachable later
* ERRORS SHOULD NOT OCCUR AFTER THIS!! * ERRORS SHOULD NOT OCCUR AFTER THIS!!
@@ -443,13 +443,13 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size)
return; return;
contextStack->nbReptIters = count; contextStack->nbReptIters = count;
contextStack->foreachName = NULL; contextStack->forName = NULL;
} }
void fstk_RunForeach(char const *symName, int32_t start, int32_t stop, int32_t step, void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size) int32_t reptLineNo, char *body, size_t size)
{ {
dbgPrint("Running FOREACH(\"%s\", %" PRId32 ", %" PRId32 ", %" PRId32 ")\n", dbgPrint("Running FOR(\"%s\", %" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
symName, start, stop, step); symName, start, stop, step);
struct Symbol *sym = sym_AddSet(symName, start); struct Symbol *sym = sym_AddSet(symName, start);
@@ -464,7 +464,7 @@ void fstk_RunForeach(char const *symName, int32_t start, int32_t stop, int32_t s
else if (step < 0 && stop < start) else if (step < 0 && stop < start)
count = (start - stop - 1) / -step + 1; count = (start - stop - 1) / -step + 1;
else if (step == 0) else if (step == 0)
error("FOREACH cannot have a step value of 0\n"); error("FOR cannot have a step value of 0\n");
if (count == 0) if (count == 0)
return; return;
@@ -472,11 +472,11 @@ void fstk_RunForeach(char const *symName, int32_t start, int32_t stop, int32_t s
return; return;
contextStack->nbReptIters = count; contextStack->nbReptIters = count;
contextStack->foreachValue = start; contextStack->forValue = start;
contextStack->foreachStep = step; contextStack->forStep = step;
contextStack->foreachName = strdup(symName); contextStack->forName = strdup(symName);
if (!contextStack->foreachName) if (!contextStack->forName)
fatalerror("Not enough memory for FOREACH name: %s\n", strerror(errno)); fatalerror("Not enough memory for FOR symbol name: %s\n", strerror(errno));
} }
void fstk_Init(char const *mainPath, size_t maxRecursionDepth) void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
@@ -508,9 +508,9 @@ void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
context->uniqueID = 0; context->uniqueID = 0;
macro_SetUniqueID(0); macro_SetUniqueID(0);
context->nbReptIters = 0; context->nbReptIters = 0;
context->foreachValue = 0; context->forValue = 0;
context->foreachStep = 0; context->forStep = 0;
context->foreachName = NULL; context->forName = NULL;
/* Now that it's set up properly, register the context */ /* Now that it's set up properly, register the context */
contextStack = context; contextStack = context;

View File

@@ -240,7 +240,7 @@ static struct KeywordMapping {
{"SHIFT", T_POP_SHIFT}, {"SHIFT", T_POP_SHIFT},
{"REPT", T_POP_REPT}, {"REPT", T_POP_REPT},
{"FOREACH", T_POP_FOREACH}, {"FOR", T_POP_FOR},
{"ENDR", T_POP_ENDR}, {"ENDR", T_POP_ENDR},
{"LOAD", T_POP_LOAD}, {"LOAD", T_POP_LOAD},
@@ -462,7 +462,7 @@ struct LexerState *lexer_OpenFileView(char *buf, size_t size, uint32_t lineNo)
void lexer_RestartRept(uint32_t lineNo) void lexer_RestartRept(uint32_t lineNo)
{ {
dbgPrint("Restarting REPT/FOREACH\n"); dbgPrint("Restarting REPT/FOR\n");
lexerState->offset = 0; lexerState->offset = 0;
initState(lexerState); initState(lexerState);
lexerState->lineNo = lineNo; lexerState->lineNo = lineNo;
@@ -2123,11 +2123,11 @@ void lexer_CaptureRept(char **capture, size_t *size)
do { /* Discard initial whitespace */ do { /* Discard initial whitespace */
c = nextChar(); c = nextChar();
} while (isWhitespace(c)); } while (isWhitespace(c));
/* Now, try to match `REPT`, `FOREACH` or `ENDR` as a **whole** identifier */ /* Now, try to match `REPT`, `FOR` or `ENDR` as a **whole** identifier */
if (startsIdentifier(c)) { if (startsIdentifier(c)) {
switch (readIdentifier(c)) { switch (readIdentifier(c)) {
case T_POP_REPT: case T_POP_REPT:
case T_POP_FOREACH: case T_POP_FOR:
level++; level++;
/* Ignore the rest of that line */ /* Ignore the rest of that line */
break; break;
@@ -2156,7 +2156,7 @@ void lexer_CaptureRept(char **capture, size_t *size)
/* Just consume characters until EOL or EOF */ /* Just consume characters until EOL or EOF */
for (;;) { for (;;) {
if (c == EOF) { if (c == EOF) {
error("Unterminated REPT/FOREACH block\n"); error("Unterminated REPT/FOR block\n");
lexerState->capturing = false; lexerState->capturing = false;
goto finish; goto finish;
} else if (c == '\n' || c == '\r') { } else if (c == '\n' || c == '\r') {

View File

@@ -310,7 +310,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
int32_t start; int32_t start;
int32_t stop; int32_t stop;
int32_t step; int32_t step;
} foreachArgs; } forArgs;
struct StrFmtArgList strfmtArgs; struct StrFmtArgList strfmtArgs;
} }
@@ -406,7 +406,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
%token T_POP_ENDM %token T_POP_ENDM
%token T_POP_RSRESET T_POP_RSSET %token T_POP_RSRESET T_POP_RSSET
%token T_POP_UNION T_POP_NEXTU T_POP_ENDU %token T_POP_UNION T_POP_NEXTU T_POP_ENDU
%token T_POP_INCBIN T_POP_REPT T_POP_FOREACH %token T_POP_INCBIN T_POP_REPT T_POP_FOR
%token T_POP_CHARMAP %token T_POP_CHARMAP
%token T_POP_NEWCHARMAP %token T_POP_NEWCHARMAP
%token T_POP_SETCHARMAP %token T_POP_SETCHARMAP
@@ -431,7 +431,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
%type <sectMod> sectmod %type <sectMod> sectmod
%type <macroArg> macroargs %type <macroArg> macroargs
%type <foreachArgs> foreach_args %type <forArgs> for_args
%token T_Z80_ADC T_Z80_ADD T_Z80_AND %token T_Z80_ADC T_Z80_ADD T_Z80_AND
%token T_Z80_BIT %token T_Z80_BIT
@@ -634,7 +634,7 @@ simple_pseudoop : include
| popc | popc
| load | load
| rept | rept
| foreach | for
| shift | shift
| fail | fail
| warn | warn
@@ -758,15 +758,15 @@ rept : T_POP_REPT uconst {
} }
; ;
foreach : T_POP_FOREACH T_ID T_COMMA foreach_args { for : T_POP_FOR T_ID T_COMMA for_args {
uint32_t nDefinitionLineNo = lexer_GetLineNo(); uint32_t nDefinitionLineNo = lexer_GetLineNo();
char *body; char *body;
size_t size; size_t size;
lexer_CaptureRept(&body, &size); lexer_CaptureRept(&body, &size);
fstk_RunForeach($2, $4.start, $4.stop, $4.step, nDefinitionLineNo, body, size); fstk_RunFor($2, $4.start, $4.stop, $4.step, nDefinitionLineNo, body, size);
} }
foreach_args : const { for_args : const {
$$.start = 0; $$.start = 0;
$$.stop = $1; $$.stop = $1;
$$.step = 1; $$.step = 1;

View File

@@ -1533,18 +1533,18 @@ As in macros, you can also use the escape sequence
blocks can be nested. blocks can be nested.
.Pp .Pp
A common pattern is to repeat a block for each value in some range. A common pattern is to repeat a block for each value in some range.
.Ic FOREACH .Ic FOR
is simpler than is simpler than
.Ic REPT .Ic REPT
for that purpose. for that purpose.
Everything between Everything between
.Ic FOREACH .Ic FOR
and the matching and the matching
.Ic ENDR .Ic ENDR
will be repeated for each value of a given symbol. will be repeated for each value of a given symbol.
For example, this code will produce a table of squared values from 0 to 255: For example, this code will produce a table of squared values from 0 to 255:
.Bd -literal -offset indent .Bd -literal -offset indent
FOREACH N, 256 FOR N, 256
dw N * N dw N * N
ENDR ENDR
.Ed .Ed
@@ -1564,24 +1564,24 @@ N = 256
.Ed .Ed
.Pp .Pp
You can customize the range of You can customize the range of
.Ic FOREACH .Ic FOR
values: values:
.Bl -column "FOREACH V, start, stop, step" .Bl -column "FOR V, start, stop, step"
.It Sy Code Ta Sy Range .It Sy Code Ta Sy Range
.It Ic FOREACH Ar V , stop Ta Ar V No increments from 0 to Ar stop No .It Ic FOR Ar V , stop Ta Ar V No increments from 0 to Ar stop No
.It Ic FOREACH Ar V , start , stop Ta Ar V No increments from Ar start No to Ar stop No .It Ic FOR Ar V , start , stop Ta Ar V No increments from Ar start No to Ar stop No
.It Ic FOREACH Ar V , start , stop , step Ta Ar V No goes from Ar start No to Ar stop No by Ar step No .It Ic FOR Ar V , start , stop , step Ta Ar V No goes from Ar start No to Ar stop No by Ar step No
.El .El
.Pp .Pp
The The
.Ic FOREACH .Ic FOR
value will be updated by value will be updated by
.Ar step .Ar step
until it reaches or exceeds until it reaches or exceeds
.Ar stop. .Ar stop.
For example: For example:
.Bd -literal -offset indent .Bd -literal -offset indent
FOREACH V, 4, 25, 5 FOR V, 4, 25, 5
PRINTT "{d:V} " PRINTT "{d:V} "
ENDR ENDR
PRINTT "done {d:V}\n" PRINTT "done {d:V}\n"
@@ -1596,7 +1596,7 @@ Just like with
blocks, you can use the escape sequence blocks, you can use the escape sequence
.Ic \[rs]@ .Ic \[rs]@
inside of inside of
.Ic FOREACH .Ic FOR
blocks, and they can be nested. blocks, and they can be nested.
.Ss Aborting the assembly process .Ss Aborting the assembly process
.Ic FAIL .Ic FAIL

View File

@@ -1,44 +1,44 @@
foreach n, 10 for n, 10
printt "{d:n} " printt "{d:n} "
endr endr
printt "-> {d:n}\n" printt "-> {d:n}\n"
foreach v, 0 for v, 0
printt "unreached" printt "unreached"
endr endr
foreach v, 2, 1 for v, 2, 1
printt "unreached" printt "unreached"
endr endr
foreach v, 1, 2, 0 for v, 1, 2, 0
printt "unreached" printt "unreached"
endr endr
foreach x, 1, 5+1 for x, 1, 5+1
printt "{d:x} " printt "{d:x} "
endr endr
printt "-> {d:x}\n" printt "-> {d:x}\n"
foreach v, 10, -1, -1 for v, 10, -1, -1
printt "{d:v} " printt "{d:v} "
v = 42 v = 42
endr endr
printt "-> {d:v}\n" printt "-> {d:v}\n"
foreach q, 5, 21, 5 for q, 5, 21, 5
printt "{d:q} " printt "{d:q} "
purge q purge q
endr endr
printt "-> {d:q}\n" printt "-> {d:q}\n"
s EQUS "x" s EQUS "x"
foreach s, 3, 30, 3 for s, 3, 30, 3
printt "{d:x} " printt "{d:x} "
endr endr
printt "-> {d:x}\n" printt "-> {d:x}\n"
foreach v, 10 for v, 10
printt "{d:v}\n" printt "{d:v}\n"
if v == 3 if v == 3
purge v purge v

6
test/asm/for.err Normal file
View File

@@ -0,0 +1,6 @@
ERROR: for.asm(16):
FOR cannot have a step value of 0
ERROR: for.asm(41) -> for.asm::REPT~5(47):
'v' already defined as constant at for.asm(41) -> for.asm::REPT~4(45)
FATAL: for.asm(41) -> for.asm::REPT~5(47):
Failed to update FOR symbol value

View File

@@ -1,6 +0,0 @@
ERROR: foreach.asm(16):
FOREACH cannot have a step value of 0
ERROR: foreach.asm(41) -> foreach.asm::REPT~5(47):
'v' already defined as constant at foreach.asm(41) -> foreach.asm::REPT~4(45)
FATAL: foreach.asm(41) -> foreach.asm::REPT~5(47):
Failed to update FOREACH symbol value