Department of Computer
Science The University of Arizona Tucson, Arizona IPD263c February 8, 1997 http://www.cs.arizona.edu/icon/docs/ipd263.htm |
Preprocessors to do these kinds of things often are written by hand, an approach that often produces unsatisfactory results. Hand-crafted preprocessors rarely treat source-language code with complete generality. For example, a hand-crafted preprocessor for modeling string scanning might not properly handle a string literal such asexpr1 ? expr2 -> Escan(Bscan(expr1), expr2)
and instead change the literal. Similarly, hand-crafted preprocessors often assume that programs are laid out in reasonable ways, and may not handle something like this:write("The form is s ? e")
And few hand-crafted preprocessors correctly handle programs that contain syntax errors.s ? while move( 1 ) do write( move( 1 ) )
imt
is itself a variant translator. It handles
only parsing and does not have to be changed to effect different meta-translations.The output ofprocedure main() while line := read() do line ? process() end
imt
for this program is a procedure Mp()
(for meta-procedure):
The procedure calls inprocedure Mp() Proc("main",); Body(WhileDo(Asgnop(":=",Var("line"), Invoke(Var("read"),Null())),Scan(Var("line"), Invoke(Var("process"),Null()))),); End(); end
Mp()
correspond to the syntactic components
of the original program. For example, Proc()
is a procedure
that corresponds to a procedure declaration header in the original program,
and WhileDo()
is a procedure corresponding to the while-do
loop. The procedure Body()
writes the code for the procedure
body.cg_basis.icn
. The code-generation procedure
for the identity translation of while-do
is
procedure WhileDo(e1, e2) return ("while " || e1 || " do " || e2) end
cg_basis.icn
with the procedure Mp()
produced by imt
and executing the result is:
This is functionally equivalent to the original program; only the layout is different.procedure main() while (line := read()) do (line ? process()) end
To get a translation for modeling string scanning, it's only necessary to change this procedure toprocedure Scan(e1, e2) return ("(" || e1 || " ? " || e2 || ")") end
For completeness, augmented string scanning should be translated in a similar manner. Seeprocedure Scan(e1, e2) return ("Escan(Bscan(" || e1 || ")," || e2 || ")" end
Augscan()
in the appendix.map()
to calls
of Map()
so that mapping can be traced. The declaration for
Map()
might be
The meta-translation can be accomplished by adding the lineprocedure Map(s1, s2, s3) return map(s1, s2, s3) end
at the beginning of the procedureif e == "map" then e := "Map" # check procedure name
Invoke()
shown in the appendix.Map()
must be included in the final
program. This can be done by adding the following lines to the beginning
or end of main()
in the code-generator procedures:
An alternative approach, which is more desirable in the case of elaborate translations, is to addwrite("procedure Map(s1, s2, s3)") write(" return map(s1, s2, s3)") write("end")
at the beginning or end ofwrite("link libe")
main()
and provide the code to be
linked with the final program in libe
.icn
.suspend
must be used instead
of return
; otherwise the procedure won't produce all the results
produced by the generator. For example, for seq()
, the procedure
would be
In fact, it doesn't hurt to useprocedure Seq(i1, i2) suspend seq(i1, i2) end
suspend
for functions that
aren't generators.
Mp()
describes the syntactic structure of a program with
a procedure call for every token, the code-generation procedure it calls
can count the number of times they are called instead of producing source
code. Consider, for example, string scanning expressions. As shown above,
the procedure for identity translation for string scanning is
To count the number of string scanning expressions in a program, all that's needed is to replace this procedure byprocedure Scan(e1, e2) return ("(" || e1 || " ? " || e2 || ")") end
where token is a table created by the main procedure beforeprocedure Scan(e1, e2) token["e1 ? e2"] +:= 1 end
Mp()
is called. When Mp()
returns, the tabulation of tokens can
be written out. (Integer suffixes, as in "e1 ? e2"
are used to make the results easy to read.)Scan()
and Augscan()
can be simply do nothing;
no code is required for them.
Mp()
that
describes it is huge. It's also necessary to link the code-generation procedures
with Mp()
, adding to the size of the intermediate program.
The memory needed usually is not a problem on platforms in the workstation
class, but it can be on personal computers.
ftp.cs.arizona.edu
;
cd /icon/meta
and get READ.ME
to see what to do
next.
6,
pp. 1-2.
27, pp. 5-11procedure Alt(e1, e2) # e1 | e2 return ("(" || e1 || "|" || e2 || ")") end procedure Arg(e) return e end procedure Augscan(e1, e2) # e1 ?:= e2 return ("(" || e1 || " ?:= " || e2 || ")") end procedure Binop(op, e1, e2) # e1 op e2 return ("(" || e1 || " " || op || " " || e2 || ")") end procedure Body(es[]) # procedure body every write(!es) return end procedure Break(e) # break e return ("break " || e) end procedure Case(e, clist) # case e of { caselist } return ("case " || e || " of {" || clist || "}") end procedure Cclause(e1, e2) # e1 : e2 return (e1 || " : " || e2) end procedure Clist(cclause1, cclause2) # cclause1 ; cclause2 return (cclause1 || ";" || cclause2) end procedure Clit(c) # 'c' return image(c) end procedure Compound(es[]) # { e1; e2; ... } local result if *es = 0 then return "{}" result := "{" every result ||:= !es || ";" return (result[1:-1] || "}") end procedure Create(e) # create e return ("create " || e) end procedure Default(s) return ("default: " || s) end procedure End() # end write("end") return end procedure Every(e) # every e return ("every " || e) end procedure EveryDo(e1, e2) # every e1 do e2 return ("every " || e1 || " do " || e2) end procedure Fail() # fail return "fail" end procedure Field(e, f) # e . f return ("(" || e || "." || f || ")") end procedure Global(vs[]) # global v1, v2, ... local result result := "" every result ||:= !vs || ", " write("global ", result[1:-2]) return end procedure IfThen(e1, e2) # if e1 then e2 return ("if " || e1 || " then " || e2) end procedure IfThenElse(e1, e2, e3) # if e1 then e2 else e3 return ("if " || e1 || " then " || e2 || " else " || e3) end procedure Ilit(i) # n return i end procedure Initial(e) # initial e write("initial ", e) return end procedure Invocable(ss[]) # invocable s1, s2, ... if \ss then write("invocable all") else write("invocable ", ss) return end procedure Invoke(e, es[]) # e(e1, e2, ...) local result if *es = 0 then return (e ||"()") result := "" every result ||:= !es || ", " return (e || "(" || result[1:-2] || ")") end procedure Key(s) # &s return ("&" || s) end procedure Limit(e1, e2) # e1 \ e2 return ("(" || e1 || "\\" || e2 || ")") end procedure Link(vs[]) # link "v1, v2, ..." local result result := "" every result ||:= !vs || ", " write("link ", result[1:-2]) return end procedure List(es[]) # [e1, e2, ... ] local result if *es = 0 then return "[]" result := "" every result ||:= !es || ", " return ("[" || result[1:-2] || "]") end procedure Local(vs[]) # local scope v1, v2, ... local result result := "" every result ||:= !vs || ", " write("local ", result[1:-2]) return end procedure Next() # next return "next" end procedure Not(e) # not e return ("not(" || e || ")") end procedure Null() # &null return "" end procedure Paren(es[]) # (e1, e2, ... ) local result if *es = 0 then return "()" result := "" every result ||:= !es || ", " return ("(" || result[1:-2] || ")") end procedure Pdco(e, es[]) # e{e1, e2, ... } local result if *es = 0 then return (e || "{}") result := "" every result ||:= !es || ", " return (e || "{" || result[1:-2] || "}") end procedure Proc(n, vs[]) # procedure n(v1, v2, ...) local result, v if *vs = 0 then write("procedure ", n, "()") result := "" every v := !vs do if \v == "[]" then result[-2:0] := v || ", " else result ||:= (\v | "") || ", " write("procedure ", n, "(", result[1:-2], ")") return end procedure Record(n, fs[]) # record n(f1, f2, ...) local result, field if *fs = 0 then write("record ", n, "()") result := "" every field := !fs do result ||:= (\field | "") || ", " write("record ", n, "(", result[1:-2], ")") return end procedure Repalt(e) # |e return ("(|" || e || ")") end procedure Repeat(e) # repeat e return ("repeat " || e) end procedure Return(e) # return e return ("return " || e) end procedure Rlit(r) # r return r end procedure Scan(e1, e2) # e1 ? e2 return ("(" || e1 || " ? " || e2 || ")") end procedure Section(op, e1, e2, e3) # e1[e2 op e3] return (e1 || "[" || e2 || op || e3 || "]") end procedure Slit(s) # "s" return image(s) end procedure Static(vs[]) # static v1, v2, ... local result result := "" every result ||:= !vs || ", " write("static ", result[1:-2]) return end procedure Subscript(e1, e2) # e1[e2] return (e1 || "[" || e2 || "]") end procedure Suspend(e) # suspend e return ("suspend " || e) end procedure SuspendDo(e1, e2) # suspend e1 do e2 return ("suspend " || e1 || " do " || e2) end procedure To(e1, e2) # e1 to e2 return ("(" || e1 || " to " || e2 || ")") end procedure ToBy(e1, e2, e3) # e1 to e2 by e3 return ("(" || e1 || " to " || e2 || " by " || e3 || ")") end procedure Unop(op, e) # op e return ("(" || op || "(" || e || "))") end procedure Until(e) # until e return ("until " || e) end procedure UntilDo(e1, e2) # until e1 do e2 return ("until " || e1 || " do " || e2) end procedure Var(v) # v return v end procedure While(e) # while e return ("while " || e) end procedure WhileDo(e1, e2) # while e1 do e2 return ("while " || e1 || " do " || e2) end