0% found this document useful (0 votes)
21 views14 pages

CD Manual

The document outlines five programming tasks related to automata theory and lexical analysis. It includes the design and implementation of a lexical analyzer in C, a calculator using LEX and YACC, finding epsilon-closure of NFA states, converting NFA to DFA, and minimizing a given DFA. Each program is accompanied by code snippets and explanations of the algorithms used.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views14 pages

CD Manual

The document outlines five programming tasks related to automata theory and lexical analysis. It includes the design and implementation of a lexical analyzer in C, a calculator using LEX and YACC, finding epsilon-closure of NFA states, converting NFA to DFA, and minimizing a given DFA. Each program is accompanied by code snippets and explanations of the algorithms used.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

PROGRAM 1: Design and implement a lexical analyzer for given language

using C and the lexical analyzer should ignore redundant spaces, tabs and
new lines.

To design and implement a lexical analyzer in C for a given language, you need to define the
language's tokens (keywords, identifiers, operators, etc.) and create a scanner that processes
the input and identifies those tokens. The lexical analyzer will also ignore redundant spaces,
tabs, and new lines.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>

int isKeyword(char buffer[]){


char keywords[32][10] = {"main","auto","break","case","char","const","continue","default",
"do","double","else","enum","extern","float","for","goto","if","int","long","register","return",
"short","signed","sizeof","static","struct","switch","typedef","unsigned","void","printf",
"while"};
int i, flag = 0;
for(i = 0; i< 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
return flag;
}

int main(){
char ch, buffer[15], operators[] = "+-*/%=";
FILE *fp;
int i,j=0;
fp = fopen("3lex_input.txt","r");
if(fp == NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch = fgetc(fp)) != EOF){
for(i = 0; i< 6; ++i){
if(ch == operators[i])
printf("%c is operator\n", ch);
}

if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;

if(isKeyword(buffer) == 1)
printf("%s is keyword\n", buffer);
else
printf("%s is identifier\n", buffer);
}

}
fclose(fp);
return 0;
}

Output:
PROGRAM 2: Implementation of Calculator using LEX and YACC.

To implement a calculator using LEX and YACC, we'll create a simple expression evaluator
that can handle arithmetic operations such as addition, subtraction, multiplication, division,
and parentheses for grouping.

Steps to Implement:
1. LEX: The lexical analyzer (lexer) will tokenize the input expression into tokens such
as numbers, operators, and parentheses.
2. YACC: The parser (using YACC) will build an abstract syntax tree (AST) or directly
evaluate the expression based on the tokens generated by the lexer.

LEX PART:
%{
#include<stdio.h> #include "[Link].h" extern intyylval;
%}
%%
[0-9]+ {
yylval=atoi(yytext);
return NUMBER; }
[\t] ;
[\n] return 0;
. return yytext[0];
%%
intyywrap()
{
return 1;
}

YACC PART:
%{ #include<stdio.h>
int flag=0;
%}
%token NUMBER
%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%%

Arithmetic Expression: E{ printf("\result=%d\n",$$); return 0;


};
E : E'+'E {$$=$1+$3;} | E'-'E {$$=$1-$3;} | E'*'E {$$=$1*$3;} | E'/'E {$$=$1/$3;} | E'%'E
{$$=$1%$3;} | '('E')' {$$=$2;} | NUMBER {$$=$1;};
%%
void main ()
{
printf ("\enter Any Arithmetic Expression which can have operations Addition, Subtraction,
Multiplication, division, Modulus and Round brackets:\n");
yyparse ();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
}
void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");flag=1;
}

Output:
PROGRAM 3: Write program to find ε – closure of all states of any given
NFA with ε transition.

The ε-closure (epsilon-closure) of a state in a Non-deterministic Finite Automaton (NFA) is


the set of states that can be reached from the given state by traversing only ε (epsilon)
transitions. In other words, it includes the state itself and all states reachable through ε-
transitions.

#include<stdio.h>
#include<stdlib.h>
struct node
{
int st;
struct node *link;
};

void findclosure(int,int);
void insert_trantbl(int ,char, int);
int findalpha(char);
void print_e_closure(int);

static int set[20],nostate,noalpha,s,notransition,c,r,buffer[20];


char alphabet[20];
static int e_closure[20][20]={0};
struct node * transition[20][20]={NULL};

void main()
{
int i,j,k,m,t,n;
struct node *temp;
printf("Enter the number of alphabets?\n");
scanf("%d",&noalpha);
getchar();
// printf("NOTE:- [ use letter e as epsilon]\n");
// printf("NOTE:- [e must be last character ,if it is present]\n");
printf("\nEnter alphabets?\n");
for(i=0;i<noalpha;i++)
{
alphabet[i]=getchar();
getchar();
}
printf("\nEnter the number of states?\n");
scanf("%d",&nostate);
printf("\nEnter no of transition?\n");
scanf("%d",&notransition);
// printf("NOTE:- [Transition is in the form->qno alphabet qno]\n",notransition);
// printf("NOTE:- [States number must be greater than zero]\n");
printf("\nEnter transition?\n");
for(i=0;i<notransition;i++)
{
scanf("%d %c%d",&r,&c,&s);
insert_trantbl(r,c,s);
}
printf("\n");
printf("e-closure of states : \n");
// printf("—————————–\n");
for(i=1;i<=nostate;i++)
{
c=0;
for(j=0;j<20;j++)
{
buffer[j]=0;
e_closure[i][j]=0;
}
findclosure(i,i);
printf("\ne-closure(q%d): ",i);
print_e_closure(i);
}
}

void findclosure(intx,intsta)
{
struct node *temp;
int i;
if(buffer[x])
return;
e_closure[sta][c++]=x;
buffer[x]=1;
if(alphabet[noalpha-1]=='e' && transition[x][noalpha-1]!=NULL)
{
temp=transition[x][noalpha-1];
while(temp!=NULL)
{
findclosure(temp->st,sta);
temp=temp->link;
}
}
}

void insert_trantbl(intr,charc,int s)
{
int j;
struct node *temp;
j=findalpha(c);
if(j==999)
{
printf("error\n");
exit(0);
}
temp=(struct node *)malloc(sizeof(struct node));
temp->st=s;
temp->link=transition[r][j];
transition[r][j]=temp;
}

int findalpha(char c)
{
int i;
for(i=0;i<noalpha;i++)
if(alphabet[i]==c)
return i;
return(999);
}
void print_e_closure(inti)
{
int j;
printf("{");
for(j=0;e_closure[i][j]!=0;j++)
printf("q%d,",e_closure[i][j]);
printf("}");
}

Output:
PROGRAM 4: Write a program to convert NFA to DFA.

To convert a Non-Deterministic Finite Automaton (NFA) to a Deterministic Finite


Automaton (DFA), we can use the subset construction algorithm. The core idea is to
represent each DFA state as a set of NFA states.

#include<stdio.h>
#include<string.h>
#include<math.h>
int ninputs;
int dfa[100][2][100] = {0};
int state[10000] = {0};
char ch[10], str[1000];
int go[10000][2] = {0};
int arr[10000] = {0};
int main()
{
int st, fin, in;
int f[10];
int i,j=3,s=0,final=0,flag=0,curr1,curr2,k,l;
int c;
printf("\nFollow the one based indexing\n");
printf("\nEnter the number of states::");
scanf("%d",&st);
printf("\nGive state numbers from 0 to %d",st-1);
for(i=0;i<st;i++)
state[(int)(pow(2,i))] = 1;
printf("\nEnter number of final states\t");
scanf("%d",&fin);
printf("\nEnter final states::");
for(i=0;i<fin;i++)
scanf("%d",&f[i]);
int p,q,r,rel;
printf("\nEnter the number of rules according to NFA::");
scanf("%d",&rel);
printf("\n\nDefine transition rule as \"initial state input symbol final state\"\n");
for(i=0; i<rel; i++)
{
scanf("%d%d%d",&p,&q,&r);
if (q==0)
dfa[p][0][r] = 1;
else
dfa[p][1][r] = 1;
}
printf("\nEnter initial state::");
scanf("%d",&in);
in = pow(2,in);
i=0;
printf("\nSolving according to DFA");
int x=0;
for(i=0;i<st;i++)
{
for(j=0;j<2;j++)
{
intstf=0;
for(k=0;k<st;k++)
{
if(dfa[i][j][k]==1)
stf = stf + pow(2,k);
}
go[(int)(pow(2,i))][j] = stf;
printf("%d-%d-->%d\n",(int)(pow(2,i)),j,stf);
if(state[stf]==0)
arr[x++] = stf;
state[stf] = 1;
}
}
for(i=0;i<x;i++)
{
printf("for %d ---- ",arr[x]);
for(j=0;j<2;j++)
{
int new=0;
for(k=0;k<st;k++)
{
if(arr[i] & (1<<k))
{
int h = pow(2,k);

if(new==0)
new = go[h][j];
new = new | (go[h][j]);
}
}
if(state[new]==0)
{
arr[x++] = new;
state[new] = 1;
}
}
}
printf("\nThe total number of distinct states are::\n");
printf("STATE 0 1\n");
for(i=0;i<10000;i++)
{
if(state[i]==1)
{
int y=0;
if(i==0)
printf("q0 ");
else
for(j=0;j<st;j++)
{
int x = 1<<j;
if(x&i)
{
printf("q%d ",j);
y = y+pow(2,j);
}
}
printf(" %d %d",go[y][0],go[y][1]);
printf("\n");
}
}
j=3;
while(j--)
{
printf("\nEnter string");
scanf("%s",str);
l = strlen(str);
curr1 = in;
flag = 0;
printf("\nString takes the following path-->\n");
printf("%d-",curr1);
for(i=0;i<l;i++)
{
curr1 = go[curr1][str[i]-'0'];
printf("%d-",curr1);
}
printf("\nFinal state - %d\n",curr1);
for(i=0;i<fin;i++)
{
if(curr1 & (1<<f[i]))
{
flag = 1;
break;
}
}
if(flag)
printf("\nString Accepted");
else
printf("\nString Rejected");
}
return 0;
}
Output:
PROGRAM 5: Write program to minimize any given DFA.

DFA minimization stands for converting a given DFA to its equivalent DFA with minimum
number of states. DFA minimization is also called as Optimization of DFA and uses
partitioning algorithm.

#include <stdio.h>
/* input format
row 1: input symbols
row 2: non-final states
row 3: final states
rows>3: transition table
*/

int table[10][10];
int matrix[10][10]={0};
int indexOf(char *array,charx,int max){
inti=0;
for(;i<max;i++){
if(array[i]==x)
return i;
}
return -1;
}
int movesToMarked(inti, int j, int l){
int k,x,y;
for(k=0;k<l;k++){
x=table[i][k]; // index of next state on kth input
y=table[j][k];
if(x!=-1 && y!=-1 && matrix[x][y]==1){
return 1;
}
}
return 0;
}
void printStates(char *states, int n, int f){ // prints new states
int i,j;
int store=0; //stores all encountered states
int bin, final;
for(i=0;i<n+f;i++){
bin=1<<i; //bitmask of state to add
if((store&bin)!=0)
continue;
final=(i>n)? 1 : 0; // is final state
store=store|bin;
printf("%c",states[i]);
for(j=i+1;j<n+f;j++){
if(matrix[j][i]==0){
bin=1<<j;
store=store|bin;
if(j>n) final=1;
printf("%c",states[j]);
}
}
if(final==1)
printf(" (f) ");
printf("\n");
}
}
int main(){
char language[10], ch;
int l = 0;
while (1){ //read input symbols till new line encountered
language[l++] = getchar();
if(getchar()=='\n')
break;
}
int n = 0, f = 0; // n: no of non-final states, f: no of final states
char states[10]; // array to store all states
while (1){
states[n++] = getchar(); //read input symbols till new line encountered
if(getchar()=='\n')
break;
}
char *finalstates;
finalstates = states + n; // address of first final state (not really required)
while (1){
finalstates[f++] = getchar();
if(getchar()=='\n')
break;
}
int i,j;
for (i = 0; i< n + f; i++){
for(j=0;j<l;j++){
scanf(" %c",&ch);
table[i][j]=indexOf(states,ch,n+f); // get transition table
}
}
for(i=0;i<n+f;i++){
matrix[i][i]=-1; // diagonal elements not required
}
for(i=n;i<n+f;i++){
for(j=0;j<n;j++){
matrix[i][j]=1;
matrix[j][i]=1; // makes matrix symmetric so (i,j)=(j,i) and order becomes irrelevent
}
}
int change=1;
while(change){
change=0;
for(i=0;i<n+f;i++){
for(j=0;j<n+f;j++){
if(matrix[i][j]==0){
if(movesToMarked(i,j,l)){ // mark i,j of i,j moves to a marked pair on some input
change=1;
matrix[i][j]=1;
matrix[j][i]=1;
}
}
}
}
}
printf(" "); // print matrix
for(i=0;i<n+f;i++){
printf("%c ",states[i]);
}
printf("\n");
for(i=0;i<n+f;i++){
printf("%c ",states[i]);
for(j=0;j<i;j++){
printf("%d ",matrix[i][j]);
}
printf("\n");
}
printStates(states,n,f); // print new states
return 0;
}

Output:

You might also like