Академический Документы
Профессиональный Документы
Культура Документы
Contents
y y y y y y y
Introduction The Scanner The Parser The Semantic Analyzer The Intermediate Code Generator The Optimizer The Code Generator
Introduction
What is a compiler?
y y
A recognizer (of some source language L). A translator (of programs written in L into programs written in some object or target language L').
source program --> COMPILER --> object program | --> error messages
A compiler is itself a program, written in some host language. (In cs536, students will implement a compiler for a simple source language using Java as the host language.) A compiler operates in phases; each phase translates the source program from one representation to another. Different compilers may include different phases, and/or may order them somewhat differently. A typical organization is shown below.
source code (sequence of characters) || || \/ ---------------------| lexical analyzer | | (scanner) | ---------------------|| || sequence of tokens
\/ ---------------------| syntax analyzer | | (parser) | ---------------------|| || abstract-syntax tree \/ ---------------------| semantic analyzer | ---------------------|| || augmented, annotated abstract-syntax tree \/ ---------------------| intermediate code | | generator | /\ ---------------------|| || FRONT END || intermediate code ---------------------------------\/ BACK END ---------------------|| | optimizer | \/ ---------------------|| || optimized intermediate code \/ ---------------------| code | | generator | ---------------------|| || \/ object program (might be assembly code or machine code)
The Scanner
The scanner is called by the parser; here's how it works:
y y y y
The scanner reads characters from the source program. The scanner groups the characters into lexemes (sequences of characters that "go together"). Each lexeme corresponds to a token; the scanner returns the next token (plus maybe some additional information) to the parser. The scanner may also discover lexical errors (e.g., erroneous characters).
The definitions of what is a lexeme, token, or bad character all depend on the source language.
Example Here are some Java lexemes and the corresponding tokens:
lexeme: 102 corresponding token: INT-LIT ; = index tmp 37
SEMI-COLON
ASSIGN
IDENT
IDENT
INT-LIT
Note that multiple lexemes can correspond to the same token (e.g., there are many identifiers). Given the source code:
position IDENT = initial + rate * 60 ;
The Parser
The parser:
y y
Groups tokens into "grammatical phrases", discovering the underlying structure of the source program. Finds syntax errors. For example, in Java the source code
position = * 5 ;
Might find some "static semantic" errors, e.g., a use of an undeclared variable, or variables that are multiply declared. Might generate code, or build some intermediate representation of the program such as an abstract-syntax tree.
Example
source code: position = initial + rate * 60 ;
= + / \ initial * / \ rate 60
Notes:
y y y
The interior nodes of the tree are operators. A node's children are its operands. Each subtree forms a "logical unit", e.g., the subtree with * at its root shows that because multiplication has higher precedence than addition, this operation must be performed as a unit (not initial+rate).
Abstract syntax tree after semantic analysis = (float) / \ / \ position + (float) (float) / \ / \ initial * (float) (float) / \ / \ rate intToFloat (float) | | 60 (int)
The Optimizer
The optimizer tries to improve code generated by the intermediate code generator. The goal is usually to make code run faster, but the optimizer may also try to make the code smaller. In the example above, an optimizer might first discover that the conversion of the integer 60 to a floating-point number can be done at compile time instead of at run time. Then it might discover that there is no need for "temp1" or "temp3". Here's the optimized code:
temp2 = rate * 60.0 position = initial + temp2