Open In App

DFA in LEX code which accepts even number of zeros and even number of ones

Last Updated : 17 May, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Lex is a computer program that generates lexical analyzers, which is commonly used with the YACC parser generator. Lex, originally written by Mike Lesk and Eric Schmidt and described in 1975, is the standard lexical analyzer generator on many Unix systems, and an equivalent tool is specified as part of the POSIX standard. Lex reads an input stream specifying the lexical analyzer and outputs source code implementing the lexer in the C programming language.

Deterministic Finite Acceptor – 
In the theory of computation, a branch of theoretical computer science, a deterministic finite automaton (DFA)— also known as a deterministic finite acceptor (DFA) and a deterministic finite state machine (DFSM)— is a finite-state machine that accepts and rejects strings of symbols and only produces a unique computation (or run) of the automaton for each input string. Deterministic refers to the uniqueness of the computation. In search of the simplest models to capture finite-state machines, McCulloch and Pitts were among the first researchers to introduce a concept similar to finite automata in 1943.

Approach –

33

LEX provides us with an INITIAL state by default. So to make a DFA, use this initial state as the initial state of the DFA. Define two more states A and B where B is the dead state that would be used if encounter a wrong or invalid input. When the user gets input that is invalid input, move to state B and the print message “INVALID” and if the user reaches INITIAL state from state A with a “\n” then display a message “Not Accepted”. But if the user get a \n on the initial state, the user display a message “Accepted”.

Examples –  

Input : 1001
Output : Accepted

Input : hjabdba
Output : INVALID

To implement the above DFA, the user needs to write the below code in a lex file with a .l Extension.

NOTE :  

To compile a lex program, user need a UNIX system and flex which can be installed using sudo apt-get install flex 
With all the above specification open unix terminal and do the following: 
1. Use the lex program to change the specification file into a C language program. The resulting program is in the lex.yy.c file. 
2. Use the cc command with the -ll flag to compile and link the program with a library of lex subroutines. The resulting executable program is in the a.out file.

lex lextest
cc lex.yy.c -lfl

Code –

C++




%{
%}
 
%s A B
 
%%
<INITIAL>1 BEGIN INITIAL;
<INITIAL>0 BEGIN A;
<INITIAL>[^0|\n] BEGIN B;
<INITIAL>\n BEGIN INITIAL; printf("Accepted\n");
<A>1 BEGIN A;
<A>0 BEGIN INITIAL;
<A>[^0|\n] BEGIN B;
<A>\n BEGIN INITIAL; printf("Not Accepted\n");
<B>0 BEGIN B;
<B>1 BEGIN B;
<B>[^0|\n] BEGIN B;
<B>\n {BEGIN INITIAL; printf("INVALID\n");}
%%
 
void main()
{
yylex();
}


Output – 

nickhil@NICKHIL:~$ lex prpg11.l
nickhil@NICKHIL:~$ cc lex.yy.c -lfl
nickhil@NICKHIL:~$ ./a.out
1000
Not Accepted
hello
INVALID
01010101
Accepted

METHOD 2:-

Approach:-

LEX provides us with an INITIAL state by default. So to make a DFA, use this as the initial state of the DFA. We define four more states: A, B, C, and DEAD where DEAD state would be used if encountering, a wrong or invalid input. When user input an invalid character, move to DEAD state and print message “INVALID” and if input string ends at state INITIAL then display a message “Accepted”. If input string ends at state A, B, C then display a message “Not Accepted”. 

LEX CODE:-

%{

%}

%s A B C DEAD

%%

<INITIAL>1 BEGIN A;

<INITIAL>0 BEGIN B;

<INITIAL>[^01\n] BEGIN DEAD;

<INITIAL>\n BEGIN INITIAL; {printf("Accepted\n");}

<A>1 BEGIN INITIAL;

<A>0 BEGIN C;

<A>[^01\n] BEGIN DEAD;

<A>\n BEGIN INITIAL; {printf("Not Accepted\n");}

<B>1 BEGIN C;

<B>0 BEGIN INITIAL;

<B>[^01\n] BEGIN DEAD;

<B>\n BEGIN INITIAL; {printf("Not Accepted\n");}  

<C>1 BEGIN B;

<C>0 BEGIN A;

<C>[^01\n] BEGIN DEAD;

<C>\n BEGIN INITIAL; {printf("Not Accepted\n");}  

<DEAD>[^\n] BEGIN DEAD;

<DEAD>\n BEGIN INITIAL; {printf("Invalid\n");}  

%%

int main()

{

   printf("Enter String\n");

   yylex();

   return 0;

}

OUTPUT:-

kashyap@kashyap-singh:~$ lex e0e1.l
Kashyap@Kashyap-singh:~$ cc lex.yy.c -lfl
Kashyap@Kashyap-singh:~$ ./a.out
1010
Accepted
hello
INVALID
11100
Not Accepted
111100
Accepted
0001
Not Accepted

Advantages:

Pattern Recognition: Using a DFA in LEX code allows for efficient and accurate recognition of strings that conform to the language requirements. LEX provides a powerful tool for pattern matching and tokenizing, making it well-suited for tasks involving string processing.

Simplicity: DFAs are relatively simple and intuitive to implement in LEX code. The construction of states and transitions based on the language requirements can be easily expressed in LEX patterns and actions. This simplicity facilitates the development and maintenance of the DFA.

Deterministic Execution: DFAs are deterministic, meaning that for every state and input symbol, there is a unique next state. This deterministic nature ensures that the DFA follows a predetermined path, simplifying the analysis and prediction of its behavior. Deterministic execution is particularly advantageous in parsing and lexical analysis tasks.

Efficiency: LEX code, combined with DFA-based pattern matching, allows for efficient execution. The DFA’s transition table can be represented in LEX patterns, enabling fast and constant-time transitions. This efficiency is valuable when processing large amounts of input to determine language membership.

Disadvantages:

Limited Expressiveness: DFAs have limited expressive power and can only recognize regular languages. While a DFA in LEX code can handle the language of even number of zeros and even number of ones, it cannot handle more complex languages or patterns that require context or memory beyond regular languages. For such languages, more powerful models like pushdown automata or Turing machines are needed.

Lack of Flexibility: DFAs have fixed state transitions and cannot dynamically adapt to changing input patterns or conditions. Once designed, the DFA follows a predetermined path based solely on the current state and input symbol. It does not easily accommodate variations in the language requirements or allow for modifications during runtime.

Difficulty in Handling Errors: DFAs, including those implemented in LEX code, typically do not handle errors or exceptions well. They expect inputs to strictly adhere to the defined language or pattern, and any deviations may result in either incorrect behavior or rejection. Incorporating error-handling capabilities often requires additional mechanisms or modifications to the DFA model.

State Explosion: Designing a DFA for certain languages, including those with multiple constraints like an even number of zeros and an even number of ones, may lead to a significant increase in the number of states and transitions required. As the complexity of the language requirements increases, the DFA may suffer from the “state explosion” problem. Managing and representing large DFAs can become challenging and impractical.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads