Compiling IMP to a stack machine
InductiveStack machine instructions#✓fully proved
An instruction of the stack machine is one of \(\mathsf{push}\ n\), \(\mathsf{load}\ x\) and \(\mathsf{store}\ x\) for natural numbers \(n\) and \(x\); the arithmetic instructions \(\mathsf{add}\), \(\mathsf{sub}\) and \(\mathsf{mul}\); the comparison and Boolean instructions \(\mathsf{eq}\), \(\mathsf{le}\), \(\mathsf{not}\) and \(\mathsf{and}\); and the jumps \(\mathsf{jump}\ t\) and \(\mathsf{jumpIfZero}\ t\) for a natural number \(t\). Jump targets are absolute program counters.
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
| jumpIfZero (target : Nat)
deriving DecidableEq, Repr
Used by 12
AbbreviationStack machine configurations#✓fully proved
A configuration of the stack machine is a triple \((pc, \sigma, s)\) of a program counter \(pc \in \mathbb{N}\), a stack \(\sigma\), which is a finite list of natural numbers whose head is the top of the stack, and a state \(s\) assigning a natural number to each variable.
abbrev Config := Nat × List Nat × State
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
Uses 1 · Used by 8
InductiveStep relation of the stack machine#✓fully proved
Let \(P\) be a program, that is a list of instructions, and write \(a :: \sigma\) for the stack with top \(a\) above the stack \(\sigma\). A configuration \((pc, \sigma, s)\) steps to a configuration \(c'\) under \(P\) exactly when \(pc < |P|\) and, for the instruction at position \(pc\) of \(P\) (counted from \(0\)), one of the following holds, where \(s[x \mapsto v]\) is the state \(s\) with variable \(x\) set to \(v\).
- \(\mathsf{push}\ n\): \(c' = (pc + 1, n :: \sigma, s)\).
- \(\mathsf{load}\ x\): \(c' = (pc + 1, s(x) :: \sigma, s)\).
- \(\mathsf{store}\ x\): \(\sigma = v :: \tau\) and \(c' = (pc + 1, \tau, s[x \mapsto v])\).
- \(\mathsf{add}\), \(\mathsf{sub}\), \(\mathsf{mul}\): \(\sigma = a :: b :: \tau\) and \(c' = (pc + 1, r :: \tau, s)\), where \(r\) is \(b + a\), \(\max(b - a, 0)\) or \(b \cdot a\) respectively.
- \(\mathsf{eq}\), \(\mathsf{le}\): \(\sigma = a :: b :: \tau\) and \(c' = (pc + 1, r :: \tau, s)\), where \(r\) is \(1\) if \(b = a\), respectively \(b \le a\), and \(r = 0\) otherwise.
- \(\mathsf{not}\): \(\sigma = a :: \tau\) and \(c' = (pc + 1, r :: \tau, s)\), where \(r = 1\) if \(a = 0\) and \(r = 0\) otherwise.
- \(\mathsf{and}\): \(\sigma = a :: b :: \tau\) and \(c' = (pc + 1, r :: \tau, s)\), where \(r = 1\) if \(b \ne 0\) and \(a \ne 0\), and \(r = 0\) otherwise.
- \(\mathsf{jump}\ t\): \(c' = (t, \sigma, s)\).
- \(\mathsf{jumpIfZero}\ t\): either \(\sigma = 0 :: \tau\) and \(c' = (t, \tau, s)\), or \(\sigma = (n + 1) :: \tau\) for some \(n\) and \(c' = (pc + 1, \tau, s)\).
For binary instructions the top of the stack \(a\) is thus the right operand and the value below it \(b\) is the left operand.
Cslib.IMP.StackMachine.Step · 44 lines
inductive Step (prog : List Instr) : Config → Config → Prop
| push {pc n : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.push n)) :
Step prog (pc, stack, s) (pc + 1, n :: stack, s)
| load {pc x : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.load x)) :
Step prog (pc, stack, s) (pc + 1, s x :: stack, s)
| store {pc x v : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.store x)) :
Step prog (pc, v :: stack, s) (pc + 1, stack, Function.update s x v)
| add {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .add) :
Step prog (pc, a :: b :: stack, s) (pc + 1, (b + a) :: stack, s)
| sub {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .sub) :
Step prog (pc, a :: b :: stack, s) (pc + 1, (b - a) :: stack, s)
| mul {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .mul) :
Step prog (pc, a :: b :: stack, s) (pc + 1, (b * a) :: stack, s)
| eqI {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .eqI) :
Step prog (pc, a :: b :: stack, s)
(pc + 1, (if b = a then 1 else 0) :: stack, s)
| leI {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .leI) :
Step prog (pc, a :: b :: stack, s)
(pc + 1, (if b ≤ a then 1 else 0) :: stack, s)
| notI {pc a : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .notI) :
Step prog (pc, a :: stack, s)
(pc + 1, (if a = 0 then 1 else 0) :: stack, s)
| andI {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .andI) :
Step prog (pc, a :: b :: stack, s)
(pc + 1, (if b ≠ 0 ∧ a ≠ 0 then 1 else 0) :: stack, s)
| jump {pc target : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.jump target)) :
Step prog (pc, stack, s) (target, stack, s)
| jumpIfZeroZero {pc target : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.jumpIfZero target)) :
Step prog (pc, 0 :: stack, s) (target, stack, s)
| jumpIfZeroSucc {pc target n : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.jumpIfZero target)) :
Step prog (pc, (n + 1) :: stack, s) (pc + 1, stack, s)
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev Config := Nat × List Nat × State
CSLibExt/Languages/IMP/StackMachine.lean:58
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
Uses 3 · Used by 6
AbbreviationMulti-step execution of the stack machine#✓fully proved
For a program \(P\), the multi-step relation on configurations is the reflexive transitive closure of the step relation of the stack machine running \(P\): it relates \(c\) to \(c'\) when \(c'\) is obtained from \(c\) by zero or more steps.
abbrev Steps (prog : List Instr) : Config → Config → Prop :=
Relation.ReflTransGen (Step prog)
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev Config := Nat × List Nat × State
CSLibExt/Languages/IMP/StackMachine.lean:58
inductive Step (prog : List Instr) : Config → Config → Prop
| push {pc n : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.push n)) :
Step prog (pc, stack, s) (pc + 1, n :: stack, s)
| load {pc x : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.load x)) :
Step prog (pc, stack, s) (pc + 1, s x :: stack, s)
| store {pc x v : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.store x)) :
Step prog (pc, v :: stack, s) (pc + 1, stack, Function.update s x v)
| add {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .add) :
⋯
CSLibExt/Languages/IMP/StackMachine.lean:64
Uses 3 · Used by 4
TheoremDeterminism of the stack machine#✓fully proved
For every program \(P\), the step relation of the stack machine running \(P\) is deterministic: if a configuration \(x\) steps to \(y\) and to \(z\), then \(y = z\). The fetched instruction and the shape of the stack determine the next configuration.
theorem Step.deterministic {prog : List Instr} {x y z : Config}
(h1 : Step prog x y) (h2 : Step prog x z) : y = z
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev Config := Nat × List Nat × State
CSLibExt/Languages/IMP/StackMachine.lean:58
inductive Step (prog : List Instr) : Config → Config → Prop
| push {pc n : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.push n)) :
Step prog (pc, stack, s) (pc + 1, n :: stack, s)
| load {pc x : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.load x)) :
Step prog (pc, stack, s) (pc + 1, s x :: stack, s)
| store {pc x v : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.store x)) :
Step prog (pc, v :: stack, s) (pc + 1, stack, Function.update s x v)
| add {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .add) :
⋯
CSLibExt/Languages/IMP/StackMachine.lean:64
Uses 4
TheoremNo step past the end of the program#✓fully proved
Let \(P\) be a program, that is a list of instructions, and let \((pc, \sigma, s)\) be a configuration with \(|P| \le pc\). Then the stack machine running \(P\) has no step from \((pc, \sigma, s)\) to any configuration, since there is no instruction at position \(pc\) to fetch.
Hence the length of the code compiled from a command at base address \(0\) is a halt address for that code.
theorem no_step_of_length_le {prog : List Instr} {pc : Nat} {stack : List Nat}
{s : State} (h : prog.length ≤ pc) (y : Config) :
¬ Step prog (pc, stack, s) y
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
abbrev Config := Nat × List Nat × State
CSLibExt/Languages/IMP/StackMachine.lean:58
inductive Step (prog : List Instr) : Config → Config → Prop
| push {pc n : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.push n)) :
Step prog (pc, stack, s) (pc + 1, n :: stack, s)
| load {pc x : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.load x)) :
Step prog (pc, stack, s) (pc + 1, s x :: stack, s)
| store {pc x v : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some (.store x)) :
Step prog (pc, v :: stack, s) (pc + 1, stack, Function.update s x v)
| add {pc a b : Nat} {stack : List Nat} {s : State}
(hfetch : prog[pc]? = some .add) :
⋯
CSLibExt/Languages/IMP/StackMachine.lean:64
Uses 4
DefinitionInstruction count of an arithmetic expression#✓fully proved
The instruction count \(\ell(a)\) of an arithmetic expression \(a\) is defined by recursion on \(a\): a constant or a variable has count \(1\), and if \(a\) is the sum, difference or product of \(a_1\) and \(a_2\), then \(\ell(a) = \ell(a_1) + \ell(a_2) + 1\).
It is the number of stack-machine instructions generated when \(a\) is compiled.
def alen : AExp → Nat
| .const _ => 1
| .var _ => 1
| .add left right => alen left + alen right + 1
| .sub left right => alen left + alen right + 1
| .mul left right => alen left + alen right + 1
inductive AExp where
| const (value : Nat)
| var (name : Nat)
| add (left right : AExp)
| sub (left right : AExp)
| mul (left right : AExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:37
Uses 1 · Used by 5
DefinitionInstruction count of a Boolean expression#✓fully proved
The instruction count \(\ell(b)\) of a Boolean expression \(b\) is defined by recursion on \(b\), using the instruction count \(\ell(a)\) of arithmetic expressions \(a\): a truth value has count \(1\); the tests \(a_1 = a_2\) and \(a_1 \le a_2\) have count \(\ell(a_1) + \ell(a_2) + 1\); the negation of \(b_1\) has count \(\ell(b_1) + 1\); and the conjunction of \(b_1\) and \(b_2\) has count \(\ell(b_1) + \ell(b_2) + 1\).
It is the number of stack-machine instructions generated when \(b\) is compiled.
def blen : BExp → Nat
| .truth _ => 1
| .eq left right => alen left + alen right + 1
| .le left right => alen left + alen right + 1
| .not body => blen body + 1
| .and left right => blen left + blen right + 1
inductive BExp where
| truth (value : Bool)
| eq (left right : AExp)
| le (left right : AExp)
| not (body : BExp)
| and (left right : BExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:46
def alen : AExp → Nat
| .const _ => 1
| .var _ => 1
| .add left right => alen left + alen right + 1
| .sub left right => alen left + alen right + 1
| .mul left right => alen left + alen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:130
Uses 3 · Used by 4
DefinitionInstruction count of a command#✓fully proved
The instruction count \(\ell(c)\) of an IMP command \(c\) is defined by recursion on \(c\), using the instruction counts \(\ell(a)\) and \(\ell(b)\) of arithmetic and Boolean expressions: \(\ell(\mathbf{skip}) = 0\); \(\ell(x := a) = \ell(a) + 1\); \(\ell(c_1; c_2) = \ell(c_1) + \ell(c_2)\); \(\ell(\mathbf{if}\ b\ \mathbf{then}\ c_1\ \mathbf{else}\ c_2) = \ell(b) + 1 + \ell(c_1) + 1 + \ell(c_2)\); and \(\ell(\mathbf{while}\ b\ \mathbf{do}\ c_1) = \ell(b) + 1 + \ell(c_1) + 1\).
It is the number of stack-machine instructions generated when \(c\) is compiled.
def codeLength : Cmd → Nat
| .skip => 0
| .assign _ value => alen value + 1
| .seq first second => codeLength first + codeLength second
| .ite guard thenBranch elseBranch =>
blen guard + 1 + codeLength thenBranch + 1 + codeLength elseBranch
| .while guard body => blen guard + 1 + codeLength body + 1
inductive Cmd where
| skip
| assign (name : Nat) (value : AExp)
| seq (first second : Cmd)
| ite (guard : BExp) (thenBranch elseBranch : Cmd)
| while (guard : BExp) (body : Cmd)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:55
def alen : AExp → Nat
| .const _ => 1
| .var _ => 1
| .add left right => alen left + alen right + 1
| .sub left right => alen left + alen right + 1
| .mul left right => alen left + alen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:130
def blen : BExp → Nat
| .truth _ => 1
| .eq left right => alen left + alen right + 1
| .le left right => alen left + alen right + 1
| .not body => blen body + 1
| .and left right => blen left + blen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:138
Uses 5 · Used by 3
DefinitionCompilation of arithmetic expressions#✓fully proved
The compiled code of an arithmetic expression is the list of stack-machine instructions defined by recursion: a constant \(n\) compiles to the single instruction push \(n\), a variable \(x\) to the single instruction load \(x\), and the sum, difference or product of \(a_1\) and \(a_2\) to the code of \(a_1\), then the code of \(a_2\), then the single instruction add, sub or mul respectively.
Running this code leaves the value of the expression on top of the stack.
def compileA : AExp → List Instr
| .const value => [.push value]
| .var name => [.load name]
| .add left right => compileA left ++ compileA right ++ [.add]
| .sub left right => compileA left ++ compileA right ++ [.sub]
| .mul left right => compileA left ++ compileA right ++ [.mul]
inductive AExp where
| const (value : Nat)
| var (name : Nat)
| add (left right : AExp)
| sub (left right : AExp)
| mul (left right : AExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:37
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
Uses 2 · Used by 5
DefinitionCompilation of Boolean expressions#✓fully proved
The compiled code of a Boolean expression is the list of stack-machine instructions defined by recursion, using the compiled code of arithmetic expressions: the truth value true compiles to the single instruction push \(1\) and false to push \(0\); the test \(a_1 = a_2\) (respectively \(a_1 \le a_2\)) compiles to the code of \(a_1\), then the code of \(a_2\), then the equality (respectively order) test instruction; the negation of \(b_1\) compiles to the code of \(b_1\) followed by the negation instruction; and the conjunction of \(b_1\) and \(b_2\) compiles to the code of \(b_1\), then the code of \(b_2\), then the conjunction instruction.
Running this code leaves \(1\) (true) or \(0\) (false) on top of the stack.
def compileB : BExp → List Instr
| .truth value => [.push (cond value 1 0)]
| .eq left right => compileA left ++ compileA right ++ [.eqI]
| .le left right => compileA left ++ compileA right ++ [.leI]
| .not body => compileB body ++ [.notI]
| .and left right => compileB left ++ compileB right ++ [.andI]
inductive BExp where
| truth (value : Bool)
| eq (left right : AExp)
| le (left right : AExp)
| not (body : BExp)
| and (left right : BExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:46
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
def compileA : AExp → List Instr
| .const value => [.push value]
| .var name => [.load name]
| .add left right => compileA left ++ compileA right ++ [.add]
| .sub left right => compileA left ++ compileA right ++ [.sub]
| .mul left right => compileA left ++ compileA right ++ [.mul]
CSLibExt/Languages/IMP/StackMachine.lean:155
Uses 4 · Used by 3
DefinitionCompilation of commands#✓fully proved
The compiled code \(C_p(c)\) of an IMP command \(c\) at base program counter \(p\) is the list of stack-machine instructions defined by recursion on \(c\), where jump targets are absolute program counters and \(\ell\) denotes instruction counts: \(C_p(\mathbf{skip})\) is empty; \(C_p(x := a)\) is the code of \(a\) followed by the instruction store \(x\); \(C_p(c_1; c_2)\) is \(C_p(c_1)\) followed by \(C_{p + \ell(c_1)}(c_2)\). For the conditional \(\mathbf{if}\ b\ \mathbf{then}\ c_1\ \mathbf{else}\ c_2\), put \(q = p + \ell(b) + 1\) and \(r = q + \ell(c_1) + 1\); its code is the code of \(b\), then jump-if-zero to \(r\), then \(C_q(c_1)\), then jump to \(r + \ell(c_2)\), then \(C_r(c_2)\). For the loop \(\mathbf{while}\ b\ \mathbf{do}\ c_1\), put \(q = p + \ell(b) + 1\); its code is the code of \(b\), then jump-if-zero to \(q + \ell(c_1) + 1\), then \(C_q(c_1)\), then jump to \(p\).
Cslib.IMP.StackMachine.compile · 16 lines
def compile : Cmd → Nat → List Instr
| .skip, _ => []
| .assign name value, _ => compileA value ++ [.store name]
| .seq first second, pc =>
compile first pc ++ compile second (pc + codeLength first)
| .ite guard thenBranch elseBranch, pc =>
compileB guard ++
[.jumpIfZero (pc + blen guard + 1 + codeLength thenBranch + 1)] ++
compile thenBranch (pc + blen guard + 1) ++
[.jump (pc + blen guard + 1 + codeLength thenBranch + 1 +
codeLength elseBranch)] ++
compile elseBranch (pc + blen guard + 1 + codeLength thenBranch + 1)
| .while guard body, pc =>
compileB guard ++
[.jumpIfZero (pc + blen guard + 1 + codeLength body + 1)] ++
compile body (pc + blen guard + 1) ++ [.jump pc]
inductive Cmd where
| skip
| assign (name : Nat) (value : AExp)
| seq (first second : Cmd)
| ite (guard : BExp) (thenBranch elseBranch : Cmd)
| while (guard : BExp) (body : Cmd)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:55
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
def compileA : AExp → List Instr
| .const value => [.push value]
| .var name => [.load name]
| .add left right => compileA left ++ compileA right ++ [.add]
| .sub left right => compileA left ++ compileA right ++ [.sub]
| .mul left right => compileA left ++ compileA right ++ [.mul]
CSLibExt/Languages/IMP/StackMachine.lean:155
def codeLength : Cmd → Nat
| .skip => 0
| .assign _ value => alen value + 1
| .seq first second => codeLength first + codeLength second
| .ite guard thenBranch elseBranch =>
blen guard + 1 + codeLength thenBranch + 1 + codeLength elseBranch
| .while guard body => blen guard + 1 + codeLength body + 1
CSLibExt/Languages/IMP/StackMachine.lean:146
def compileB : BExp → List Instr
| .truth value => [.push (cond value 1 0)]
| .eq left right => compileA left ++ compileA right ++ [.eqI]
| .le left right => compileA left ++ compileA right ++ [.leI]
| .not body => compileB body ++ [.notI]
| .and left right => compileB left ++ compileB right ++ [.andI]
CSLibExt/Languages/IMP/StackMachine.lean:164
def blen : BExp → Nat
| .truth _ => 1
| .eq left right => alen left + alen right + 1
| .le left right => alen left + alen right + 1
| .not body => blen body + 1
| .and left right => blen left + blen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:138
TheoremFetching from an embedded code segment#✓fully proved
Let \(B\), \(S\) and \(A\) be lists of instructions and let \(i < |S|\) be a natural number. Then the instruction at position \(|B| + i\) of the concatenation \(B\,S\,A\) of the three lists equals the instruction at position \(i\) of \(S\), positions being counted from \(0\).
theorem fetch_segment {before seg after : List Instr} {i : Nat}
(hi : i < seg.length) :
(before ++ seg ++ after)[before.length + i]? = seg[i]?
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
TheoremCompiled arithmetic code pushes the value of the expression#✓fully proved
Let \(a\) be an arithmetic expression with compiled code \(C(a)\) and instruction count \(\ell(a)\), let \(P\) and \(Q\) be lists of instructions, \(\sigma\) a stack and \(s\) a state, and write \(|P|\) for the length of \(P\). The stack machine running the program \(P \, C(a) \, Q\) (the concatenation of \(P\), \(C(a)\) and \(Q\)) goes in finitely many steps from program counter \(|P|\), stack \(\sigma\) and state \(s\) to program counter \(|P| + \ell(a)\), the stack obtained from \(\sigma\) by pushing the value of \(a\) in \(s\), and the same state \(s\).
theorem compileA_runs {a : AExp} {before after : List Instr} {stack : List Nat}
{s : State} :
Steps (before ++ compileA a ++ after) (before.length, stack, s)
(before.length + alen a, a.eval s :: stack, s)
inductive AExp where
| const (value : Nat)
| var (name : Nat)
| add (left right : AExp)
| sub (left right : AExp)
| mul (left right : AExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:37
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
abbrev Steps (prog : List Instr) : Config → Config → Prop :=
Relation.ReflTransGen (Step prog)
CSLibExt/Languages/IMP/StackMachine.lean:110
def compileA : AExp → List Instr
| .const value => [.push value]
| .var name => [.load name]
| .add left right => compileA left ++ compileA right ++ [.add]
| .sub left right => compileA left ++ compileA right ++ [.sub]
| .mul left right => compileA left ++ compileA right ++ [.mul]
CSLibExt/Languages/IMP/StackMachine.lean:155
def alen : AExp → Nat
| .const _ => 1
| .var _ => 1
| .add left right => alen left + alen right + 1
| .sub left right => alen left + alen right + 1
| .mul left right => alen left + alen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:130
Uses 10 · Used by 2
TheoremCompiled Boolean code pushes the truth value of the expression#✓fully proved
Let \(b\) be a Boolean expression with compiled code \(C(b)\) and instruction count \(\ell(b)\), let \(P\) and \(Q\) be lists of instructions, \(\sigma\) a stack and \(s\) a state, and write \(|P|\) for the length of \(P\). The stack machine running the program \(P \, C(b) \, Q\) (the concatenation of \(P\), \(C(b)\) and \(Q\)) goes in finitely many steps from program counter \(|P|\), stack \(\sigma\) and state \(s\) to program counter \(|P| + \ell(b)\), the stack obtained from \(\sigma\) by pushing \(1\) if \(b\) evaluates to true in \(s\) and \(0\) otherwise, and the same state \(s\).
theorem compileB_runs {b : BExp} {before after : List Instr} {stack : List Nat}
{s : State} :
Steps (before ++ compileB b ++ after) (before.length, stack, s)
(before.length + blen b, cond (b.eval s) 1 0 :: stack, s)
inductive BExp where
| truth (value : Bool)
| eq (left right : AExp)
| le (left right : AExp)
| not (body : BExp)
| and (left right : BExp)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:46
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
abbrev Steps (prog : List Instr) : Config → Config → Prop :=
Relation.ReflTransGen (Step prog)
CSLibExt/Languages/IMP/StackMachine.lean:110
def compileB : BExp → List Instr
| .truth value => [.push (cond value 1 0)]
| .eq left right => compileA left ++ compileA right ++ [.eqI]
| .le left right => compileA left ++ compileA right ++ [.leI]
| .not body => compileB body ++ [.notI]
| .and left right => compileB left ++ compileB right ++ [.andI]
CSLibExt/Languages/IMP/StackMachine.lean:164
def blen : BExp → Nat
| .truth _ => 1
| .eq left right => alen left + alen right + 1
| .le left right => alen left + alen right + 1
| .not body => blen body + 1
| .and left right => blen left + blen right + 1
CSLibExt/Languages/IMP/StackMachine.lean:138
Uses 15 · Used by 1
TheoremCompiled command code simulates big-step execution#✓fully proved
Let \(c\) be a command and \(s\), \(s'\) states such that \(c\) run from \(s\) terminates in \(s'\) under the big-step semantics. Let \(P\) and \(Q\) be lists of instructions, \(\sigma\) a stack, \(|P|\) the length of \(P\), \(C_p(c)\) the compiled code of \(c\) at base program counter \(p\), and \(\ell(c)\) the instruction count of \(c\). Then the stack machine running the program \(P \, C_{|P|}(c) \, Q\) (the concatenation of \(P\), \(C_{|P|}(c)\) and \(Q\)) goes in finitely many steps from program counter \(|P|\), stack \(\sigma\) and state \(s\) to program counter \(|P| + \ell(c)\), the same stack \(\sigma\) and state \(s'\).
theorem compile_runs {c : Cmd} {s s' : State} (h : BigStep c s s')
{before after : List Instr} {stack : List Nat} :
Steps (before ++ compile c before.length ++ after) (before.length, stack, s)
(before.length + codeLength c, stack, s')
inductive Cmd where
| skip
| assign (name : Nat) (value : AExp)
| seq (first second : Cmd)
| ite (guard : BExp) (thenBranch elseBranch : Cmd)
| while (guard : BExp) (body : Cmd)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:55
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
inductive BigStep : Cmd → State → State → Prop
| skip (state) : BigStep .skip state state
| assign (state) (name) (value) :
BigStep (.assign name value) state (Function.update state name (value.eval state))
| seq {first second initial middle final}
(firstStep : BigStep first initial middle)
(secondStep : BigStep second middle final) :
BigStep (.seq first second) initial final
| iteTrue {guard thenBranch elseBranch initial final}
(guardTrue : guard.eval initial = true)
(branchStep : BigStep thenBranch initial final) :
BigStep (.ite guard thenBranch elseBranch) initial final
⋯
CSLibExt/Languages/IMP/BigStep.lean:34
inductive Instr where
| push (n : Nat)
| load (x : Nat)
| store (x : Nat)
| add
| sub
| mul
| eqI
| leI
| notI
| andI
| jump (target : Nat)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:42
abbrev Steps (prog : List Instr) : Config → Config → Prop :=
Relation.ReflTransGen (Step prog)
CSLibExt/Languages/IMP/StackMachine.lean:110
def compile : Cmd → Nat → List Instr
| .skip, _ => []
| .assign name value, _ => compileA value ++ [.store name]
| .seq first second, pc =>
compile first pc ++ compile second (pc + codeLength first)
| .ite guard thenBranch elseBranch, pc =>
compileB guard ++
[.jumpIfZero (pc + blen guard + 1 + codeLength thenBranch + 1)] ++
compile thenBranch (pc + blen guard + 1) ++
[.jump (pc + blen guard + 1 + codeLength thenBranch + 1 +
codeLength elseBranch)] ++
compile elseBranch (pc + blen guard + 1 + codeLength thenBranch + 1)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:173
def codeLength : Cmd → Nat
| .skip => 0
| .assign _ value => alen value + 1
| .seq first second => codeLength first + codeLength second
| .ite guard thenBranch elseBranch =>
blen guard + 1 + codeLength thenBranch + 1 + codeLength elseBranch
| .while guard body => blen guard + 1 + codeLength body + 1
CSLibExt/Languages/IMP/StackMachine.lean:146
Uses 20 · Used by 1
TheoremCorrectness of compilation to the stack machine#✓fully proved
Let \(c\) be a command and \(s\), \(s'\) states such that \(c\) run from \(s\) terminates in \(s'\) under the big-step semantics. Let \(C_0(c)\) be the compiled code of \(c\) at base program counter \(0\) and \(\ell(c)\) the instruction count of \(c\). Then the stack machine running \(C_0(c)\) goes in finitely many steps from program counter \(0\), the empty stack and state \(s\) to program counter \(\ell(c)\), the empty stack and state \(s'\).
Since \(C_0(c)\) has exactly \(\ell(c)\) instructions, no step is possible at program counter \(\ell(c)\), so the machine halts there. Only this forward simulation is claimed, not its converse.
theorem compile_correct {c : Cmd} {s s' : State} (h : BigStep c s s') :
Steps (compile c 0) (0, [], s) (codeLength c, [], s')
inductive Cmd where
| skip
| assign (name : Nat) (value : AExp)
| seq (first second : Cmd)
| ite (guard : BExp) (thenBranch elseBranch : Cmd)
| while (guard : BExp) (body : Cmd)
deriving DecidableEq, Repr
CSLibExt/Languages/IMP/Syntax.lean:55
abbrev State := Nat → Nat
CSLibExt/Languages/IMP/Syntax.lean:34
inductive BigStep : Cmd → State → State → Prop
| skip (state) : BigStep .skip state state
| assign (state) (name) (value) :
BigStep (.assign name value) state (Function.update state name (value.eval state))
| seq {first second initial middle final}
(firstStep : BigStep first initial middle)
(secondStep : BigStep second middle final) :
BigStep (.seq first second) initial final
| iteTrue {guard thenBranch elseBranch initial final}
(guardTrue : guard.eval initial = true)
(branchStep : BigStep thenBranch initial final) :
BigStep (.ite guard thenBranch elseBranch) initial final
⋯
CSLibExt/Languages/IMP/BigStep.lean:34
abbrev Steps (prog : List Instr) : Config → Config → Prop :=
Relation.ReflTransGen (Step prog)
CSLibExt/Languages/IMP/StackMachine.lean:110
def compile : Cmd → Nat → List Instr
| .skip, _ => []
| .assign name value, _ => compileA value ++ [.store name]
| .seq first second, pc =>
compile first pc ++ compile second (pc + codeLength first)
| .ite guard thenBranch elseBranch, pc =>
compileB guard ++
[.jumpIfZero (pc + blen guard + 1 + codeLength thenBranch + 1)] ++
compile thenBranch (pc + blen guard + 1) ++
[.jump (pc + blen guard + 1 + codeLength thenBranch + 1 +
codeLength elseBranch)] ++
compile elseBranch (pc + blen guard + 1 + codeLength thenBranch + 1)
⋯
CSLibExt/Languages/IMP/StackMachine.lean:173
def codeLength : Cmd → Nat
| .skip => 0
| .assign _ value => alen value + 1
| .seq first second => codeLength first + codeLength second
| .ite guard thenBranch elseBranch =>
blen guard + 1 + codeLength thenBranch + 1 + codeLength elseBranch
| .while guard body => blen guard + 1 + codeLength body + 1
CSLibExt/Languages/IMP/StackMachine.lean:146
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.