vi Preface
consumption, to extend battery life and to reduce electricity bills. Dynamic memory
allocation in embedded systems requires a balance between speed and thrift, and the
question is how compiler design can help. These subjects are covered in Sections
9.2, 9.3, and 10.2.8, respectively.
With age comes legacy. There is much legacy code around, code which is so
old that it can no longer be modified and recompiled with reasonable effort. If the
source code is still available but there is no compiler any more, recompilation must
start with a grammar of the source code. For fifty years programmers and compiler
designers have used grammars to produce and analyze programs; now large legacy
programs are used to produce grammars for them. The recovery of the grammar
from legacy source code is discussed in Section 3.6. If just the binary executable
program is left, it must be disassembled or even decompiled. For fifty years com-
piler designers have been called upon to design compilers and assemblers to convert
source programs to binary code; now they are called upon to design disassemblers
and decompilers, to roll back the assembly and compilation process. The required
techniques are treated in Sections 8.4 and 8.5.
The bibliography
The literature list has been updated, but its usefulness is more limited than before,
for two reasons. The first is that by the time it appears in print, the Internet can pro-
vide more up-to-date and more to-the-point information, in larger quantities, than a
printed text can hope to achieve. It is our contention that anybody who has under-
stood a larger part of the ideas explained in this book is able to evaluate Internet
information on compiler design.
The second is that many of the papers we refer to are available only to those
fortunate enough to have login facilities at an institute with sufficient budget to
obtain subscriptions to the larger publishers; they are no longer available to just
anyone who walks into a university library. Both phenomena point to paradigm
shifts with which readers, authors, publishers and librarians will have to cope.
The structure of the book
This book is conceptually divided into two parts. The first, comprising Chapters 1
through 10, is concerned with techniques for program processing in general; it in-
cludes a chapter on memory management, both in the compiler and in the generated
code. The second part, Chapters 11 through 14, covers the specific techniques re-
quired by the various programming paradigms. The interactions between the parts
of the book are outlined in the adjacent table. The leftmost column shows the four
phases of compiler construction: analysis, context handling, synthesis, and run-time
systems. Chapters in this column cover both the manual and the automatic creation