All these programs require standard
C/C++ compiler and some may require
additional compiler tools LEX and YACC.
Dev-C++, LEX and YACC tools can be
downloaded from the following links.
Dev C++
Flex (Fast Lexical analyser)
Bison (Improved Yacc)
GNU C/C++ compiler is available on all
Linux systems. On ubuntu Linux system
directly flex and bison tools can be
installed using "apt". If any other
distribution is used follow suitable
instructions for installation of flex and
bison.
$ sudo apt install flex
$ sudo apt install bison
1. Meaning of [] (Square Brackets)
[] are used for character classes.
A character class means:
match any ONE character from the list
inside the brackets.
Examples:
[0-9] → any single digit
[a-z] → any lowercase letter
[+-] → either + or -
[abc] → a OR b OR c
Use [] when you want to match single
characters. 2. Meaning of {} (Curly
Braces)
2. {} are used to reference LEX
definitions (macros) you declared at the
top.
Example definitions:
digit [0-9]
num {digit}+
Here:
{digit} means: replace with [0-9]
{num} means: replace with {digit}
+, i.e., one or more digits
Use {} when you want to use a named
pattern defined earlier.
3. ? means “0 or 1 times” (optional)
It makes the preceding element
optional.
Optional sign in a number
[+-]?
Matches:
+
-
`` (nothing)
Used in LEX for signed numbers.
Example : Optional decimal part
[0-9]+(\.[0-9]+)?
Matches:
12
12.34
(Because (\.[0-9]+) may appear once or
not at all)
[Link]()
yylex() is the scanner function
generated by LEX.
When you run the program:
1. main() calls yylex()
2. yylex() reads input from stdin
3. It checks each line against the
rules
4. For every match:
o It executes the corresponding C
code block { … }
o Uses yytext to access the
matched token
5. Stops when input ends (Ctrl+D)
yytext
is a built-in character array that contains the
exact text matched by the current rule.
LEX automatically fills yytext with the
characters that matched your pattern.
You do not create it.
You do not modify it.
LEX handles it.
Example -1
Write a program in LEX to recognize
Floating point numbers
digit [0-9]
num {digit}+
snum [-+]?{num}
%{
#include<stdio.h>
/* Program to identify floating point
numbers
digit → single digit
num → sequence of digits (integer)
snum → optional sign + digits
*/ %}
%%
{ snum }[.]{ num }
{ printf("Floating point number: %s\n",
yytext); }
[.]{ num } { printf("Floating
point number: %s\n", yytext); }
{ snum }[.] { printf("Floating
point number: %s\n", yytext); }
[+-]?[.]{ num } { printf("Floating
point number: %s\n", yytext); }
/* Integers (not floating point) */
{snum} { /* Ignore integers
*/ }
/* Ignore spaces and newline */
[ \t\n]+ {;}
{ printf("Invalid token: %s\n", yytext); }
%%
int main() {
yylex();
return 0;
}
How to execute lex program
$lex example.l //[Link].c
program will be generated
$gcc [Link].c -o cexample -ll
$./ cexample
Example-2
Write a LEX program to recognize the
following tokens of a simple
programming language:
Keywords: if, then, else
Identifiers
Numbers (including real numbers
and exponential form)
Relational operators: <, <=, >, >=,
==, !=
Ignore whitespace characters
(spaces, tabs, newlines)
The program should also store
identifiers and numbers into a symbol
table using the functions installID() and
installNum().
Solution:
%{
/* Definitions / C prologue */
#include <stdio.h>
#include <stdlib.h>
/* token name constants */
#define LT 1
#define LE 2
#define EQ 3
#define NE 4
#define GT 5
#define GE 6
#define IF 10
#define THEN 11
#define ELSE 12
#define ID 20
#define NUMBER 21
/* yylval is typically provided by the
parser; here declare for demo */
extern int yylval;
/* prototypes for helper functions */
int installID(void);
int installNum(void);
%}
/* ---------- Definitions (named
regexes/macros) ---------- */
delim [ \t\n]
ws {delim}+
letter [A-Za-z]
digit [0-9]
id { letter } ( { letter } | { digit } )*
number { digit }+ ( \. { digit }+ ) ?
( [ Ee ] [ +- ]? { digit }+ )?
%%
{ws} { /* skip whitespace */
}
"if" { return(IF); } /*
keyword if */
"then" { return(THEN); } /*
keyword then */
"else" { return(ELSE); } /*
keyword else */
{id} { yylval = installID();
return(ID); }
{number} { yylval =
installNum(); return(NUMBER); }
/* Any other single character (fallback)
*/
. { printf("Unknown token:
%s\n", yytext); }
%%
/* ---------- C helper functions ---------- */
int installID(void) {
/* Example implementation (very
simple)
Normally: insert lexeme (yytext,
yyleng) in symbol table and return
pointer/index.
Here we just print and return 0 for
demo. */
printf("Installing ID: %.*s\n", yyleng,
yytext);
return 0;
}
int installNum(void) {
/* Convert yytext to number and store
in some table; return index/pointer.
Here we just print it and return 0. */
printf("Installing NUMBER: %.*s\n",
yyleng, yytext);
return 0;
}
int main(void) {
yylex();
return 0;
}
Explanation
LEX processes each identifier through
the rule:
{id} { yylval = installID(); return(ID); }
[Link] lexeme:
x
yytext = "x"
installID() → stores "x" in symbol
table index 0
yylval = 0
returns token ID
Output:
Token = ID, Lexeme = x, yylval(symbol
index) = 0
2. Next lexeme:
y
"y" not found, added at index 1
yylval = 1
Output:
Token = ID, Lexeme = y, yylval(symbol
index) = 1
3. Next lexeme:
x
"x" already in table at index 0
yylval = 0
Output:
Token = ID, Lexeme = x, yylval(symbol
index) = 0
4. sum
added at index 2
yylval = 2
Token = ID, Lexeme = sum,
yylval(symbol index) = 2
5. total
added at index 3
yylval = 3
Token = ID, Lexeme = total,
yylval(symbol index) = 3
6. again sum
found at index 2
yylval = 2
Token = ID, Lexeme = sum,
yylval(symbol index) = 2
Symbol Table Final State
Inde Identifi
x er
0 X
1 y
Inde Identifi
x er
2 Sum
3 Total
This shows how semantic value
(yylval) and token code (ID) work
together.
🎯 Meaning of Each Component
{id}
Matches identifiers (x, sum, value1)
yytext
Contains actual matched text
example: "sum"
yyleng
Length of lexeme
example: 3
installID()
puts lexeme into symbol table
returns its index
yylval = installID()
Stores semantic info so parser can know
which identifier it is.
return(ID)
Tells the parser:
“Token type is IDENTIFIER.”