SIMPLEX.YAC



/* SIMPLIFICADOR DE EXPRESIONES MATEMATICAS */
/* ========================================================*/
/* === Programa:    simplex.yac                         ===*/
/* === Objetivo:    simplificar expresiones matemAticas ===*/
/* === TEcnica:     Dirigida por la sintAxis            ===*/
/* === Programador: J. Rafael R. Ochoa                  ===*/
/* ========================================================*/

%{
   struct nodos
   {
      int valor;
      char dato[80];
      int exp;
      struct nodos *sig;
   };
%}

%union
{
   struct nodos *lista;
   char cadena[80];
}

%token LEFT RIGHT MAS POR LINEA CERO
%token <cadena> NUM VAR
%type <lista> expr term factor

%%
/* producciones de la gramatica */
inicio  : expr LINEA       { imprime($1); return 1;}
        ;
expr    : expr MAS term    { $$ = suma($1,$3); }
        | term             { $$ = $1; }
        ;
term    : term POR factor  { $$ = producto($1,$3); }
        | factor           { $$ = $1; }
        ;
factor  : VAR              { $$ = reserva($1); }
        | NUM              { $$ = reserva($1); }
        | LEFT expr RIGHT  { $$ = $2; }
        ;
%%

/* funciones auxiliares */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct nodos *reserva(char *);
void imprime(struct nodos *);
struct nodos *suma(struct nodos *, struct nodos *);
struct nodos *producto(struct nodos *, struct nodos *);
struct nodos *termino_que_falta(struct nodos *,struct nodos *);
struct nodos *copia_nodo(struct nodos *);

extern int yylex();  /* Liga con la funcion yylex generada por LEX */
extern int yynerrs;

int yyparse();


void main(void)
{
   printf("\n=========================================\n");
   yyparse();
   printf("\n=========================================\n");
}

yyerror(char *mess)           /* llamado por yyparse() cuando ocurra */
{                             /*   un error                          */
  printf("\n [error...%s] \n",mess);
  return 1;
}

struct nodos *suma(struct nodos *dato1, struct nodos *datos)
{
   struct nodos *signo   = NULL;
   struct nodos *nuevo   = NULL;
   struct nodos *dato2   = NULL;
   struct nodos *salida  = NULL;
   char sum[10];
   int match;

   salida = datos;
   while(dato1)
   {
      dato2 = datos;
      while(dato2)
      {
         match = 0;

         if((strncmp(dato1->dato,dato2->dato,1)==0) &&
            (dato1->exp==dato2->exp)
           )
         {
           dato2->valor += dato1->valor;
           match = 1; break;
         }
         dato2=dato2->sig;
      }
      if(!match)
      {
         signo = reserva("+");
         nuevo = copia_nodo(dato1);
         nuevo->sig = signo; signo->sig = datos;
         datos = nuevo; salida = datos;
      }
      dato1=dato1->sig;
   }
   return salida;
}

struct nodos *copia_nodo(struct nodos *nodo)
{
   struct nodos *copia = NULL;

   copia = reserva(nodo->dato);
   copia->valor = nodo->valor;
   copia->exp = nodo->exp;
   strcpy(copia->dato,nodo->dato);
   return copia;
}

struct nodos *producto(struct nodos *dato1, struct nodos *dato2)
{
   char prod[5]; struct nodos *nuevo=NULL;
   struct nodos *termino2 = NULL;

   if ((dato1->valor==0) || (dato2->valor==0))   return reserva("0");

   sprintf(prod,"%d",dato1->valor*dato2->valor);
   nuevo = reserva(prod);
   if((strncmp(dato1->dato,"x",1)==0) && (strncmp(dato2->dato,"x",1)==0))
      {  nuevo->exp = dato1->exp + dato2->exp;
         strcpy(nuevo->dato,"x");
         termino2 = termino_que_falta(dato1,dato2);
         nuevo->sig = termino2;
         return nuevo;
      }
   if((strncmp(dato1->dato,"x",1)==0) || (strncmp(dato2->dato,"x",1)==0))
      {  strcpy(nuevo->dato,"x");
         if(strncmp(dato1->dato,"x",1)==0) nuevo->exp = dato1->exp;
         else nuevo->exp = dato2->exp;
         termino2 = termino_que_falta(dato1,dato2);
         nuevo->sig = termino2;
  termino2 = termino_que_falta(dato1,dato2);
         nuevo->sig = termino2;
         return nuevo;
      }
   strcpy(nuevo->dato,"0");
   return nuevo;
}

struct nodos *reserva(char *cad)
{
   struct nodos *nodo_nuevo=NULL;
   nodo_nuevo = (struct nodos *)malloc(sizeof(struct nodos));

   if( strncmp(cad,"+",1)==0)
   { strcpy(nodo_nuevo->dato,"+"); nodo_nuevo->valor = 0; }

   else if( strncmp(cad,"x",1)==0)
   { strcpy(nodo_nuevo->dato,"x"); nodo_nuevo->valor = 1; }

   else
   { strcpy(nodo_nuevo->dato,"0"); nodo_nuevo->valor = atoi(cad); }
   nodo_nuevo->exp = 1;
   nodo_nuevo->sig = NULL;
   return nodo_nuevo;
}

void imprime(struct nodos *lista)
{
   while(lista)
   {
      if(strncmp(lista->dato,"0",1)==0)
      {
         if (lista->valor !=0) printf("%d",lista->valor);
      }
      if(strncmp(lista->dato,"+",1)==0)
      {
         if(lista->sig->valor !=0) printf("+");
      }
      if(strncmp(lista->dato,"x",1)==0)
      {
         if(lista->valor != 1) printf("%d",lista->valor);
         printf("x");
         if(lista->exp != 1) printf("^%d",lista->exp);         
      }
      lista = lista->sig;
   }
}

struct nodos *termino_que_falta(struct nodos *dato1,struct nodos *dato2)
{
   struct nodos *nuevo = NULL;
   char num[10];

   if(!dato1->sig && !dato2->sig) return NULL;
   if(!dato1->sig)
   {
      sprintf(num,"%d",dato1->valor*dato2->sig->valor);
      nuevo = reserva(num);
      if((strncmp(dato1->dato,"x",1)==0) ||
         (strncmp(dato2->sig->dato,"x",1)==0))
      strcpy(nuevo->dato,"x");
   }
   else
   {
      sprintf(num,"%d",dato2->valor*dato1->sig->valor);
      nuevo = reserva(num);
      if((strncmp(dato1->dato,"x",1)==0) ||
         (strncmp(dato2->sig->dato,"x",1)==0))
      strcpy(nuevo->dato,"x");
   }
   return nuevo;
}