[ Pobierz całość w formacie PDF ]
and division in an 8-bit machine, but it is the principle that matters here).
15.30 Follow up the suggestion made earlier, and extend Clang or Topsy to allow constant
expressions to appear in constant declarations, for example
CONST
Max = 100;
Limit = 2 * Max + 1;
NegMax = - Max;
15.31 Perusal of our example assignment should suggest the possibility of producing a still smaller
tree for the right-hand side expression (Figure 15.4(a)). And, were the assignment to have been
A[X + 4] := (A[3] + Z) * (4 - 4 * 1) - Y
perhaps we could do better still (see Figure 15.4(b)). How would you modify the tree-building
routines to achieve this sort of improvement? Can you do this in a way that still allows your
compiler to support the notion of a constant expression as part of a constant declaration?
15.32 (More extensive) Modify the attributed grammar and tree-building code generator so that
node classes are introduced for the various categories of Statement. Then develop code generator
routines that can effect the sorts of optimizations hinted at earlier for removing redundant code for
unreachable components of IfStatements and WhileStatements. Sophisticated compilers often issue
warnings when they discover code that can never be executed. Can you incorporate such a feature
into your compiler?
15.33 (Harder) Use a tree-based representation to generate code for Boolean expressions that
require short- circuit semantics (see Exercises 13.10 and 15.19).
15.34 (More extensive) Develop a code generator for a register-based machine such as that
suggested in section 13.3. Can you do this without altering the Cocol specification, as we claim is
possible for the single-accumulator machine of Chapter 4?
15.35 Many development environments incorporate "debuggers" - sophisticated tools that will trace
the execution of a compiled program in conjunction with the source code, referring run-time errors
to source code statements, allowing the user to interrogate (and even alter) the values of variables
by using the identifiers of the source code, and so on. Development of such a system could be a
very open- ended project. As a less ambitious project, extend the interpretive compiler for Clang or
Topsy that, in the event of a run-time error, will relate this to the corresponding line in the source,
and then print a post-mortem dump showing the values of the variables at the time the error
occurred. A system of this sort was described for the well-known subset of Pascal known as
Pascal-S (Wirth, 1981; Rees and Robson, 1987), and is also used in the implementation of the
simple teaching language Umbriel (Terry, 1995).
15.36 Develop a code generator that produces correct C or C++ code from Clang or Topsy source.
Further reading
Our treatment of code generation has been dangerously superficial. "Real" code generation tends to
become highly machine dependent, and the literature reflects this. Although all of the standard texts
have a lot to say on the subject, those texts which do not confine themselves to generalities (by
stopping short of showing how it is actually done) inevitably relate their material to one or other
real machine, which can become confusing for a beginner who has little if any experience of that
machine. Watson (1989) has a very readable discussion of the use of tree structures. Considerably
more detail is given in the comprehensive books by Aho, Sethi and Ullman (1986) and Fischer and
LeBlanc (1988, 1991). Various texts discuss code generation for familiar microprocessors. For
example, the book by Mak (1991) develops a Pascal compiler that generates assembler code for the
Intel 80x86 range of machines, and the book by Ullman (1994) develops a subset Modula-2
compiler that generates a variant of Intel assembler. The recent book by Holmes (1995) uses object
orientation to develop a Pascal compiler, discussing the generation of assembler code for a SUN
SPARC workstation. Wirth (1996) presents a tightly written account of developing a compiler for a
subset of Oberon that generates code for a slightly idealized processor, modelled on the
hypothetical RISC processor named DLX by Hennessy and Patterson (1990) to resemble the MIPS
processor. Elder (1994) gives a thorough description of many aspects of code generation for a more
advanced stack-based machine than the one described here.
[ Pobierz całość w formacie PDF ]