This book is an introduction to the construction of assemblers, compilers, and interpreters. It is aimed at students with a practical rather than mathematical orientation, and at computer hobbyists who are interested in language implementation.
The author’s general approach is to describe a complete implementation of a very simple language and to extend it gradually by adding major features. Thus, one chapter describes a simple assembler, and the following chapter adds macro assembly and conditional assembly. Likewise, for high-level languages, one chapter describes a complete implementation of a very simple language, and subsequent chapters successively add subprograms, arrays, semaphores, and monitors. The author’s decision to cover implementation of concurrency and data abstraction is unusual and commendable in a book of this nature; but the obverse is that important topics such as data types are hardly covered at all.
In addition to the chapters already mentioned, there is an introductory chapter discussing translators and interpreters in general, using T-diagrams to characterize various types of translators and to explain bootstrapping. The material on compilers is preceded by two chapters on grammars and parsing. The latter chapter is mainly about recursive descent, the obvious choice; but this topic is treated in a surprisingly rigorous manner (considering that the book is aimed at mathematically weak students).
Otherwise, the emphasis of the book is firmly practical. Several assemblers, compilers, and interpreters are listed in full (and are also available from the author in machine-readable form). The listings are accompanied by extensive notes explaining the code. A rich selection of exercises is included, many consisting of extensions and modifications to the sample implementations.
An unpleasant consequence of the author’s approach is excessive concentration on the details of the implementations and not enough on the concepts underlying them. This weakness is compounded by the crudely unmodular structure of the sample compilers (a property, regrettably, shared by far too many published compilers). For example, the author argues (reasonably) that the efficiency of the declaration-table data structure is of secondary importance at an introductory level; but the student is unlikely to accept the challenge of improving it if the relevant code is scattered all over the compiler. In the wider context of an undergraduate computer science curriculum, a compiler is likely to be one of the few moderately large programs studied in detail by the student; a sample compiler can and should be an exemplar of good software engineering practice.
Some of the implementation techniques described are limited in their applicability. The author is generally conscientious in admitting these limitations, and he guides the reader towards appropriate further reading. There is one serious omission, however, in that the display handling technique described here fails for procedural parameters. I fear that hobbyists might be encouraged to copy sample compilers--limitations, unmodularities, and all--and modify them with a false sense of security.
In summary, the book is a mixture of virtues and vices. Its virtues do not outweigh its vices, nor do they make it a particularly strong competitor in a crowded market.