Kenneth C. Louden

Programming Languages - Principles and Practice, 2nd Edition

Thomson - Course Technology © 2003


This book is an introduction to the broad field of programming languages. It combines a general presentation of principles with considerable detail about many modem languages, including some of the newest functional and object-oriented languages. Unlike many introductory texts, it contains significant material on implementation issues, the theoretical foundations of programming languages, and a large number of exercises. All of these features make this text a useful bridge to compiler courses and to the theoretical study of programming languages. However, it is specifically designed for use as a text in an advanced undergraduate programming languages survey course that covers most of the programming languages requirements specified in the 1991 ACM/IEEE-CS Joint Curriculum Task Force Report, and the CS8 course of the 1978 ACM Curriculum.   My goals in preparing this new edition are to bring the language-specific material in line with the changes in the popularity and use of programming languages since the publication of the first edition in 1993, to improve and expand the coverage in certain areas, and to improve the presentation and usefulness of the examples and exercises, while retaining as much of the original text and organization as possible.   Students are not expected to know any one particular language. However, experience with at least one language is necessary. A certain degree of "computational sophistication," such as that provided by a course in data structures and a discrete mathematics course, is also expected. Major languages used in this edition include C, C++, Java, Ada, ML, Haskell, Scheme, and Prolog; many other languages are discussed more briefly. Overview and Organization
In most cases, each chapter largely is independent of the others without artificially restricting the material in each. Cross references in the text allow the student or instructor to fill in any gaps that might arise even if a particular chapter or section is skipped.
Chapter 1 surveys the concepts studied in later chapters, and introduces the different language paradigms with simple examples in typical languages.   Chapters 2 and 3 provide overviews of the history of programming languages and language design principles, respectively. Chapter 3 could serve well as a culminating chapter for the book, but I find it arouses interest in later topics when covered here.   Chapter 4 treats syntax in some detail, including the use of BNF, EBNF, and syntax diagrams. A brief section views recursive definitions (like BNF) as set equations to be solved, a view that recurs periodically throughout the text. One section is devoted to recursive-descent parsing and the use of parsing tools.   Chapters 5, 6, 7, and 8 cover the central semantic issues of programming languages: declaration, allocation, evaluation; the symbol table and runtime environment as semantic functions; data types and type checking; procedure activation and parameter passing; and exceptions and exception handling.   Chapter 9 gives an overview of modules and abstract data types, including language mechanisms and equational, or algebraic, specification.   Chapters 10, 11, 12, and 13 address language paradigms, beginning with the object-oriented paradigms in Chapter 10. I use Java to introduce the concepts in this chapter. Individual sections feature C++ and Smalltalk. Chapter 11 deals with the functional paradigm. Each of the languages Scheme, ML, and Haskell are covered in some detail. This chapter also introduces the lambda calculus and the theory of recursive function definitions. Chapter 12, on logic programming, offers an extended section on Prolog, and devotes one section to equational languages such as OBJ.   Chapter 13 introduces the three principal methods of formal semantics: operational, denotational, and axiomatic. This is somewhat unique among introductory texts in that it gives enough detail to provide a real flavor for the methods.   Chapter 14 treats the major ways parallelism has been introduced into programming languages: coroutines, threads, semaphores, monitors, and message passing, with examples primarily from Java and Ada. Its final section surveys recent efforts to introduce parallelism into LISP and Prolog. Use as a Text I have used this text for over ten years in my CS 152 classes of upper division computer science majors and graduate students at San Jose State University. I have taught the course using two completely different organizations, which could loosely be called the "principles" approach and the "paradigm" approach. Two suggested organizations of these approaches in a semester-long course are as follow:
  The principles approach: Chapters 1, 4, 5, 6, 7, 8 and 9. If there is extra time, Chapters 2 and 3.   The paradigm approach: Chapters 1, 10, 11, 12, 13 and 14 (not necessarily in that order). If there is extra time, Chapters 2 and 3, or selected topics from the remaining chapters.

In a two-semester or two-quarter sequence it should be possible to cover most of the book.

  Selected answers for many of exercises the end of each chapter may be found at the author's web site, Many are programming exercises (none extremely long) in languages discussed in the text. Conceptual exercises range from the short-answer type that test understanding of the material to longer, essay-style exercises and challenging "thought" questions. A few moments’ reflection should give the reader adequate insight into the potential difficulty of a particular exercise. Further knowledge can be gained by reading the on-line answers, which I treat as an extension of the text and sometimes provide additional information beyond that required to solve the problem. Occasionally the answer to an exercise on a particular language requires the reader to consult a language reference manual or have knowledge of the language not specifically covered in the text.Throughout the book I have tried to improve the usefulness of the code examples by adding line numbers where appropriate, and by augmenting many examples with main program drivers that allow them to be executed to demonstrate their described behavior. All such examples, as well as a number of others (in which, for space or other reasons, such extra code was suppressed), are available through the author's web site listed above. This web site also contains links to free, downloadable translators for all the major languages of the book, many of which I have used to test the examples. Other materials may also be available.
Summary of Changes between
the First and Second Editions In the first edition, I used examples from the most widely known imperative languages, including C, Pascal, Ada, Modula-2, and FORTRAN, as well as some of the less widely known languages representing other language paradigms, such as Scheme, ML, Miranda, C++, Eiffel, Smalltalk, and Prolog. The most extensive change in the current edition is the replacement of Pascal and Modula-2 largely by C, C++, and Java in the examples. Modula-2 has disappeared, except for a "historical" section in Chapter 9, on ADTs; a few examples in Pascal remain. I also use Ada quite a bit, especially for features that are not well represented in C/C++/Java (e.g. subranges, arrays and slices, name equivalence of data types). Java replaces Simula as the primary example in Chapter 10, on object-oriented programming languages, and I eliminated the section on Eiffel. I devote considerably more space to ML and Haskell in Chapter 11, on functional languages, and I added ML examples liberally throughout the book. Finally, I use Java threads as the basic example of concurrency in Chapter 14, on parallel programming languages. Additional significant changes are as follows: Acknowledgments I would like to thank all those persons too numerous to mention who, over the years, have emailed me with comments, corrections, and suggestions. I especially thank the reviewers of this edition for their many useful suggestions and comments: Leonard M. Faltz of Arizona State University, Jesse Yu of the College of St. Elizabeth, Mike Frazier of Abilene Christian University, Ariel Ortiz Ramírez of ITESM Campus Estado de Mexico, James J. Ball of Indiana State University, Samuel A. Rebelsky, of Grinnell College, and Arthur Fleck of the University of Iowa.   I also thank Eran Yahav of Tel-Aviv University for reading and commenting on Chapter 14 on concurrency, and Hamilton Richards of the University of Texas for his comments and suggestions on survey Chapter 1 and Chapter 11, on functional programming.   I remain grateful to the many students in my CS 152 sections at San Jose State University for their direct and indirect contributions to this edition and to and the previous edition; to my colleagues at San Jose State, Michael Beeson, Cay Horstmann, and Vinh Phat, who read and commented on individual chapters in the first edition, and to the reviewers of that edition, Ray Fanselau of American River College, Larry Irwin of Ohio University, Zane C. Motteler of California Polytechnic State University, Tony P. Ng of the University of Illinois-Urbana, Rick Ruth of Shippensburg University of Pennsylvania, and Ryan Stansifer of the University of North Texas.   Of course, I alone am responsible for the shortcomings and errors in this book. I am happy to receive reports of errors and any other comments from readers at louden "@t" cs "d.t" sjsu "d.t" edu.   I particularly thank Kallie Swanson, computer science editor at Brooks/Cole, for her encouragement and patience during the seemingly endless process of revision. A special thanks is owed to Marjorie Schlaikjer, who first convinced me to write this book.   Finally, I give my thanks and appreciation, as ever, for the patience, support, and love of my wife, Margreth, and my sons, Andrew and Robin. Without you, much of this would never have happened.