comparison book/src/StackMachine.v @ 10:d8363f2a3bef

Target language and translation
author Adam Chlipala <adamc@hcoop.net>
date Mon, 01 Sep 2008 11:30:27 -0400
parents c2e8e9c20643
children e5501b9c965d
comparison
equal deleted inserted replaced
9:c2e8e9c20643 10:d8363f2a3bef
90 (** We declare explicitly that this is a recursive definition, using the keyword [Fixpoint]. The rest should be old hat for functional programmers. *) 90 (** We declare explicitly that this is a recursive definition, using the keyword [Fixpoint]. The rest should be old hat for functional programmers. *)
91 91
92 92
93 (** ** Target language *) 93 (** ** Target language *)
94 94
95 (** We will compile our source programs onto a simple stack machine, whose syntax is: *)
96
95 Inductive instr : Set := 97 Inductive instr : Set :=
96 | IConst : nat -> instr 98 | IConst : nat -> instr
97 | IBinop : binop -> instr. 99 | IBinop : binop -> instr.
98 100
99 Definition prog := list instr. 101 Definition prog := list instr.
100 Definition stack := list nat. 102 Definition stack := list nat.
103
104 (** An instruction either pushes a constant onto the stack or pops two arguments, applies a binary operator to them, and pushes the result onto the stack. A program is a list of instructions, and a stack is a list of natural numbers.
105
106 We can give instructions meanings as functions from stacks to optional stacks, where running an instruction results in [None] in case of a stack underflow and results in [Some s'] when the result of execution is the new stack [s']. [::] is the "list cons" operator from the Coq standard library. *)
101 107
102 Definition instrDenote (i : instr) (s : stack) : option stack := 108 Definition instrDenote (i : instr) (s : stack) : option stack :=
103 match i with 109 match i with
104 | IConst n => Some (n :: s) 110 | IConst n => Some (n :: s)
105 | IBinop b => 111 | IBinop b =>
107 | arg1 :: arg2 :: s' => Some ((binopDenote b) arg1 arg2 :: s') 113 | arg1 :: arg2 :: s' => Some ((binopDenote b) arg1 arg2 :: s')
108 | _ => None 114 | _ => None
109 end 115 end
110 end. 116 end.
111 117
118 (** With [instrDenote] defined, it is easy to define a function [progDenote], which iterates application of [instrDenote] through a whole program. *)
119
112 Fixpoint progDenote (p : prog) (s : stack) {struct p} : option stack := 120 Fixpoint progDenote (p : prog) (s : stack) {struct p} : option stack :=
113 match p with 121 match p with
114 | nil => Some s 122 | nil => Some s
115 | i :: p' => 123 | i :: p' =>
116 match instrDenote i s with 124 match instrDenote i s with
117 | None => None 125 | None => None
118 | Some s' => progDenote p' s' 126 | Some s' => progDenote p' s'
119 end 127 end
120 end. 128 end.
121 129
130 (** There is one interesting difference compared to our previous example of a [Fixpoint]. This recursive function takes two arguments, [p] and [s]. It is critical for the soundness of Coq that every program terminate, so a shallow syntactic termination check is imposed on every recursive function definition. One of the function parameters must be designated to decrease monotonically across recursive calls. That is, every recursive call must use a version of that argument that has been pulled out of the current argument by some number of [match] expressions. [expDenote] has only one argument, so we did not need to specify which of its arguments decreases. For [progDenote], we resolve the ambiguity by writing [{struct p}] to indicate that argument [p] decreases structurally. *)
131
122 132
123 (** ** Translation *) 133 (** ** Translation *)
134
135 (** Our compiler itself is now unsurprising. [++] is the list concatenation operator from the Coq standard library. *)
124 136
125 Fixpoint compile (e : exp) : prog := 137 Fixpoint compile (e : exp) : prog :=
126 match e with 138 match e with
127 | Const n => IConst n :: nil 139 | Const n => IConst n :: nil
128 | Binop b e1 e2 => compile e2 ++ compile e1 ++ IBinop b :: nil 140 | Binop b e1 e2 => compile e2 ++ compile e1 ++ IBinop b :: nil