Documente Academic
Documente Profesional
Documente Cultură
Simply stated, a compiler is a program that reads a program written in one language-the
source language-and translates it into an equivalent program in another language-the target language
(see fig.1) As an important part of this translation process, the compiler reports to its user the
presence of errors in the source program.
Phases of a Compiler
1. Lexical analysis (“scanning”)
o Reads in program, groups characters into “tokens”
2. Syntax analysis (“parsing”)
o Structures token sequence according to grammar rules of the language.
3. Semantic analysis
o Checks semantic constraints of the language.
4. Intermediate code generation
o Translates to “lower level” representation.
5. Program analysis and code optimization
2
Conceptually, a compiler operates in phases, each of which transforms the source program
from one representation to another.
The first three phases, forms the bulk of the analysis portion of a compiler. Symbol table
management and error handling, are shown interacting with the six phases.
An essential function of a compiler is to record the identifiers used in the source program and collect
information about various attributes of each identifier. A symbol table is a data structure containing a
record for each identifier, with fields for the attributes of the identifier. The data structure allows us to
find the record for each identifier quickly and to store or retrieve data from that record quickly. When
an identifier in the source program is detected by the lex analyzer, the identifier is entered into the
symbol table.
Each phase can encounter errors. A compiler that stops when it finds the first error is not as
helpful as it could be.
The syntax and semantic analysis phases usually handle a large fraction of the errors detectable by the
compiler. The lexical phase can detect errors where the characters remaining in the input do not form
any token of the language. Errors when the token stream violates the syntax of the language are
determined by the syntax analysis phase. During semantic analysis the compiler tries to detect
constructs that have the right syntactic structure but no meaning to the operation involved.
As translation progresses, the compiler’s internal representation of the source program changes.
Consider the statement,
The lexical analysis phase reads the characters in the source pgm and groups them into a stream of
tokens in which each token represents a logically cohesive sequence of characters, such as an
identifier, a keyword etc. The character sequence forming a token is called the lexeme for the token.
Certain tokens will be augmented by a ‘lexical value’. For example, for any identifier the lex analyzer
generates not only the token id but also enter s the lexeme into the symbol table, if it is not already
present there. The lexical value associated this occurrence of id points to the symbol table entry for
this lexeme. The representation of the statement given above after the lexical analysis would be:
Syntax analysis imposes a hierarchical structure on the token stream, which is shown by syntax trees
(fig 3).
After syntax and semantic analysis, some compilers generate an explicit intermediate representation
of the source program. This intermediate representation can have a variety of forms.
id1: = temp3
4
Code Optimisation
The code optimization phase attempts to improve the intermediate code, so that faster running
machine codes will result. Some optimizations are trivial. There is a great variation in the amount of
code optimization different compilers perform. In those that do the most, called ‘optimising
compilers’, a significant fraction of the time of the compiler is spent on this phase.
Code Generation
The final phase of the compiler is the generation of target code, consisting normally of
relocatable machine code or assembly code. Memory locations are selected for each of the variables
used by the program. Then, intermediate instructions are each translated into a sequence of machine
instructions that perform the same task. A crucial aspect is the assignment of variables to registers.
Phases
Compil
temp3 := id2 + temp2
syntax analyzer
of a
The
id1 := temp3
er
:=
id1 +
MOVF id3, R2
MULF #60.0, R2
id2 * MOVF id2, R1
ADDF R2, R1
id3 inttoreal MOVF R1, id1
60
6)What are roles and tasks of a lexical analyzer?
Main Task: Take a token sequence from the scanner and verify that it is a syntactically correct
program.
Secondary Tasks:
o Process declarations and set up symbol table information accordingly, in preparation
for semantic analysis.
o Construct a syntax tree in preparation for intermediate code generation.
o Define Context free grammar.
o Context-free Grammars
o A context-free grammar for a language specifies the syntactic structure of programs in that
language.
o Components of a grammar:
o a finite set of tokens (obtained from the scanner);
6
Example of CFG :
E ==>EAE | (E) | -E | id
A==> + | - | * | / |
Where E,A are the non-terminals while id, +, *, -, /,(, ) are the terminals.
Parser obtains a string of tokens from the lexical analyzer and verifies that it can be generated by
the language for the source program. The parser should report any syntax errors in an intelligible
fashion.
1.Top down parser: which build parse trees from top(root) to bottom(leaves)
2.Bottom up parser: which build parse trees from leaves and work up the root.
7
Therefore there are two types of parsing methods– top-down parsing and bottom-up parsing.
E ::= E ”+” T | T
T ::= T ”_” F | F
F ::= ”1” | ”(” E ”)”
8) What is left recursion? How it is eliminated?
A à αβ1 | αβ2
A à αA’
A’ à β1 | β2
S à aABe
A à Abc | b
B -> d
abbcde
aAbcde
aAde
aABe
S
S rm
=> aABe rm
=>aAde rm
=>aAbcde rm
=> abbcde
• Repeat the following process, starting from string of tokens until obtain start symbol:
– Locate handle in current right-sentential form
– Replace handle with left side of appropriate production
• Two problems that need to be solved:
– How to locate handle
– How to choose appropriate production
11
Shift-Reduce Parsing
• Data structures include a stack and an input buffer
– Stack holds grammar symbols and starts off empty
– Input buffer holds the string w to be parsed
• Parser shifts input symbols onto stack until a handle β is on top of the stack
– Handle is reduced to the left side of appropriate production
– If stack contains only start symbol and input is empty, this indicates success
Actions of a Shift-Reduce Parser
• Shift – the next input symbol is shifted onto the top of the stack
• Reduce – The parser reduces the handle at the top of the stack to a nonterminal (the left
side of the appropriate production)
• Accept – The parser announces success
• Error – The parser discovers a syntax error and calls a recovery routine
• If operator θ1 has higher precedence than operator θ2, make θ1 ·> θ2 and θ2 <· θ1
• If θ1 and θ2 are of equal precedence:
– If they are left associative, make θ1 ·> θ2 and θ2 ·> θ1
14
i
+ - * / ^ ( ) $
d
f 2 2 4 4 4 0 6 6 0
g 1 1 3 35 5 0 5 0
28) How precedence functions are constructed?
i
+ * $
d
f 2 4 4 0
g 1 3 5 0
29) How error recovery is enforced in operator precedence parsers?
Detecting and Handling Errors
• Errors can occur at two points:
– If no precedence relation holds between the terminal on top of stack and current
input
– If a handle has been found, but no production is found with this handle as right
side
• Errors during reductions can be handled with diagnostic message
• Errors due to lack of precedence relation can be handled by recovery routines specified in
table
32) Explain LR parsing Algorithm with diagrams. For a given grammar and parsing table
Tabulate the moves of LR parser for a given input string id * id + id.
Model of LR Parser
(1) E à E + T
(2) E à T
(3) T à T * F
(4) T à F
(5) F à (E)
Moves of LR parser on id * id + id
A Predictive Parser
INPUT: id + id id $ OUTPUT:
E
T E’
STACK: T
F
Predictive Parsing
F T’
E’
T’ Program
E’
$
$
PARSING
TABLE: (Aho,Sethi,
Ullman,
pp. 186)