Skip to content

Translating Once

Turn the whole program into numbers before it runs, then get out of the way. The thinnest translator that does this fits in eight lines, and you are about to write it.

The interpreter’s problem was where the translating happened: inside the loop, on every pass. The fix is to move it.

Translate the whole program first. All of it, before a single line runs. What is left afterwards is a row of numbers with no working-out still to do, and the machine runs those at full speed. The loop that cost a thousand translations in Unit 2 now costs none, because the translating happened once, up above it.

WhenRead the lineWork out what it meansDo ittotal
before runningLET total = total + 1put total plus one in total
pass 10 + 11
pass 21 + 12
pass 1000999 + 11000

The middle column has one entry now, and it is above the loop rather than inside it. The thousand passes do only the thousand additions you asked for.

A translator that works this way is called a compiler. It takes a whole program, produces the numbers, and is finished before the program starts.

The thinnest translator there is

A compiler has a hard job. It turns ideas into numbers: a FOR loop is one line to you and many instructions to the machine, and the compiler has to work out which.

There is a simpler translator that does not deal in ideas at all. It deals in names. One name in, one number out, straight from a table. That is an assembler, and the table is the one from Unit 1:

Name Number
INC 1
DOUBLE 2
SHOW 3

Look up each name, write down its number. That is the entire job.

Build it

You have everything you need. Two lists, a loop that walks a program, and a question that checks a name.

LET names = ["INC", "DOUBLE", "SHOW"]
LET codes = [1, 2, 3]
LET program = ["INC", "INC", "DOUBLE", "SHOW"]

FOR EACH word IN program
  FOR i = 1 TO 3
    IF word = names[i] THEN SHOW codes[i]
  END
END
Output
1
1
2
3

Read it through. For each word in the program, look along the list of names. When you find the one that matches, show the number in the same place in the other list.

1 1 2 3. That is the row of numbers from Unit 1, and you just produced it from the names. You have written an assembler.

It is a toy, and it is missing a great deal that a real one has. But nothing a real assembler does is a different kind of thing from this. It looks names up in a table and writes numbers down. The table is bigger. The job is the same.

What runs afterwards

Once the assembler has done its work, the names are gone. The machine is handed 1 1 2 3 and runs it, and nothing is looked up ever again. Add one, add one, double, show.

That is why programs written this way keep up with the screen. The game loop is made of numbers the machine already understands, and every frame is spent on the game.

When it’s wrong, see why

  • A name was not in the table. The assembler found nothing to match, so it wrote nothing down, and the machine got a shorter program than you wrote. A real assembler stops and tells you. This toy does not, which is a good reason to make yours do so.
  • You changed the program and nothing changed. The old numbers are still what the machine has. Translating once means translating again when you change something.
  • You are looking for the interpreter’s kindness. It has gone. Nothing is reading your line as it runs, so nothing can tell you where a mistake is. That is the subject of the next unit.

What you’ve learnt

  • A compiler translates the whole program into numbers before it runs, so the loop pays no translating cost.
  • An assembler is the thinnest translator: one name to one number, from a table.
  • You built one from two lists and a loop.
  • What runs afterwards is numbers only, which is why it keeps up.

What’s next

Speed is bought, not free. In Unit 4 we count what you hand over for it, so you arrive at a real machine knowing the deal you have made.