Skip to content

Instantly share code, notes, and snippets.

@carlosbrando
Created June 20, 2011 14:13
Show Gist options
  • Save carlosbrando/1035669 to your computer and use it in GitHub Desktop.
Save carlosbrando/1035669 to your computer and use it in GitHub Desktop.
Um analisador recursivo descendente bem simples.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "..\h\parser.h"
/* Variáveis para controlar a analise da expressão */
char *prog; /* contém a expressão a ser analisada */
char token[80];
char tok_type;
/* Esse array armazena as variáveis de A-Z disponíveis no parser */
double vars[26] = {
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0
};
/* main(void) {
printf("A resposta é %.2f\n", parser("a=1"));
printf("A resposta é %.2f\n", parser("a+10"));
} */
double parser_expression(char *expression) {
double answer;
char p[100];
prog = p;
strcpy(prog, expression);
eval_exp(&answer);
return answer;
}
/* Ponto de entrada do analisador */
void eval_exp(double *answer) {
get_token();
if (!*token) {
serror(2);
return;
}
eval_exp1(answer);
if (*token)
serror(0); /* o último token deve ser nulo */
}
/* Processa uma atribuição */
void eval_exp1(double *result) {
int slot, ttok_type;
char temp_token[80];
if (tok_type == VARIAVEL) {
/* salva token antigo */
strcpy(temp_token, token);
ttok_type = tok_type;
/* calcula o índice da variável */
slot = toupper(*token) - 'A';
get_token();
if (*token != '=') {
putback(); /* devolve token atual */
/* restaura token antigo - nenhuma atribuição */
strcpy(token, temp_token);
tok_type = ttok_type;
} else {
get_token();
eval_exp2(result);
vars[slot] = *result;
return;
}
}
eval_exp2(result);
}
/* Soma ou subtrai dois termos */
void eval_exp2(double *answer) {
register char op;
double temp;
eval_exp3(answer);
while ((op = *token) == '+' || op == '-') {
get_token();
eval_exp3(&temp);
switch(op) {
case '-':
*answer = *answer - temp;
break;
case '+':
*answer = *answer + temp;
break;
}
}
}
/* Multiplica ou divide dois fatores */
void eval_exp3(double *answer) {
register char op;
double temp;
eval_exp4(answer);
while ((op = *token) == '*' || op == '/' || op == '%') {
get_token();
eval_exp4(&temp);
switch(op) {
case '*':
*answer = *answer * temp;
break;
case '/':
*answer = *answer / temp;
break;
case '%':
*answer = (int) *answer % (int) temp;
break;
}
}
}
/* Processa um expoente */
void eval_exp4(double *answer) {
double temp, ex;
register int t;
eval_exp5(answer);
while (*token == '^') {
get_token();
eval_exp4(&temp);
ex = *answer;
if (temp == 0.0)
*answer = 1.0;
return;
}
for (t = temp - 1; t > 0; --t)
*answer = (*answer) * (double)ex;
}
/* Avalia um + ou - unário */
void eval_exp5(double *answer) {
register char op;
op = 0;
if ((tok_type == DELIMITADOR) && *token == '+' || *token == '-') {
op = *token;
get_token();
}
eval_exp6(answer);
if (op == '-')
*answer = -(*answer);
}
/* Processa uma operação entre parênteses */
void eval_exp6(double *answer) {
if (*token == '(') {
get_token();
eval_exp2(answer);
if (*token != ')')
serror(1);
get_token();
} else {
atom(answer);
}
}
/* Obtém o valor de um número ou variável */
void atom(double *answer) {
switch(tok_type) {
case VARIAVEL:
*answer = find_var(token);
get_token();
return;
case NUMERO:
*answer = atof(token);
get_token();
return;
default:
serror(0); /* erro de sintaxe na expressão */
}
}
/* Devolve um token à stream de entrada */
void putback(void) {
char *t;
t = token;
for (; *t; t++)
prog--;
}
/* Apresenta um erro de sintaxe */
void serror(int error) {
static char *e[] = {
"Erro de sintaxe",
"Falta parênteses",
"Nenhuma expressão presente"
};
printf("%s\n", e[error]);
}
/* Devolve o próximo token */
void get_token(void) {
register char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
/* final da expressão */
if (!prog) return;
/* ignora espaços em branco */
while (isspace(*prog)) ++prog;
if (strchr("+-*/%^=()", *prog)) {
tok_type = DELIMITADOR;
*temp++ = *prog++; /* avança para o próximo char */
} else if (isalpha(*prog)) {
while (!isdelim(*prog)) *temp++ = *prog++;
tok_type = VARIAVEL;
} else if (isdigit(*prog)) {
while (!isdelim(*prog)) *temp++ = *prog++;
tok_type = NUMERO;
}
*temp = '\0';
}
/* Devolve verdadeiro se c é um delimitador */
int isdelim(char c) {
if (strchr(" +-*/%^=()", c) || c == 9 || c == '\r' || c == 0)
return 1;
return 0;
}
/* Devolve o valor de uma variável */
double find_var(char *s) {
if (!isalpha(*s)) {
serror(1);
return 0;
}
return vars[toupper(*s) - 'A'];
}
#ifndef _PARSER_H_
#define _PARSER_H_
#define DELIMITADOR 1
#define VARIAVEL 2
#define NUMERO 3
/* Funções */
void eval_exp(double *);
void eval_exp2(double *);
void eval_exp3(double *);
void eval_exp4(double *);
void eval_exp5(double *);
void eval_exp6(double *);
void atom(double *);
void putback(void);
void serror(int);
void get_token(void);
int isdelim(char);
double find_var(char *);
void eval_exp1(double *);
double parser_expression(char *);
#endif /* _PARSER_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment