From Transistor to Browser

The Software · Chapter 6.b
How does text become tokens?

Updated Oct 12, 2026
Summarize
Transcript

How does text become tokens? Every program starts as one flat row of characters, spaces and all.

I figured you'd just cut it at the spaces. But total equals twelve plus three can be written with no spaces at all, and it means the same.

So read it one character at a time, and group. A letter starts a name, so keep reading letters until they stop: total. An equals sign is one token on its own. A digit starts a number, so keep reading digits. Twelve is one number, not two. Then plus, then three. Five tokens, each with a kind: name, equals, number, plus, number. And a stray character that starts no token is refused, not guessed.

So text becomes tokens by grouping, not by spaces! The lexer cuts flat text into tokens, the pieces a parser reads.

Type a line into the lexer below, spaces or none, and watch the tokens come out whole.

The hosts' voices are synthetic, made with Breeze TTS 2 by BreezeBlue.

  1. The browser
  2. The network
  3. Software and languages
  4. The CPU
  5. Memory
  6. Arithmetic
  7. Logic gates
  8. The switch
Figure 6.b.1: Where we are in the climb from transistor to browser: at the front of the software rung. This chapter cuts a line of source text into the tokens a language is read from.

Chapter 6’s assembler already did a first version of this job: it cut each line of assembly into a label, a mnemonic, and an operand. This chapter takes that cutting seriously as a stage of its own, because richer languages need more than a line-by-line split. The languages of the next chapters are described as trees, but a program does not arrive as a tree. It arrives as a line of flat text, a row of characters. Before anything can be parsed into a tree, that text has to be cut into the pieces a parser reads: the name total, an equals sign, the number 12, a plus, the number 3. That cutting is the job of the lexer, the very first stage of every compiler and interpreter.

6.b.1 Cutting text into tokens

The lexer scans the text left to right and groups it. Its one real subtlety is that grouping: 12 is a single number, not two separate tokens, and total is one name, not five letters. So when the lexer meets a digit it keeps reading digits as far as they go, and likewise for letters. Figure 6.b.2 shows a line cut up.

cutcut
Figure 6.b.2: Cutting a line into tokens. A run of letters becomes one name, a run of digits one number, a symbol its own token. The two digits of 12 group into a single number, not two tokens.

Example 6.b-1. Tokenizing a line of source

def tokenize(source: str) -> list:
    """Cut a line of source into tokens, grouping digit runs into numbers and
    letter runs into names. Raise on a character that begins no token."""
    tokens = []
    index = 0
    while index < len(source):
        char = source[index]
        if char.isspace():
            index += 1
        elif char.isdigit():
            start = index
            while index < len(source) and source[index].isdigit():
                index += 1
            tokens.append(Token("NUMBER", source[start:index]))1
        elif char.isalpha():
            start = index
            while index < len(source) and source[index].isalpha():
                index += 1
            tokens.append(Token("NAME", source[start:index]))2
        elif char in _SYMBOLS:
            tokens.append(Token(_SYMBOLS[char], char))
            index += 1
        else:
            raise ValueError(f"unexpected character {char!r}")3
    return tokens

6.b.2 The front end

The lexer is the first of a short pipeline. It turns text into tokens; the parser of the next chapter turns tokens into a tree; the tree is then run or compiled. Each stage hands the next a tidier form of the program, as Figure 6.b.3 lays out.

The next two languages reuse this scanning idea with their own small lexers. Those return plain strings rather than this chapter’s Token(kind, value) pairs, and let digits follow the first letter of a name. Their parsers recognize the kind from the string. The representation changes; grouping characters before building a tree remains the same stage.

frontendfrontend
Figure 6.b.3: Where the lexer sits. Text becomes tokens here, tokens become a tree in the next chapter, and the tree is run or compiled. The lexer is the first stage.

The interactive version needs the in-browser runtime.

6.b.3 The lexer, run

Running ftb.lexer tokenizes a couple of lines and then meets a character it cannot place.

output · ftb.lexer
'total = 12 + 3'
  NAME    total
  EQUALS  =
  NUMBER  12
  PLUS    +
  NUMBER  3

'y = (x + 40)'
  NAME    y
  EQUALS  =
  LPAREN  (
  NAME    x
  PLUS    +
  NUMBER  40
  RPAREN  )

a stray character is rejected:
  unexpected character '?'

Names and numbers come out whole however the spacing falls, and a stray character is refused rather than guessed at. With the text cut into tokens, the next chapter can build a tree of meaning from these pieces, and run it.

Exercises