Dismantle full numeric expression in C

1

Hello; I have a code that must be done in C language, which is to receive a numeric expression, including the result of the same, for example: "20 + 30 = 50", which will be stored in a string. After receiving the expression, I want to dismember this expression by putting each number in an int variable, and the operators ("+" and "=", in this case) into variables of type char and display each one separately in their respective int variables char. I can do what I want by using atoi, but only the first number ("20"), the first operator ("+") and the equality operator ("=") that I can store in the correct variables, the other numbers are empty. The following is my code for you to analyze and help me, it is not complete yet, I need to read and "break" the string to complete the program. I have already researched in several places, I already had several doubts with several people, and nothing has been solved yet. Anyone who can point out the error, present me with a new solution, I will be very grateful.

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

int main(void)
{
    char expressao[20];
    int tamExpressao;
    int aux1;
    int aux2;
    int aux3;
    int aux4;
    char num1[3]={0};
    char num2[3]={0};
    char num3[3]={0};
    char oper1;
    char operIgual;
    int numero1=0;
    int numero2=0;
    int numero3=0;

    printf("Digite expressao:\n");
    scanf("%s", expressao);

    printf("%s\n\n", expressao);
    tamExpressao=strlen(expressao);
    printf("%i\n\n", tamExpressao);

         for (aux1=0; aux1<tamExpressao; aux1++)
         {
             if  (expressao[aux1]=='0'|expressao[aux1]=='1'|expressao[aux1]=='2'|expressao[aux1]=='3'|expressao[aux1]=='4'|expressao[aux1]=='5'|expressao[aux1]=='6'|expressao[aux1]=='7'|expressao[aux1]=='8'|expressao[aux1]=='9')
             {
                 for (aux2=0; aux2<3; aux2++)
                 {
                     if (numero1>0)
                     {
                         if (numero2>0)
                         {
                             num3[aux2]=num3[3]+expressao[aux1];
                         } else {num2[aux2]=num2[3]+expressao[aux1];}
                     } else {num1[aux2]=num1[3]+expressao[aux1];}
                     }
                     } else if  (expressao[aux1]=='+'|expressao[aux1]=='-')
                     {
                        numero1=atoi(&num1[aux2]);
                        oper1=expressao[aux1];
                        } else if  (expressao[aux1]=='=')
                            {
                                numero2=atoi(&num2[aux2]);
                                operIgual=expressao[aux1];
                            }
         }
         numero3=atoi(&num3[3]);
                        //Apresentação dos números digitados
                        printf("%i\t%i\t%c\t%i\t%c\t%i\n", aux1, numero1, oper1, numero2, operIgual, numero3);
                        //---

    system("PAUSE");
    return 0;
}
    
asked by anonymous 17.11.2014 / 15:10

1 answer

2

I do not know if it's worth trying to adapt your code to make it work. It will not be very certain to have a loophole on the outside being that in each iteration you want to do something different (in the first you want to save the number in the first variable, in the second you want to save the operator, in the third you want to get another number, etc. ). The traditional way to solve this problem is to create a separate lexer that reads one token at a time.

First we can define a type of data to represent an element of its expression:

enum TIPO_TOKEN = {
    TK_NUM,
    TK_OP,
    TK_EQ,
}

In addition to the type, you'll need a place to store the "value" of the read object. A simple (but gambiarrosa) way is to use even global variables:

TIPO_TOKEN token_type;
int number_value;
char op_value;

In addition, we'll need to keep the read state (which is the first unread position of our entry). In C the normal would be to use a pointer to do this - so you do not have to deal with indices all the time. Also, since strings in C are terminated by a %code% , you do not need to strengh to see when your entry ends.

char * next_char;

With this in hand, you can try to write a function that reads one element at a time, and saves the values in those globals:

void init_lexer(char *str){
    next_char = str;
}

int next_token(){ 
    if(*next_char == '='){
        token_type = TK_EQ;
        ++next_char;
        return 0; //OK
    }else if(*next_char == '+' || *next_char == '-'){
        token_type = TK_OP;
        op_value = *next_char;
        ++next_char;
        return 0;
    }else if(isdigit(*next_char)){
        token_type = TK_NUMBER;
        num_value = /* ...*/ ;
        /*...*/
        return 0;
    }else{
       /*...*/
    }
}

Once you have implemented lexer, your main is much easier to write:

int n1;
char op;
int n2;
int n3;

init_lexer(entrada);
if(next_token()){ /* erro: não conseguiu ler token */ }
if(token_type != TK_NUM){ /* erro: entrada nao comeca com numero */ }
n1 = num_value;
if(next_token()){ /* erro */ }
if(token_type != TK_OP){ /* erro */ }
op = op_value;
/*...*/

In short: What's important here is that it's worth separating your code into a lexer, the routine that converts text input to a structured tokens sequence (the lexer) and a parser, the routine responsible for consuming this sequence of tokens and check if they are in the right order (for example, "10 + + 5" is a token sequence that does not make sense).

Specifics can vary widely - you can use global variables or not, unions to store the value of the token, etc. Also, there are external tools such as flex and bison that are very useful if your program starts getting more complicated (for example, flex lets you write the lexer specification using regular expressions)

    
17.11.2014 / 15:45