Understanding And Writing Compilers A Doityourself Guide Richard Bornat
Understanding And Writing Compilers A Doityourself Guide Richard Bornat
Understanding And Writing Compilers A Doityourself Guide Richard Bornat
Understanding And Writing Compilers A Doityourself Guide Richard Bornat
1. Understanding And Writing Compilers A
Doityourself Guide Richard Bornat download
https://ebookbell.com/product/understanding-and-writing-
compilers-a-doityourself-guide-richard-bornat-36529634
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Smart Thinking Skills For Critical Understanding And Writing Second
Edition Reissue Matthew Allen
https://ebookbell.com/product/smart-thinking-skills-for-critical-
understanding-and-writing-second-edition-reissue-matthew-
allen-57136102
Smart Thinking Skills For Critical Understanding And Writing 2nd Ed
Matthew Allen
https://ebookbell.com/product/smart-thinking-skills-for-critical-
understanding-and-writing-2nd-ed-matthew-allen-4121292
Smart Thinking Skills For Critical Understanding And Writing 2nd
Edition Matthew Allen
https://ebookbell.com/product/smart-thinking-skills-for-critical-
understanding-and-writing-2nd-edition-matthew-allen-1272680
Smart Thinking Skills For Critical Understanding And Writing Matthew
Allen Allen
https://ebookbell.com/product/smart-thinking-skills-for-critical-
understanding-and-writing-matthew-allen-allen-27821526
3. The Pester Book The Allinone Guide To Understanding And Writing Tests
For Powershell Adam Bertram
https://ebookbell.com/product/the-pester-book-the-allinone-guide-to-
understanding-and-writing-tests-for-powershell-adam-bertram-22295790
Understanding Development And Proficiency In Writing Quantitative
Corpus Linguistic Approaches Philip Durrant
https://ebookbell.com/product/understanding-development-and-
proficiency-in-writing-quantitative-corpus-linguistic-approaches-
philip-durrant-33030350
Get Funded A Practical Guide To Understanding The Grant Application
Process And Writing Winning Proposals In The Behavioral And Biomedical
Fields 1st Edition Elias Phd
https://ebookbell.com/product/get-funded-a-practical-guide-to-
understanding-the-grant-application-process-and-writing-winning-
proposals-in-the-behavioral-and-biomedical-fields-1st-edition-elias-
phd-56481488
Understanding Developing And Writing Effective Ieps A Stepbystep Guide
For Educators Roger Pierangelo George Giuliani
https://ebookbell.com/product/understanding-developing-and-writing-
effective-ieps-a-stepbystep-guide-for-educators-roger-pierangelo-
george-giuliani-48922738
Understanding Chinese Multilingual Scholars Experiences Of Writing And
Publishing In English A Socialcognitive Perspective Congjun Mu
https://ebookbell.com/product/understanding-chinese-multilingual-
scholars-experiences-of-writing-and-publishing-in-english-a-
socialcognitive-perspective-congjun-mu-10788004
6. First published—1979.
Internet edition—2007; corrected 2008.
Copyright c 1979, 2007, 2008 Richard Bornat.
Permission to copy without fee all or part of this material is granted provided
that the copies are not made or distributed for direct commercial advantage,
the copyright notice above and the title of the book appear, and notice is given
that copying is by permission of Richard Bornat.
Original edition published by Macmillan Press Ltd., Basingstoke, UK.
Internet edition published by Richard Bornat, 28 Albany Road, LONDON N4
4RL, UK. richard@bornat.me.uk
7. Preface to the online
edition
I wrote this book on compiling in the late 1970s. It was a success. I still meet
people who learnt about compiling from it. I get three or four requests a year
from people who’d like a copy. I used to tell them to use Abebooks.com, but
now there aren’t any copies even there. Since I own the copyright (thanks to
Macmillan), I can publish it again, for free.
For a while I tried to reproduce the original book from the original nroff source,
but Unix version 6 nroff is long dead, and the printer-driver hacks that made
bold and underlining work are even deader. So I hacked it into L
A
TEX, and here
it is. I fixed the errors that I knew about, changed a very few infelicities, and
otherwise tried to change as little as possible.
Why isn’t it in C?
When I began to write this book I was heavily into BCPL. By the time it was
finished I was a C programmer. The display editor ded that I developed to write
the book was written in C. C is in many respects a direct descendant of BCPL.
I was pressed, even before the book came out, to rewrite all the examples in C.
I didn’t do that for various reasons, some good and some bad. It would be an
enormous effort to do it now, because C is now so far from its origins.
Old-fashioned opinions
I agree with quite a lot of this book, but by no means all of it. I’ve decided to
change nothing. For better or worse, here it is.
i
9. Preface
In the past compiler writers and designers seemed to form an elite group within
computing science, set apart by their esoteric knowledge and their ability to
produce large, important system programs which really worked. The admiration
of the computing public, whether it was once deserved or not, is no longer
merited now that the principles of programming-language implementation are
so well understood. Compiler-writing is no longer a mystery.
This book attempts to explain and demystify the principles of compiler writing
so that you can go out and build a working compiler of your own. There is
enough detail in this book for you to build a compiler for quite a complicated
language – certainly PASCAL, perhaps ALGOL 68 or SIMULA 67 – but it
doesn’t attempt an encyclopaedic coverage of the field. It is intended more as an
introduction to compiler-writing and a do-it-yourself kit for the compiler-writer,
giving enough detail for you to understand the principles of the subject, than as
a survey of past history or present horizons. The principles of interpretation are
close enough to those of compilation for chapter 19 to give a simple introduction
to interpreter writing.
The method of treatment and the relative amount of attention given to various
topics in this book reflects my own views about the relative importance of those
topics. There is a separate section on run-time support, less attention is paid
than is perhaps usual to the topic of parsing or syntax analysis and the discussion
of translation is totally oriented to tree-walking. I have presented the subject
in this way for both practical and educational reasons. First, the object code
instruction sequences which implement run-time support are more important
in practice than is usually recognised. It is differences in run-time mechanisms,
as much as or more than anything else, which distinguish one language from
another – say SIMULA 67 from ALGOL 68, POP-2 from ALGOL 60 – and
the efficiency of run-time support code fragments is crucial to the efficiency of
the object program. Second, I believe it is more important to give a practical
description of syntax analysis in a book which is intended for the practical
compiler-writer than to give a more formal and complete introduction to the
topic. The syntax analysis mechanisms chosen for illustration in section IV] are
selected for their practical relevance. Of the three mechanisms presented, the
‘one-track’ and ‘operator-precedence’ mechanisms are now rather old-fashioned
but are still quite adequate to the task of parsing popular modern languages.
iii
10. iv
Finally, my insistence on tree-walking as the best means of translation is both
because it makes explanation of translation algorithms much easier and enables
me to bring out the topic of ‘crucial code fragments’ which forms so much of the
life of the professional compiler writer; also in my experience it is a practical
way in which both novice and expert can quickly build a working translator
containing the minimum number of errors.
Throughout the book I have emphasised the fact that the task of compilation can
be divided into separate modular sub-tasks. It is largely the identification of and
emphasis on this essential modularity that has clarified the subject. Emphasis
on modular design also helps me to avoid discussing every known technique
for each of the tasks – if you know what the task is, one or two good ways to
accomplish it and how to recognise another good way if somebody shows you
one, then you are on the way to becoming a capable compiler writer.
Throughout the book I have emphasised the need for the compiler to provide
a service to its users. It seems to me that the demands of system or compiler
efficiency are too often given precedence over the justifiable demands of the
user who wants understandable error reports, accurate and reliable object code
or strict adherence to an industry standard. The same goes, I believe, for the
demands of small compiler size or simplicity of construction. A good compiler
can be acceptably efficient and reasonably small yet still provide a good user
service. Indeed I believe that the well-designed compiler will out-perform the
‘efficient’ special-purpose construction, but even if it isn’t so the compiler writer
should stand by the principle that machines are provided to save human time
and effort. A few seconds of machine time which saves minutes (or more often
hours) of human time is machine time well spent!
Host, Object and Source Language in Examples
In the examples throughout the book most algorithms are written in a version
of the language BCPL, details of which are briefly explained in appendix A.
Some example algorithms are in PASCAL: I would have used PASCAL more
extensively were it not for the fact that its lack of block structure, lack of
conditional expressions and lack of a simple ‘union-type’ convention forces an
obscure programming style. BCPL’s advantage is that it is untyped and that
therefore the examples can show the bare bones of an algorithm without too
much unnecessary hedging round of type declarations. At the same time this
is a drawback: BCPL’s lack of data structure declarations makes it difficult to
explain some fairly simple algorithms. Early examples give some explanation
of the data structures which are manipulated by the algorithms: it is worth
pointing out that in every case the values which are manipulated are pointers
to record-structures rather than the structures themselves.
Appendix B explains the assembly code which is used to illustrate the oper-
ation of the translation algorithms in sections II and III. It is the code of a
single-address, multi-register single-segment-addressing machine. Throughout
11. v
the book there is an emphasis on the machine-independence of compiler design
and the fact that details of the object machine’s instruction set don’t affect the
design of the compiler. Nevertheless it is useful, when discussing translation al-
gorithms, to illustrate the code of an example object machine in order to show
the advantages of good design of code fragments.
With the present explosion in the use of microprocessors interest in compil-
ing has re-emerged, particularly interest in compiling system-programming lan-
guages. The problems of compiler-writing for small machines are mainly to do
with producing compact object code: the examples presented in this book are
not directly oriented towards this purpose but may be readily adapted to it.
The desire to produce a very small compiler, as opposed to a small object pro-
gram, should be curbed until you properly understand the principles of compiler
design (when perhaps the desire will go away!)
The source language which is used to illustrate syntax analysis and translation
algorithms has a variable syntax and semantics, floating somewhere in the space
between BCPL, ALGOL 60, ALGOL 68 and PASCAL. Some attention is given
to the detailed difficulties which arise in writing a compiler for each of these
languages. I didn’t wish to limit the discussion to those features displayed by
any particular language, however, nor to get bogged down in the details of that
language. Most examples therefore relate to the general difficulties of compiling
any language which includes recursive procedures, block-structuring, dynamic
arrays, pointer variables, and so on.
Acknowledgements
I’m enormously indebted to all the people who have argued with me about
compilers and compiling over the years, lectured to me, listened to me, corrected
me and generally helped me develop the ideas I present in this book. Many of
the good ideas are those of my mentors. Thanks especially to Jeff Rohl for
helping me in my first steps and encouraging me to develop my ideas as far as
they have gone: thanks also to Bernard Sufrin for so many invaluable discussions
about the best way to build and to explain compilers. Thanks to my colleagues
at the University of Essex – Bruce Anderson, Mike Brady, Tony Brooker, Mike
Foster, Pete Gardner, Pat Hayes, John Laski, Bob Wielinga and all the students
who listened to earlier versions of this book in the form of lectures.
This book was type-set on a DEC PDP-11/40 and printed using a Diablo printer.
Thanks to the denizens of the Queen Mary College Computer Systems Labo-
ratory for allowing me to use the machine so heavily and especially to George
Coulouris, Jon Rowson, Ben Salama and Harold Thimbleby for leading me
through the intricacies of the local software.
23. 3
Compilers, at first appearance, seem to display a bewildering variety of organisa-
tion: there are single-pass compilers, multi-pass compilers, optimising compilers,
load-and-go compilers, interactive compilers and so on and on. Luckily for the
compiler-writer, all these apparently different forms can be seen as variations on
a simple theme. All compilers perform the same collection of tasks and apparent
variations come about because the tasks are put together in slightly different
ways or because certain of the tasks are given more emphasis than others in
some variations. Below the surface the theme is constant – all compilers per-
form the same sequence of essential tasks in the same order and by and large
the optional tasks which they may perform have a fixed position in the sequence
as well.
It’s this underlying regularity of organisation which makes it possible to describe
the principles of compiler writing in a space as small as this book, because the
question of the organisation of the compiler as a whole can be separated from
the questions of the design of its sub-sections. Each of the sub-tasks, and the
various algorithms for carrying it out, can then be studied in relative isolation.
In addition the regularity makes compiler writing largely source-language inde-
pendent: though to the novice it might seem that a COBOL compiler would
differ enormously from a PASCAL compiler I shall show that it isn’t so. Per-
haps even more surprising is that the problems of compiler writing are largely
object-machine independent as well. Both source language and object machine
affect only details of compiler construction, whilst the overall organisation re-
mains fixed. Once you have understood the principles of compiler design, most
of the details fall naturally into place.
Of the chapters in this section, chapter 1 discusses the organisation of compi-
lation as a sequence of phases, each carried out by a separate module of the
compiler, and gives brief examples of the operation of each phase. Chapter 2
gives a more detailed introduction to the principles of translation and justifies
the use of a tree-walking translation mechanism. Chapter 3 gives an introduc-
tion to the principles of syntax analysis. Chapter 4 discusses lexical analysis
and loading: apart from a discussion of lexical analysis grammars in chapter 15
and a discussion of symbol-table building algorithms in chapter 8, both of these
rather simple topics are then ignored for the rest of the book.
Later sections expand the treatment. Section II concentrates on translation
and code optimisation, section III on the code which performs run-time sup-
port functions such as stack handling during a procedure call, section IV deals
with syntax analysis and section V treats the allied topics of interpretation (as
distinct from compilation) of source programs and the run-time debugging of
compiled programs.
I discuss these topics in this order because I believe that it is useful to un-
derstand mechanisms of translation before mechanisms of syntax analysis, even
though syntax analysis occurs before translation when a program is compiled.
Translation, with code optimisation, is probably the most interesting phase of
compilation to the active compiler-writer. The novice needs some instruction in
the mechanisms of syntax analysis – but it comes much easier if you’ve seen the
24. 4
requirements of a translator first. In that way you can see why a syntax analyser
is necessary and why it must produce the kind of output that it does. Also,
having seen the powers and limitations of simple translation, you’re in a better
position to assess the importance (or unimportance) of code optimisation.
25. Chapter 1
Phases and Passes
The most obvious overall task of a compiler is to read a program in one language
– the ‘source’ program in the ‘source’ language – and to translate it to produce
an equivalent program in another language – the ‘object’ program in the ‘object’
language. The object language is usually the machine language of a computer,
or something close to it, and the source program is usually in a ‘high-level’
language such as FORTRAN, PASCAL, ALGOL 68, SIMULA 67 or BCPL,
because translation from high-level language to machine language is the practical
problem which compilers exist to solve. Compilers can be written to translate
from any kind of programming language into any other, however, with varying
degrees of efficiency of the resulting object program.
Another part of the compiler’s overall task, just as important but too often
neglected, is that the compiler must check that the source program makes some
kind of sense and, when it doesn’t seem to make sense, must produce a descrip-
tion of the problem (an error report) so that the programmer can correct the
program. I’ll return to discuss the tasks of error detection and reporting later
in this chapter.
Before describing how the overall tasks are split up into sub-tasks it’s worth
discussing the ways in which the sub-sections of a compiler can be combined to
make a complete compiler. The overall activity of compilation can be divided
into a sequence of phases, during each of which one of the sub-tasks is carried
out. As emphasised in the introduction to this section, all compilers perform
the same sub-tasks in the same sequence, and therefore all compilers consist
of the same sequence of phases. Conceptually each phase transforms the pro-
gram fragment-by-fragment, taking as input a fragment of some representation
of the source program and producing as output a fragment of some other, trans-
formed, representation. Because the transformation is fragment-by-fragment it
is possible to choose how the phases are linked. If each separate fragment goes
through all the phases before compilation of the next fragment starts we have
a single-pass compiler, because all of the source program is compiled in a single
pass over the source text. Conversely, if the entire program goes through each
5
26. 6 CHAPTER 1. PHASES AND PASSES
one of the phases before any of it is presented to the next phase we have a multi-
pass compiler, because each phase performs a separate pass over the program.
Clearly if there are N phases, you can organise the compiler into anything from
1 to N passes.
Thus every compiler must be multi-phase, but it may or may not be multi-pass.
Logically the phases must be joined together in the same order no matter how
many passes are employed, so that it might not seem to matter whether this book
concentrates on multi-pass or single-pass organisation. In practice, however, the
multi-pass organisation is simpler to describe and to understand because the
interface between the phases is so much more straightforward. Indeed for some
languages – ALGOL 60 is a prominent example – it is difficult to construct an
effective single-pass compiler at all and therefore the multi-pass organisation is
also more generally useful.
It is often believed that multi-pass compilation is inherently less efficient than
single-pass. This is simply untrue: since in any compiler each fragment must be
processed by the same sequence of phases, a single-pass compiler must perform
the same amount of work as a multi-pass compiler. Suppose, however, that each
pass of a multi-pass compiler were to write its output into a disc file (or any
backing store file) from which the next pass had to read it in again. Such a multi-
pass compiler would indeed be less efficient than a single-pass compiler which
didn’t use backing store but the inefficiency would be caused by the overhead
of input and output between passes.
A multi-pass compiler which stores the output of each pass in the main computer
memory will certainly be no slower than a single-pass compiler. On a modern
computer the only disadvantage of multi-pass compilation is that it may use
quite a lot of space to store the output of the various passes. Nowadays com-
puter memories (for everything but the smallest micro-processors!) are large
enough for this minor drawback to be overwhelmed by the enormous advan-
tages of clarity of design, and consequent ease of construction, of a multi-pass
compiler. For most of the rest of this book I describe a compiler organised in
two passes, which is an effective compromise between economy of space and
clarity of organisation. In the discussion of compilation algorithms, however,
it is usually simplest to imagine that each of the phases in a compiler always
performs a separate pass over the program.
1.1 Tasks and Sub-tasks
Figure 1.1 shows a coarse breakdown of the overall compilation task (I deal with
the parallel task of error processing separately below). A compiler must first
analyse a program to see what its intended effect is. The result of this analysis
will be a representation of the program which is adequate for later translation
into the object language. As I show below and in chapter 2, this representation
is a structure which shows how the separate fragments of program inter-relate.
It splits naturally into two parts:
27. 1.1. TASKS AND SUB-TASKS 7
source
program
analysed
program
object
program
ANALYSE TRANSLATE
Figure 1.1: Coarse structure of compilation
(i) the ‘parse tree’ which shows the structure of the program text – how the
fragments of program join together to make up larger fragments, how those
join to make still larger fragments and so on.
(ii) the ‘symbol table’ which provides a correlation between all the different
occurrences of each name throughout the program and hence provides a
link between each name and its declaration, whether implicit or explicit,
in the source text.
These two information structures are the most important milestones in the
compilation process. Compilation as a whole is an activity which first builds up
information structures which describe how the program may be broken into frag-
ments and how these fragments inter-relate, then extracts from these structures
the information which is required in order to translate the program.
Neither analysis nor translation is yet a simple enough sub-task to describe
individually. Figure 1.2 shows a more detailed breakdown into sub-tasks. The
figure shows clearly the hierarchical-sequential nature of the compiling process:
each of the sub-tasks is entrusted to a particular phase and the phases don’t
overlap at all.1
Capital letters (e.g. LEXICAL ANALYSIS) indicate a phase
or sub-task, lower case letters (e.g. parse tree) an information structure or an
intermediate program representation.
The arrangement of phases in figure 1.2 is partly determined by the nature of
the compiling task but is also partly conventional. In particular the LEXICAL
ANALYSIS phase is present for convenience’ sake and the fact that the com-
piler’s output is most commonly presented to a LOAD phase before execution
is equally a matter of convenience.
Consider the LEXICAL ANALYSIS phase: it has been found convenient to in-
clude a phase, immediately before SYNTAX ANALYSIS, which partitions the
characters of the source program into ‘items’, roughly analogous to words and
punctuation marks in natural languages. This not only makes the design of
the syntax analyser easier, but also it happens that almost all of those sections
of the compiler whose speed of operation is important fall into the READ and
LEXICAL ANALYSIS phases. Thus the task of improving the compiler’s op-
erating efficiency can be reduced to the task of improving the efficiency of the
relatively simple input phases and in the rest of the compiler it is possible to
1 There are some minor exceptions to this rule when compiling rather old languages such as
FORTRAN. These exceptions have been eliminated in most modern languages.
28. 8 CHAPTER 1. PHASES AND PASSES
source program
characters
lexical items
parse tree
object code
object program
s
y
m
b
o
l
t
a
b
l
e
READ
LEXICAL
ANALYSIS
SYNTAX
ANALYSIS
SIMPLE
TRANSLATION
LOAD
OBJECT
DESCRIPTION
OPTIMISE
TREE
(optional)
OPTIMISE
CODE
(optional)
Figure 1.2: Finer structure of compilation
29. 1.2. TRANSLATION AND OPTIMISATION 9
ignore the demands of speed of operation in order to concentrate on clarity of
design and construction.
Consider next the LOAD phase shown in figure 1.2. If the source program is
split into sections which are compiled separately to produce separate sections of
object code, it is necessary eventually to use a loader program to combine all the
separate code sections into a complete executable program. At the same time
the loader can automatically incorporate sections of code from a separate code
library. People find the facility to split their program into sections convenient,
so the loader increases human efficiency although in terms of machine utilisation
alone it can be more efficient to compile the entire program in one piece and
to avoid the loading overhead entirely. At any rate the compiler may, but need
not, output code in ‘loadable’ form as the compiler-writer wishes.
I discuss the input and output phases (READ, LEXICAL ANALYSIS and
LOAD in figure 1.2) together with the question of code output formats in chap-
ter 4, so as to separate these matters from the more central and more important
phases of analysis, translation and optimisation which occupy most of this book.
1.2 Translation and Optimisation
Two of the phases in figure 1.2 are marked as optional – OPTIMISE TREE
and OPTIMISE CODE. They are included in the figure because they are so
important and so frequently included (or desired by the user if they are not
included!). In order to explain the breakdown of the diagram at this point
it’s necessary to distinguish between ‘simple translation’ and ‘optimisation’ in
general
Simple translation takes a representation of a fragment of the source program
and produces an equivalent fragment of object code. It doesn’t take much
account of the interaction between fragments, except insofar as it must do
in order to produce correct code, but it may be quite sophisticated in the
way in which it selects the particular code fragment which it generates as
the translation of each source program construct.
Optimisation takes a wider view of the program: it looks at a representation
of a larger section of the source program and reorganises the fragments
within it, or improves the way in which they interface, so as to produce a
shorter object program or a faster object program than simple translation
could produce. Sometimes it is possible to produce an optimised object
program which is both shorter and faster than one produced by simple
translation.
It’s not possible to draw a hard line between the two approaches because it’s
not clear when sophisticated simple translation becomes primitive optimisa-
tion. Some so-called ‘optimising’ compilers would be better viewed as rather
good simple translators: many straightforward compilers include some element
30. 10 CHAPTER 1. PHASES AND PASSES
of optimisation. True optimisations, for the purposes of this book, are those
translations which exploit peculiarities of the control flow specified in the source
program. Chapter 10 discusses this topic more fully.
There are essentially two ways in which a compiler can optimise a program –
i.e. produce a better-than-simple translation
(i) It can include a phase which alters the source program algorithm in such
a way that subsequent simple translation can produce the desired effect.
This is shown as OPTIMISE TREE in figure 1.2: essentially it replaces
the source program’s algorithm with another which has the same effect
but which can be translated into more efficient code.
(ii) It can include a phase which modifies the code produced by simple trans-
lation in order to increase the efficiency of the object program. This is
shown as OPTIMISE CODE in figure 1.2: this phase looks mainly at the
ways in which the code fragments interface with each other.
These two approaches can be equivalent in their effect and sometimes com-
pilers employ both. The OPTIMISE TREE technique is the more machine-
independent of the two and is perhaps potentially the more powerful.
1.3 Object Descriptions in the Symbol Table
The names used in a program are merely used to identify run-time objects of one
kind or another – variables, arrays, records, procedures, labels and so on. Apart
from the needs of debugging, the source program names used are completely
arbitrary and the object program operates entirely upon the run-time objects
without taking any account of the names which originally introduced them. In
order to keep track of the association between names and run-time objects, the
compiler must keep a table (the symbol table in figure 1.2) in which it stores
against each name a description of the run-time object which that name denotes.
The translator uses this table to replace each occurrence of a name by a reference
to the corresponding run-time object.
As names are encountered in the source program they are inserted into the
symbol table by the lexical analyser (more discussion of this in chapters 4 and
8) but information about the associated run-time object can only be inserted
after the program has been syntactically analysed. Names are ‘declared’ ei-
ther implicitly (e.g. in FORTRAN) or explicitly (most other languages!). In
general the declarative information must be processed before any statement
using the name can be translated. Thus correlation of names with run-time
objects must precede translation, but must of course follow syntax analysis in
which the declarative information is recognised. So there is only one time in the
compilation process at which such correlation is possible – hence the OBJECT
DESCRIPTION phase in figure 1.2 falls between syntax analysis and simple
translation or optimisation.
31. 1.4. RUN-TIME SUPPORT 11
program: begin integer a,b;
....
procedure A(x) real x;
begin real y;
.... B(‘a’); ....
end;
procedure B(u) character u;
begin string v;
.... A(3.7); ....
end;
.... A(1.0); ....
end
After outer block calls A, which calls B, which calls A again:
a b
outer
block
x y
A(i)
u v
B
x y
A(ii)
Figure 1.3: Activation Record Structure in a simple program
1.4 Run-time Support
Much of the object program consists of instructions which carry out the tasks
of calculation, assignment, comparison, etc. which are specified in the source
program. However there are also sections of the source program whose task is
run-time support of various kinds. Two important tasks of run-time support are
to implement the storage and register manipulations necessary for the execution
of a procedure call2
(discussed in detail throughout section III) and the mainte-
nance of ‘heap’ storage systems (touched on in chapter 14). The efficiency of the
run-time support fragments in the object program ought to be a major concern
of the compiler writer: users will present programs for compilation which are
based on highly efficient algorithms and will be justifiably annoyed if the object
program is inefficient purely because of the operation of run-time support code
fragments ‘behind the scenes’.
The most important task of the run-time support fragments is to maintain the
Activation Record Structure. When a procedure call is executed a procedure
2 Throughout this book I use the word ‘procedure’ to include the word ‘function’ – a function
is merely a procedure which computes and returns a result. So far as run-time support is
concerned, functions and procedures are almost identical.
32. 12 CHAPTER 1. PHASES AND PASSES
activation is created, which exists until the corresponding procedure return is
executed. In non-recursive languages such as FORTRAN only one activation at
most can ever exist for each procedure but in languages which permit recursion
there may be several activations in existence, each in a different stage of exe-
cution of a single procedure body and each with its private storage and private
copy of the arguments with which it was called. Each of these activations can
be described by a data structure – in a recursive programming language the
data structure is an ‘activation record’, ‘data frame’ or ‘stack frame’ stored on
a stack – and the linkages between these data structures define the Activation
Record Structure. Figure 1.3 shows a simple example of the structure which
can result.
The maintenance of the Activation Record Structure in an implementation of a
recursive programming language is an important ‘overhead’ cost in the execution
of the object program. By prohibiting recursion, languages such as FORTRAN
reduce the overhead cost but the discussion in section III shows how careful
design of code fragments can minimise or even eliminate the efficiency gap be-
tween recursive and non-recursive languages. Even recursive languages must
restrict the manipulation of some values in the object program in order to allow
the Activation Record Structure to be kept in a stack: chapter 14 discusses the
way in which the necessary restrictions can be applied in an implementation of
ALGOL 68 and touches on the implementation of SIMULA 67, which can avoid
the imposition of such restrictions because it doesn’t use a data-frame stack.
1.5 Source Program Errors
“Any fool can write a compiler for correct source programs”
(J.S. Rohl 1972)
People write programs and people make mistakes. They often need help in order
to correct their mistakes and sometimes a compiler can provide it. Compiler
designers too often seem to place ‘helping people’ rather low down on their
scale of priorities, well below ‘compiler efficiency’, ‘object program efficiency’
and ‘source language facilities’. My opinion is that this order of priorities is
wrong-headed but I hope to demonstrate in this book that it is unnecessary
as well. There is no conflict in practice between, on the one hand, the goal of
providing help with errors in source programs and, on the other hand, the goal
of providing a compiler which is efficient and which produces efficient object
programs.
A compiler has two basic tasks to perform in connection with source programs
which contain errors:
(i) Compile-time error processing:
The compiler must somehow provide information to a programmer who
has submitted a program which cannot be compiled. The information
must, as far as possible, give an explanation of why the program cannot
33. 1.5. SOURCE PROGRAM ERRORS 13
be compiled and if possible make suggestions as to how the error might
be corrected.
(ii) Error-checking code:
Many programs, though syntactically correct, specify impossible sequences
of operations when they are executed. Some object program errors (e.g.
arithmetic overflow) may be detected by the object machine’s hardware
but probably many others will not be. In order to detect run-time errors
which are not covered by hardware checks the compiler must produce ob-
ject code fragments which check whether a run-time error has occurred
each time they are run. An example is the array-bound check: it is com-
mon for a compiler to generate code for an array access which checks the
validity of the array subscript each time an access is made.
In either case error processing can be divided into three separate activities: error
detection, error reporting and error recovery.
First consider compile-time errors: chapter 3 and section IV show that compile-
time error detection is an automatic consequence of the normal compilation
process. This implies that detection of errors cannot affect the speed of op-
eration of a compiler; therefore the (imaginary super-human) user who always
writes correct programs is not affected by the vagaries of ordinary mortals, at
least so far as speed of compilation is concerned. Once an error has been de-
tected in the source program the programmer is no longer concerned simply with
how rapidly the compiler translates but rather with how quickly the error can
be removed from the program. A small amount of computer time spent in error
reporting and recovery is well spent if it saves human time and effort. Of course
a compiler which includes a great deal of error reporting and recovery facilities
will be larger than one that contains only a small amount and so there is some
penalty in terms of space occupied, but the extra space and the few fractions of
a second of computer time spent in producing a readable error report are surely
worthwhile if they save minutes (or perhaps hours!) of human effort.
Similar considerations apply to run-time error-handling. In this case error-
detection can be expensive – the code fragments which repeatedly check for
error will inevitably slow down the execution of the object program – but the
bulk of the error processing code will be concerned with error reporting and error
recovery and so will only be activated when an error has already been detected.
It’s outside the scope of this book to debate when, if ever, the programmer
should ask the compiler to omit error checking code so as to save execution
time and object program space – at any rate the compiler should always give
the option that it can be included.
Chapter 20 discusses run-time error handling in detail. I include run-time error
checking as a task of the compiler, rather than of the operating system or
of some other separate program, because the design of object code fragments
must take into account the needs of run-time error-checking and error-reporting.
Furthermore the compiler designer must consider the production, at compile-
time, of information structures which will be used by a run-time debugger to
34. 14 CHAPTER 1. PHASES AND PASSES
begin integer a; real b;
a := 1; b := 1.2;
a := b+1;
print(a*2)
end
Figure 1.4: Example program
provide error reports related to the original source program. The requirements
of run-time error processing can have a major influence on the detail design of
object code fragments.
Figure 1.2 doesn’t include any mention of error processing but in reality it is a
part of the task of every phase of compilation. I shall return again and again
in later chapters to the question of how the various phases may be designed to
produce readable and understandable error reports.
1.6 Two-pass Compilation
Most compilers that aren’t single-pass use only two passes rather than the four
or five implied by the structure of figure 1.2. Using two passes is a popular com-
promise between generality and the somewhat demanding space requirements of
a true multi-pass compiler. The two-pass organisation essentially follows figure
1.1 – there is an analysis pass and a translation pass. The analysis pass includes
the READ, LEXICAL ANALYSIS and SYNTAX ANALYSIS phases. In order
to combine these phases into a single pass it is conventional to make READ a
subroutine of LEXICAL ANALYSIS and LEXICAL ANALYSIS a subroutine
of SYNTAX ANALYSIS – as chapter 4 shows, this isn’t very difficult. The
translation pass usually consists of a SIMPLE TRANSLATION phase only.
The two-pass organisation seems to leave out the OBJECT DESCRIPTION
phase entirely and in a two pass compiler this phase is rather difficult to include
as a separate entity. Object description is usually carried out piecemeal during
one or other (or both) of the passes. Perhaps most convenient is to perform
all object description during the translation pass: every time the translator
encounters a section of the tree that may contain declarative information it
must be processed by the object description phase, which creates symbol table
descriptors based on any declarations contained in that section of the tree,
before it can be translated into object code. The examples in sections II and
III show algorithms in which the object description phase is a subroutine of
the translation phase, called each time the translator encounters a ‘procedure
declaration’ node or a ‘block’ node in the parse tree.
35. 1.6. TWO-PASS COMPILATION 15
beginsymbol
integersymbol
name,
semicolonsymbol
realsymbol
name,
semicolonsymbol
name,
assignsymbol
number, 1
semicolonsymbol
name,
assignsymbol
....
a
b
(empty)
(empty)
Name Description
Figure 1.5: Part of the output from the lexical analyser
block
declarations statements
intdecl realdecl assign assign assign ProcCall
a b a 1 b 1.2 a +
b 1
print *
a 2
Figure 1.6: Output from the syntax analyser
36. 16 CHAPTER 1. PHASES AND PASSES
assign
name plus
name 1
number
(pointer to entry
for ‘a’ in
symbol table)
(pointer to entry
for ‘b’ in
symbol table)
Figure 1.7: Data structure representation of a tree
a variable, integer, address #1
b variable, real, address #2
print
procedure, one integer argument,
address from loader
Figure 1.8: Symbol table descriptors
LOAD 1, address #2
fADDn 1, 1.0
FIX 1,
STORE 1, address #1
Figure 1.9: Possible machine (assembly) code output
37. 1.7. AN EXAMPLE OF COMPILATION 17
1.7 An Example of Compilation
In the rest of this chapter I show, very briefly, the action of some of the phases
of compilation taking as example input the program of figure 1.4. First of all
the characters of the program are read in, then these characters are lexically
analysed into separate items. Some of the items will represent source program
identifiers and will include a pointer to the symbol table.3
Figure 1.5 shows
part of the results of lexical analysis: in most languages subdivision of the input
into items can be performed without regard to the context in which the name
occurs.
Next, the syntax analyser examines the sequence of items produced by the lexical
analyser and discovers how the items relate together to form ‘phrase’ fragments,
how the phrases inter-relate to form larger phrases and so on. The most general
description of these relationships of the fragments is a tree, as shown in figure
1.6.
Each node of the tree includes a tag or type field which identifies the kind of
source program fragment described by that node, together with a number of
pointers to nodes which describe the subphrases which make it up. Figure 1.7
shows how part of the tree shown in figure 1.6 might actually be represented as
a data structure. There are of course a number of different ways of representing
the same tree, and that shown in figure 1.7 is merely an example. There are as
many different ways of drawing the structure, and throughout most of this book
I shall show trees in the manner of figure 1.6. The only significant differences
between the two picturings is that, in the first, nodes aren’t shown as sequences
of boxes and names aren’t shown as pointers to the symbol table. Figure 1.7
is perhaps more faithful to reality, so it should be borne in mind whenever you
encounter a simplified representation like that in figure 1.6.
After syntax analysis, the object description phase takes the tree and the symbol
table entries produced by the lexical analyser. It analyses the declarative nodes
in the tree, producing descriptive information in the symbol table as shown in
figure 1.8. Standard procedures, such as ‘print’, may receive a default declara-
tion before translation: figure 1.8 shows a possible entry in the symbol table.
Note that, since the tree contains a pointer to the symbol table in each node
which contains a reference to an identifier, neither object description phase nor
translator need search the symbol table but need merely to follow the pointer
to the relevant entry.
After the object description phase has filled in the descriptors in the symbol
table, a simple translation phase can take the tree of figure 1.7 together with
the symbol table of figure 1.8 and produce an instruction sequence like that
shown in figure 1.9.4
3 The item which represents a number may also contain a pointer to a table which contains
a representation of the number. For simplicity figures 1.5 and 1.6 show the value of the
number as part of the lexical item itself.
4 See appendix B for a brief description of the assembly code instructions used in this and
38. 18 CHAPTER 1. PHASES AND PASSES
The addresses used in the instructions need finally to be relocated by the loader.
Suppose that, when the program is loaded into store, its memory cell space
starts at address 23. Then the first line of figure 1.9 would be converted into
‘LOAD 1, 24’ and the last line into ‘STORE 1, 23’.
Optimisation of the object code in this case could produce an enormous im-
provement in its execution efficiency. The total effect of the program is to print
the number ‘4’. By looking at the way in which the values of variables are used
throughout the program and by deferring translation of assignment statements
until their result is required – in this case they are never required – an optimi-
sation phase could reduce the program just to the single statement ‘print(4)’.
Optimisation is a mighty sledgehammer designed for bigger nuts than this ex-
ample, of course, and it is always an issue whether the expense of optimisation
is worth it: in the case of figure 1.4 it would certainly cost more to optimise the
program than it would to run it!
Summary
The underlying organisation of compilers is simple and modular. This chapter
discusses how the various phases cooperate so that later chapters can concen-
trate on the separate phases in isolation.
Input and lexical analysis is discussed in chapters 4 and 8; syntax analysis in
chapters 3, 16, 17 and 18; object description in chapter 8; translation in chapters
5, 6, 7 and 9; optimisation in chapter 10; loading in chapter 4; run-time support
in chapters 11, 12, 13 and 14; run-time debugging in chapter 20.
other examples.
39. Chapter 2
Introduction to Translation
The most important task that a compiler performs is to translate a program
from one language into another – from source language to object language.
Simple translation is a mechanism which takes a representation of a fragment of
the source program and produces an equivalent fragment in the object language
– a code fragment which, when executed by the object machine, will perform
the operations specified by the original source fragment.
Since the object program produced by a simple translator consists of a sequence
of relatively independent object code fragments, it will be less efficient than
one produced by a mechanism which pays some attention to the context in
which each fragment must operate. Optimisation is a mechanism which exists
to cover up the mistakes of simple translation: it translates larger sections of
program than the simple translator does, in an attempt to reduce the object
code inefficiencies caused by poor interfacing of code fragments.
In order to be able to produce object code phrases the translator must have
access to a symbol table which provides a mapping from source program names
to the run-time objects which they denote. This table is built by the lexical
analyser (see chapters 4 and 8) which correlates the various occurrences of each
name throughout the program. The mapping to run-time objects is provided
by the object description phase (see chapter 8) which processes declarative in-
formation from the source program to associate each identifier in the symbol
table with a description of a run-time object.
This chapter introduces the notion of a ‘tree-walking’ translator, which I believe
is a mechanism that is not only easy to construct but which can readily and
reliably produce efficient object code fragments. Such a translator consists of a
number of mutually recursive procedures, each of which is capable of translating
one kind of source program fragment and each of which can generate a variety
of different kinds of object code fragments depending on the detailed structure
of the source fragment which is presented to it.
Because the process of translation depends on the selection at each point of one
19
40. 20 CHAPTER 2. INTRODUCTION TO TRANSLATION
Statement:
if hour*60+minute=1050 or tired then leave(workplace)
conditional statement
[EXPRESSION]
Boolean or
[STATEMENT]
procedure call
[LEFT]
relation =
[RIGHT]
name
tired
[LEFT]
arithmetic +
[RIGHT]
number
[PROCEDURE]
name
[ARGUMENTS]
name
leave workplace
1050
[LEFT]
arithmetic *
[RIGHT]
name
minute
[LEFT]
name
hour
[RIGHT]
number
60
Figure 2.1: Tree describing a simple statement
of a number of possible code fragments translators tend to be voluminous, but
since the selection of a fragment is fairly simple and generating the instructions
is very straightforward, they tend to run very rapidly. A simple translator will
usually use less than 15% of the machine time used by all phases of the compiler
together, but will make up more than 50% of the compiler’s own source code.
2.1 Phrases and Trees
In this chapter I introduce the technical term phrase, which is used to describe
a logically complete fragment of source program. Statements, for example, are
phrases; so are expressions. Phrases are either ‘atomic’ – e.g. a name, a number
– or are made up of sub-phrases – e.g. a statement may have a sub-phrase which
is an expression, the statement itself may be a sub-phrase of a block which is
a sub-phrase of a procedure declaration, and so on. In this chapter the largest
phrase shown in the examples is an expression or a simple structured statement.
In a multi-pass compiler the unit of translation is the entire program – at least
41. 2.1. PHRASES AND TREES 21
cond
or
=
+
*
call
numb 1050
numb 60
tired
(in symbol table)
leave
(in symbol table)
workplace
(in symbol table)
minute
(in symbol table)
hour
(in symbol table)
Figure 2.2: Data-structure representation of the tree
42. 22 CHAPTER 2. INTRODUCTION TO TRANSLATION
at the topmost level – but a single page isn’t large enough to show the necessary
trees!
The state of the art in programming language translation is now, and will remain
for some time, that a program can only be translated if it is first analysed to
find how the phrases inter-relate: then the translator can consider each phrase
in turn. The result of the analysis shows how the program (the phrase being
translated) can be divided into sub-phrases and shows how these sub-phrases
inter-relate to make up the entire phrase. For each sub-phrase the description
shows how it is divided into sub-sub-phrases and how they are inter-related.
The description continues to show the subdivision of phrases in this way until
the atomic phrases – the items of the source text – are reached.
The most general representation of the results of such an analysis is a tree
like that in figure 2.1. The lines are branches, the place where branches start
and finish are nodes. The topmost node of the tree is its root – the tree is
conventionally drawn ‘upside down’. Nodes which don’t divide into branches
are leaves and represent the atomic items of the source program. Each phrase of
the source program is represented by a separate node of the tree. To translate a
phrase it is merely necessary to concentrate on one node and, if it has sub-nodes,
to translate its sub-nodes as well.
Figure 2.2 shows a possible data-structure representation of the tree of figure
2.1 using record-vectors and pointers. Many other representations are possible
– for example one in which each pointer is represented by a subscript of a
large integer vector. The tree structure, no matter how it is represented, gives
the translator the information it needs in order to translate the statement – it
shows which phrases are related, and how they are related. From the source
statement it isn’t immediately obvious what the object program should do.
Should it, for example, evaluate ‘hour*60’? Must it evaluate ‘minute=1050’?
What about ‘1050 or tired’? A glance at the tree gives the answers – only the
first is represented by a node because analysis has shown it to be a phrase of
the program.
In order to be able to translate a phrase of a program it is essential to know what
kind of phrase it is, what its sub-phrases are and how they are inter-related.
There can be non-tree-like representations of the necessary information, but the
tree holds and displays the information in its most accessible and useful form. In
addition it emphasises the essentially recursive nature of translation – a nature
which is somewhat hidden, but not denied, in so-called ‘linear’ representations.
2.2 Tree Walking
It’s extremely easy to translate – generate code for – a phrase if you know how
to generate code for its sub-phrases. Figures 2.3 and 2.4 show some sample
procedures which translate in this way. Each procedure translates a phrase by
generating a single instruction, or a short sequence of instructions, which links
together the code fragments that are the translation of its sub-phrases. Only
43. 2.2. TREE WALKING 23
• Conditional statement (if-then):
1. call procedure which generates code to load value of expression part
into register 1;
2. invent a label #Lf;
3. generate JUMPFALSE 1, #Lf;
4. call procedure which generates code to carry out statement part;
5. generate #Lf:.
• Boolean or (result to be in register k):
1. : call procedure which generates code to load value of left operand
into register k;
2. call procedure which generates code to load value of right operand
into register k+1;
3. generate ORr k, k+1.
• Relation ‘=’ (result to be in register k):
1. call procedure which generates code to load value of left operand into
register k+1;
2. call procedure which generates code to load value of right operand
into register k+2;
3. generate LOADn k, TRUE
SKIPEQr k+1, k+2
LOADn k, FALSE.
• arithmetic ‘+’ (result to be in register k):
Exactly as for Boolean or, except that the final instruction is
ADDr k, k+1.
• arithmetic ‘*’ (result to be in register k):
Exactly as for Boolean or, except that the final instruction is
MULTr k, k+1.
Figure 2.3: Translation procedures for non-leaf nodes
44. 24 CHAPTER 2. INTRODUCTION TO TRANSLATION
• name (value to be loaded into register k)
generate LOAD k, <run-time address of variable denoted by name>
• number (value to be loaded into register k)
if value is small enough then
generate LOADn k, <value of number>
else generate LOAD k, <run-time address where value will be found>
Figure 2.4: Translation procedures for leaf nodes
ADDr 2, 3
LOADn 3, 1050
LOADn 1, TRUE
SKIPEQr 2, 3
LOADn 1, FALSE
LOAD 2, tired
JUMPFALSE 1, #Lf
....
<procedure call>
#Lf:
<rest of program>
LOAD 2, hour
LOADn 3, 60
MULTr 2, 3
LOAD 3, minute
ORr 1, 2
....
....
[name]
[name]
[name]
[number]
[number]
[*]
[+]
[=]
[or]
[if]
Figure 2.5: Code produced by the translation procedures
45. 2.3. LINEAR TREE REPRESENTATIONS 25
hour, 60, *, minute, +, 1050, =, tired, or
Figure 2.6: Linearised expression
for indivisible phrases (leaf nodes) is it necessary to know how to translate the
entire phrase. In order to generate code for a sub-phrase, all the translator
needs to do is to look at the type of phrase it is – the ‘tag’ or ‘type’ field of the
tree node – and to call the relevant translation procedure.
Figure 2.5 shows the code produced by these procedures when presented with
the tree of figure 2.1. (The figures don’t show the translation procedure which
handles the procedure call node, or the code produced – section III deals with
this topic.) Starting at the root of the tree, the translator works downwards. It’s
essentially a recursive process – one operand of a ‘+’ node may be another ‘+’
node or may contain a ‘+’ node, for example. Since the process is recursive it’s
trivially easy to translate structured statements like the conditional statement
which might at first seem the hardest to translate. Imagine how straightforward
it is to translate a PASCAL compound statement or an ALGOL 68 serial clause!
The most important thing to note about figure 2.5 is that the code would work
if it was given to the object machine to execute. Tree walking is a powerful
technique precisely because it is easy to design procedures like those in figures 2.3
and 2.4 which really will generate accurate code. The object code produced by
these procedures isn’t optimal by any means, but it’s relatively trivial to change
the procedures to improve it. Each procedure is a separate module: although
figure 2.3 doesn’t include all of the standard programming language expression
operators, it wouldn’t be necessary to make any changes to the existing set when
new node-translating procedures are added.
2.3 Linear Tree Representations
Before describing how to improve the code produced by the translation proce-
dures of figure 2.3 and 2.4 it is necessary to dispose of a red herring – ‘Reverse
Polish’ or ‘postfix string’ representation. The collection of procedures in figures
2.3 and 2.4 describe a tree walk – a process which visits the nodes of the tree in
a particular, predetermined order. If the nodes of the expression part of the tree
of figure 2.1 are written out in just the order in which the tree walker would visit
them then a translator can walk them with a non-recursive algorithm. Figure
2.6 shows the nodes of the tree from figure 2.1, written out in the order in which
they are visited by the tree walker.
Considering only the string which represents the expression part of the tree in
figure 2.1, it is possible to define a simple iterative procedure which generates
code for it: figure 2.7 shows a possible algorithm. There is a slight difficulty with
the ‘=’ node, which is in effect ‘visited’ twice in the tree walk, once to reserve
the register which will hold TRUE or FALSE and once to actually generate the
46. 26 CHAPTER 2. INTRODUCTION TO TRANSLATION
k := 1 /* k records next free register */
until end-of-string do
switchon current-element into
case name:
Gen(LOAD, k, <address of variable>)
k := k+1 endcase
case number:
if number is small enough then
Gen(LOADn, k, <value of number>)
else
Gen(LOAD, k, <address where value will be found>)
k := k+1 endcase
case ‘+’:
Gen(ADDr, k-2, k-1); k := k-1 endcase
case ‘*’:
Gen(MULTr, k-2, k-1); k := k-1 endcase
case ‘=’:
Gen(LOADn, k, TRUE)
Gen(SKIPEQr, k-1, k-2)
Gen(LOADn, k, FALSE)
Gen(LOADr, k-2, k)
k := k-1 endcase
case ‘or’:
Gen(ORr, k-2, k-1); k := k-1 endcase
default: CompilerFail("invalid element in string")
current-element := next-element
Figure 2.7: Linear string walker
47. 2.4. IMPROVING THE TREE WALKER 27
LOAD 1, hour
LOADn 2, 60
MULTr 1, 2
LOAD 2, minute
ADDr 1, 2
LOADn 2, 1050
LOADn 3, TRUE
SKIPEQr 1, 2
LOADn 1, FALSE
LOADr 1, 3 /* extra instruction */
LOAD 2, tired
ORr 1, 2
Figure 2.8: Code produced by the linear string walker
instructions which carry out the comparison. In the case of a simple Reverse
Polish string the operator appears only once, so that the code for the ‘=’ node
must move the computed value into its intended register – the ‘extra instruction’
shown in figure 2.8.
The string walking algorithm uses a stack of registers, so its status as ‘non-
recursive’ is in doubt anyway. Note that it is impossible to vary the way in which
the tree is walked, according to some code generation strategy, after the string
has been generated. Use of a postfix string representation of the source pro-
gram merely freezes the compiler into a particular kind of tree walk. Although
the string-walking algorithm could be improved quite easily in some ways (e.g.
avoiding ‘LOAD, ADDr’ instructions in sequence) most of the improvements which
are introduced below and discussed in detail in later chapters involve changing
the way the tree is walked and so are impossible (or at best extremely difficult)
using any linear representation.
2.4 Improving the Tree Walker
Once you have a working translator, you are in business as a compiler-writer.
Using tree walking will get you to this point faster. It will also help you to get
farther and faster along the road to better code than any ad hoc solution could.
Improving the efficiency of the code produced by a tree-walking translator means
looking at the code fragments generated by one or more of the procedures and
deciding that the procedure’s strategy was weak, or that it should look out for
that particular source construct and generate a specially selected code fragment
for it. The various possibilities are summarised in figure 2.9. It’s hard to decide
where tactics shade into strategy: figure 2.10 shows an improved arithmetic ‘+’
procedure. This procedure saves an instruction and a register when the right
operand is a leaf: I would classify this as a tactical manoeuvre. Using this
48. 28 CHAPTER 2. INTRODUCTION TO TRANSLATION
1. Generate special code for a node with a special local property (tactics).
2. Alter the way the tree is walked when a node has a particular general
property (strategy).
3. Modify the tree before it is walked (optimise the tree).
4. Modify the code which was generated, after the tree walk has finished
(optimise the code).
Figure 2.9: Tactics and strategy
• arithmetic ‘+’ (result to be in register k)
1. generate code to calculate value of left operand in register k
2. if right operand is a name then
generate ADD k, <address of variable>
else if right operand is a number then
generate ADDn k, <value of number>
or ADD k, <place where value will be found>
else
(a) generate code to calculate value of right operand in register k+1;
(b) generate ADDr k, k+1.
Figure 2.10: Improved translation of binary operation nodes
49. 2.4. IMPROVING THE TREE WALKER 29
LOAD 2, hour
MULTn 2, 60
ADD 2, minute
LOADn 1, TRUE
SKIPEQn 2, 1050
LOADn 1, FALSE
OR 1, tired
Figure 2.11: Code produced by improved translator
procedure the first three instructions of figure 2.5 would be compressed into
two and, if a similar improvement were made to the procedures which translate
‘=’ and or nodes, the translator would produce the code shown in figure 2.11
for the example expression. This code is a considerable improvement over that
of figure 2.5 – it uses two rather than three registers, seven rather than eleven
instructions – and it was reached by making simple and modular changes to
the procedures of the translator. Chapter 5 shows that much more can be done
about the code generated for arithmetic operator nodes, and chapter 6 shows
that quite a different approach is possible for Boolean operation nodes.
Improvements like that in figure 2.10 can also be made to the iterative string-
walking procedure. Strategic alterations are far more difficult, however, since a
linear representation doesn’t allow the translator to take account of the structure
of an expression.
Some further tactical possibilities are shown in figure 2.12. These are ‘sub-
optimisations’ because the code which is generated for a particular source frag-
ment doesn’t depend on the control context within which the object code frag-
ment will operate. True optimisations take account of this context and consider,
for example, whether there are any registers which already hold the values of
variables, whose contents can be used to avoid an unnecessary LOAD instruc-
tion. To generate this code, the procedure for assignment nodes must look for
nodes with a particular special property and generate a special code fragment
for them. The number of possible tactical improvements is enormous and the
translator should implement only those tactics which are cost-effective – i.e.
where the improvement in object program efficiency is sufficient to justify the
cost of recognising the tactical situation and also the frequency with which the
situation arises is sufficient to justify checking each possible node in the tree.
Modifying the tree and modifying the code (cases 3 and 4 in figure 2.9) are
examples of optimisation techniques. Case 3 is illustrated by ‘code motion’ out
of a loop to reduce the number of times a fixed calculation is carried out (figure
2.13) and case 4 by ‘register remembering’ to eliminate unnecessary LOAD and
STORE instructions (figure 2.14). Code modification can be done after translation
has finished or, perhaps better, as a sort of filter on the code proposed by the
translator as it generates it.
50. 30 CHAPTER 2. INTRODUCTION TO TRANSLATION
1. Statement: a := 0 Tree: assign
a 0
Normal code: LOADn 1, 0
STORE 1, a
Optimised code: STOZ , a
2. Statement: b := b+<anything> Tree: assign
b +
b <anything>
Normal code: Optimised code:
LOAD 1, <anything>
ADD 1, b
STORE 1, b
LOAD 1, <anything>
ADDST 1, b
3. Statement: c := c+1 Tree: assign
c +
c 1
Good code: LOADn 1, 1
ADDST 1, c
Better code: INCST , c
Figure 2.12: Some simple sub-optimisations
51. 2.4. IMPROVING THE TREE WALKER 31
Program: for i = 1 to 100 do
begin
x := 0.5 * sqrt(y+z);
a[i] := x;
b[i] := y;
....
end
Tree:
... ... for ... ...
i 1 100 compound
x:=... a[i]:=x b[i]:=y ...
program
Altered tree:
... ... for ... ...
i 1 100 compound
x:=...
a[i]:=x b[i]:=y ...
program
Figure 2.13: Moving code out of a loop
Program: a := b+1;
c := a
Original code: LOAD 1, b
ADDn 1, 1
STORE 1, a /* possibly unnecessary */
LOAD 1, a /* certainly unnecessary */
STORE 1, c /* possibly unnecessary */
Figure 2.14: Removing unnecessary instructions
52. 32 CHAPTER 2. INTRODUCTION TO TRANSLATION
1 INTEGER + INTEGER LOAD n, a
ADD n, b
2. REAL + INTEGER LOAD n, a
LOAD n+1, b
FLOATr n+1,
fADDr n, n+1
3. REAL + COMPLEX LOAD n, a
ADD n, breal
LOAD n+1, bimag
Figure 2.15: Code for various type combinations
2.5 Using the Symbol Table Descriptors
The symbol table is built by the lexical analyser in order to correlate the vari-
ous occurrences of each particular source program name. The object description
phase inserts into the symbol table against each name a descriptor which gives
information about the run-time object which is denoted by that name, deter-
mined by the declarations in which the name appears.
The descriptor not only distinguishes between different kinds of objects – vari-
ables, arrays, procedures – but also in a compiler for an algebraic language the
descriptor will give the type of the run-time object. Figure 2.15 shows some
possible code fragments for combinations of FORTRAN’s INTEGER, REAL
and COMPLEX types in an arithmetic ‘+’ node each of whose sub-nodes is
an arithmetic variable name. As well as recording the type and kind of the
object, the descriptor must contain the (possibly relocatable) store address of
the run-time object so that the a’s and b’s in the instructions of figure 2.15 can
be replaced by the proper run-time addresses.
In languages with more complex data structures, such as COBOL, PL/1, AL-
GOL 68 or SIMULA 67, the descriptor structure will not be a simple description
of an object but rather a description of a run-time structure. In the case of
COBOL, the ADD CORRESPONDING statement provides the most obvious
example – the descriptor for HEAD-OFFICE and that for NORTH-OFFICE in
figure 2.16 must give the underlying hierarchical structure so that the transla-
tor can generate code for the necessary sequence of simple ADD statements. In
such a case, the tree obviously extends into the symbol table.
2.6 Translation Error Handling
A translation error report is generated when a source fragment appears to be
of the correct superficial form, but for some reason can’t be translated. Some
obvious causes of this are undeclared names, names whose descriptor types don’t
match the required context and so on. Figure 2.17 gives some examples. These
errors are almost all discovered by checking the tree against the contents of
53. 2.6. TRANSLATION ERROR HANDLING 33
Statement: ADD CORRESPONDING NORTH-OFFICE TO HEAD-OFFICE
Tree: add.corr
name name
NORTH-OFFICE HEAD-OFFICE
Descriptors:
MANAGER WAGES
PLANT
NORTH-OFFICE
OFFICE
OFFICE
MANAGING-DIRECTOR SALARY
PLANT
HEAD-OFFICE
Figure 2.16: Symbol table which contains structure
54. 34 CHAPTER 2. INTRODUCTION TO TRANSLATION
1. Operands of a node are of wrong type
Statement: if a then x := b+1
Tree: conditional
a assignment
x +
b 1
Symbol Table: a is a real variable
b is a Boolean variable
2. Name not declared - so its descriptor is empty
e.g. name 'x' not declared in example above
3. Ambiguous data name (COBOL)
Statement: MOVE PLANT TO PLANT
Symbol Table: as in figure 2.12 above.
4. Invalid combination of phrases
Statement: if u=v=0 then ....
Tree: conditional
= ....
= 0
u v
Figure 2.17: Some kinds of error detected in translation
57. CHAPTER I
MY LORD'S LEVEE
It is three years later. We are now in the year 1750.
At twelve o'clock in the morning the anteroom of the town house of
the Right Honourable the Earl of Fylingdale was tolerably filled with
a mixed company attending his levee. Some were standing at the
windows; some were sitting: a few were talking: most, however,
were unknown to each other, and if they spoke at all, it was only to
ask each other when his lordship might be expected to appear.
As is customary at a great lord's levee there were present men of all
conditions; they agreed, however, in one point, that they were all
beggars. It is the lot of the nobleman that he is chiefly courted for
the things that he can give away, and that the number of his friends
and the warmth of their friendship depend upon the influence he is
supposed to possess in the bestowal of places and appointments.
Among the suitors this morning, for instance, was a half-pay captain
who sought for a company in a newly raised regiment: he bore
himself bravely, but his face betrayed his anxiety and his necessities.
The poor man would solicit his lordship in vain, but this he did not
know, and so he would be buoyed up for a time with new hopes.
Beside him stood a lieutenant in the navy, who wanted promotion
and a ship. If good service and wounds in battle were of any avail he
should have commanded both, but it is very well known that in the
Royal Navy there are no rewards for gallantry; men grow old without
promotion: nothing helps but interest: a man may remain a
midshipman for life without interest: never has it been known that
without interest a ship has been bestowed even upon the most
deserving officer and after the most signal service. The lieutenant,
58. too, would be cheered by a promise, and lulled by false hopes—but
that he did not know.
One man wanted a post in the admiralty: the pay is small but the
perquisites and the pickings are large: for the same reason another
asked for a place in the customs. A young poet attended with a
subscription list and a dedication. He thought that his volume of
verse, once published, would bring him fortune, fame, and friends:
he, too, would be disappointed. The clergyman wanted another
living: one of the fat and comfortable churches in the city: a deanery
would not be amiss: he was even ready to take upon himself the
office of bishop, for which, indeed, he considered that his
qualifications admirably fitted him. Would his lordship exercise his all
powerful influence in the matter of that benefice or that promotion?
A young man, whose face betrayed the battered rake, would be
contented even with carrying the colours on the Cape Coast
regiment if nothing better could be had. Surely his lordship would
procure so small a thing as that! If nothing could be found for him
then—the common side of the King's Bench Prison and rags and
starvation until death released him. Poor wretch! He was on his way
to that refuge, but he knew it not; for my lord would promise to
procure for him what he wanted.
So they all waited, hungry and expectant, thinking how best to
frame their requests: how best to appear grateful before there was
any call for gratitude. Surely a nobleman must grow wearied with
the assurances of gratitude and promises of prayers. His experience
must teach him that gratitude is but a short-lived plant: a weed
which commonly flourishes for a brief period and produces neither
flowers nor fruit; while as for the prayers, though we may make no
doubt that the fervent prayer of the righteous availeth much, we are
nowhere assured that the prayers of the worldly and the unrighteous
are heard on behalf of another; while there is no certainty that the
promised petition will ever be offered up before the throne. Yet the
59. suitors, day after day, repeat the same promise, and rely on the
same belief. "Oh! my lord," they say, or sing with one accord, "your
name: your voice: your influence: it is all that I ask. My gratitude:
my life-long gratitude: my service: my prayers will all be yours."
Soon after twelve o'clock the doors of the private apartments were
thrown open and his lordship appeared, wearing the look of dignity
and proud condescension combined, which well became the star he
wore and the ancient title which he had inherited. His age was about
thirty, a time of life when there linger some remains of youth and
the serious responsibilities are yet, with some men, hardly felt. His
face was cold and proud and hard; the lips firmly set: the eyes keen
and even piercing; the features regular: his stature tall, but not
ungainly, his figure manly. It was remarkable, among those who
knew him intimately, that there was as yet no sign of luxurious living
on face and figure. He was not as yet swelled out with wine and
punch: his neck was still slender; his face pale, without any telltale
marks of wine and debauchery; so far as appearance goes he might
pass if he chose, for a person of the most rigid and even austere
virtue. This, as I have said, was considered remarkable by his
friends, most of whom were already stamped on face and feature
and figure with the outward and visible tokens of a profligate life.
For, to confess the truth at the very beginning and not to attempt
concealment, or to suffer a false belief as regards this nobleman, he
was nothing better than a cold-blooded, pitiless, selfish libertine; a
rake, and a voluptuary; one who knew and obeyed no laws save the
laws of (so-called) honour. These laws allow a man to waste his
fortune at the gaming table: to ruin confiding girls: to spend his time
with rake hell companions in drink and riot and debauchery of all
kinds. He must, however, pay his gambling debts: he must not cheat
at cards; he must be polite in speech: he must be ready to fight
whenever the occasion calls for his sword, and the quarrel seems of
sufficient importance. Lord Fylingdale, however, was not among
those who found his chief pleasure scouring the streets and in mad
60. riot. You shall learn, in due course, what forms of pleasure chiefly
attracted him.
I have said that his face was proud. There was not, I believe, any
man living in the whole world, who could compare with Lord
Fylingdale for pride. An overwhelming pride sat upon his brow; was
proclaimed by his eyes and was betrayed by his carriage. With such
pride did Lucifer look round upon his companions, fallen as they
were, and in the depths of hopeless ruin.
In many voyages to foreign parts I have seen something of foreign
peoples; every nation possesses its own nobility; I suppose that
king, lords and commons is the order designed for human society by
Providence. But I think that there is nowhere any pride equal to the
pride of the English aristocracy. The Spaniard, if I have observed him
aright, wraps himself in the pride of birth as with a cloak: it is often
a tattered cloak: poverty has no terrors for him so long as he has his
pride of birth. Yet he tolerates his fellow-countrymen whom he does
not despise because they lack what most he prizes. The English
nobleman, whether a peer or only a younger son, or a nephew or a
cousin, provided he is a sprig of quality, disdains and despises all
those who belong to the world of work, and have neither title, nor
pedigree, nor coat of arms. He does not see any necessity for
concealing this contempt. He lacks the courtesy which would hide it
in the presence of the man of trade or the man of a learned
profession. To be sure, the custom of the country encourages him,
because to him is given every place and every preferment. He fills
the House of Commons as well as the House of Lords: he commands
our armies, our regiments, even the companies in the regiments: he
commands our fleets and our ships: he holds all the appointments
and draws all the salaries: he makes our laws, and, as justice of the
peace, he administers them: he receives pensions, having done
nothing to deserve them; he holds sinecures which require no
duties. And the people who do the work—the merchants who bring
wealth to the country: the manufacturers; the craftsmen; the
61. farmers; the soldiers who fight the wars which the aristocracy
consider necessary; the sailor who carries the flag over the world: all
these are supposed to be sufficiently rewarded with a livelihood
while they maintain the nobility and their children in luxury and in
idleness and are received and treated with contempt.
I speak of what I have myself witnessed. This man's pride I have
compared with the pride of Lucifer. You shall learn while I narrate
the things which follow, that he might well be compared, as regards
his actions as well, with that proud and presumptuous spirit.
He was dressed in a manner becoming to his rank: need we dwell
upon his coat of purple velvet; his embroidered waistcoat; his white
silk stockings; his lace of ruffles and cravat; his gold buckles and his
gold clocks; his laced hat carried under his arm; his jewelled sword
hilt and the rings upon his fingers? You would think, by his dress,
that his wealth was equal to his pride, and, by his reception of the
suitors, that his power was equal to both pride and wealth together.
The levee began; one after the other stepped up to him, spoke a
few words, received a few words in reply and retired, each,
apparently, well pleased. For promises cost nothing. To the poet who
asked for a subscription and preferred a dedication, my lord
promised the former, accepted the latter, and added a few words of
praise and good wishes. But the subscription was never paid; and
the dedication was afterwards altered so far as the superscription, to
another noble patron. To the clergyman who asked for a country
living then vacant, my lord promised the most kindly consideration
and bade him write his request and send it him by letter, for better
assurance of remembrance. To the officer he promised his company
as only due to gallantry and military skill: to the place hunter he
promised a post far beyond the dreams and the hopes of the
suppliant. Nothing more came of it to either.
The company grew thin: one after the other, the suitors withdrew to
feed on promises. It is like opening your mouth to drink the wind.
62. But 'twas all they got.
Among those who remained to the last was a man in the dress of a
substantial shopkeeper, with a brown cloth coat and silver buttons.
He, when his opportunity arrived, advanced and bowed low to my
lord.
"Sir," said his lordship, with gracious, but cold looks, "in what way
may I be of service to you?"
"With your lordship's permission, I would seek a place in your
household—any place—scullion in the kitchen, or groom to the
stable—any place."
"Why should I give you a place? Have I room in my household for
every broken cit?"
"My lord, it is to save me from bankruptcy and the King's Bench. It is
to save my wife and children from destitution. There are already
many shopkeepers in Westminster and the city who have been
admitted servants in the households of noblemen. It is no new thing
—your lordship must have heard of the custom."
"I do not know why I should save thy family or thyself. However, this
is the affair of my steward. Go and see him. Tell him that a place in
my household will save thee from bankruptcy and prison—it may be
that a place is vacant."
The man bowed again and retired. He knew very well what was
meant. He would have to pay a round sum for the privilege. This
noble lord, like many others of his rank, took money, through his
steward, for nominal places in his household, making one citizen
yeoman of his dairy; in Leicester Fields, perhaps, where no dairy
could be placed; another steward of the granaries, having in the
town neither barns nor storehouses nor ricks: a third, clerk to the
stud book, having no race horses; and so on. Thus justice is
63. defeated, a man's creditors may be defied and a man may escape
payment of his just debts.
When he was gone, Lord Fylingdale looked round the room. In the
window stood, dangling a cane from his wrist, a gentleman dressed
in the highest and the latest fashion. In his left hand he held a
snuffbox adorned with the figure of a heathen goddess. To those
who know the meaning of fashion it was evident that he was in the
front rank, belonging to the few who follow or command, the
variations of the passing hour. These descend to the smallest details.
I am told that the secrets of the inner circle, the select few, who
lead the fashion, are displayed for their own gratification in the
length of the cravat, the colour of the sash, the angle of the sword,
the breadth of the ruffles, the width of the skirts, the tye of the wig.
They are also shown in the mincing voice, and the affected tone,
and the use of the latest adjectives and oaths. Yet, when one looked
more closely, it was seen that this gallant exterior arrayed an ancient
gentleman whose years were proclaimed by the sharpening of his
features, the wrinkles of his feet, the crows'-feet round his eyes, and
his bending shoulders which he continually endeavoured to set
square and upright. Hat in one hand, and snuffbox in the other, he
ambled towards his lordship on tiptoe, which happened just then to
be the fashionable gait.
"Thy servant, Sir Harry"—my lord offered him his hand with
condescension. "It warms my heart to see thee. Therefore I sent a
letter. Briefly, Sir Harry, wouldst do me a service?"
"I am always at your lordship's commands. This, I hope, I have
proved."
"Then, Sir Harry, this is the case. It is probable that for certain
private reasons, I may have to pay a visit to a country town—a town
of tarpaulins and traders, not a town of fashion"—Sir Harry
shuddered—"patience, my friend. I know not how long I shall
endure the barbaric company. But I must go—there are reasons—let
64. me whisper—reasons of state—important secrets which call me
there"—Sir Harry smiled and looked incredulous—"I want, on the
spot, a friend"—Sir Harry smiled again, as one who began to
understand—"a friend who would appear to be a stranger. Would
you, therefore, play the part of such a friend?"
"I will do whatever your lordship commands. Yet to leave town at
this season"—it was then the month of April—"the assembly, the
park, the card table—the society of the ladies——"
"The loss will be theirs, Sir Harry. To lose their old favourite—oh!
there will be lamentations, at the rout—— Perhaps, however, we
may find consolations."
"Impossible. There are none out of town, except at Bath or
Tunbridge——"
"The ladies of Norfolk are famous for their beauty."
"Hoydens—I know them,
"'I who erst beneath a tree
Sung, Bumpkinet, and Bowzybee,
And Blouzelind and Marian bright
In aprons blue or aprons white,'
"as Gay hath it. Hoydens, my lord, I know them. They play whist
and dance jigs."
"The Norfolk gentlemen drink hard and the wine is good."
"Nay, my lord, this is cruel. For I can drink no longer."
"I shall find other diversions for you. It is possible—I say—possible—
that the Lady Anastasia may go there as well. She will, as usual,
keep the bank if she does go."
65. The old beau's face cleared, whether in anticipation of Lady
Anastasia's society or her card table I know not.
"My character, Sir Harry, will be in your hands. I leave it there
confidently. For reasons—reasons of state—it should be a character
of…."
"I understand. Your lordship is a model of all the virtues——"
"So—we understand. My secretary will converse with thee further on
the point of expenditure."
Sir Harry retired, bowing and twisting his body something like an
ape.
Then a gentleman in scarlet presented himself.
"Your lordship's most obedient," he said, with scant courtesy. "I
come in obedience to your letter—for command."
"Colonel, you will hold yourself in readiness to go into the country.
There will be play—you may lose as much as you please—to Sir
Harry Malyus or to any one else whom my secretary will point out to
you. Perhaps you may have to receive a remonstrance from me. We
are strangers, remember, and I am no gambler, though I sometimes
take a card."
"I await your lordship's further commands." So he, too, retired. A
proper well-set-up figure he was, with the insolence of the trooper in
his face, and the signs of strong drink on his nose. Any one who
knew the town would set him down for a half-pay captain, a sharper,
a bully, a roysterer, one who lived by his wits, one who was skilled in
billiards and commonly lucky at any game of cards. Perhaps such a
judgment of the gallant colonel would not be far wrong.
There remained one suitor. He was a clergyman dressed in a fine silk
cassock with bands of the whitest and a noble wig of the order
66. Ecclesiastic. I doubt if the archbishop himself had a finer. He was in
all respects a divine of the superior kind: a dean, perhaps; an
archdeacon, perhaps; a canon, rector, vicar, chaplain, with a dozen
benefices, no doubt. His thin, slight figure carried a head too big for
his body. His face was sallow and thin, the features regular; he bore
the stamp of a scholar and had the manner of a scoffer. He spoke as
if he was in the pulpit, with a voice loud, clear and resonant, as
though the mere power of hearing that voice diffused around him
the blessings of virtue and piety and a clear conscience.
"Good, my lord," he said, "I am, as usual, a suppliant. The rectory of
St. Leonard le Size, Jewry, in the city, is now vacant. With my small
benefices in the country, it would suit me hugely. A word from your
lordship to the lord mayor—the rectory is in the gift of the
corporation—would, I am sure, suffice."
"If, my old tutor, the thing can be done by me, you may consider it
as settled. There are, however, I would have you to consider, one or
two scandals still outstanding, the memory of which may have
reached the ears of the city. These city people, for all their ignorance
of fashion, do sometimes hear of things. The little affair at Bath, for
instance——"
"The lady hath since returned to her own home. It is now quite
forgotten and blown over. My innocency is always well known to
your lordship."
"Assuredly. Has that other little business at Oxford blown over? Are
certain verses still attributed to the Reverend Benjamin Purdon?"
His reverence lightly blew upon his fingers. "That report is now
forgotten. But 'tis a censorious world. One man is hanged for looking
over a gate while another steals a pig and is applauded. As for the
author of those verses, he still remains undiscovered, while the
verses themselves—a deplorable fact—are handed about for the joy
of the undergraduates."
67. "Next time, then, steal the pig. Frankly, friend Purdon, thy name is
none of the sweetest, and I doubt if the bishop would consent.
Meantime, you are living, as usual, I suppose, at great expense——"
"At small expense, considering my abilities; but still at greater
expense than my slender income will allow. Am I not your lordship's
domestic chaplain? Must I not keep up the dignity due to the
position?"
"Your dignity is costly. I must get a bishopric or a deanery for you.
Meantime I have a small service to ask of you."
"Small? My lord, let it be great: it cannot be too great."
"It is that you go into the country for me."
"Not to Bath—or to Oxford?" His reverence betrayed an anxiety on
this point which was not quite in harmony with his previous
declarations.
"Not to either. To another place, where they know not thy name or
thy fame. Very good. I thought I could depend upon your loyalty. As
for arrangements and time, you will hear from my secretary." So my
lord turned on his heel and his chaplain was dismissed. He remained
for a moment, looking after his master doubtfully. The order liked
him not. He was growing old and would have chosen, had he the
power of choice, some fat city benefice with two or three country
livings thrown in. He was tired of his dependence: perhaps he was
tired of a life that ill became his profession: perhaps he could no
longer enjoy it as of old. There was, at least, no sign of repentance
as there was no touch of the spiritual life in his face, which was
stamped with the plain and visible marks of the world, the flesh and
the devil. What is that stamp? Nobody can paint it, or describe it: yet
it is understood and recognised whenever one sees it. And it stood
out legible so that all those who ran might read upon the face of this
reverend and learned divine.
68. When the levee was finished and everybody gone, Lord Fylingdale
sank into a chair. I know not the nature of his thoughts save that
they were not pleasant, for his face grew darker every moment.
Finally, he sprang to his feet and rang the bell. "Tell Mr. Semple that
I would speak with him," he ordered.
Mr. Semple, the same Samuel whom you have seen under a basting
from the captain, was now changed and for the better. His dress was
simple. No one could guess from his apparel the nature of his
occupation. For all professions and all crafts there is a kind of
uniform. The divine wears gown and cassock, bands and wig, which
proclaim his calling: the lawyer is also known by his gown and marks
his rank at the bar by coif and wig: the attorney puts on broadcloth
black of hue: the physician assumes black velvet, a magisterial wig,
and a gold-headed cane. The officer wears the King's scarlet; the
nobleman his star: the sprig of quality puts on fine apparel and
assumes an air and manner unknown to Cheapside and Ludgate Hill:
you may also know him by his speech. The merchant wears black
velvet with gold buttons, gold buckles, white silk stockings and a
gold-laced hat; the shopkeeper substitutes silver for gold and cloth
for velvet: the clerk has brown cloth metal buttons and worsted
stockings. As for the crafts, has not each its own jacket, sleeves,
apron, cap, and badge?
But for this man, where would we place him? What calling did he
represent? For he wore the flowered waist-coat—somewhat frayed
and stained, of a beau, and the black coat of the merchant: the
worsted stockings of the clerk and his metal buttons. Yet he was
neither gentleman, merchant, shopkeeper, clerk, nor craftsman. He
was a member of that fraternity which is no fraternity because there
is no brotherhood among them all; in which every man delights to
slander, gird at, and to depreciate his brother. In other words he
wore the dress—which is no uniform—of a poet. At this time he also
called himself secretary to his lordship having by ways known only to
himself, and by wrigglings up back stairs, and services of a kind
69. never proclaimed to the world, made himself useful. The position
also granted him, as it granted certain tradesmen, immunity from
arrest. He had the privilege of walking abroad through a street full of
hungering creditors, and that, not on Sundays only, like most of his
tribe, but on every day in the week.
He obeyed the summons and entered the room with a humble
cringe.
"Semple," said his lordship, crossing his legs and playing with the
tassel of his sword knot, "I have read thy letter——"
"Your lordship will impute——"
"First, what is the meaning of the preamble?"
"I have been your lordship's secretary for six months. I have
therefore perused all your lordship's letters. I have also in my zeal
for your lordship's interests—looked about me. And I discovered—
what I ventured to state in that preamble."
"Well, sir?"
"Namely, that the Fylingdale estates are gone so far as your
lordship's life is concerned—but—in a word, all is gone. And that—
your lordship will pardon the plain truth—your lordship's credit
cannot last long and that—I now touch a most delicate point to a
man of your lordship's nice sense of honour—the only resource left
is precarious."
"You mean?"
"I mean—a certain lady and a certain bank."
"How, sir? Do you dare? What has put this suspicion into your
head?"
70. "Nay, my lord—I have no thought but for your lordship's interests,
believe me."
"And so you tell me about the rustic heiress, and you propose a plan
——"
"I have had the temerity to do so."
"Yes. Tell me once more about this girl—and about her fortune."
"Her name is Molly Miller: she is an orphan: her guardian is an
honest sailor who has taken the greatest care of her property. She
was an heiress already when her father died. That was eighteen
years ago; she is now nineteen."
"Is she passable—to look at? A hoyden with a high colour, I
warrant."
"A cream-coloured complexion, touched with red and pink: light hair
in curls and blue eyes; the face and figure of a Venus; the sweetest
mouth in the world and the fondest manner."
"Hang me if the fellow isn't in love with her, himself! If she is all this,
man, why not apply yourself, for the post of spouse?"
"Because her guardian keeps off all would-be lovers and destines his
ward for a gentleman at least—for a nobleman, he hopes."
"He is ambitious. Now as to her fortune."
"She has a fleet of half a dozen tall vessels—nay, there are more,
but I know not how many. I was formerly clerk in a countinghouse
of the town and I learned a great deal—what each is worth and
what the freight of each voyage may produce—but not all. The
captain, her guardian, keeps things close. My lord, I can assure you,
from what I learned in that capacity and by looking into old books,
that she must be worth over a hundred thousand pounds—over a
hundred thousand pounds! My lord, there is no such heiress in the
71. city. In your lordship's interests I have enquired in the taverns where
the merchants' clerks congregate. They know of all the city
heiresses. The greatest, at this moment, is the only daughter of a
tallow chandler who has twenty thousand to her name. She squints."
"Why have you given me this information? The girl belongs to your
friends—are you anxious for her happiness? You know my way of
life. Would that way make her happier?"
The man made no reply.
"Come, Semple, out with it. Your reasons—gratitude—to me—or
revenge upon an enemy?"
The man coloured. He looked up: he stood upright but for a moment
only. Then his eyes dropped and his shoulders contracted.
"Gratitude, my lord, to you," he replied. "Revenge? Why what reason
should I have for revenge?"
"How should I know of any? Let it be gratitude, then."
"I have ventured to submit—not a condition—but a prayer."
"I have read the clause. I grant it. On the day after the marriage if
the plan comes to anything, I will present thee to a place where
there are no duties and many perquisites. That is understood. I
would put this promise in writing but no writing would bind me more
than my word."
"Yet I would have the promise in writing."
"You are insolent, sirrah."
"I am protecting myself. My lord, I must speak openly in this matter.
How many promises have you made this morning? How many will
you keep? I must not be pushed aside with such a promise."
72. Lord Fylingdale made no reply.
"I offer you a fortune of a hundred thousands pounds and more."
"I can now take this fortune without your assistance."
"With submission, my lord, you cannot. I know too much."
"What shall I write, then?"
"I am only reasonable. The girl's fortune when you have it will go
the same way as your rents and woods have gone. Provide for me,
therefore, before you begin to spend that money."
"Semple, I did not think you had so much courage. Learn that a
dozen times I have been on the point of kicking you out of the
house. Now," he rose, "give me paper and a pen—and I will write
this promise."
Semple placed a chair at the table and laid paper and pen before it.
"Let me presume so far as to dictate the promise," he said. "I
undertake and promise that on the day after my marriage with the
girl named Molly Miller, I will give Samuel Semple such a place as will
provide him for life with a salary of not less than £200 a year. So—
will your lordship sign it?"
He took up this precious paper from the table, read it, folded it and
put it in his pocket.
"What next?" asked his patron.
"I am preparing a scheme which will give a plausible excuse for your
lordship's visit to the town. I have already suggested that certain
friends should prepare the way. The lady's guardian has prejudices
in favour of morality and religion. They are, I know, beneath your
lordship's notice—yet still—it will be in fact, necessary that your
lordship's character shall be such as will commend itself to this
unfashionable old sailor."
73. "We will speak again upon this point. The girl you say has no lover."
"She has no lover. Your lordship's rank: your manner: your
appearance will certainly carry the day. By contrast alone with the
country bumpkins the heart of the girl will be won."
"Mr. Semple," his lordship yawned. "Do you suppose that the heart
of the girl concerns me? Go and complete your scheme—of
gratitude, not revenge."
74. CHAPTER II
THE LADY ANASTASIA
The Lady Anastasia was in her dressing-room in the hands of her
friseur, the French hairdresser, and her maid. She sat in a dishabille
which was a loose robe, called, I believe a nightgown, of pink silk,
trimmed with lace, which showed the greater part of a very well
shaped arm; she had one slipper off and one slipper on, which
showed a very small and well shaped foot, but no one was there to
see. Her maid was busy at the toilette table which was covered with
glass bottles containing liquids of attractive colour; silver patch
boxes; powder boxes; powder puffs; cosmetics in pots, and other
mysterious secrets into which it would be useless and fruitless to
inquire. The artist, for his part, was laboriously and conscientiously
building the edifice—object of so much ingenuity and thought—
called a "Head."
She was in the best temper imaginable. When you hear that she had
won overnight the sum of a hundred and twenty guineas you will
understand that she had exactly that number of reasons for being
satisfied with the world. Moreover, she had received from an admirer
a present in the shape of a piece of china representing a monkey,
which, she reflected with satisfaction, would awaken in the minds of
her friends the keenest feelings of envy, jealousy, hatred, longing,
and despair.
The Lady Anastasia was the young widow of an old baronet: she
was also the daughter of an earl and the sister of his successor. She
therefore enjoyed the freedom of a widow; the happiness natural to
youth; and all the privileges of rank. No woman could be happier. It
was reported that her love of the card table had greatly impaired her
income: the world said that her own private dowry was wholly gone
75. and a large part of her jointure. But it is a spiteful world—all that
was known for certain was that she played much and that she
played high. Perhaps Fortune, in a mood of penitence, was giving
back what she had previously taken away. The contrary is commonly
the case, viz, that Fortune, which certainly takes away with alacrity,
restores with reluctance.
Perhaps, however, the reports were not true.
She kept a small establishment in Mount Street: her people
consisted of no more than two footmen, a butler, a lady's maid, a
housekeeper, and three or four maids with two chairmen. She did
not live as a rich woman: she received, it is true, twice a week, on
Sundays and Wednesdays, but not with any expense of supper and
wine. Her friends came to play cards and she held the bank for
them. On other evenings she went out and played at the houses of
her friends.
Except for fashions and her dress—what fine woman but makes that
exception?—she had no other occupation; no other pursuit; no other
subject of conversation, than the playing of cards. She played at all
games and knew them all; she sat down with a willing mind to
Ombre, Faro, Quadrille, Basset, Loo, Cribbage, All Fours, or Beggar
my Neighbour, but mostly she preferred the game of Hazard, when
she herself kept the bank. It is a game which more than any other
allures and draws on the player so that a young man who has never
before been known to set a guinea on any card, or to play at any
game, will in a single night be filled with all the ardour and
eagerness of a practised gamester; will know the extremes of joy
and despair; and will regard the largest fortune as bestowed by
Providence for no other purpose than to prolong the excitement and
the agony of a gamester.
While the Lady Anastasia was still admiring the china vase set upon
the table, so that she might gaze upon it and so refresh her soul,
and while the friseur was still completing her head, Lord Fylingdale
76. was announced. The lady blushed violently: she sat up and looked
anxiously in the glass.
"Betty," she cried, "a touch of red—not much, you clumsy creature!
Will you never learn to have a lighter hand? So! that is better. I am
horribly pale. His lordship can wait in the morning room. You have
nearly finished, monsieur? Quick then! The last touches. Betty, the
flowered satin petticoat. My fan. The pearl necklace. So," she looked
again at the glass, "am I looking tolerable, Betty?"
"Your ladyship is ravishing," said Betty finishing the toilette. In truth,
it was a very pretty creature if one knew how much was real and
how much was due to art. The complexion was certainly laid on; the
hair was powdered and built up over cushions and pillows; there
were patches on the cheek: the neck was powdered; eyes naturally
very fine were set off and made more lustrous with a touch of dark
powder: the frock and petticoat and hoop were all alike removed
from nature. However, the result was a beautiful woman of fashion
who is far removed indeed from the beautiful woman as made by
the Creator. For her age the Lady Anastasia might have been seven
and twenty, or even thirty—an age when with some women, the
maturity of their beauty is even more charming than the first
sprightly loveliness of youth.
She swam out of the room with a gliding movement, then the
fashion, and entered the morning room where Lord Fylingdale
awaited her.
"Anastasia!" he said, softly, taking her hand. "It is very good of you
to see me alone. I feared you would be surrounded with courtiers
and fine ladies or with singers, musicians, hairdressers, and other
baboons. Permit me," he raised her hand to his lips. "You look divine
this morning. It is long since I have seen you look so perfectly
charming."
77. The lady murmured something. She was one of those women who
like above all things to hear praises of what most they prize, their
beauty, and to believe what they most desire to be the truth, the
preservation and perfecting of that beauty.
"But you came to see me alone. Was it to tell me that I look
charming? Other men tell me as much in company."
"Not altogether that, dear lady, though that is something. I come to
tell you of a change of plans."
"You have heard that the grand jury of Middlesex has presented me
by name as a corruptor of innocence, and I know not what, because
I hold my bank on Sunday nights."
"I have heard something of the matter. It is almost time, I think, to
give these presumptuous shopkeepers a lesson not to interfere with
the pursuits of persons of rank. Let them confine themselves to the
prentices who play at pitch and toss."
"Oh! what matters their presentment? I shall continue to keep the
bank on Sunday nights. Now, my dear lord, what about these plans?
What is changed?"
"We thought, you remember, about going to Tunbridge, in July."
"Well? Shall we not go there?"
"Perhaps. But there is something to be done first. Let me confide in
you——"
"My dear lord—you have never confided in anybody."
"Except in you. I think you know all my secrets if I have any. In
whom else can I confide? In the creatures who importune me for
places? In friends of the green table? In friends of the race course?
My dear Anastasia, you know, I assure you, as much about my
personal affairs as I know myself."
78. "If you would always speak so kindly"—her eyes became humid but
not tearful. A lady of fashion must not spoil her cheek by tears.
"Well, then, the case is this. You know of the condition of my affairs
—no one better. An opportunity presents itself to effect a great
improvement. I am invited by the highest personage to take a more
active part in the affairs of state. No one is to know this. For reasons
connected with this proposal I am to visit a certain town—a trading
town—a town of rough sailors, there to conduct certain enquiries.
There is to be a gathering at this town of the gentry and people of
the county. Would you like to go, my dear friend? It will be next
month."
"To leave town—and in May, just before the end of the season?"
"There will be opportunities, I am told, of holding a bank; and a
good many sportsmen—'tis a sporting county—may be expected to
lay their money. In a word, Anastasia, it will not be a bad exchange."
"And how can I help you? Why should I go there?"
"By letting the people—the county people, understand the many
virtues and graces which distinguish my character. No one knows me
better than yourself."
The lady smiled—"No one," she murmured.
"—Or can speak with greater authority on the subject. There will be
certain of our friends there—the parson—Sir Harry—the colonel——"
"Pah! a beggarly crew—and blown upon—they are dangerous."
"Not at this quiet and secluded town. They will be strangers to you
as well as to me. And they will be useful. After all, in such a place
you need an opening. They will lead the way."
The lady made no response.
79. "I may call it settled, then?" He still held her hand. "If you would
rather not go, Anastasia, I will find some one else—but I had hoped
——"
She drew away her hand. "You are right," she said, "no one knows
you so well as myself. And all I know about you is that you are
always contriving some devilry. What is it this time? But you will not
tell me. You never tell me."
"Anastasia, you do me an injustice. This is a purely political step."
"As you will. Call it what you please. I am your servant—you know
that—your handmaid—in all things—save one. Not for any other
woman, Ludovick—not for any other—unfortunate—woman will I lift
my little finger. Should you betray me in this respect——"
He laughed. "A woman? And in that company? Rest easy, dear child.
Be jealous as much as you please but not with such a cause."
He touched her cheek with his finger: he stooped and kissed her
hand and withdrew.
The Lady Anastasia stood awhile where he left her. The joy had gone
out of her heart: she trembled: she was seized with a foreboding of
evil. She threw herself upon the sofa and buried her face in her
hands, and forgetful of paste and patch and paint she suffered the
murderous tears to destroy that work of art—her finished face.
80. CHAPTER III
THE "SOCIETY" OF LYNN
It was about seven o'clock in the evening of early April, at the going
down of the sun that I was at last able to drop into the dingy and go
ashore. All day and all night and all the day before we had been
beating through the shallows of the Wash and the narrow channel of
the Ouse. We had laid her to her moorings off the Common Stath
and made all taut and trim: the captain had gone ashore with the
papers: the customhouse officer had been aboard: we were to begin
breaking cargo on the morrow. The ship was The Lady of Lynn, 380
tons, Robert Jaggard, master marines, being captain, and I the mate
or chief officer. There was no better skipper in the port of Lynn than
Captain Jaggard: there was no better crew than that aboard The
Lady of Lynn, not a skulker or a lubber in the whole ship's company;
and though I say it myself, I dare affirm that the mate did credit to
his ship as much as the captain and the crew. We were in the Lisbon
trade: we had therefore come home laden with casks of the rich
strong wine of the country: the Port and Lisbon Sherry and Malaga,
besides Madeira and the wine of Teneriffe and the Grand Canary.
Our people of the Marshland and the Fens and those of Lincolnshire
and Norfolk where the strong air of the east winds kill all but the
stoutest, cannot have too much of this rich wine: they will not drink
the lighter wines of Bordeaux which neither fire the blood nor mount
to the head. A prosperous voyage we had made: the Bay of Biscay
suffered us to cross with no more than half a gale: The Lady of
Lynn, in fact, was known in port to be a lucky ship—as lucky as her
owner—lucky in her voyages and lucky in her cargoes.
At the stairs of the Common Stath Yard I made fast the painter and
shipped the sculls. And there, waiting for me, was none other than
my good old friend and patron, Captain Crowle.
81. The captain was by this time well advanced in life, being upwards of
seventy: yet he showed little touch of time: his honest face being
still round and full; his eyes still free from lines and crows'-feet; his
cheek ruddy and freckled, as if with the salt sea breeze and the
driving spray. He was also as upright as any man of thirty and
walked with as firm a step and had no need of the stout stick which
he carried in his hand, as a weapon and a cudgel for the
unrighteous, more than a staff for the bending knees of old age.
"What cheer—ahoy?" He shouted from the quay as I dropped over
the side into the dingy. "What cheer, Jack?" he repeated when I ran
up the steps. "I've seen the skipper. Come with me to the Crown"—
but the proper place for mates was the Duke's Head. "Nay, it shall
be the Crown. A bowl of punch shall welcome back The Lady of
Lynn." He turned and looked at the ship lying in the river at her
moorings among the other craft. "She's as fine a vessel as this old
port can show—and she's named after as fine a maid. Shalt see her
to-morrow, Jack, but not to-night."
"I trust, sir, that she is well and in good spirits."
"Ay—ay. Nothing ails her—nothing ails her, Jack," he pointed with his
stick. "Look how she flourishes. There are fifteen tall ships moored
two and two off the King's Stath and half a dozen more off the
Common Stath. Count them, Jack. Six of these ships belong to the
little maid. Six of them—and two more are afloat, of which one is
homeward bound and should be in port soon if all goes well. Eight
noble ships, Jack, are hers. And the income of nigh upon eighteen
years and houses and broad lands."
"She has a prudent guardian, captain."
"May be—may be. I don't deny, Jack, but I've done the best I could.
Year after year, the money mounteth up more and more. You love
her, Jack, and therefore I tell you these things. And you can keep
counsel. I talk not in the market place. No one knows her wealth but
82. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com