One command, four steps
You type one command and a C program becomes something the machine can run. That one command hides four steps. When a build fails, the error comes from one of them, and knowing which step spoke tells you where to look.
By the end of this lesson
Note
I can name the stages a compiler takes a program through.
Key words
- Compiler: a program that turns source code into instructions for a processor.
- Preprocessor: the first step, which pastes in files and replaces names.
- Assembly: a processor's instructions, written as words.
- Linker: the last step, which joins pieces of machine code into one program.
- Token: one word of a program, such as a number or a sign.
- Parser: the part that checks tokens against the grammar.
Starter: what you already know
Note
Answer in your head. 1. What does cd do? 2. What does cat print? 3. What is in a file whose name ends in .c? You need the third answer straight away.
Before you start
Note
Press Start the lab on the bar at the top of this lesson. This lab is a whole Ubuntu machine of your own, so it takes a little longer to come up than a container. Each Run button types its command into the machine's terminal, one after another in the same session. If one says the machine is still starting, wait a few seconds and press it again. Where the lesson says Type this, the program waits for you to type to it, so press Open terminal on the bar and type it yourself.
The preprocessor pastes and replaces
gcc -E stops after the first step and prints what it made. The line #include <stdio.h> has become hundreds of lines, so tail -n 8 shows only the end. Look at main: the name GREETING has gone, and the words of the macro are in its place. The comment has gone too.
cd ~/compilerShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
gcc -E hello.c | tail -n 8Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Check
Tip
What happened to GREETING? Answer: the preprocessor replaced it with its text, before the compiler proper ever saw the program.
Compile, assemble, link
gcc -S stops after compiling and writes hello.s, the program in assembly for this machine's own processor. Find square and main in it, and the call or bl that runs square. gcc -c goes one step further and writes hello.o, machine code. The last gcc links it with the C library, where printf lives, into a program.
gcc -S hello.cShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
cat hello.sShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
gcc -c hello.cShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
gcc hello.o -o helloShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
./helloShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think a compiler turns C into a program in one go, so every error is a mistake in the code. It runs four steps. An error such as undefined reference to a name comes from the linker: the code compiled, and a piece it needs was not given to the last step.
Check
Tip
Which command stops at assembly, and which writes the object file? Answer: gcc -S writes hello.s, and gcc -c writes hello.o.
The compiler checks meaning too
A program can follow every rule of C's grammar and still make no sense. In scope.c, step is made inside the loop and used after it, where it no longer exists. -Wall asks gcc for its common warnings. Read the answer: an error that step is undeclared, which stops the build, and a warning that unused is never used.
gcc -Wall -c scope.cShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A lexer and a parser you can build
calc.l tells flex what each token looks like: a number, a sign or a bracket. calc.y tells bison the grammar, and that * and / come before + and -. make reads the Makefile and runs bison, flex and gcc in the right order. The calculator then prints 14 for the sum, not 20.
makeShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
echo "2 + 3 * 4" | ./calcShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Exit check
Tip
Answer without looking back. 1. Name the four stages in order. 2. Which stage replaces a macro? 3. Which part turns characters into tokens? 4. Is an unused variable an error or a warning? Answers: preprocess, compile, assemble, link; the preprocessor; the lexer, here made by flex; a warning.
For teachers
Tip
This lesson is a small example of a lesson worked in a lab: the steps and the Run buttons are the lesson, and the lab is each student's own copy. This lesson is worked in a VM lab: each student has an Ubuntu machine of their own, and a Run types into its terminal and shows what it printed. Key learning points: 1. A build has four stages: preprocess, compile, assemble and link. 2. gcc -E, -S and -c stop after each one so it can be read. 3. A lexer makes tokens and a parser checks them against a grammar. Common mistake: reading a linker error as a mistake in the code. Equipment: the lab and a browser. Tip: put hello.c beside hello.s and ask students to find each line of C in the assembly. The lab has no check and marks nothing; set a hand-in of your own if you want one. Copy it into your own module and change it, or build one from scratch with the Lab menu in the lesson builder.