static void FuncRight (void) /* Handle the .RIGHT function */ { long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Count argument. Correct negative counts to zero. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the complete token list */ List = CollectTokens (0, 9999); /* Delete tokens from the list until Count tokens are remaining */ while (List->Count > (unsigned) Count) { /* Get the first node */ TokNode* T = List->Root; /* Remove it from the list */ List->Root = List->Root->Next; /* Free the node */ FreeTokNode (T); /* Corrent the token counter */ List->Count--; } /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".RIGHT"); /* Skip the current token */ NextTok (); }
static void FuncMid (void) /* Handle the .MID function */ { long Start; long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Start argument. Since the start argument can get negative with * expressions like ".tcount(arg)-2", we correct it to zero silently. */ Start = ConstExpression (); if (Start < 0 || Start > 100) { Start = 0; } ConsumeComma (); /* Count argument. Similar as above, we will accept negative counts and * correct them to zero silently. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the token list */ List = CollectTokens ((unsigned) Start, (unsigned) Count); /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".MID"); /* Skip the current token */ NextTok (); }
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; }
static TokList* CollectTokens (unsigned Start, unsigned Count) /* Read a list of tokens that is optionally enclosed in curly braces and * terminated by a right paren. For all tokens starting at the one with index * Start, and ending at (Start+Count-1), place them into a token list, and * return this token list. */ { /* Create the token list */ TokList* List = NewTokList (); /* Determine if the list is enclosed in curly braces. */ token_t Term = GetTokListTerm (TOK_RPAREN); /* Read the token list */ unsigned Current = 0; while (CurTok.Tok != Term) { /* Check for end of line or end of input */ if (TokIsSep (CurTok.Tok)) { Error ("Unexpected end of line"); return List; } /* Collect tokens in the given range */ if (Current >= Start && Current < Start+Count) { /* Add the current token to the list */ AddCurTok (List); } /* Get the next token */ ++Current; NextTok (); } /* Eat the terminator token */ NextTok (); /* If the list was enclosed in curly braces, we do expect now a right paren */ if (Term == TOK_RCURLY) { ConsumeRParen (); } /* Return the list of collected tokens */ return List; }
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; }
static void FuncLeft (void) /* Handle the .LEFT function */ { long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Count argument. Correct negative counts to zero. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the token list */ List = CollectTokens (0, (unsigned) Count); /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".LEFT"); /* Skip the current token */ NextTok (); }