Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Em resposta a esse tópico criei uma versão extremamente simplificada e bem falha de uma calculadora simples interpretada.Não aceita parenteses e só aceita operadores binários.A função pow deve ser ou definida ou linkada.
Interpreta strings simples como: 2^2+2*10+10-1+2>1
Segue:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern double pow(double base, double expoent);
//DEFINICAO UTILITARIA DE TIPO BOOLEANO
typedef char mBool;
//Macros utilitarios
#define TRUE 1
#define FALSE 0
#define MATH_EXPR_SIZE 50
#define I_ERROR_STR_SIZE 50
#define IF_ERROR(action) ({ \
if(error) action; \
});
//Retira espacos em branco e etc da string.Modifica a propria string
void formatToInterpreter(char str, size_t len, size_t newLen)
{
if(str == NULL) {
*newLen = 0;
return;
}
char * temp = malloc(len);
unsigned it = 0;
unsigned tempIt = 0;
for(;it < len;++it) {
char cur = str[it];
if(cur == ' ' || cur == '\r' || cur == '\n' || cur == '\t')
continue;
if(cur == 0x00)
break;
temp[tempIt] = cur;
++tempIt;
}
*newLen = tempIt;
strncpy(str, temp, tempIt);
str[tempIt] = 0x00;
free(temp);
}
//Funcao que diz a precedencia dos operadores binarios
unsigned precedence(char op)
{
if(op == '*' || op == '/' || op == '%')
return 1;
if(op == '>' || op == '<' || op == '|' || op == '&')
return 2;
return 0;
}
//Como os operadores binarios devem ser executados
mBool opExecute(char op, float n1, float n2, float res, char error)
{
*res = 0;
switch(op)
{
case '|':
n1 = (n1 || n2);
break;
case '&':
n1 = (n1 && n2);
break;
case '>':
n1 = (n1 > n2);
break;
case '<':
n1 = (n1 < n2);
break;
case '^':
n1 = pow(n1, n2);
break;
case '+':
n1 += n2;
break;
case '-':
n1 -= n2;
break;
case '*':
n1 *= n2;
break;
case '/':
if(n2 == 0) {
IF_ERROR(strcpy(error, "Divisao por zero."));
return FALSE;
}
n1 /= n2;
break;
case '%':
if((int)n2 == 0) {
IF_ERROR(strcpy(error, "Modulo por zero."));
return FALSE;
}
n1 = (int)n1%(int)n2;
break;
default:
IF_ERROR(sprintf(error, "Operador '%c' eh desconhecido.", op));
return FALSE;
}
*res = n1;
return TRUE;
}
//Interpretador
mBool execute(char str, size_t len, float res, char * error)
{
*res = 0;
if(len == 0)
return TRUE;
float n1;
float n2;
char op1;
char op2;
//FORMATO IDEAL:NUMERO OPERADOR NUMERO OU NUMERO
unsigned r = sscanf(str, "%f%c%f%c", &n1, &op1, &n2, &op2);
if(r < 3) {
//Formato:NUMERO
if(r == 1) {
*res = n1;
return TRUE;
} else if(r == 0) { //FORMATO:VAZIO
IF_ERROR(strcpy(error, "Esperava um numero."));
} else if(r == 2) { //FORMATO:NUMERO OPERADOR
IF_ERROR(sprintf(error, "Esperava um numero depois do operador '%c'.", op1));
}
return FALSE;
}
//So 1 operacao,ja retornamos
if(!op2)
return opExecute(op1, n1, n2, res, error);
char curOp = op1;
char *op1Pos = strchr(str, op1);
char *op2Pos = strchr(op1Pos+(op1 == op2), op2);
unsigned pos = 0;
if(precedence(op1) > precedence(op2)) {
curOp = op2;
pos = op2Pos-str;
//FORMATO: NUMERO OPERADOR
if(len-pos-1 == 0) {
IF_ERROR(sprintf(error, "Esperava um numero depois do operador '%c'.", op2));
return FALSE;
}
if(!opExecute(op1, n1, n2, &n1, error))
return FALSE;
} else {
pos = op1Pos-str;
}
++pos;
if(!execute(str+pos, len-pos, &n2, error))
return FALSE;
if(!opExecute(curOp, n1, n2, res, error))
return FALSE;
return TRUE;
}
//Programa
int main()
{
char mathExpression[MATH_EXPR_SIZE];
char interpreterError[i_ERROR_STR_SIZE];
size_t mathExprLen;
float r;
puts("---b2code calculator");
while(1) {
printf(">");
fgets(mathExpression, MATH_EXPR_SIZE, stdin);
if(strcmp(mathExpression, "quit\n") == 0)
break;
formatToInterpreter(mathExpression, MATH_EXPR_SIZE, &mathExprLen);
if(!execute(mathExpression, mathExprLen, &r, interpreterError))
printf("%s\n", interpreterError);
else
printf("%g\n", r);
}
return 0;
}Carregando comentários...