1 (* Adapted from Pottier's PP compiler *)
5 (* ------------------------------------------------------------------------- *)
7 (* The functor [Visit] implements the core of the translation of
12 (* [fetch l] is the statement found at label [l] in the source
15 val fetch: Label.t -> LTL.statement
17 (* [translate_statement stmt] translates the [LTL] statement [stmt] to
18 a [LIN] statement. [LTL] statements that have one explicit
19 successor are turned into [LIN] statements with an implicit
20 successor. [LTL] statements that have two explicit successors
21 are turned into [LIN] statements where the first successor is
22 explicit and the second successor is implicit. *)
24 val translate_statement: LTL.statement -> LIN.statement
26 (* [generate stmt] generates statement [stmt]. Statements are
27 generated sequentially. *)
29 val generate: LIN.statement -> unit
31 (* [require l] records the fact that the label [l] should explicitly
32 exist in the [LIN] program. It must be used whenever a [LIN]
33 branch statement is issued. *)
35 val require: Label.t -> unit
37 (* [mark l] marks the label [l]. [marked l] tells whether [l] is
40 val mark: Label.t -> unit
41 val marked: Label.t -> bool
49 if marked l then begin
51 (* Label [l] has been visited before. This implies that an [St_label l]
52 statement has been issued already. We must now generate an
53 [St_goto] statement that transfers control to this place. Because
54 [l] is the target of a branch statement, we require it to exist
58 generate (LIN.St_goto l)
63 (* Label [l] has never been visited before. First, record that it
64 now has been visited, so as to avoid looping. *)
68 (* Then, generate an [St_label l] statement. This statement
69 will be useless if [l] turns out not to be the target of a
70 branch: this is taken care of later. *)
72 generate (LIN.St_label l);
74 (* Fetch the statement found at label [l] in the source program. *)
76 let statement = fetch l in
78 (* As an optional optimization, check if this is a conditional branch
79 whose implicit successor has been visited before and whose explicit
80 successor has not. In that case, if we did nothing special, we would
81 produce a conditional branch immediately followed with an
82 unconditional one, like this:
89 This can be avoided simply by reversing the condition:
96 (* But in fact, there is only a unique conditional branch statement in
97 LTL for the 8051, so this is optimization is not used. *)
99 (* Translate the statement. *)
101 generate (translate_statement statement);
103 (* Note that [translate_statement] never produces an [St_goto]
104 statement. As a result, the code above never generates an [St_label]
105 statement immediately followed with an [St_goto] statement. This
106 proves that we never generate a (conditional or unconditional) branch
107 towards an [St_goto] statement. *)
109 (* There now remains to visit the statement's successors. *)
113 (* Sequential statements. There is only one successor, with implicit
117 | LTL.St_comment (_, l)
119 | LTL.St_int (_, _, l)
123 | LTL.St_from_acc (_, l)
124 | LTL.St_to_acc (_, l)
125 | LTL.St_opaccs (_, l)
127 | LTL.St_op2 (_, _, l)
128 | LTL.St_clear_carry l
132 | LTL.St_call_id (_, l)
133 | LTL.St_call_ptr l ->
137 (* Conditional branch statement. The label that is reached by
138 falling through in [LIN] is [l2], which means that it must be
139 translated first, so that its statements are contiguous with the
140 [LIN] branch statement. The label [l1], on the other hand,
141 becomes the target of a jump, so it is required to exist in the
144 Code for [l1] is generated, if necessary, after we are done dealing
145 with [l2]. If [l1] has already been visited at this point, no code
146 needs be produced, so the second call to visit is made only if [l1]
147 has not been visited yet. *)
149 | LTL.St_condacc (l1, l2) ->
153 if not (marked l1) then
156 (* Statement without a successor. *)
158 (* We would prefer to duplicate, rather than share, these
159 statements. Indeed, it is inefficient to generate a jump towards
160 one of these statements. Unfortunately, it is not easy to achieve
161 this, for two reasons. First, frame deletion is in the way. Second,
162 and worse, we must not generate duplicate labels. Maybe I will find
163 a fix in the future. *)