Compiler Course: Lexical Analysis
Compiler Course: Lexical Analysis
Compiler Course: Lexical Analysis
Lexical Analysis
Outline
• Role of lexical analyzer
• Specification of tokens
• Recognition of tokens
• Lexical analyzer generator
• Finite automata
• Design of lexical analyzer generator
The role of lexical analyzer
token
Source Lexical To semantic
program Parser analysis
Analyzer
getNextToken
Symbol
table
Why to separate Lexical analysis and
parsing
1. Simplicity of design
2. Improving compiler efficiency
3. Enhancing compiler portability
Tokens, Patterns and Lexemes
• A token is a pair a token name and an optional
token value
• A pattern is a description of the form that the
lexemes of a token may take
• A lexeme is a sequence of characters in the
source program that matches the pattern for a
token
Example
• Example:
letter_ -> A | B | … | Z | a | b | … | Z | _
digit -> 0 | 1 | … | 9
id -> letter_ (letter_ | digit)*
Extensions
• One or more instances: (r)+
• Zero of one instances: r?
• Character classes: [abc]
• Example:
– letter_ -> [A-Za-z_]
– digit -> [0-9]
– id -> letter_(letter|digit)*
Recognition of tokens
• Starting point is the language grammar to
understand the tokens:
stmt -> if expr then stmt
| if expr then stmt else stmt
|Ɛ
expr -> term relop term
| term
term -> id
| number
Recognition of tokens (cont.)
• The next step is to formalize the patterns:
digit -> [0-9]
Digits -> digit+
number -> digit(.digits)? (E[+-]? Digit)?
letter -> [A-Za-z_]
id -> letter (letter|digit)*
If -> if
Then -> then
Else -> else
Relop -> < | > | <= | >= | = | <>
• We also need to handle whitespaces:
ws -> (blank | tab | newline)+
Transition diagrams
• Transition diagram for relop
Transition diagrams (cont.)
• Transition diagram for reserved words and
identifiers
Transition diagrams (cont.)
• Transition diagram for unsigned numbers
Transition diagrams (cont.)
• Transition diagram for whitespace
Architecture of a transition-
diagram-based lexical analyzer
TOKEN getRelop()
{
TOKEN retToken = new (RELOP)
while (1) { /* repeat character processing until a
return or failure occurs */
switch(state) {
case 0: c= nextchar();
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);
}
Lexical Analyzer Generator - Lex
lex.yy.c
C a.out
compiler
Sequence
Input stream a.out
of tokens
Structure of Lex programs
declarations
%%
translation rules Pattern {Action}
%%
auxiliary functions
Example
%{
Int installID() {/* funtion to install the
/* definitions of manifest constants
lexeme, whose first character is
LT, LE, EQ, NE, GT, GE, pointed to by yytext, and whose
IF, THEN, ELSE, ID, NUMBER, RELOP */ length is yyleng, into the symbol
%} table and return a pointer thereto
*/
/* regular definitions }
delim [ \t\n]
ws {delim}+ Int installNum() { /* similar to
installID, but puts numerical
letter [A-Za-z]
constants into a separate table */
digit [0-9]
}
id {letter}({letter}|{digit})*
number {digit}+(\.{digit}+)?(E[+-]?{digit}+)?
%%
{ws} {/* no action and no return */}
if {return(IF);}
then {return(THEN);}
else {return(ELSE);}
{id} {yylval = (int) installID(); return(ID); }
{number} {yylval = (int) installNum(); return(NUMBER);}
…
Finite Automata
• Regular expressions = specification
• Finite automata = implementation
• If end of input
– If in accepting state => accept, othewise => reject
• If no transition possible => reject
27
Finite Automata State Graphs
• A state
• An accepting state
a
• A transition
28
A Simple Example
• A finite automaton that accepts only “1”
1
0 0
1
1
31
And Another Example
• Alphabet still { 0, 1 }
1
33
Deterministic and
Nondeterministic Automata
• Deterministic Finite Automata (DFA)
– One transition per input per state
– No -moves
• Nondeterministic Finite Automata (NFA)
– Can have multiple transitions for one input in a
given state
– Can have -moves
• Finite automata have finite memory
– Need only to encode the current state
34
Execution of Finite Automata
• A DFA can take only one path through the
state graph
– Completely determined by input
35
Acceptance of NFAs
• An NFA can get into multiple states
1
0 1
• Input: 1 0 1
36
NFA vs. DFA (1)
• NFAs and DFAs recognize the same set of
languages (regular languages)
37
NFA vs. DFA (2)
• For a given language the NFA can be simpler
than the DFA
1
0 0
NFA
0
1 0
0 0
DFA
1
1
38
Regular Expressions to Finite
Automata
• High-level sketch
NFA
Regular
expressions DFA
Lexical Table-driven
Specification Implementation of DFA
39
Regular Expressions to NFA (1)
• For each kind of rexp, define an NFA
– Notation: NFA for rexp A
A
• For
• For input a
a
40
Regular Expressions to NFA (2)
• For AB
A
B
• For A | B
B
A
41
Regular Expressions to NFA (3)
• For A*
A
42
Example of RegExp -> NFA
conversion
• Consider the regular expression
(1 | 0)*1
• The NFA is
C 1 E
1
A B
D
0 F
G H I J
43
Next
NFA
Regular
expressions DFA
Lexical Table-driven
Specification Implementation of DFA
44
NFA to DFA. The Trick
• Simulate the NFA
• Each state of resulting DFA
= a non-empty subset of states of the NFA
• Start state
= the set of NFA states reachable through -moves
from NFA start state
• Add a transition S a S’ to DFA iff
– S’ is the set of NFA states reachable from the
states in S after seeing the input a
• considering -moves as well 45
NFA -> DFA Example
C 1 E
1
A B
D
0 F
G H I J
0
0 FGABCDHI
0 1
ABCDHI
1
1 EJGABCDHI
46
NFA to DFA. Remark
• An NFA may be in many states at any time
48
Table Implementation of a DFA
0
0 T
0 1
S
1
1 U
0 1
S T U
T T U
U T U
49
Implementation (Cont.)
• NFA -> DFA conversion is at the heart of tools
such as flex or jflex
50