Thread: Finite State Machine for numbers and identifiers(Wrong output)

  1. #1
    Registered User
    Join Date
    Apr 2011
    Posts
    48

    Finite State Machine for numbers and identifiers(Wrong output)

    Hello,
    I'm studying a book right now.(Problem Solving and Program Design in C)
    I solved the question.But it gives me wrong output.
    For example
    input > rate R2D2 48 2 time 555666 .
    output >
    rate - Identifier
    R2D2 - Number
    48 - Number
    2 - Number
    time - Identifier
    555666 - Number
    According to the book R2D2 must be Identifier
    I can't figure out where is the problem.Please help me to find where is the problem.
    Code:
    #include <stdio.h>
    #include <ctype.h>
    typedef enum
    	{start, build_id, build_num, number, identifier, stop}
    state_t;
    state_t transition(state_t current_state,char transition_char);
    int main(void)
    {
    	int i = 0;
    	state_t current_state;
    	char transition_char[30];
    	current_state = start;	
    	printf("Enter text> ");
    	do{
    		if (current_state == identifier){
    			printf(" - Identifier\n");
    			current_state = start;
    		}
    		else if ( current_state == number){
    			printf(" - Number\n");
    			current_state = start;
    		}
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);		
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    	}while(current_state != stop);
    	
    	return(0);
    }
    	
    state_t transition(state_t current_state,char transition_char){
    		if(isdigit((int)transition_char))
    			switch(transition_char){
    				case 1:
    				case 9:
    				default:
    					current_state = number;
    				}
    		else if(isalpha((int)transition_char))
    			switch(transition_char){
    				case 1:
    				case 9:
    				case 'A':
    				case 'Z':
    				case 'a':
    				case 'z':
    				case '_':
    				default :
    					current_state = identifier;
    				}
    		else if (transition_char == '.')
    			current_state = stop;
    	return(current_state);
    }

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    First, you should initialize current_state to some appropriate value, otherwise it could end up being any one of your enums at the beginning (altho it is probably none of them).

    The reason "rate" is reported as an identifier is because in transition() you have a switch statement for isalpha whose default is current_state = identifier. Since 'r' is not in the switch, that default is used.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Apr 2011
    Posts
    48
    Quote Originally Posted by MK27 View Post
    First, you should initialize current_state to some appropriate value, otherwise it could end up being any one of your enums at the beginning (altho it is probably none of them).

    The reason "rate" is reported as an identifier is because in transition() you have a switch statement for isalpha whose default is current_state = identifier. Since 'r' is not in the switch, that default is used.
    I think, you misunderstood my question.I'm asking how output for R2D2 will be Identifier.My program says it's a number.I guess the problem is in
    Code:
    else if(isalpha((int)transition_char))
    Because of its last character , it gives me wrong output
    And also, I initialized curent_state.( current_state = start; ) just before loop.

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by paranoidgnu View Post
    I think, you misunderstood my question.I'm asking how output for R2D2 will be Identifier.My program says it's a number
    Yes, sorry.

    Anyway, you can see the reason. The solution is to take into account the fact that an identifier contains alphabetic characters and can include numeric characters, while a number includes only numeric characters. Also, you only have these two states. So:

    Code:
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);		
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    Add a state_t variable here to set the state for a whole word/item. This is by default "number", but if current state comes back as an identifier, you set this state to identifier:

    Code:
    	state_t tag = start;
              
           [...]
    		tag = number; 
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);
    		if (current_state == identifier) tag = identifier;
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    Now you have to adjust the rest of the code to deal with this:

    Code:
    	printf("Enter text> ");
    	do{
    		if (tag == identifier){
    			printf(" - Identifier\n");
    			current_state = start;
    			tag = number;
    		}
    		else if (tag == number){
    			printf(" - Number\n");
    			current_state = start;
    		}
    		tag = number;
    Tested, works, and you should be able to follow the logic.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Apr 2011
    Posts
    48
    Quote Originally Posted by MK27 View Post
    Yes, sorry.

    Anyway, you can see the reason. The solution is to take into account the fact that an identifier contains alphabetic characters and can include numeric characters, while a number includes only numeric characters. Also, you only have these two states. So:

    Code:
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);		
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    Add a state_t variable here to set the state for a whole word/item. This is by default "number", but if current state comes back as an identifier, you set this state to identifier:

    Code:
    	state_t tag = start;
              
           [...]
    		tag = number; 
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);
    		if (current_state == identifier) tag = identifier;
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    Now you have to adjust the rest of the code to deal with this:

    Code:
    	printf("Enter text> ");
    	do{
    		if (tag == identifier){
    			printf(" - Identifier\n");
    			current_state = start;
    			tag = number;
    		}
    		else if (tag == number){
    			printf(" - Number\n");
    			current_state = start;
    		}
    		tag = number;
    Tested, works, and you should be able to follow the logic.
    Code:
    #include <stdio.h>
    #include <ctype.h>
    typedef enum
    	{start, build_id, build_num, number, identifier, stop}
    state_t;
    state_t transition(state_t current_state,char transition_char);
    int main(void)
    {
    	int i = 0;
    	state_t current_state, tag = start;
    	char transition_char[30];
    	current_state = start;	
    	printf("Enter text> ");
    	do{
    		if (tag == identifier){
    			printf(" - Identifier\n");
    			current_state = start;
    			tag = number;
    		}
    		else if ( tag == number){
    			printf(" - Number\n");
    			current_state = start;
    		}
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);
    		if (current_state == identifier) 
    			tag = identifier;
    		else if(current_state == number)
    			tag = number;
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    	}while(current_state != stop);
    	
    	return(0);
    }
    	
    state_t transition(state_t current_state,char transition_char){
    		if(isdigit((int)transition_char))
    			switch(transition_char){
    				case 1:
    				case 9:
    				default:
    					current_state = number;
    				}
    		else if(isalpha((int)transition_char))
    			switch(transition_char){
    				case 1:
    				case 9:
    				case 'A':
    				case 'Z':
    				case 'a':
    				case 'z':
    				case '_':
    				default :
    					current_state = identifier;
    				}
    		else if (transition_char == '.')
    			current_state = stop;
    	return(current_state);
    }
    Nothing changed here,
    Enter text> R2R2 f3f3f3 .
    R2R2 - Number
    f3f3f3 - Number

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    I'm sorry, but the reason this is happening is obvious.

    There is simply no state machinery in place here. (You are indiscriminately performing the same operations regardless of the current state.) Without that machinery in place, the resulting datum will always pretend to be whatever the last character processed is pretending to be.

    In other words, "R2D2" is a number because "2" is a number.

    Here is some code to get you started in the right direction. It is needlessly verbose because I simply modified your code. You'll see that I perform different tests with different results depending on the state.

    Also, the code is untested as I only typed it into my browser. (My own machines are not available at the moment.)

    [Edit]
    Oh, and the code builds on what MK27 has said.

    If it does work, it is all me; if it doesn't work, blame him. ^_^
    [/Edit]

    Soma

    Code:
    #include <stdio.h>
    #include <ctype.h>
    typedef enum
    	{start, building_id, building_num, breaker, stop}
    state_t;
    typedef enum
    	{unknown, number, identifier}
    types_t;
    state_t transition(state_t current_state, types_t * result_type, char transition_char);
    int main(void)
    {
    	int i = 0;
    	state_t current_state;
    	types_t result_type;
    	char transition_char[30];
    	current_state = start;
    	result_type = unknown;
    	printf("Enter text> ");
    	do{
    		if (result_type == identifier){
    			printf(" - Identifier\n");
    			current_state = start;
    			result_type = unknown;
    		}
    		else if ( result_type == number){
    			printf(" - Number\n");
    			current_state = start;
    			result_type = unknown;
    		}
    		do{
    		if(EOF == scanf("%c", &transition_char[i]))
    		{
                current_state = stop;
    		}
    		current_state = transition(current_state, &result_type, transition_char[i]);
    		printf("%c", transition_char[i]);
    		i++;
    		}while(!(current_state == breaker || current_state == stop));
    	}while(current_state != stop);
    
    	return(0);
    }
    
    state_t transition(state_t current_state, types_t * result_type,char transition_char){
            if(start == current_state)
            {
                if(isdigit((int)transition_char))
                {
                    current_state = building_num;
                    *result_type = number;
                }
                else if(isalpha((int)transition_char))
                {
                    current_state = building_id;
                    *result_type = identifier;
                }
                else if (transition_char == ' ')
                    current_state = breaker;
                else if (transition_char == '.')
                    current_state = stop;
            }
            else if((stop == current_state) || (breaker == current_state))
            {
            }
            else if(building_num == current_state)
            {
                if(isdigit((int)transition_char))
                {
                    current_state = building_num;
                    *result_type = number;
                }
                else if (transition_char == ' ')
                    current_state = breaker;
                else if (transition_char == '.')
                    current_state = stop;
            }
            else if(building_id == current_state)
            {
                if (transition_char == ' ')
                    current_state = breaker;
                else if (transition_char == '.')
                    current_state = stop;
            }
    	return(current_state);
    }
    Last edited by phantomotap; 04-24-2011 at 11:22 AM. Reason: none of your business

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by paranoidgnu View Post
    Nothing changed here,
    You missed a couple of crucial bits, and you completely missed the point:

    Code:
    		do{
    		scanf("%c", &transition_char[i]);
    		i++;
    		current_state = transition(current_state, transition_char[i-1]);
    		if (current_state == identifier) 
    			tag = identifier;
    		else if(current_state == number)
    			tag = number;
    		printf("%c",transition_char[i-1]);
    		}while(transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    That just reproduces your original mistake.

    The idea is simple: an "identifier" has letters, and possibly numbers. A "number" only has numbers. So if during that do..while, current_state comes back as "identifier", the tag state for that tag/word/item is identifier. Period. End of story. So (and you missed this bit, but it is in the code from my previous post) you set the tag state to "number" before the do..while:

    Code:
    		tag = number;
    		do{
    Now, you go thru the loop and if you find alphabetic characters, set tag to "identifier":

    Code:
    		do{
    			scanf("%c", &transition_char[i]);
    			i++;
    			current_state = transition(current_state, transition_char[i-1]);
    			if (current_state == identifier) tag = identifier;
    			printf("%c",transition_char[i-1]);
    		} while (transition_char[i-1] != ' ' && transition_char[i-1] != '.');
    Notice, I DID NOT EXPLICITLY SET TAG TO "NUMBER" INSIDE THIS LOOP. Tag is already "number"; if it changes to "identifier", IT SHOULD REMAIN THAT WAY AND NOT BE CHANGED BACK TO "NUMBER".

    The reason I haven't posted the whole program is because: 1) actually it is all here, but in seperate bits, 2) I think it is important for you to think about the changes and the logic behind them. But if you are desperate, ask And it does work, here's the output:

    Code:
    [root~/C] echo "rate R2D2 48 2 time 555666 ." | ./a.out
    Enter text> rate  - Identifier
    R2D2  - Identifier
    48  - Number
    2  - Number
    time  - Identifier
    555666  - Number
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Main loop of the Finite State Machine
    By makonikor in forum C Programming
    Replies: 3
    Last Post: 11-18-2010, 11:54 PM
  2. spell checker using finite state machine
    By DurellP in forum C++ Programming
    Replies: 5
    Last Post: 03-13-2010, 02:00 AM
  3. State machine
    By sergio in forum General Discussions
    Replies: 3
    Last Post: 07-03-2009, 09:03 AM
  4. Finite State Machine
    By ArlexBee-871RBO in forum C++ Programming
    Replies: 8
    Last Post: 07-14-2008, 11:59 AM
  5. Finite State Machine Project Help
    By ryanbradley in forum C++ Programming
    Replies: 4
    Last Post: 03-06-2004, 10:23 AM