ComparativeProgramming(1)(2)(4)
ComparativeProgramming(1)(2)(4)
Programming languages
3
4 Chapter 1 Programming languages
Just as important as the individual concepts are the ways in which they may
be put together to design complete programming languages. Different selections
of key concepts support radically different styles of programming, which are
called paradigms. There are six major paradigms. Imperative programming is
characterized by the use of variables, commands, and procedures; object-oriented
programming by the use of objects, classes, and inheritance; concurrent pro-
gramming by the use of concurrent processes, and various control abstractions;
functional programming by the use of functions; logic programming by the use of
relations; and scripting languages by the presence of very high-level features. We
shall study all of these paradigms in Part IV of this book.
FORTRAN
LISP
ALGOL60 COBOL 1960
PL/I
SIMULA
ALGOL68
PASCAL 1970
SMALLTALK PROLOG
C
MODULA
ML
1980
ADA83
C++
HASKELL 1990
JAVA ADA95
Key:
C# major minor 2000
influence influence
COBOL was another early major high-level language. Its most important
contribution was the concept of data descriptions, a forerunner of today’s data
types. Like FORTRAN, COBOL’s control flow was fairly low-level. Also like FORTRAN,
COBOL has developed a long way from its original design, the latest version being
standardized in 2002.
ALGOL60 was the first major programming language to be designed for
communicating algorithms, not just for programming a computer. ALGOL60 intro-
duced the concept of block structure, whereby variables and procedures could
be declared wherever in the program they were needed. It was also the first
major programming language to support recursive procedures. ALGOL60 influ-
enced numerous successor languages so strongly that they are collectively called
ALGOL-like languages.
FORTRAN and ALGOL60 were most useful for numerical computation, and
COBOL for commercial data processing. PL/I was an attempt to design a
general-purpose programming language by merging features from all three. On
8 Chapter 1 Programming languages
top of these it introduced many new features, including low-level forms of excep-
tions and concurrency. The resulting language was huge, complex, incoherent,
and difficult to implement. The PL/I experience showed that simply piling feature
upon feature is a bad way to make a programming language more powerful and
general-purpose.
A better way to gain expressive power is to choose an adequate set of concepts
and allow them to be combined systematically. This was the design philosophy
of ALGOL68. For instance, starting with concepts such as integers, arrays, and
procedures, the ALGOL68 programmer can declare an array of integers, an array of
arrays, or an array of procedures; likewise, the programmer can define a procedure
whose parameter or result is an integer, an array, or another procedure.
PASCAL, however, turned out to be the most popular of the ALGOL-like
languages. It is simple, systematic, and efficiently implementable. PASCAL and
ALGOL68 were among the first major programming languages with both a rich
variety of control structures (conditional and iterative commands) and a rich
variety of data types (such as arrays, records, and recursive types).
C was originally designed to be the system programming language of the UNIX
operating system. The symbiotic relationship between C and UNIX has proved very
good for both of them. C is suitable for writing both low-level code (such as the
UNIX system kernel) and higher-level applications. However, its low-level features
are easily misused, resulting in code that is unportable and unmaintainable.
PASCAL’s powerful successor, ADA, introduced packages and generic units –
designed to aid the construction of large modular programs – as well as high-level
forms of exceptions and concurrency. Like PL/I, ADA was intended by its designers
to become the standard general-purpose programming language. Such a stated
ambition is perhaps very rash, and ADA also attracted a lot of criticism. (For
example, Tony Hoare quipped that PASCAL, like ALGOL60 before it, was a marked
advance on its successors!) The critics were wrong: ADA was very well designed,
is particularly suitable for developing high-quality (reliable, robust, maintainable,
efficient) software, and is the language of choice for mission-critical applications
in fields such as aerospace.
We can discern certain trends in the history of programming languages. One
has been a trend towards higher levels of abstraction. The mnemonics and symbolic
labels of assembly languages abstract away from operation codes and machine
addresses. Variables and assignment abstract away from inspection and updating
of storage locations. Data types abstract away from storage structures. Control
structures abstract away from jumps. Procedures abstract away from subroutines.
Packages achieve encapsulation, and thus improve modularity. Generic units
abstract procedures and packages away from the types of data on which they
operate, and thus improve reusability.
Another trend has been a proliferation of paradigms. Nearly all the languages
mentioned so far have supported imperative programming, which is characterized
by the use of commands and procedures that update variables. PL/I and ADA sup-
port concurrent programming, characterized by the use of concurrent processes.
However, other paradigms have also become popular and important.
1.2 Historical development 9
script that will later be called whenever required. An office system (such as a word
processor or spreadsheet system) might enable the user to store a script (‘‘macro’’)
embodying a common sequence of commands, typically written in VISUAL BASIC.
The Internet has created a variety of new niches for scripting. For example, the
results of a database query might be converted to a dynamic Web page by a script,
typically written in PERL. All these applications are examples of scripting. Scripts
(‘‘programs’’ written in scripting languages) typically are short and high-level, are
developed very quickly, and are used to glue together subsystems written in other
languages. So scripting languages, while having much in common with imperative
programming languages, have different design constraints. The most modern and
best-designed of these scripting languages is PYTHON.
Summary
In this introductory chapter:
• We have seen what is meant by programming linguistics, and the topics encompassed
by this term: concepts and paradigms; syntax, semantics, and pragmatics; and
language processors.
• We have briefly surveyed the history of programming languages. We saw how new
languages inherited successful concepts from their ancestors, and sometimes intro-
duced new concepts of their own. We also saw how the major paradigms evolved:
imperative programming, object-oriented programming, concurrent programming,
functional programming, logic programming, and scripting.
Further reading
Programming language concepts and paradigms are cov- in WEXELBLAT (1980). Comparative studies of program-
ered not only in this book, but also in TENNENT (1981), ming languages may be found in HOROWITZ (1995), PRATT
GHEZZI and JAZAYERI (1997), SEBESTA (2001), and SETHI and ZELCOWITZ (2001), and SEBESTA (2001). A survey
(1996). Programming language syntax and semantics are of scripting languages may be found in BARRON
covered in WATT (1991). Programming language proces- (2000).
sors are covered in AHO et al. (1986), APPEL (1998), and
WATT and BROWN (2000). More detailed information on the programming languages
The early history of programming languages (up to the mentioned in this chapter may be found in the references
1970s) was the theme of a major conference, reported cited in Table 1.1.
Exercises
Note: Harder exercises are marked *.
Programming
language Description
1 Introduction
1.1 The diversity of languages
1.2 The software development process
1.3 Language design
1.4 Languages or systems?
1.5 The lexical elements
Summary
Exercises
Bibliography
2 Historical survey
2.1 Early machines
2.2 Fortran
2.3 Algol
2.4 Business data processing languages
2.5 General or multipurpose languages
2.6 Developing programs interactively
2.7 Special-purpose languages
2.8 Systems programming languages
2.9 Modules, classes and abstract data types
2.10 Functional and logic languages
2.1 1 Conclusions
Summary
Exercises
Bibliography
viii Contents
5 Program structure
5.1 lntroduction
5.2 Procedural and object-oriented architecture
5.3 Alternative program architectures
5.4 Separate compilation
5.5 Larger units
Summary
Exercises
Bibliography
9 Functional languages
9.1 lntroduction
9.2 Lisp
9.3 FP systems
9.4 Modern functional languages
9.5 Concluding remarks
Summary
Exercises
Bibliography
10 Logic programming
10.1 The Prolog approach
10.2 The basics of Prolog
10.3 Data objects
10.4 Efficiency in Prolog
10.5 A Prolog example
10.6 Concluding remarks
Summary
Exercises
Bibliography
c Contents
14 The future
14.1 lntroduction
14.2 Procedural and object-oriented languages
14.3 Declarative languages
14.4 Language design
14.5 Implementation considerations
14.6 Development methods
14.7 Conclusions
Summary
Bibliography
Appendices
1 Language summaries
2 Language texts
Index
Preface to the third edition
In this book we consider the principal programming language concepts and show ho
they are dealt with in object-oriented languages such as Java and Delphi, in tradition
procedural languages such as Pascal, C and Fortran, in hybrid object-oriented or ohjec
based languages such as C++ and Ada 95, in functional languages such as ML and
logic languages like Prolog.
Theprogramminglanguagescenehas always been bedevilledby protagonists pushi
their favourite language. This often leads to a reluctance to examine rival languag
and to a 'love me, love my language' approach. The lack of a scientific approach
languages tends to emphasise the differences between them, even when these are qu
minor. Our approach is to find common ground between languages and to identi
the underlying principles. Although the top-level organisation of a program writt
in an object-oriented language is different from that of one written in a procedur
language, their underlying principles are the same. Similarly, although the approa
.of logic languages and functional languages is different from that of procedural a
object-oriented languages, there are many areas of similarity, and seeing these helps
to understand the differences better.
This approach is important at the present time when there are major and importa
controversies as to which way we should be heading. To what extent is it worthwh
developing new versions of the old faithfuls as has happened with Fortran 90 and Obje
Oriented Cobol? Should we standardise instead on modem object-oriented languag
like Java? It is certainly the case that procedural languages have proved themselv
extremely resilient and have been given a new lease of life by the incorporation
object-oriented features as has happened with C++, Ada 95 and Object Pascal. Wh
is going to be the future position of functional and logic languages? What effect w
new hardware designs and the growth of the Internet have on programming language
Although it is likely that many of these issues will not be resolved for many years, it
xii Preface to the third edition
Intended audience
Although this bookis intended primarily as a student text for a comparative language or
language concepts course, we hope that it will also be read by practising computer pro-
Preface to the third edition x
Chapter 10 Logic programming This deals with logic programming and is mainly
concerned with the language Prolog.
Chapter 11 Concurrency and networking This describes how concurrency ishan-
dled in Ada 95 and Java and how these languages deal with inter-process communi-
cation and synchronisation. Applets, CGI scripts and distributed programming are
then discussed.
Chapter 12 Syntax and semantics This describes how the syntax of programming
languages can be described formally in BNF and outlines two approaches, denota-
tional and axiomatic semantics, for fonndly describing the semantics of program-
ming language constructs.
Chapter 13 Input, output and GUIs This describes both traditional text-basedin-
put and output and the now standard approach of graphical user interfaces.
Chapter 14 The future This reviews the present situation and attempts to predict
the direction in which language design is likely to go.
Appendix 1 Language summaries This summarises the features of the principal
languages dealt with in the text.
Appendix 2 Language texts This gives a11 annotated bibliography for a wide range
of programming languages.
Chapters 1-6 introduce the basic concepts and are best read in the given order, while
Chapters 7-13 build on earlier material and, as they are largely self-contained, can be
takenin any order. Each chapter contains a synopsis, outlining the major topics to be
covered, a concise end-of-chapter summary, exercises and an annotated bibliography.
Solutions to selected exercises arc given at thc end of the hook.
Finally we should make clear what this book is not. It is not a language reference
manual or a text on language implementation. We make no attempt to teach any pastic-
ular language, but the annotated bibliography at the end of the book gives suggestions
for further reading in all the languages covered. It is also not a book on the principles of
program construction, although throughout the book we view each language construct
from the point of view of whether or not it helps or hinders the construction of readable
and reliable programs.
Acknowledgements
We would like to thank colleagues in the Computing Science Department at the Uni-
versity of Stirling, in particular Alan Hamilton, Simon Jones, Sam Nelson, Charles
Rattray and Leslie Smith. They have acted as an ideal sounding board and their helpful
criticisms of various chapter drafts have prevented us from straying too far into error.
In addition, we would like to thank Kate Brewin of Pearson Education for her help
and encouragement.
Robert Clark
Stirling, June 2000
Introduction
1.1 The diversity of languages
1.2 The software development process
1.3 Language design
1.4 Languages or systems?
1.5 The lexical elements
maintenance
Development models
It is important to realise that the software development process is iterative, not seque
tial. Therefore, knowledge gained at any one of the stages outlined can (and should) b
used to give feedback to earlier stages. The traditional approach is to treat the differe
stages in thedevelopmentprocess as being self-contained and this has led to the waterfa
model of software development shown in Figure 1.1.
However, there has been increasing acceptance of the idea that an incremental an
iterative approach is much more realistic. Central to this approach is the idea of ris
management. Every time we make a decision, there is the possibility that we get
wrong. Wetherefore wantto have continual feedhackto show up possible errors becau
the longer an error remains undetected, the more expensive it will be to put right. Th
led to the spiral model shown in Figure 1.2 (Boehm, 1988). We start at the centre of th
spiral and go repeatedly through the different stages as our systemis built incrementall
Many modem languages are object-oriented and this has led to the creation
object-oriented development methods. In other development methods, there is a cle
distinction in the techniques used in specification, design and implementation. Howeve
in object-oriented development, a problem can be understood and a solution designe
and then implemented using the same framework of a set of communicating objec
The object-oriented development process is therefore well suited to an incremental an
iterative approach. At any given stage, different objects can be described at differe
levels of abstraction. As the iterative development process continues, we incremental
add more detail to the object descriptions.
The need for a notation in which a specification or design can he written dow
Introduction
has led to the development of both specification and program design languages. Such
languages are at a higher level of abstraction and give fewer details than implementation
languages. Many specification languages are mathematical in form and are amenable to
prooftechniques. However, languages of this type are outside the scope of this book and
so we only look at what are conventionally considered to be implementation languages,
although some functional languages have been used as executable specification lan-
guages.
Another approach is to use graphical notations to capture the requirements and
represent designs. Examples of diagrams that occur in many different development
methods are data flow diagrams, entity relationship diagrams, state transition diagrams
and message sequence charts. A problem is that each development method can use its
own set of diagram notations which, although they arerepresentingmuchthe same thing,
can differ in detail. This situation is far from satisfactory as it can suggest differences
in the development process that do not really exist. In object-oriented development,
a standard notation called the Unified Modeling Language (UML) has been adopted
so that different methods now use a common notation (Booch et al., 1998). There are
several different kinds of diagram in UML, but the single most important is the class
diagram which shows the classes involved in an object system and their associations.
An example class diagram is shown in Chapter 8.
The use of a systematic software development process has greatly influenced both
language design and how languages are used. For example, Pascal was designed to
support the ideas of structured programming. The problems of constructing large
systems and of program maintenance led to the introduction of language feahues that
allow large systems to be broken down into self-contained modules. Packages in Ada
and classes in object-oriented languages satisfy that need. It is clear, therefore, that
programming languages do not exist in a vacuum; rather, the design of modern languages
is a direct response to the needs and problems of the software development process.
Language design
a
Language design
Most widely used programming languages are imperative; examples are Fortra
COBOL, C, C++, Pascal, Ada and Java. A program written in an imperative langua
achieves its effect by changing the value of variables or the attributes of objects b
means of assignment statements. Until quite recently, most widely used imperati
languages were procedural, that is their organisation was centred around the definiti
of procedures. Many .procedural languages have now been extended to include objec
nrientedfeatures (C by C++, Pascal by Delphi, Adaby Ada95, COBOLby OOCOBO
Basic by Visual Basic) while other neW.purely object-oriented languages such as Eif
and Java have been designed. Object-oriented programs are organised as a set of objec
which communicate with one another through small strictly defined interfaces.
Other approaches to language design include functional languages (such as pu
Lisp and ML) and logic languages (such as Prolog). These alternative approaches a
dealt with in Chapters 9 and 10 respectively.
The p r i m q purpose of a programming language is to support the constmcti
of reliable software. Hence, in most modem languages, type checking takes place
compile time, which is a considerable help in catching logical errors before the progra
is run. It is also important that a language is user friendly so that it is straightforward
design, write, read, test, m, document and modify programs written in that languag
To understand how these objectives may be achieved, the issues of language desig
can be divided into several broad categories:
expressive power,
slmpl~cityand orthogonality,
implementation,
a error detection and correction.
"correctness and standards
Expressive power
A programming language with high expressive power enables solutions to be express
in terms of the problem being solved rather than in terms of the computer on whi
the solution is to be implemented. Hence, the programmer can concentrate on proble
solving. Such a language should provide a convenient notation to describe both alg
rithms and data stmctures in addition to supporting the ideas of structured programmin
and modularisation.
Another aspect of expressive power is the number of types provided together wi
their associated operations. Instead of providing a large number of built-in types, mo
modem languages provide facilities, such as the Adapackage or the C++ and Java cla
for defining new types, called abstract data types. Such languages can then provide
wide range of predefined types by means of standard libraries which the programm
can use to build new types for the problem in hand. When a language, together wi
its standard libraries, does not include a suitable range of types and operations, th
the programmer generally has to provide these by declarations, thereby distracti
5 Introduction
the programmer's attention to the lower level aspects of solving the problem. Often,
languages may have high expressive power in some areas, but not in others; for example,
Ada has a range of numerical operations that give it expressive power for numerical
work, but it is less effective in data processing applications.
Also included under the heading of expressive power is readability; that is, the ease
with which someone familiar with the language can read and understand programs
written by other people. Readability is considerably enhanced by a well-designed
comment facility, and good layout and naming conventions. In practice, it should be
possible to write programs that can act, to anextent, as their own documentation, thereby
making maintenance and extension of the pregram much easier.
object. We therefore have the same syntax meaning different things. Although this i
inconsistent, it can be argued that inventing new syntax to make the distinction clea
would have just complicated matters.
Implementation
Execution of a program written in an imperative language, such as Pascal, Ada or C++
normally takes place by translating (compiling) the source program into an equivalen
machine code program. This machine code program is then executed. The ease wit
which a language can be translated m d the efficiency of the resulting code can b
major factors in a language's success. Large languages, for example, have an inheren
disadvantage in this respect because the compiler will, almost inevitably, be large, slo
and expensive.
An alternative to compiling a source program is to use an interpreter. An interprete
can directly execute a source program, hut what is more commonis for a source program
to be translated into some intermediate form which is then executed by the interprete
The interpreter can be said to implement a virtual machine. Executing a program
under the control of an interpreter is much slower than running the equivalent machin
code program, but does give much more flexibility at rnn time. The added flexibili
is important in languages whose main purpose is symbolic manipulation rather tha
numerical calculation. Examples of such languages are the string processing languag
SNOBOL4, the object-oriented language Smalltalk, the functional language Lisp, th
logic language Prolog and the scripting language Perl.
The use of an interpreter also supports an interactive programming environmen
in which programs may be developed incrementally. When developing a Lisp program
for example, a programmer can interact directly with the Lisp interpreter and type
the definition of functions followed by expressions which call these functions. Th
expressions are immediately executed and the results made available. This allows th
early detection, and easy correction, of logical errors. Once the complete program ha
been developed, it can be compiled so that it will run faster.
Java is an imperative language and so we would expect that it would normal
he compiled into machine code. However, that is not the case; Java programs a
interpreted. An exciting use of Java is to animate web pages. A person can download
.web page which contains a Java applet (a small application) and, using a Java-enable
web browser such as Netscape or Internet Explorer, can run the applet. To achieve thi
it must he possible for a Java program to be translated on one computer and to ru
on a different kind of computer and the easiest way of doing this is to translate Jav
source programs into code for a Java virtual machine. Java-enabled browsers provid
interpreters for the Java virtual machine.
Some language designers, notably Wirth the designer of Pascal and Modula-2, hav
made many of their design decisions on the basis of the ease with which a feature ca
be compiled and executed efficiently. One of the many advantages of having a clo
working relationship between the language design and language implementation team
is that the designers can obtain early feedback on constructs that are causing troubl
Often, features that are difficult to translate are also difficult for human programme
to understand. Algol 68 is a prime example of a language that had a lack of success du
B Introduction
to the fact that it was designed by a committee who largely ignored inlplementation
considerations, as they felt that such considerations would restrict the ability to produce
a powerful language. In contrast, the implementation of C, C++, Pascal ;md Java went
hand in hand with their design and the Ada design team was dominated by language
implementers.
However, it is necessary to achieve a proper balance between the introduction of
powerful new features and their ease of implementation. I S 0 Standard Pascal, for
example, has features, such as procedures being able to accept array parameters of
differing lengths, which were omitted from the original version of the language on the
grounds that they were too expensive to implement.
An impoaant feature of programs that use graphical user interfaces is that they are
event driven. They wait for some user event such as the click of a mouse over the
representation of a button on the screen, handle that event and then wait for the next
user event to occur. This leads to a very different program structure from that provided
by traditional programming languages. Writing event driven programs is difficult, but is
dealt with in languages such as Java, Visual Basic and Delphi by most of the work being
done behind the scenes. This allows the programmer to work at a very high level of
abstraction and not worry about implementation details. With earlier languages, event
handling had to be explicitly programmed. This is therefore another example of where
the distinction between a language and its supporting environment has become blurred.
Character set
The character set can be thought of as containing the basic building blocks of a pro-
gramming language - letters, digits and special characters such as arithmetic operators
and punctuation symbols. Two different approaches were taken when deciding the
character set to be used in early languages. One is to choose all the characters deemed
necessary. This is the approach taken with APL and Algol 60, but it has the drawback
that either special input/output equipment has to be used or changes have to be made
to the published language when it is used on a computer.
The other approach is to use only the characters commonly available with current
input and output devices. Hence, the character set of early versions of Fortran was
restricted by the 64 characters available with punched cards while Pascal initially was
constrained by the character set available with the CDC 6000 series computer on which
it was first implemented.
Since the early 1970s, most input and output devices have supported internationally
accepted character sets such as ASCII (American Standard Code for Information
Interchange) and this has been reflected in the character sets of languages. The ASCII
character set has 128 characters of which 95 are printable; the remaining characters are
special control characters. The printable characters are the upper and lower case letters,
digits, punctuation characters, arithmetic operators and three different sets of brackets
0,[I and 1). Composite symbols are used to extend the range of symbols available.
Commonly used examples are the relational operators <= and >= and the assignment
operator :=used in the Algol family of languages.
More recently, the Unicode character set has been created to give a much larger
range of characters. Each Unicode character occupies 16 bits rather than the 8 used
with ASCII characters. Java uses the Unicode character set.
The lexical elements 1
Comments
Almost all languages allow comments, thereby making the program more readi
understood by the human reader. Such comments are, however, ignored by the compile
In early languages such as Fortran, which has a fixed format of one statement per lin
12 Introduction
comments are terminated by the end of a line. In Fortran's case, the comment lines were
started by a C in column 1. A similar method is used in other early languages such as
COBOL and SNOBOU.
Algol 60 uses a different method for comments: they begin with the reserved word
connnent and terminate with a semi-colon. However, the problem with this method is
that programmers often fail to terminate comments correctly. Consequently, the com-
piler, interpreting the program exactly, incorporates the next declaration or statement
into the comment. Errors caused in this way are difficult to find as the error message, if
one is generated, is usually quite unrelated to the actual error.
Most later languages enclose comments iff brackets. Pascal, for example, uses either
( * and * ) or [ and ] while C uses / * and * / . But this approach still leaves the problem
of terminating a comment unresolved. Some compilers alleviate this problem by giving
a warning if a statement separator - that is, a semi-colon - occurs within a comment.
Ada, in contrast, commences a comment wilh two hyphens and ends it by the end of
a line, so reverting to the methods of the earliest high-level languages. In C++ and
Java, the programmer can either use C style comments or start a comment by / / and
terminate it by the end of a line.
The problem of failing to properly terminats acomment is largely solved by integrated
development environments (IDES) which automatically colour-code different parts of
the program. When a comment is in a different colour, it is obvious when it has not
been properly terminated.
Summary
( Bibliography )
The approach taken in this book to focus op language concepts and show how these
concepts are realised in different programming languages is similar to that adopted by
Ghezzi and Jazayeri (1997) and Sebesta (1998). The hook by Sethi (1996) also takes
this approach, but is more theoretical.
The alternative approach of having separate chapters on the main programming
languages has been adopted by MacLennan (1987) and Friedman (1991). Pratt and
Zelkowitz (1996), on the other hand, has combined both approaches: the language
features are discussed in the first part of the book while the second part is devoted to
individual languages. The result is comprehensive, although it leads to a very large
text. Both F'ratt and MacLennan also contain a large amount of material on language
implementation.
Boehm, B.W. (1988). 'A Spiral Mode1 of Software Development and Enhancement'
Computer, 21(5), 61-72.
Booch, G., Rumhaugh, J. and Jacobson, I. (1998). The Un$ied Modeling Language
User Guide. Addison-Wesley.
Friedman, L.W. (1991). Comparative Programming Languages. Prentice-Hall.
Ghezzi, C . and Jazayeri, M. (1997). Programming Language Concepts (Third Edition).
John Wiley & Sons.
MacLennan, B.J. (1987). Principles of Programming Languages (Second Edition).
Holt, Rinehart and Winston.
F'ratt, T.W. and Zelkowitz,M. (1996). Programming Languages: Design andlmplement-
atidn (Third Edition). Prentice-Hall.
Sebesta, R. (1998). Concepts of Programming Languages (Fourth Edition). Addison-
Wesley.
Sethi, R. (1996). Programming Languages (Second Edition). Addison-Wesley.
Wirth, N. (1975). 'On the Design of Programming Languages', Z F I P 74, pp. 386-393,
North-Holland.