Compiler 56
Compiler 56
Compiler 56
DATE :
LEX Tool
Lex is a tool used for generating lexical analyzers, also known as lexers or scanners, for
processing text or source code.
Lex is often used in combination with the yacc or Bison parser generator to create complete
syntax analysis tools for programming languages and other formal languages.
Lex, along with yacc (or Bison), has been a fundamental tool in the development of compilers
and interpreters for programming languages.
%{
Definition Section #include<stdio.h>
%}
Rules Section %%
[0−9]+ {printf(“%s is an
integer”, yytext);
%%
Definition Section :
C code
➢ Is used for defining file variables, and for prototypes of routines that are defined in the code
segment.
Definitions
➢ A definition is very much like a #define cpp directive.
State definitions
➢ A state definition lookslike %s STATE, and by default a state INITIAL is already given.
Rules Section :
• The rulessection has a number of pattern−action pairs
• The patterns are regular expressions and the actions are either a single C command, or a sequence
enclosed in braces.
• If more than one rule matches the input, the longer match istaken. If two matches are the same
length, the earlier one in the list is taken.
Properties:
• Regular Expression-Based Tokenization: Lex allows you to define token recognition rules using
regular expressions. This makes it easy to specify complex patternsfor identifying tokens within
the input text.
• Automatic Code Generation: Lex generates the lexer code in a target programming language
(usually C or C++). This code can be compiled into an executable program, saving developers
from writing the lexer code manually.
• Customizable Actions: For each regular expression rule, you can specify associated actions,
which determine what happens when a particular pattern is matched. These actions can include
updating variables, recording token values, or performing other custom logic.
• Efficient DFA-Based Matching: Lex uses a deterministic finite automaton (DFA) to perform
efficient pattern matching. This results in fast and optimized tokenization of input text.
Result :
PROGRAM CODE:
%{
%}
%%
^[-][0-9]+ {negative_no++;
[0-9]+ {positive_no++;
%%
int yywrap(){}
int main()
yylex();
positive_no, negative_no);
return 0;
Output:
RESULT:
Thus, we executed a Lex program for counting the positive and negative numbers.
Exp No: 06 b
Date
PROGRAM CODE:
%{
#include<stdio.h>
int lc=0,sc=0,tc=0,ch=0,wc=0;
%%
%%
int main(){
return 0;
Output:
RESULT:
Thus, we executed a Lex program for counting number of words, characters and lines.
Exp No: 06 c
Date:
PROGRAM CODE:
%{
int vow_count=0;
%}
%%
[aeiouAEIOU] {vow_count++;}
[a-zA-Z] {const_count++;}
%%
int yywrap(){}
int main()
{
yylex();
return 0;
Output:
RESULT:
PROGRAM CODE:
%{
#include<stdio.h>
int i;
%}
%%
[0-9]+ {i=atoi(yytext);
if(i%2==0)
printf("Even");
else
printf("Odd");}
%%
int yywrap(){}
int main()
yylex();
return 0;
Output:
RESULT:
PROGRAM CODE:
%{
#include<stdio.h>
#include<stdlib.h>
int flag=0;
%}
%%
%%
int yywrap(){}
int main() {
yylex();
if(flag==1)
printf("Valid \n");
else
Output:
RESULT:
PROGRAM CODE:
%{
#include<stdio.h>
%}
%%
((0[1-9])|([1-2][0-9])|(3[0-1]))\/((0[1-9])|(1[0-2]))\/(19[0-9]{2}|2[0-9]{3}) printf("Valid");
.* printf("Invalid");
%%
int main()
yylex();
return 0; }
OUTPUT:
RESULT:
PROGRAM CODE:
%%
[Aa].
* printf(“string starts with ‘A’ or ‘a’: %s\n”,yytext);
.
\n
%%
int main() {
yylex();
return 0;}
Output:
RESULT:
Thus, we executed a Lex program to determine if string starts with 'a' or not.
Exp No: 06 h
Date:
PROGRAM CODE:
%{
%}
%option noyywrap
%%
%%
int main()
printf("\n");
return 0;
OUTPUT:
RESULT:
Hence, we have successfully executed a Lex program for mobile number validation.
Exp No: 06 i
Date
PROGRAM CODE:
%{
%}
%%
; printf("%s is an delimiter\n",yytext);
, printf("%s is a separator\n",yytext);
%%
int yywrap(void)
{
return 1;
int main()
yylex();
return 0;
Test.c:
OUTPUT:
RESULT:
YACC (Yet Another Compiler Compiler)," serves as a powerful grammar parser and generator. In essence, it
functions as a tool that takes in a grammar specification and transforms it into executable code capable of
meticulously structuring input tokens into a coherent syntactic tree, aligning seamlessly with the
prescribed grammar rules.
Stephen C. Johnson developed YACC in compiler design in the early 1970s. Initially, the YACC was written in
the B programming language and was soon rewritten in C. It was originally designed for being
complemented by Lex.
In addition to that, YACC was also rewritten in OCaml, Ratfor, ML, ADA, Pascal, Java < Python, Ruby and Go.
The input of YACC in compiler design is the rule or grammar, and the output is a C program.
/* definitions */
....
%%
/* rules */
....
%%
/* auxiliary routines */
....
Definitions: these include the header files and any token information used in the syntax. These are located
at the top of the input file. Here, the tokens are defined using a modulus sign. In the YACC, numbers are
automatically assigned for tokens.
%token ID
{% #include <stdio.h> %}
Rules: The rules are defined between %% and %%. These rules define the actions for when the token is
scanned and are executed when a token matches the grammar.
Auxiliary Routines: Auxiliary routines contain the function required in the rules section. This Auxiliary
section includes the main() function, where the yyparse() function is always called.
This yyparse() function plays the role of reading the token, performing actions and then returning to the
main() after the execution or in the case of an error.
The YACC is responsible for converting these sections into subroutines which will examine the inputs. This
process is made to work by a call to a low-level scanner and is named Parsing
Workings of YACC:
YACC in compiler design is set to work in C programming language along with its parser generator.
RESULT:
PROGRAM CODE:
Command: vi pp1.l
pp1.l
%{
#include<stdio.h>
#include "y.tab.h"
%}
%%
1 {yylval=1;return One;}
%%
Yacc Code:
%{
#include<stdio.h>
#include<stdlib.h>
#include "y.tab.h"
void yyerror(char *s);
int yylex();
%}
%token Zero One
%%
stmt:S;
S:SA | A;
A:Zero Zero | One One;
%%
int main()
{yyparse(); printf("Accepted\t");
exit(0);}
void yyerror(char *s)
(printf("Not Accepted\n");
exit(0);
OUTPUT:
RESULT:
PROGRAM CODE:
%{
#include "y.tab.h"
%}
%%
[ \t] ;
. { yyerror("Invalid character"); }
%%
int yywrap() {
return 1;
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token NUM
%%
calclist: /* empty */
exp: NUM
if ($3 == 0) {
yyerror("Division by zero");
exit(1);
} else {
$$ = $1 / $3;
%%
int main() {
yyparse();
return 0;
./calculator
OUTPUT:
RESULT:
Thus, we have successfully executed the calculator program using lex and yacc.
Exp No: 10
Date
PROGRAM CODE:
three_address.l:
%{
#include "y.tab.h"
%}
DIGIT [0-9]
ID [a-zA-Z][a-zA-Z0-9]*
%%
[ \t\n] ;
. { yyerror("Invalid character"); }
%%
int yywrap() {
return 1;
three_address.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int yylex();
int temp_count = 1;
%}
%union {
int num;
char *id;}
%%
program: stmt_list
stmt_list:
statement:
free($3);
| term { $$ = $1; }
| factor { $$ = $1; }
| IDENTIFIER { $$ = strdup(yytext); }
%%
int main() {
yyparse();
return 0;}
char temp[10];
sprintf(temp, "t%d", temp_count++);
return strdup(temp);
commands to generate the Lex and Yacc files and compile the program:
./three_address
INPUT:
OUTPUT:
RESULT:
Hence the Three Address Code Generation using LEX and YACC was implemented successfully.
Exp No: 11
Date:
PROGRAM CODE:
#include<stdio.h>
#include<string.h>
struct op
{
char l;
char r[20];
op[10], pr[10];
int main ()
int a, i, k, j, n, z = 0, m, q;
char temp, t;
char *tem;
scanf (" %c", &op[i].l); // space added before %c to consume the newline character
temp = op[i].l;
{
p = strchr (op[j].r, temp);
if (p)
pr[z].l = op[i].l;
z++;
z++;
tem = pr[m].r;
if (p)
t = pr[j].l;
pr[j].l = pr[m].l;
{
l = strchr (pr[i].r, t);
if (l)
a = l - pr[i].r;
pr[i].r[a] = pr[m].l;
pr[i].l = '\0';
if (pr[i].l != '\0')
return 0;}
INPUT:
OUTPUT:
RESULT:
Thus, a C program for code optimization has been developed and executed successfully.
Exp No: 12
Date:
PROGRAM CODE:
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
int n,i,j;
char a[50][50];
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<6;j++)
scanf("%c",&a[i][j]);}
for(i=0;i<n;i++)
printf("\nMov %c,R%d",a[i][3],i);
if(a[i][4]=='-')
printf("\nSub %c,R%d",a[i][5],i);}
if(a[i][4]=='+')
printf("\nAdd %c,R%d",a[i][5],i);}
if(a[i][4]=='*')
printf("\nMul %c,R%d",a[i][5],i);}
if(a[i][4]=='/')
printf("\nDiv %c,R%d",a[i][5],i);}
printf("\n");
}
getch();
INPUT:
OUTPUT:
RESULT:
Thus, a C program for code generation has been developed and executed successfully