/* 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);
}