COMPIL_C.YAC



/* GENERAR PSEUDOCODIGO INTERMEDIO DE C */
/*
   --------------------------------------------------
   ---   Programa: com.yac                        ---
   ---   TEcnica:  dirigida por la sintAxis       ---
   ---   Objetivo: generar pseudocOdigo           ---
   ---             intermedio del lenguaje c      ---
   ---   Recibe:   un archivo con codigo c        ---
   ---   Regresa:  un archivo con pseudocOdigo    ---
   ---   Programador: J. Rafael R. Ochoa          ---
   --------------------------------------------------
*/

%{
   struct codigo			/* almacena el codigo objeto (*.ok)*/
   {
      char comando[50];			/* nombre de comando*/
      struct codigo *sig;		/* apuntador al siguiente nodo*/
   };
   struct args
   {
      char tipo[50];
      char nombre[50];
      struct args *sig;
   };
   struct var_locs
   {
      char tipo[50];
      char nombre[50];
      char valor[50];
      struct var_locs *sig;
   };
   struct prototipos
   {
      char tipo[50];
      char nombre[80];
//      struct args *arg;
      struct prototipos *sig;
   };
   char e1[20], e2[20], b1[20], b2[20];	/* variables de etiqueta y brinco*/
   char varia[256], variable[256];	/* variable para formar cadenas */
   char ret[10];			/* tipo de variable a regresar */
   int n, ok=0;				/* variable para ciclos*/
   int etiqueta = 0;			/* inicio de la etiqueta*/
   int rafa = 0,flag = 0;			/* banderas para los espacios */
   struct args *checa_args;
   struct var_locs *checa_var_locs;
   struct prototipos *checa_protos;

   struct codigo *nodo(char *cad);
   int quita_espacios(char arch[]);
   struct codigo *append(struct codigo *append1, struct codigo *append2);
   char *genera_etiqueta(void);
   void archiva(struct codigo *programa);
   void inserta_proto(char [], char []);
   void inserta_arg (char [], char []);
   void inserta_var_locs(char [], char [], char []);
   int checa_n_args(struct codigo *, struct codigo *);
   int checa_tipos(struct codigo *, struct codigo *);
   char *substr(int , char *);
   char *extrae_nom(struct codigo *lista);

%}

%union
{ 
   struct codigo *pseudo;
   char str[80];
}

/* __________________________________________________________dominio_*/
%token <str> L_LLAVE R_LLAVE L_PARENT R_PARENT L_CUADRO R_CUADRO
/* _____________________________________________________________tipo_*/
%token <str> F_LIN F_INT F_CAD F_CAR CAD CHAR INT VOID
/* ___________________________________________________________varios_*/
%token <str> DIAGONAL COMILLA APOSTROFE PUNTO_COMA COMA GATO
%token <str> INCLUDE DEFINE AMPER PUNTO FORMATO ESPACIO
/* _________________________________________________________operacion_*/
%token <str> MAS MENOS DIV ASTER
%token <str> IDENTICO ASIGNA OR AND MENOR MAYOR NOT NOT_EQ
%token <str> MAYOR_IGUAL MENOR_IGUAL
%token <str> TEXTO RETURN
/* ___________________________________________________________ciclos_*/
%token <str> WHILE FOR 
%token <str> PRINTF PUTS
%token <str> GETS SCANF FFLUSH STDOUT
%token <str> IF ELSE
/* ________________________________________tokens que regresan valor_*/
%token <str> NUM
/* ______________________________________________reglas gramaticales_*/
%type <pseudo> programa
%type <pseudo> includes include
%type <pseudo> resto ambos_pro_fun pro_fun
%type <pseudo> instrucciones instruccion
%type <pseudo> args arg arg_resto
%type <pseudo> atomica progresion
%type <pseudo> llamada_funcion parametros parametro param_coma
%type <pseudo> var_locs var_loc var_resto
%type <pseudo> expr termino factor var asignacion
%type <pseudo> condicion printf else
%type <pseudo> textos
%type <pseudo> var_format v_format v_for_fin var_scan
%type <str> tipo asig_resto operador

%%
programa	: includes resto
		   { archiva($2); }
		;
includes	: include { $$ = $1; }
		| include includes { $$ = append($1, $2); }
		;
include		: GATO INCLUDE MENOR TEXTO PUNTO TEXTO MAYOR
		   { sprintf(variable,"ic %s",$4); $$ = nodo(variable); }
		;
resto		: tipo TEXTO PUNTO_COMA resto
		   {
		      sprintf(variable,"vl %s",$2);
		      $$ = append(nodo(variable), $4);
		   }
		| tipo TEXTO L_PARENT ambos_pro_fun resto
		   {
		         if(rafa==0)
		         {
		            sprintf(variable,"vl %s",$2);
		            rafa = 0;
		            $$ = nodo(variable);
		         }
		         if(rafa==1)
		         {
		            sprintf(variable,"fu %s",$2);
		            sprintf(varia,"mv %s %s",ret,$2);
		            rafa = 1;
		            $$ = append(nodo(variable), append(nodo(varia),
		                 append($4,$5)));
		         }
		   }
		| { $$ = NULL; }
		;
ambos_pro_fun	: args R_PARENT pro_fun /* prototipo o funcion */
		   {
		      if (!$3) { $$ = NULL; rafa=0; }
		      else
		      {
		         strcpy(ret,"num");
		         rafa = 1;
		         $$ = $3;
		      }
		   }
		;
args		: { $$ = NULL; }
		| VOID { $$ = NULL; }
		| arg { $$ = $1; }
		;
arg		: tipo arg_resto
		   /*{ $$ = NULL; }*/
		   { $$ = $2; }
		;
arg_resto	: { $$ = NULL; }
		| COMA arg
		   { $$ = $2; }
		| TEXTO
		   { $$ = nodo($1); }
		| TEXTO COMA arg
		   { $$ = append(nodo($1), $3); }
		;
pro_fun		: PUNTO_COMA /* prototipo */
		   { $$ = NULL; }
		| L_LLAVE var_locs instrucciones R_LLAVE /* funcion */
		   {
		      $$ = append($2, append($3,nodo("rs")));
		      checa_var_locs = NULL;
		   }
		;
var_locs	: { $$ = NULL; }
		| var_loc var_locs
		   { $$ = append($1,$2); }
		;
var_loc		: tipo TEXTO var_resto PUNTO_COMA
		   {
		     sprintf(variable,"vl %s",$2);
		     $$ = append(nodo(variable), $3);
		     inserta_var_locs($1,$2,"");
		   }
		;
var_resto	: { $$ = NULL; }
		| ASIGNA NUM
		   { $$ = append(nodo("va"),nodo($2)); }
		| COMA TEXTO var_resto
		   { $$ = append(nodo($2),$3); }
		;

tipo		: INT  { strcpy($$,"int"); }
		| CHAR { strcpy($$,"char"); }
		| CAD  { strcpy($$,"char *"); }
		| VOID { strcpy($$,"void"); }
		;
instrucciones	: instruccion { $$ = $1; }
		| instruccion instrucciones { $$ = append($1,$2); }
		;
instruccion	: PUNTO_COMA { $$ = NULL; }
		| atomica PUNTO_COMA { $$ = $1; }
		| IF L_PARENT condicion R_PARENT instruccion else
		     {
		       sprintf(e1, "%s", genera_etiqueta());
                       sprintf(e2, "%s", genera_etiqueta());
                       sprintf(b1, "sa %s", e1);
                       sprintf(b2, "sa %s", e2);
                       $$ = append($3, append(nodo(b1),
                                      append($5,
                                      append(nodo(b2),
                                      append(nodo(e1),
                                      append($5, nodo(e2))))))
                                 );
                     }
		| FOR L_PARENT asignacion PUNTO_COMA condicion PUNTO_COMA
		      progresion R_PARENT instruccion
		     {
		       sprintf(e1, "%s", genera_etiqueta());
		       sprintf(e2, "%s", genera_etiqueta());
		       sprintf(b1, "sa %s", e1);
		       sprintf(b2, "sa %s", e2);
			  $$ = append($3, append(nodo(e1), append($5,
			       append(nodo(b2), append($9, append($7,
			       append(nodo(b1), nodo(e2)))))))
				     );
		     }
		| WHILE L_PARENT condicion R_PARENT instruccion
		     {
		       sprintf(e1, "%s", genera_etiqueta());
		       sprintf(e2, "%s", genera_etiqueta());
		       sprintf(b1, "sa %s", e1);
		       sprintf(b2, "sa %s", e2);
			  $$ = append(nodo(e1), append($3,
			       append(nodo(b2), append($5,
			       append(nodo(b1), nodo(e2)))))
				     );
		     }
		| L_LLAVE instrucciones R_LLAVE
		     { $$ = $2; }
		;
else		: { $$ = NULL; }
		| ELSE instruccion { $$ = $2; }
		;
llamada_funcion	: TEXTO L_PARENT parametros R_PARENT
		     {
		       sprintf(varia,"mv %s %s",ret, $1);
		       sprintf(variable,"ca %s",$1);
		       $$ = append(nodo(varia), append($3, nodo(variable)));
		     }
		;
asignacion	: TEXTO ASIGNA asig_resto
		   {
		      if(strncmp($3,"mu",2)==0 || strncmp($3,"ad",2)==0)
		      {
		         sprintf(variable,"mv %s %s",substr(2,$3),$1);
		         $$ = append(nodo($3), nodo(variable));
		      }
		      else
		      {
		         sprintf(variable,"mv %s %s",$3,$1);
		         $$ = nodo(variable);
		      }
/*		      sprintf(variable,"mv %s %s",substr(2,$3),$1);
		      $$ = append(nodo($3), nodo(variable));
*/
		   }
		;
asig_resto	: TEXTO { strcpy($$, $1); }
		| NUM   { strcpy($$, $1); }
		| expr  { strcpy($$, $1->comando); }
		;
progresion	: TEXTO MAS MAS
		   {
		     sprintf(variable,"mm %s",$1);
		     $$ = nodo(variable);
		   }
		| TEXTO MENOS MENOS
		   {
		     sprintf(variable,"ll %s",$1);
		     $$ = nodo(variable);
		   }
		| MAS MAS TEXTO
		   {
		     sprintf(variable,"mm %s",$1);
		     $$ = nodo(variable);
		   }
		| MENOS MENOS TEXTO
		   {
		     sprintf(variable,"ll %s",$1);
		     $$ = nodo(variable);
		   }
		| asignacion { $$ = $1; }
		;
condicion	: TEXTO operador TEXTO
		   {
		     sprintf(variable,"%s %s %s",$1,$2,"num");
		     $$ = nodo(variable);
		   }
		| TEXTO operador NUM
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| TEXTO operador expr
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| NUM operador TEXTO
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| NUM operador NUM
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| NUM operador expr
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| expr operador NUM
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| expr operador TEXTO
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| expr operador expr
		   {
		     sprintf(variable,"%s %s %s",$1,$2,$3);
		     $$ = nodo(variable);
		   }
		| NOT expr
		   {
		     sprintf(variable,"no %s",$1,$2);
		     $$ = nodo(variable);
		   }
		;
operador	: IDENTICO    { strcpy($$, "id"); }
		| MAYOR       { strcpy($$, "ma"); }
		| MENOR       { strcpy($$, "me"); }
		| MAYOR_IGUAL { strcpy($$, "ge"); }
		| MENOR_IGUAL { strcpy($$, "le"); }
		| NOT_EQ      { strcpy($$, "ne"); }
		;
parametros	: { $$ = NULL; }
		| parametro parametros { $$ = append($1,$2); }
		;
parametro	: NUM param_coma
		   {
		      $$ = append(nodo("pa"), append(nodo($1),$2));
		   }
		| TEXTO
		   {
		      sprintf(ret,"%s",$1);
		      $$ = NULL;
		   }
		| APOSTROFE TEXTO APOSTROFE param_coma
		   {
		      $$ = append(nodo("pa"), append(nodo($2),$4));
		   }
		| var param_coma
		   { $$ = append(nodo("pa"), append($1, $2)); }
		| expr param_coma
		   { $$ = append(nodo("pa"), append($1, $2)); }
		;
param_coma	: { $$ = NULL; }
		| COMA parametro { $$ = $2; }
		;
atomica		: PRINTF
		  L_PARENT
		        COMILLA {flag=1;} textos {flag=0;} COMILLA printf
		  R_PARENT
		  {
		     $$ = append($5, $8);
		     /*if(!checa_n_args($5, $8))
		     {
		        strcpy(error, "n_args != n_var en printf");
		        return 0;
		     }
		     if(!checa_tipos($5,$8))
		     {
		        strcpy(error, "tipos no compatibles en printf");
		        return 0;
		     }*/
		  }
		| RETURN TEXTO
		     {
		        sprintf(ret,"%s",$2);
		        $$ = NULL;
		     }
		| FFLUSH L_PARENT STDOUT R_PARENT
		     { $$ = nodo("ff"); }
		| PUTS L_PARENT COMILLA textos COMILLA R_PARENT
		     { $$ = append(nodo("pu"),$4); }
		| GETS L_PARENT var R_PARENT
		     { $$ = append(nodo("ge"),$3); }
		| SCANF L_PARENT COMILLA textos COMILLA COMA
		  var_scan R_PARENT
		     { $$ = $7; }
		| asignacion { $$ = $1; }
		| expr { $$ = $1; }
		| llamada_funcion { $$ = $1; }
		;
printf		: { $$ = NULL; }
		| COMA var_format { $$ = $2; }
		;
textos		: { $$ = NULL; }
		| F_LIN textos
		   {
		      sprintf(variable,"pr f_lin",$1);
		      $$ = append(nodo(variable), $2);
		   }
		| TEXTO textos 
		   {
		      sprintf(variable,"pr \"%s\"",$1);
		      $$ = append(nodo(variable), $2);
		   }
		;
expr		: expr MAS termino
		   {
		      sprintf(variable,"ad %s %s",$1,$3);
		      $$ = nodo(variable);
		   }
		| expr MENOS termino
		   {
		      sprintf(variable,"su %s %s",$1,$3);
		      $$ = nodo(variable);
		   }
		| termino { $$ = $1; }
		;
termino		: termino ASTER factor
		   {
		      sprintf(variable,"mu %s %s",$1,$3);
		      $$ = nodo(variable);
		   }
		| termino DIV factor
		   {
		      sprintf(variable,"di %s %s",$1,$3);
		      $$ = nodo(variable);
		   }
		| factor { $$ = $1; }
		;
factor		: var { $$ = $1; }
		| NUM { $$ = nodo($1); }
		| TEXTO ASIGNA expr
		   {
		     sprintf(variable,"mv %s %s",$3->comando,$1);
		     $$ = nodo(variable);
		   }
		| TEXTO ASIGNA llamada_funcion
		   {
		     sprintf(variable,"mv %s %s",extrae_nom($3),$1);
		     sprintf(varia,"ca %s",extrae_nom($3));
		     $$ = append(nodo(varia), nodo(variable));
		   }
		| L_PARENT expr R_PARENT { $$ = $2; }
		;
var		: TEXTO { $$ = nodo($1); }
		;
var_scan	: TEXTO
		   {
		      sprintf(variable,"sc %s", $1);
		      $$ = nodo(variable);
		   }
		| AMPER TEXTO
		   {
		      sprintf(variable,"sc %s", $2);
		      $$ = nodo(variable);
		   }
		;
var_format	: { $$ = NULL; }
		| v_format var_format
		   { $$ = append($1,$2); }
		;
v_format	: NUM  v_for_fin
		   {
		      sprintf(variable,"pr %s",$1);
		      $$ = append(nodo(variable),$2);
		   }
		| TEXTO  v_for_fin	/* es una variable */
		   {
		      sprintf(variable,"pr %s",$1);
		      $$ = append(nodo(variable),$2);
		   }
		| expr v_for_fin
		   {
		      sprintf(variable,"pr %s",$1->comando);
		      $$ = append(nodo(variable),$2);
		   }
		;
v_for_fin	: { $$ = NULL; }
		| COMA v_format { $$ = $2; }
		;
%%

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

extern int yylex();  /* Liga con la funcion yylex generada por FLEX */
extern int yynerrs;
extern FILE *yyin;


int yyparse();

int main(int argc, char *argv[])
{
   if (argc != 2)
      { printf ("\nuso: com archivo.c\n:-)\n"); return 1; }

   quita_espacios(argv[1]);

   if ((yyin = fopen("arch.c","rt")) == NULL)  // archivo de entrada
      { printf ("error al abrir el archivo\n:-(\n"); return 0; }
   
   checa_args = NULL;
   checa_var_locs = NULL;
   checa_protos = NULL;
   yyparse();        /* Llama al analizador sintactico */
   fclose(yyin);
   if(strlen(error)>5) printf("error: %s\n",error);
   printf("\n:-)\n");
   return 1;
}

yyerror()                     /* llamado por yyparse() cuando ocurra */
{                             /*   un error                          */
  printf("\n  [error en linea %d]", n_lines);
  printf("\n %s ==> %d",yylval.str, ok);
  return 1;
}

struct codigo *nodo(char *cad)
{
   struct codigo *nodo_nuevo = NULL;

   nodo_nuevo = (struct codigo *)malloc(sizeof(struct codigo));
   strcpy(nodo_nuevo->comando, cad);
   nodo_nuevo->sig     = NULL;
   return nodo_nuevo;
}

struct codigo *append(struct codigo *append1, struct codigo *append2)
{
   struct codigo *append_total = append1;
   struct codigo *anterior;

   if (!append1 && !append2) return NULL;
   if (append2 == NULL ) return append1;
   if (append1 == NULL ) return append2;
   while(append1) { anterior = append1; append1 = append1->sig; }
   anterior->sig = append2;
   return append_total;
}

char *genera_etiqueta(void)
{
   char etiq[20];

   sprintf(etiq, "etiq_%d", etiqueta);
   etiqueta++;
   return strdup(etiq);
}

void archiva(struct codigo *programa)
{
   FILE *out;
   printf("hola mundo ...");

   if ((out = fopen("pseudo.ok", "wt")) == NULL)   // archivo de salida
      { printf("No se puede crear el archivo pseudo.ok\n"); return; }
   printf("\nAlmacenando el archivo pseudo.ok\n");
   while(programa)
   {
      fprintf(out, "%s\n", programa->comando);
      programa = programa->sig;
   }

   fprintf(out, "ok\n");
   fclose(out);
}

int quita_espacios(char arch[])
{
   FILE *in,*out;
   char car1,car2;
   int ok = 0;

   if ((in  = fopen(arch,"rt")) == NULL)	// archivo fuente
      {  printf("No se puede abrir el archivo"); return 0; }
   if ((out = fopen("arch.c","w")) == NULL)	// archivo sin comentarios
      {  printf("No se puede abrir el archivo"); return 0; }

   car1 = fgetc(in);
   while (car1 != EOF)
   {
      if( car1 == '/')
      {
	car2 = fgetc(in); ok = 1;
	if (car2 == EOF) break;

	if( car2 == '/')
	{
	   ok = 0;
	   while(car1 != '\n' && car1 != EOF)
	      car1=fgetc(in);
	   continue;
	}
	if( car2 == '*')
	{
	   ok = 0;
	   while(1)
	   {
	      car1 = fgetc(in);
	      if(car1 == '*')
	       if(fgetc(in) == '/')
	       {  car1 = fgetc(in);
		  break;
	       }
	   }
	   continue;
	}
      }
      fputc(car1, out);
      if (ok) fputc(car2,out);
      car1 = fgetc(in);
   }
   if (car1 != EOF) fputc(car1,out);
   fclose(in);
   fclose(out);
   return 1;
}


void inserta_proto(char tipo[], char nombre[])
{
   struct prototipos *act = NULL;

   act = (struct prototipos *)malloc(sizeof(struct prototipos));
   
   strcpy(act->tipo,tipo);
   strcpy(act->nombre, nombre);
   act->sig = NULL;
   if (!checa_protos) checa_protos = act;
   else
   {
      act->sig = checa_protos;
      checa_protos = act;
   }
}

void inserta_var_locs(char tipo[], char nombre[], char valor[])
{
   struct var_locs *act = NULL;
   
   act = (struct var_locs *)malloc(sizeof(struct var_locs));
   
   strcpy(act->tipo, tipo);
   strcpy(act->nombre, nombre);
   strcpy(act->valor, valor);
   act->sig = NULL;
   
   if (!checa_var_locs) checa_var_locs = act;
   else
   {
      act->sig = checa_var_locs;
      checa_var_locs = act;
   }   
}

void inserta_arg(char tipo[], char nombre[])
{
   struct args *act = NULL;
   
   act = (struct args *)malloc(sizeof(struct args));
   
   strcpy(act->tipo, tipo);
   strcpy(act->nombre, nombre);
   act->sig = NULL;
   
   if (!checa_args) checa_args = act;
   else
   {
      act->sig = checa_args;
      checa_args = act;
   }   
}

int checa_n_args(struct codigo *args, struct codigo *vars)
{
   char formato[256];
   
   while(args)
   {
      strcpy(formato, args->comando);
      if(
            !strncmp(formato,"f_int",5) ||
            !strncmp(formato,"f_car",5) ||
            !strncmp(formato,"f_cad",5)
        )
      {
         if(vars)
            vars = vars->sig;
         else return 0;
      }
      args = args->sig;
   }
   return 1;
}

int checa_tipos(struct codigo *args, struct codigo *vars)
{
   char formato[256];
   
   while(args)
   {
      strcpy(formato, args->comando);
      if(
            !strncmp(formato,"f_int",5) ||
            !strncmp(formato,"f_car",5) ||
            !strncmp(formato,"f_cad",5)
        )
      {
         if( strncmp(vars->comando, formato,5)!=0)
         return 0;
         else vars = vars->sig;
      }
      args = args->sig;
   }
   return 1;
}

char *extrae_nom(struct codigo *lista)
{
   struct codigo *copia = lista;
   
   while(copia)
   {
      if(strncmp(copia->comando,"ca",2)==0) break;
      copia = copia->sig;
   }
   if (!copia)
   {
      printf("error, es llamada a funcion sin nombre de funcion");
      return '\0';
   }
   return substr(2, copia->comando);
}

char *substr(int n, char *string)	// devuelve palabra n de string
{
   char ch = string[0], car[1], ret[100], *cadena;

   cadena = (char *)malloc(80);
   cadena=strdup(string);
   while(n>1)
   { while (ch != ' ') { cadena++; ch = cadena[0]; }	// busca posicion
     cadena = cadena++; ch = cadena[0]; n--;
   }

   ch = cadena[0]; ret[0] = '\0';
   while (ch != ' ' && ch != '\0' &&  ch != '\n' && ch != ';')	// busca finalizador
   { car[0] = ch; car[1] = '\0'; strcat(ret, car);
      cadena++; ch = cadena[0];
   }
   return strdup(ret);
}