A model of the phases of compilation:
In the lexical analysis or scanning phase, the compiler translates the stream of input characters into a sequence of lexemes. For each lexeme, the lexer produces a token like
In the syntax analysis or parsing phase, the compiler translates the stream of tokens into a syntax tree.
The semantic analyzer checks the program for semantic consistency. This includes type checking.
Compilers often generate a machine-language-like intermediate representation after semantic analysis.
Parallelism refers to the computer doing more than one thing simultaneously.
In instruction-level parallelism, the processor executes multiple operations simultaneously. This may be accomplished by the hardware determining that certain operations do not depend on one another, and therefore may be executed out of order without changing the result. From the programmer's point of view, all instructions are executed in sequence.
Very Long Instruction Word (VLIW) architectures such as Intel IA64 include explicit instruction that operate in parallel. For example, they might have instructions that operate on an entire vector of data simultaneously.
At the processor level, multiple threads of the same application may run on different processors. Such multithreading may be written explicitly by the programmer or else generated by the compiler.
Memory hierarchies refers to the multiple different types of memory available, each with its own size and speed. For example, registers, processor caches, physical memory, and finally secondary storage such as hard drives. Optimizing memory accesses involves satisfying as many memory accesses as possible from the fastest type of memory.
The Reduced Instruction-Set Computer (RISC) architectures supports fewer, simpler instructions, which are easier for compilers to optimize for. By contrast, Complex Instruction-Set Computer (CISC) architectures have more complex instructions, but it may be more efficient for compilers to decompose complex actions into sequences of simple instructions than to use the more complex ones. Modern architectures are all influenced by RISC.
If something in a language may be decided at compile time, then it is said to be static. If it can only be decided at runtime, then it is said to be dynamic.
A language uses static scope or lexical scope if the scope of a declaration can be decided by looking at the program code. Otherwise, the language uses dynamic scope, and a variable might at runtime refer to one of several declarations of the variable.
Dynamic scope resolution is needed for polymorphic procedures, unless the language can determine the type of arguments at compile time.
In this book, name and variable are distinguished: variable refers to the run-time location denoted by compile-time names. An identifier like
y is a string that may refer to some entity. A qualified name like
x.y is a name, but not an identifier.
The actual parameters of a procedure are those actually used in the call of the procedure. By contrast, the formal parameters of a procedure are those used in the definition of the procedure.
In call-by-value, the callee receives a copy of the value of its parameter, and typically cannot modify the source of that value. However, if a pointer is passed, the callee may dereference the pointer and modify the value in this way. This is also the case in C, C++, or Java when an array name is passed to a procedure: a pointer to the beginning of the array is the actual value passed.
In call-by-reference, callees receive a pointer to the value of the parameter.
In call-by-name, used in Algol 60, the callee acts as though the text of parameter value were used in place of the parameter's usage, as though the parameter were a macro substituting its value in. This is not used today.
|Alfred V. Aho||Author|
|Jeffrey D. Ullman||Author|
|Monica S. Lam||Author|
|Pearson Education, Inc.||Publisher|