Você está na página 1de 8

/*************************************************************

* Parser para uma calculadora *


* Coded by Leon de Castela *
* Esse é o parser que que acompanha o tutorial que eu fiz *
* sobre o assunto. *
* www.scribd.com/leon_de_castela *
* www.twitter.com/leon_de_castela *
*************************************************************/

// Parser.cpp
#include <iostream>
#include <stack> // header para a pilha
#include <string>
#include <stdlib.h>
#define INICIO 1
#define ACEITAR 5
#define MORRE 0
#define FIM '='
#define ABRE '('
#define FECHA ')'
#define MAXEXP 20
//Códigos de ERRO
#define ER_DIV_ZERO -1
#define ER_EXP -2
#define ER_NO_EXP -3

inline int eh_num(char c);


inline int eh_oper(char c);

int automato(char* exp);


double parse(char*);
void posfixo(char*,char*);
int prioridade(char,char);

int main(int argc, char** argv){


char exp[20];
cout << "Parser Simples para uma Calculadora\n";
cout << "Coded by Leon de Castela\n";
cout << "Digite = para sair" << endl;
cout << "Expressão:";
cin >> exp;
while (exp[0] != FIM){
cout << "=" << parse(exp) << endl;
cout << "Expressão:";
cin >> exp;
}
cout << "Tchau!";
return 0;
}

int automato(char* exp){


char token;
int i = 0, estado = INICIO;
token = exp[i];
while (token != '\0'){
if (estado == INICIO && eh_num(token)){
estado = INICIO;
}
else
if (estado == INICIO && token == ABRE){
estado = 2;
}
else
if (estado == INICIO && eh_oper(token)){
estado = 6;
}
else
if (estado == INICIO && token == FIM){
return ACEITAR;
}
else
if (estado == INICIO && token == FECHA){
return MORRE;
}
else
if (estado == 2 && eh_num(token) ){
estado = 2;
}
else
if (estado == 2 && eh_oper(token) ){
estado = 3;
}
else
if (estado == 2 && token == FIM ){
return MORRE;
}
else
if (estado == 3 && eh_oper(token) ){
return MORRE;
}
else
if (estado == 3 && eh_num(token) ){
estado = 3;
}
else
if (estado == 3 && token == FECHA ){
estado = 4;
}
else
if (estado == 3 && token == FIM ){
return MORRE;
}
else
if (estado == 4 && eh_num(token) ){
return MORRE;
}
else
if (estado == 4 && token == FIM ){
return ACEITAR;
}
else
if (estado == 4 && eh_oper(token) ){
estado = 6;
}
else
if (estado == 6 && eh_oper(token) ){
return MORRE;
}
else
if (estado == 6 && eh_num(token) ){
estado = INICIO;
}
else
if (estado == 6 && token == FIM ){
return ACEITAR;
}
if (estado == 6 && token == ABRE ){
estado = 2;
}
token = exp[++i];
}//while
}

inline int eh_num(char c){


//0x30 e 0x39 são os caracteres de 0 a 9 na tabela ascii
if (c >= 0x30 && c <= 0x39)
return 1 ;
else
return 0;
}

inline int eh_oper(char c){


if (c == 0x2A || c == 0x2B || c == 0x2F || c == 0x2D )
return 1 ;
else
return 0;
}

/*************
* posfixo *
**********************************************************
*
* Converte uma expressão para a forma posfixa
* origem = expressão original
* dest = expressão destino
*
*
*********************************************************/

void posfixo(char *origem, char* dest ){


char token;
int pos = 0;
int pos_dest = 0;
stack<char> pilha;
token = origem[pos];
while (token != '\0'){
// se for operador verifica a pilha
if (token == ABRE){
pilha.push(token);

}
else if (token == FECHA){
while (pilha.top() != ABRE){
dest[pos_dest] = pilha.top();
pilha.pop();
pos_dest++;
}
if (!pilha.empty())
pilha.pop();
}
else if ( token == FIM){
while (!pilha.empty()){
dest[pos_dest] = pilha.top();
pilha.pop();
pos_dest++;
}
}

else if ( eh_num(token) ){
dest[pos_dest] = token;
pos_dest++;
}
else if ( eh_oper(token) )
{
if (pilha.empty())
{
pilha.push(token);
}
else if (prioridade(token, pilha.top())){
pilha.push(token);
}
else{
dest[pos_dest] = pilha.top();
pilha.pop();
pos_dest++;
}
}
token = origem[++pos];
}//while
}

// A mais esperada de todas!


double parse(char* exp){
stack<double> pilha;
char destino[MAXEXP];
int pos = 0;
double res,op1=0,op2=0,aux;
char token;
memset(destino,'\0',MAXEXP);
//verificação da sintaxe
if (automato(exp) == ACEITAR){
cout << "Expressão correta!\n";
}
else{
cout << "Erro de Sintaxe!\n";
exit(ER_EXP);
}
cout << "Convertendo expressão " << exp << endl;
posfixo(exp, destino);
cout << "Calculando expressão " << destino << endl;
token = destino[pos];
if (token == '\0' ){
cout << "Tchau!\n";
exit(ER_NO_EXP);
}
while (token != '\0'){
if (eh_num(token)){
aux = atof (&token);
pilha.push(aux);
}
else if (eh_oper(token)){
if (!pilha.empty()){
op2 = pilha.top();
pilha.pop();
}
if (!pilha.empty()){
op1 = pilha.top();
pilha.pop();
}
switch (token){
case '+' : pilha.push(op1 + op2);
break;
case '-' : pilha.push(op1 - op2);
break;
case '/' : if (op2 != '0')
pilha.push(op1 / op2);
else
exit(ER_DIV_ZERO);
break;
case '*' : pilha.push(op1 * op2);
break;
}
}
token = destino[++pos];
}
res = pilha.top();
return res;
}

int prioridade(char op1, char op2){


if (op1 == '+' || op1 == '-' && op2 == '+' || op2 == '-')
return 1;
else
if (op1 == '+' || op1 == '-' && op2 == '*' || op2 == '/')
return 0;
else
if (op1 == '+' || op1 == '-' && op2 == '(')
return 1;
else
if (op1 == '(' && op2 == '+' || op2 == '-')
return 0;
else
if (op1 == '(' && op2 == '*' || op2 == '/')
return 0;
else
if (op1 == '(' && op2 == '(' )
return 1;
else
if (op1 == '*' || op1 == '/' && op2 == '+' || op2 == '-')
return 1;
else
if (op1 == '*' || op1 == '/' && op2 == '*' || op2 == '/')
return 1;
else
if (op1 == '*' || op1 == '/' && op2 == '(')
return 1;
}