CSE 428: Lecture 1
Formal Definition Programming Languages
Why formal definitions
Natural languages are full of ambiguities. An example is the phrase:
This sentence in fact can be interpreted in different ways: does each boy
like a different girl or do they all like the same girl?
Another example is:
Again, several meanings are possible, depending on whether the rabbit
is a pet, or a dish, or a fur...
In the human-to-human communication, ambiguities in the language are
usually resolved by using additional knowledge (context, culture,...).
When we deal with computers, however, we cannot pretend them to have such
knowledge. Yet we want them to understand and interpret a program
according to the programmer's intentions. Therefore it is important that
programming languages be defined rigorously (i.e. formally) and leave no
room to ambiguity. It is essential that all the people which deal
with the language (implementers, tool-developers, users) attribute to each
sentence the same meaning.
The various levels of definition of a language
There are various levels of definition:
This term refers to the way a program is written, i.e. which sequences
of symbols are considered "legal" programs. It is obvious that in order
to give a rigorous meaning to sentences it is important first to establish
what these sentences can be and how are they constructed.
Usually the syntax is described by a context-free
grammar, which is a particularly simple kind of recursive definition.
The syntactical correctness of a program is
checked statically, i.e. before the execution (the common way of saying
is "at compile time"). The tool which does
this check is called parser.
The static semantics specifies additional restrictions to the set of legal
sentences. The word "semantics" here is misleading: the concept of static
semantics is more similar to syntax rather than to semantics.
The typical kind of restrictions specified by static semantics are those
which cannot be captured with a context-free grammar, like consistency
between the declaration of a variable and the way it is used in a program
(types). The rules of the static semantics
are usually defined in a formalism similar to the one used for specifying
the (dynamic) semantics. (This is the reason why the name "semantics" is
As for the syntax, also the correctness w.r.t. static semantics (static
correctness) is checked at compile-time. This check is called static
The reason for distinguishing two levels of static rules is convenience:
it is usually more convenient to keep the syntax simple so to have a more
efficient parsing, and to check the other static constraints in a separate
Semantics (or dynamic semantics)
Defines the meaning of programs, i.e. what should be the result (depending
on the data in input).
Various styles/formalisms have been proposed for describing the semantics:
meaning is defined by describing the way an abstract
machine interprets the program. There are two main kinds of description
in this style:
This formalism is the most popular, nowadays. It is simple enough to be
understood by the programmers and it is also the most appropriate as a
guide to implementation.
Big steps (or natural semantics)
Denotational. The meaning is defined
by mapping each construct/operator in the elements/functions of a certain
mathematical domain. This style is very elegant but too complicated for
the majority of programmers.
Axiomatic. The meaning of each sentence
is a logical assertion, relating the properties of the state before and
after the execution of the sentence. This formalism is used especially
in the development of systems for checking the dynamic correctness of programs,
but it is not so popular anymore since those systems are usually too complicated
to be really useful.