Today the tokenizer becomes whole - it skips whitespace, chains every rule you wrote, and ends the stream with an explicit end-of-input token that the parser will rely on.
Tokenize a complete statement into a token list that skips whitespace and ends with an EOF token.
Today the individual rules become one tokenizer loop: skip any run of whitespace, look at the next character, and dispatch to the rule that handles it
The finishing touch is the EOF token. Rather than making the parser constantly ask “are there more tokens?”, the tokenizer appends a single end-of-input token so the parser can treat “end of statement” as just another token to match. That one convention makes the recursive-descent parser you start next chapter markedly simpler.
func Tokenize(input string) ([]Token, error) {// loop: skip whitespace; if at end, append EOF and return// otherwise dispatch on the next char to the right rule}