|
CS 3723
Programming Languages |
Contrasts
|
Contrasts:
- Syntax versus
Semantics.
- Syntax:
The word syntax when used in programming languages
refers to the appearance of a program.
During the semester we will be giving this vague
definition a precise, formal, mathematical (and very useful)
definition.
Our syntax will be what is called context-free syntax,
referring to a description of the correct appearance
of a program element that is independent of the context,
that is, independent of what comes before or after.
Thus a = b + 17; is a syntactically correct assignment
statement in most of our languages these days, but it is
incorrect if a and b are arrays or files or classes.
- Semantics:
The word semantics in programming languages
refers to the meaning of a program.
There are formal mathematical ways to define
semantics, but these are difficult and have not been
as successful as the definitions of syntax, so we
will use informal descriptions in this course.
- Run-time versus
Compile-time.
In this course, when applied to a "normal" programming
language, compile-time refers to the time and
actions taken during compilations, linking, and loading of a program:
everything before the actual execution.
Run-time refers to the time and actions taking
during the execution of a program.
In studying, and particularly in writing compilers, it
is very important to keep these two times straight.
It turns out that these issues can be confusing, and we
will see some of this in the course (on a small scale).
- Translation versus
Interpretation
For a program, translation means the process of
converting the program to another equivalent form.
When we are translating a program in a high-level
language into a lower-level language (one that is closer
to the machine), one uses the term compilation.
In the case of an "ordinary" compiled language, there are several distinct
phases:
- first the compile (= translation) phase,
at compile-time,
- then the process of getting ready for execution,
which may include linking and loading (also at
compile-time), and
- finally the execution phase,
at run-time.
The term interpretation refers to an equivalent
way to handle (execute) a program, where there is
no separate compile phase, but simply a single execution
or interpretation phase that does everything, during which the program
is directly executed. To say this differently, an
interpreter will take an input program, and directly
carry out the intent of the program, line-by-line,
without any compilation. A "pure" interpreter
has no compile-time, but just run-time.
For real programming languages, there are often
intermediate forms, where partial compilation occurs,
to translate the program into another form, and then
this other form might be interpreted (executed directly).
Whether a language is compiled or interpreted, or
what degree of intermediate form is used, has significant
implications:
- Compiled: extra compile time, runs faster,
often less flexible language.
- Interpreted: no compile time, runs slower,
often more flexible language.
- Example of Translation versus
Interpretation
Consider a program that calls for an addition, say like: a = a + b;
- Compiler: Here the compiler will output an
actual machine language "add" instruction. No add occurs
at compile-time. At run-time the add instruction will be
executed and the add operation will be carried out.
The compiler will decide at compile-time whether it is
adding integers or doubles or what, and will output the
proper add instruction. At run-time the correct type
of add will be hard-wired in so that it can be executed
very efficiently.
If the compiler encounters something like (8 + 5),
it can let this addition happen during run-time, or in some
cases it can improve run-time performance by moving the
addition back into compile time, that is, replacing the expression
with 13.
- Interpreter: Here the interpreter will read the
statement, will fetch values for a and b, and then will
add them, all at the same time. The machine language
"add" instruction that is used will be buried in the
code for the interpreter program. The interpreter
will be prepared to carry out a variety of adds, including
for integers and for doubles. During its processing
it will decide based on the types of a and b and will
select the correct add, all at run-time. Thus far more
is going on at run-time here than with a compiler.
Further Examples:
- Straight compiler: C++ or C.
These are the gold
standard for compiled languages that produce efficient programs
to run.
- Hybrid system:
Java Compiler and Virtual Machine.
Originally, the Java compiler translated Java code to byte code
This byte code was then interpreted by the Java virtual machine.
The result was fairly efficient, but not at all competitive with
C or C++. Now the Java virtual machine usually does on-the-fly
compilation of the byte code to machine
language, and execution can be comparable to C or C++
(though still off by a factor of 2 to 10).
- Straight (or "pure") interpreter: Ruby,
Python, etc.
These are examples of scripting languages. Examples also
include the old standby Perl, and many others. These have become
ever more important over the years. Originally they were always
interpreted, but now they are often compiled. They allow quick
implementation of complex tasks and are extremely powerful.
With such languages, systems programming tasks (for example)
which could be carried out in C, end up requiring far less time
to write and a far smaller program.
( Revision date: 2014-05-21.
Please use ISO
8601, the International Standard.)
|