A compiler for arithmetic expressions #
A formalization of the correctness of a compiler from arithmetic expressions to machine language described by McCarthy and Painter, which is considered the first proof of compiler correctness.
Main definitions #
Expr
: the syntax of the source language.value
: the semantics of the source language.Instruction
: the syntax of the target language.step
: the semantics of the target language.compile
: the compiler.
Main results #
compiler_correctness
: the compiler correctness theorem.
Notation #
≃[t]/ac
: partial equality of two machine states excluding registers x ≥ t and the accumulator.≃[t]
: partial equality of two machine states excluding registers x ≥ t.
References #
- John McCarthy and James Painter. Correctness of a compiler for arithmetic expressions. In Mathematical Aspects of Computer Science, volume 19 of Proceedings of Symposia in Applied Mathematics. American Mathematical Society, 1967. http://jmc.stanford.edu/articles/mcpain/mcpain.pdf
Tags #
compiler
Types #
Value type shared by both source and target languages.
Equations
Instances For
Variable identifier type in the source language.
Equations
Instances For
Register name type in the target language.
Equations
Instances For
Source language #
An expression in the source language is formed by constants, variables, and sums.
- const (v : Arithcc.Word) : Arithcc.Expr
- var (x : Arithcc.Identifier) : Arithcc.Expr
- sum (s₁ s₂ : Arithcc.Expr) : Arithcc.Expr
Instances For
Equations
- Arithcc.instInhabitedExpr = { default := Arithcc.Expr.const default }
The semantics of the source language (2.1).
Equations
- Arithcc.value (Arithcc.Expr.const v) x✝ = v
- Arithcc.value (Arithcc.Expr.var x_2) x✝ = x✝ x_2
- Arithcc.value (s₁.sum s₂) x✝ = Arithcc.value s₁ x✝ + Arithcc.value s₂ x✝
Instances For
Target language #
Instructions of the target machine language (3.1--3.7).
- li : Arithcc.Word → Arithcc.Instruction
- load : Arithcc.Register → Arithcc.Instruction
- sto : Arithcc.Register → Arithcc.Instruction
- add : Arithcc.Register → Arithcc.Instruction
Instances For
Equations
- Arithcc.instInhabitedInstruction = { default := Arithcc.Instruction.li default }
Machine state consists of the accumulator and a vector of registers.
The paper uses two functions c
and a
for accessing both the accumulator and registers.
For clarity, we make accessing the accumulator explicit and use read
/write
for registers.
- ac : Arithcc.Word
- rs : Arithcc.Register → Arithcc.Word
Instances For
Equations
- Arithcc.instInhabitedState = { default := { ac := 0, rs := fun (x : Arithcc.Register) => 0 } }
This is similar to the c
function (3.8), but for registers only.
Equations
- Arithcc.read r η = η.rs r
Instances For
This is similar to the a
function (3.9), but for registers only.
Equations
- Arithcc.write r v η = { ac := η.ac, rs := fun (x : Arithcc.Register) => if x = r then v else η.rs x }
Instances For
The semantics of the target language (3.11).
Equations
- Arithcc.step (Arithcc.Instruction.li v) x✝ = { ac := v, rs := x✝.rs }
- Arithcc.step (Arithcc.Instruction.load r) x✝ = { ac := Arithcc.read r x✝, rs := x✝.rs }
- Arithcc.step (Arithcc.Instruction.sto r) x✝ = Arithcc.write r x✝.ac x✝
- Arithcc.step (Arithcc.Instruction.add r) x✝ = { ac := Arithcc.read r x✝ + x✝.ac, rs := x✝.rs }
Instances For
The resulting machine state of running a target program from a given machine state (3.12).
Equations
- Arithcc.outcome [] x✝ = x✝
- Arithcc.outcome (i :: is) x✝ = Arithcc.outcome is (Arithcc.step i x✝)
Instances For
A lemma on the concatenation of two programs (3.13).
Compiler #
Map a variable in the source expression to a machine register.
Equations
- Arithcc.loc ν map = map ν
Instances For
The implementation of the compiler (4.2).
This definition explicitly takes a map from variables to registers.
Equations
- Arithcc.compile map (Arithcc.Expr.const v) x✝ = [Arithcc.Instruction.li v]
- Arithcc.compile map (Arithcc.Expr.var x_2) x✝ = [Arithcc.Instruction.load (Arithcc.loc x_2 map)]
- Arithcc.compile map (s₁.sum s₂) x✝ = Arithcc.compile map s₁ x✝ ++ [Arithcc.Instruction.sto x✝] ++ Arithcc.compile map s₂ (x✝ + 1) ++ [Arithcc.Instruction.add x✝]
Instances For
Correctness #
Machine states ζ₁ and ζ₂ are equal except for the accumulator and registers {x | x ≥ t}.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Machine states ζ₁ and ζ₂ are equal except for registers {x | x ≥ t}.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Arithcc.instTransStateStateEqHAddRegisterOfNat t = { trans := ⋯ }
Transitivity of chaining ≃[t]
and ≃[t]/ac
.
Equations
- Arithcc.instTransStateStateEqHAddRegisterOfNatStateEqRs t = { trans := ⋯ }
Writing the same value to register t
gives ≃[t + 1]
from ≃[t]
.
Writing the same value to any register preserves ≃[t]/ac
.
≃[t + 1]
with writing to register t
implies ≃[t]
.
The main compiler correctness theorem.
Unlike Theorem 1 in the paper, both map
and the assumption on t
are explicit.