![]() | 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)
write("The form is s ? e")
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:
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.
procedure main()
while line := read() do
line ? process()
end
The output of imt for this program is a procedure Mp()
(for meta-procedure):
procedure Mp()
Proc("main",);
Body(WhileDo(Asgnop(":=",Var("line"),
Invoke(Var("read"),Null())),Scan(Var("line"),
Invoke(Var("process"),Null()))),);
End();
end
The procedure calls in 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
procedure Scan(e1, e2)
return ("(" || e1 || " ? " || e2 || ")")
end
To get a translation for modeling string scanning, it's only necessary to
change this procedure to
procedure Scan(e1, e2)
return ("Escan(Bscan(" || e1 || ")," || e2 || ")"
end
For completeness, augmented string scanning should be translated in a similar
manner. See 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:
write("procedure Map(s1, s2, s3)")
write(" return map(s1, s2, s3)")
write("end")
An alternative approach, which is more desirable in the case of elaborate
translations, is to add
write("link libe")
at the beginning or end of 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
procedure Scan(e1, e2)
return ("(" || e1 || " ? " || e2 || ")")
end
To count the number of string scanning expressions in a program, all that's
needed is to replace this procedure by
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-11
procedure 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