Introduction To Compiler Lexical Analysis Notes
Introduction To Compiler Lexical Analysis Notes
INRODUCTION TO COMPILING
Translator:
It is a program that translates one language to another.
Types of Translator:
1.Interpreter
2.Compiler
3.Assembler
1.Interpreter:
It is one of the translators that translate high level language to low level language.
2.Assembler:
It translates assembly level language to machine code.
3.Compiler:
It is a program that translates one language(source code) to another language (target
code).
Compiler Interpreter
It is a translator that translates high level to It is a translator that translates high level to low
low level language level language
It displays the errors after the whole program is It checks line by line for errors.
executed.
Examples: Basic, lower version of Pascal. Examples: C, C++, Cobol, higher version of
Pascal.
PARTS OF COMPILATION
Analysis part breaks down the source program into constituent pieces and creates an
intermediate representation of the source program.
Synthesis part constructs the desired target program from the intermediate representation.
source code
Analysis
intermediate code
Synthesis
object code
1) Structure editor:
rce program.
-creation and modification functions of an
ordinary text editor, but it also analyzes the program text, putting an appropriate
hierarchical structure on the source program.
le , it can supply key words automatically - while …. do and begin….. end.
2) Pretty printers :
An interpreter might build a syntax tree and then carry out the operations at the nodes as
it walks the tree.
eters are frequently used to execute command language since each operator
executed in a command language is usually an invocation of a complex routine such as an
editor or complier.
ANALYSIS OF THE SOURCE PROGRAM
Linear/Lexical Analysis :
grouped into
the following tokens:
i) The identifier1 ‘a’
ii) The assignment symbol (=)
iii) The identifier2 ‘b’
iv) The plus sign (+)
v) The identifier3 ‘c’
vi) The multiplication sign (*)
vii) The constant ‘2’
Syntax Analysis :
t is called parsing or hierarchical analysis. It involves grouping the tokens of the source
program into grammatical phrases that are used by the compiler to synthesize output.
a +
b *
c 2
syntax tree is the tree generated as a result of syntax analysis in which the interior
nodes are the operators and the exterior nodes are the operands.
Semantic Analysis :
checks the source programs for semantic errors and gathers type information for the
subsequent code generation phase. It uses the syntax tree to identify the operators and
operands of statements.
A Compiler operates in phases, each of which transforms the source program from one
representation into another. The following are the phases of the compiler:
Main phases:
1) Lexical analysis
2) Syntax analysis
3) Semantic analysis
4) Intermediate code generation
5) Code optimization
6) Code generation
Sub-Phases:
1) Symbol table management
2) Error handling
LEXICAL ANALYSIS:
tokens as output.
token stream as input from the lexical analyser of the compiler and generates
syntax tree as the output.
It is a tree in which interior nodes are operators and exterior nodes are operands.
Example: For a=b+c*2, syntax tree is
a +
b *
c 2
SEMANTIC ANALYSIS:
correct or not.
data types.
CODE OPTIMIZATION:
output.
result.
the identifier.
ta from
that record.
ERROR HANDLING:
To illustrate the translation of source code through each phase, consider the statement a=b+c*2.
The figure shows the representation of this statement after each phase:
a=b+c*2
Lexical analyser
id1=id2+id3*2
Syntax analyser
=
Symbol Table
id1 +
a id1
b id2 id2 *
c id3
id3 2
Semantic analyser =
id1 +
id2 *
id3 inttoreal
2
Intermediate code generator
temp1=inttoreal(2)
temp2=id3*temp1
temp3=id2+temp2
id1=temp3
Code optimizer
temp1=id3*2.0
id1=id2+temp1
Code generator
MOVF id3,R2
MULF #2.0,R2
MOVF id2,R1
ADDF R2,R1
MOVF R1,id1
COUSINS OF COMPILER
1. Preprocessor
2. Assembler
3. Loader and Link-editor
PREPROCESSOR
A preprocessor is a program that processes its input data to produce output that is used as
input to another program. The output is said to be a preprocessed form of the input data, which is
often used by some subsequent programs like compilers.
They may perform the following functions :
1. Macro processing
2. File Inclusion
3. Rational Preprocessors
4. Language extension
1. Macro processing:
A macro is a rule or pattern that specifies how a certain input sequence should be mapped to
an output sequence according to a defined procedure. The mapping process that instantiates a
macro into a specific output sequence is known as macro expansion.
2. File Inclusion:
Preprocessor includes header files into the program text. When the preprocessor finds an
#include directive it replaces it by the entire content of the specified file.
3. Rational Preprocessors:
These processors change older languages with more modern flow-of-control and
datastructuring facilities.
4. Language extension :
These processors attempt to add capabilities to the language by what amounts to built-in
macros. For example, the language Equel is a database query language embedded in C.
ASSEMBLER
Assembler creates object code by translating assembly instruction mnemonics into
machine code. There are two types of assemblers:
-pass assemblers go through the source code once and assume that all symbols will
be defined before any instruction that references them.
-pass assemblers create a table with all symbols and their values in the first pass, and
then use the table in a second pass to generate code.
A loader is the part of an operating system that is responsible for loading programs in
memory, one of the essential stages in the process of starting a program.
GROUPING OF THE PHASES
Compiler passes
A collection of phases is done only once (single pass) or multiple times (multi pass)
program.
Several phases can be grouped into one single pass and the activities of these phases are
interleaved during the pass. For example, lexical analysis, syntax analysis, semantic analysis and
intermediate code generation might be grouped into one pass.
COMPILER CONSTRUCTION TOOLS These are specialized tools that have been developed for helping
implement various phases of a compiler. The following are the compiler construction tools:
1) Parser Generators:
-These produce syntax analyzers, normally from input that is based on a context-free
grammar.
-It consumes a large fraction of the running time of a compiler. -
Example-YACC (Yet Another Compiler-Compiler).
2) Scanner Generator:
-These generate lexical analyzers, normally from a specification based on regular expressions. -The
basic organization of lexical analyzers is based on finite automation.
3) Syntax-Directed Translation:
-These produce routines that walk the parse tree and as a result generate intermediate code. -
Each translation is defined in terms of translations at its neighbor nodes in the tree.
5) Data-Flow Engines:-It does code optimization using data-flow analysis, that is, the gathering of information
about how values are transmitted from one part of a program to each other part.
LEXICAL ANALYSIS
token
source lexical parser
program analyser
get next token
symbol
table
TOKENS
PATTERN:
A pattern is a description of the form that the lexemes of a token may take.
In the case of a keyword as a token, the pattern is just the sequence of characters that
form the keyword. For identifiers and some other tokens, the pattern is a more complex structure
that is matched by many strings.
Some tokens have attributes that can be passed back to the parser. The lexical analyzer
collects information about tokens into their associated attributes. The attributes influence the
translation of tokens.
5) Panic mode recovery: Deletion of successive characters from the token until error is
resolved.
INPUT BUFFERING
We often have to look one or more characters beyond the next lexeme before we can be sure
we have the right lexeme. As characters are read from left to right, each character is stored in the
buffer to form a meaningful token as shown below:
Forward pointer
A = B + C
We introduce a two-buffer scheme that handles large look aheads safely. We then
consider an improvement involving "sentinels" that saves time checking for the ends of buffers.
BUFFER PAIRS
::E::=::M:* C : * : : * : 2 : eof
lexeme_beginning
forward
Each buffer is of the same size N, and N is usually the number of characters on one disk
block. E.g., 1024 or 4096 bytes.
Using one system read command we can read N characters into a buffer.
If fewer than N characters remain in the input file, then a special character, represented
by eof, marks the end of the source file.
Two pointers to the input are maintained:
1. Pointer lexeme_beginning, marks the beginning of the current lexeme,
whose extent we are attempting to determine.
2. Pointer forward scans ahead until a pattern match is found.
Once the next lexeme is determined, forward is set to the character at its right
end.
The string of characters between the two pointers is the current lexeme.
After the lexeme is recorded as an attribute value of a token returned to the parser,
lexeme_beginning is set to the character immediately after the lexeme just found.
Advancing forward pointer:Advancing forward pointer requires that we first test whether we
have reached the end of one of the buffers, and if so, we must reload the other buffer from the
input, and move forward to the beginning of the newly loaded buffer. If the end of second buffer
is reached, we must again reload the first buffer with input and the pointer wraps to the
beginning of the buffer.
SENTINELS
determine what character is read. We can combine the buffer-end test with the test for the
current character if we extend each buffer to hold a sentinel character at the end.
am, and a natural
choice is the character eof.
: : E : : = : : M : * : eof C : * : : * : 2 : eof : : : eof
eof***
lexeme_beginning
forward
Note that eof retains its use as a marker for the end of the entire input. Any eof that
appears other than at the end of a buffer means that the input is at an end.
forward : = forward + 1;
if forward ↑ = eof then begin
if forward at end of first half then begin
reload second half;
forward := forward + 1
end
else if forward at end of second half then begin
reload first half;
move forward to beginning of first half
end
else /* eof within a buffer signifying end of input */
terminate lexical analysis
end
SPECIFICATION OF TOKENS
A string over an alphabet is a finite sequence of symbols drawn from that alphabet. A
In language theory, the terms "sentence" and "word" are often used as synonyms for
"string." The length of a string s, usually written |s|, is the number of occurrences of symbols in s.
For example, banana is a string of length six. The empty string, denoted ε, is the string of length
zero.
Operations on strings
1. A prefix of string s is any string obtained by removing zero or more symbols from the end of
string s.
2. A suffix of string s is any string obtained by removing zero or more symbols from the
beginning of s.
For example, nana is a suffix of banana.
4. The proper prefixes, suffixes, and substrings of a string s are those prefixes, suffixes, and
substrings, respectively of s that are not ε or not equal to s itself.
5. A subsequence of s is any string formed by deleting zero or more not necessarily consecutive
positions of s.
For example, baan is a subsequence of banana.
Operations on languages:
1.Union
2.Concatenation
3.Kleene closure
4.Positive closure
Here are the rules that define the regular expressions over some alphabet Σ and the languages that
those expressions denote:
1. ε is a regular expression, and L(ε) is { ε }, that is, the language whose sole member is the
empty string.
2. If ‘a’ is a symbol in Σ, then ‘a’ is a regular expression, and L(a) = {a}, that is, the language with
one string, of length one, with ‘a’ in its one position.
3. Suppose r and s are regular expressions denoting the languages L(r) and L(s). Then,
Regular set
There are a number of algebraic laws for regular expressions that can be used to
manipulate into equivalent forms.
For instance, r|s = s|r is commutative; r|(s|t)=(r|s)|t is associative.
Regular Definitions
dl → r 1
d2 → r2
………
dn → rn
Example: Identifiers is the set of strings of letters and digits beginning with a letter. Regular
definition for this set:
letter → A | B | …. | Z | a | b | …. | z |
digit → 0 | 1 | …. | 9
id → letter ( letter | digit ) *
Shorthands
Certain constructs occur so frequently in regular expressions that it is convenient to
introduce notational shorthands for them.
1. One or more instances (+):
- If r is a regular expression that denotes the language L(r), then ( r )+ is a regular expression that
denotes the language (L (r ))+
- Thus the regular expression a+ denotes the set of all strings of one or more a’s.
- The operator + has the same precedence and associativity as the operator *.
2. Zero or one instance ( ?):
- If ‘r’ is a regular expression, then ( r )? is a regular expression that denotes the language L( r )
U { ε }.
3. Character Classes:
- The notation [abc] where a, b and c are alphabet symbols denotes the regular expression a | b |
c.
- We can describe identifiers as being strings generated by the regular expression, [A-
Za-z][A-Za-z0-9]*
Non-regular Set A language which cannot be described by any regular expression is a non-regular set.
Example: The set of all strings of balanced parentheses and repeating strings cannot be described by a
regular expression. This set can be specified by a context-free grammar.
RECOGNITION OF TOKENS
term → id
| num
where the terminals if , then, else, relop, id and num generate sets of strings given by the
following regular definitions:
if → if
then → then
else → else
relop → <|<=|=|<>|>|>=
id → letter(letter|digit)*
num → digit+ (.digit+)?(E(+|-)?digit+)?
For this language fragment the lexical analyzer will recognize the keywords if, then, else, as
well as the lexemes denoted by relop, id, and num. To simplify matters, we assume keywords are
reserved; that is, they cannot be used as identifiers.
Transition diagram
A transition diagram is similar to a flowchart for (a part of) the lexer. We draw one for
each possible token. It shows the decisions that must be made based on the input seen.
The two main components are circles representing states (think of them as decision
points of the lexer) and arrows representing edges (think of them as the decisions made).
The transition diagram for relop is shown below.
1. The double circles represent accepting or final states at which point a lexeme has
been found. There is often an action to be done (e.g., returning the token), which
is written to the right of the double circle.
2. If we have moved one (or more) characters too far in finding the token, one (or
more) stars are drawn.
3. An imaginary start state exists and has an arrow coming from it to indicate where
to begin the process.
It is fairly clear how to write code corresponding to this diagram. You look at the first
character, if it is <, you look at the next character. If that character is =, you return
(relop,LE) to the parser. If instead that character is >, you return (relop,NE). If it is
another character, return (relop,LT) and adjust the input buffer so that you will read this
character again since you have not used it for the current lexeme. If the first character
was =, you return (relop,EQ).
Recognition of Reserved Words and Identifiers
Recognizing keywords and identifiers presents a problem . Usually, keywords like if or then are
reserved, so they are not identifiers even though they look like identifiers .
There are two ways that we can handle reserved words that look like iden tifiers:
1. Install the reserved words in the symbol table initially . A field of the
symbol -table entry indicates that these strings are never ordinary identi
fiers , and tells which token they represent . When we find an identifier , a call to
installlD places it in the symbol table if it is not already there and returns a pointer
to the symbol -table entry for the lexeme found . Of course , any identifier
not in the symbol table during lexical analysis cannot be a reserved word ,
so its token is id . The function getToken examines the symbol table entry
for the lexeme found , and returns whatever token name the symbol table
says.
2. Create separate transition diagrams for each keyword. Note that such a transition
diagram consists of states representing the situation after each successive
letter of the keyword is seen.
Recognition of Numbers
The transition diagram for token n u m b e r is shown in Fig. and is so far the most
complex diagram we have seen . Beginning in state 12, if we see a digit , we go to state 13.
In that state , we can read any number of additional digits . However , if we see anything but
a digit or a dot , we have seen a number
in the form of an integer ; 123 is an example . That case is handled by entering state 20,
where we return token n u m b e r and a pointer to a table of constants
where the found lexeme is entered . These mechanics are not shown on the
diagram but are analogous to the way we handled identifiers . If we instead see a dot in
state 13, then we have an "optional fraction ." State 14 is entered , and we look for one or
more additional digits ; state 15 is used for that purpose . If we see an E , then we have an
"optional exponent ," whose recognition is the job of states 16 through 19. Should we , in
state 15, instead see anything but E or a digit , then we have come to the end of the
fraction , there is no exponent , and we return the lexeme found , via state 21.
The transition diagram , shown in Fig , is for whitespace . In that diagram , we look for
one or more "whitespace" characters , represented by delim in that diagram — typically these
characters would be blank , tab , newline.
TOKEN getRelopO
{
TOKEN retToken = new (RELOP ) ;
while ( 1 ) { /* repeat character processing until a return
or failure occurs */
switch (state ) {
case 0: c = nextCharQ ;
if ( c == '<» ) state = 1;
else if ( c == '=' ) state = 5;
else if ( c == '>' ) state - 6;
else fail ( ) ; /* lexeme is not a relop */
break ;
case 1:
case 8 : retract ( ) ;
retToken .attribute = GT ;
return (retToken ) ;
Finite Automata is one of the mathematical models that consist of a number of states and
edges. It is a transition diagram that recognizes a regular expression or grammar.
The following steps are involved in the construction of DFA from regular expression:
i) Convert RE to NFA using Thomson’s rules
ii) Convert NFA to DFA
iii) Construct minimized DFA