void ParseRepeat (void) /* Parse and handle the .REPEAT statement */ { char* Name; TokList* List; /* Repeat count follows */ long RepCount = ConstExpression (); if (RepCount < 0) { Error ("Range error"); RepCount = 0; } /* Optional there is a comma and a counter variable */ Name = 0; if (Tok == TOK_COMMA) { /* Skip the comma */ NextTok (); /* Check for an identifier */ if (Tok != TOK_IDENT) { ErrorSkip ("Identifier expected"); } else { /* Remember the name and skip it */ SB_Terminate (&SVal); Name = xstrdup (SB_GetConstBuf (&SVal)); NextTok (); } } /* Separator */ ConsumeSep (); /* Read the token list */ List = CollectRepeatTokens (); /* If we had an error, bail out */ if (List == 0) { xfree (Name); return; } /* Update the token list for replay */ List->RepMax = (unsigned) RepCount; List->Data = Name; List->Check = RepeatTokenCheck; /* If the list is empty, or repeat count zero, there is nothing * to repeat. */ if (List->Count == 0 || RepCount == 0) { FreeTokList (List); return; } /* Read input from the repeat descriptor */ PushTokList (List, ".REPEAT"); }
static TokList* CollectRepeatTokens (void) /* Collect all tokens inside the .REPEAT body in a token list and return * this list. In case of errors, NULL is returned. */ { /* Create the token list */ TokList* List = NewTokList (); /* Read the token list */ unsigned Repeats = 0; while (Repeats != 0 || Tok != TOK_ENDREP) { /* Check for end of input */ if (Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeTokList (List); return 0; } /* If we find a token that is equal to the repeat counter name, * replace it by a REPCOUNTER token. This way we have to do strcmps * only once for each identifier, and not for each expansion. * Note: This will fail for nested repeats using the same repeat * counter name, but */ /* Collect all tokens in the list */ AddCurTok (List); /* Check for and count nested .REPEATs */ if (Tok == TOK_REPEAT) { ++Repeats; } else if (Tok == TOK_ENDREP) { --Repeats; } /* Get the next token */ NextTok (); } /* Eat the closing .ENDREP */ NextTok (); /* Return the list of collected tokens */ return List; }
void PushTokList (TokList* List, const char* Desc) /* Push a token list to be used as input for InputFromStack. This includes * several initializations needed in the token list structure, so don't use * PushInput directly. */ { /* If the list is empty, just delete it and bail out */ if (List->Count == 0) { FreeTokList (List); return; } /* Reset the last pointer to the first element */ List->Last = List->Root; /* Insert the list specifying our input function */ PushInput (ReplayTokList, List, Desc); }
static int ReplayTokList (void* List) /* Function that gets the next token from a token list and sets it. This * function may be used together with the PushInput function from the istack * module. */ { /* Cast the generic pointer to an actual list */ TokList* L = List; /* Last may never be a NULL pointer, otherwise there's a bug in the code */ CHECK (L->Last != 0); /* Set the next token from the list */ TokSet (L->Last); /* If a check function is defined, call it, so it may look at the token * just set and changed it as apropriate. */ if (L->Check) { L->Check (L); } /* Set the pointer to the next token */ L->Last = L->Last->Next; /* If this was the last token, decrement the repeat counter. If it goes * zero, delete the list and remove the function from the stack. */ if (L->Last == 0) { if (++L->RepCount >= L->RepMax) { /* Done with this list */ FreeTokList (L); PopInput (); } else { /* Replay one more time */ L->Last = L->Root; } } /* We have a token */ return 1; }
static TokList* CollectRepeatTokens (void) /* Collect all tokens inside the .REPEAT body in a token list and return * this list. In case of errors, NULL is returned. */ { /* Create the token list */ TokList* List = NewTokList (); /* Read the token list */ unsigned Repeats = 0; while (Repeats != 0 || CurTok.Tok != TOK_ENDREP) { /* Check for end of input */ if (CurTok.Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeTokList (List); return 0; } /* Collect all tokens in the list */ AddCurTok (List); /* Check for and count nested .REPEATs */ if (CurTok.Tok == TOK_REPEAT) { ++Repeats; } else if (CurTok.Tok == TOK_ENDREP) { --Repeats; } /* Get the next token */ NextTok (); } /* Eat the closing .ENDREP */ NextTok (); /* Return the list of collected tokens */ return List; }