[anterior] [seguinte]
Implemente um analisador sintáctico para reconhecimento duma expressão aritmética, utilizando o bison. A gramática é a seguinte:
S → DECL L | VAR '=' E | E | HELP
E → E '+' E | E '-' E | E '*' E | E '/' E | '-' E | ( E ) | VAR | FUNCAO '(' E ')' | INT | REAL
L → VAR R
R → ',' VAR | ε
onde:
DECL é a palavra "decl" para declaração de uma variável;
VAR é um identificador de uma variável;
HELP é a palavra "help" ou o simbolo ?;
INT um número inteiro;
REAL um número real;
FUNCAO é o identificador para chamada a uma função predefinida..
O parser deve analisar múltiplas expressões e obter resultados, apresentando-os. Devem ser sempre definidas as variáveis que queremos utilizar e se uma variável tentar ser
redefinida deve ocorrer um erro.
Sempre que for pedido inserido HELP deve ser apresentadas as variáveis e funções definidas.
Sempre que haja uma atribuição esse valor deve ser guardado para ser utilizado com o identificador respectivo e se a variável não estiver definida deve ser apresentado um erro.
Para se implementar o parser no bison é necessário rescrever a gramática para obedecer às precedências entre os operadores..
S → ID '=' E
S → E
S → DECL L
S → HELP
L → ID R
R → ',' ID | ε
E → E '+' T
E → E '-' T
E → T
T → T '*' F
T → T '/' F
T → F
F → '-' F
F → '(' E ')'
F → ID
F → ID '(' E ')'
F → INT
F → REAL
%{ #include"exercicio9.codigo.h" #include"exercicio9.tab.h" #include<math.h> #include<strings.h> %} digito [0-9] letra [A-Za-z] %% [ \t]+ <<EOF>> return 0; {digito}+ yylval.valint=atoi(yytext);return INT; ({digito}*\.)?{digito}+([eE][-+]?{digito}+)? yylval.valreal=atof(yytext);return REAL; help|ajuda|"?" return HELP; decl return DECL; ({letra}|_)({letra}|{digito}|_)* { yylval.smb=getSimbolo(yytext); return ID; } "("|")"|"+"|"-"|"*"|"/"|"="|","|\n return yytext[0]; . printf("erro lexico: %s\n",yytext); %% int yywrap () { }
%{ #include"exercicio9.codigo.h" #include<math.h> extern char *yytext; %} %union { double valreal; int valint; simbolo *smb; } %left '+' '-' %left '*' '/' %nonassoc UMENOS %token <valint> INT %token <valreal> REAL %token <smb> ID %token HELP DECL %token VAR FUNCAO /* token utilizado somente para definir tipo de ID */ %type <valreal> termo %% calculadora: /* vazio */ {printf("#");} | calculadora expressao '\n' {printf("#");} | calculadora error '\n' {printf("#");yyerrok;} ; /* A produção "expressao" tem uma alternativa com código intermédio, a alternativa ID {Acção Semântica 1} '=' termo {Acção Semântica 2} Quando se utiliza, acções semânticas intermédias, estas ocupam uma variável dos tokens, isto é o ID é $1, a Acção semântica 1 é $2, o '=' é $3 e o termo é $4 e já agora a acção semântica 2 é $5. Numa acção semântica, só podem ser utilizados os $'s até ao menores que a própria acção (na acção semântica 1 só pode ser utilizado o $1), podendo no entanto ser atribuído um valor ao $ da acção ex.: $2=1; */ expressao: termo {printf("resultado %f\n", $1);} | ID { if ($1==NULL) /* verifica se a variável existe */ yyerror("Variavel não definida"); }/* este codigo intermédio ocoupa o $2 */ '=' termo { if ($1!=NULL) /* só guarda se a variável existir */ {printf("guardado %f\n", $4); $1->valor.var=$4; } } | HELP {apresenta_ajuda();} | DECL listaID ; listaID: ID {if ($1==NULL) /* identificador ainda não foi utilizado */ { printf("Adicionando a variável %s\n",yytext); addSimbolo(yytext,VAR); } else /* identificador já foi utilizado */ yyerror("Variavel redeclarada"); } | listaID ',' ID {if ($3==NULL) /* identificador ainda não foi utilizado */ { printf("Adicionando a variável %s\n",yytext); addSimbolo(yytext,VAR); } else /* identificador já foi utilizado */ yyerror("Variavel redeclarada"); } ; termo: termo '+' termo {$$=$1+$3;} | termo '-' termo {$$=$1-$3;} | termo '*' termo {$$=$1*$3;} | termo '/' termo {if ($3==0) yyerror("divisao por zero"); else $$=$1/$3; } | '-' termo %prec UMENOS {$$=-$2;} | '(' termo ')' {$$=$2;} | REAL {$$=$1;} | INT {$$=$1;} | ID {if($1==NULL) /* variável não existe */ { yyerror("variavel não declarada"); $$=0; } else if($1->tipo==VAR) /* identificador é variável */ $$=$1->valor.var; else /* identificador não é variável */ { yyerror("identificador mal utilizado"); $$=0; } } | ID '(' termo ')' {if($1==NULL) /* identificador não existe */ yyerror("função não declarada"); else if($1->tipo==FUNCAO) /* identificador é função */ $$=$1->valor.funcptr($3); else /* identificador não é função */ yyerror("identificador não é função"); } ; %% void main(){ /* adicionar funções */ addFunc("sqrt",sqrt); addFunc("sin",sin); addFunc("cos",cos); addFunc("tan",tan); addFunc("log",log); yyparse(); } int yyerror(char *s){ printf("erro sintactico/semantico: %s\n",s); }
typedef struct simbolo { char *nome; int tipo; /* tipo do identificador VAR, FUNCAO */ union { double var; /* Valor da variável */ double (*funcptr)(); /* Apontador para a função */ }valor; struct simbolo *prox; }simbolo; extern simbolo *tabela_simbolos; simbolo *getSimbolo(char*); simbolo *addSimbolo(char*, int); simbolo *addFunc(char*, double (*)()); void apresenta_ajuda();
#include"exercicio9.codigo.h" #include"exercicio9.tab.h" #include<strings.h> simbolo *tabela_simbolos=NULL; void apresenta_ajuda() { simbolo *ptr; printf("ajuda\n"); printf("?|ajuda|help - Este texto de ajuda\n"); printf("decl <id> - declara uma variável\n"); printf("<id> = <expressão> - atribui à variável o resultado da expressão\n"); printf("<expressão> - apresenta o resultado da expressão\n"); /* Apresenta funções definidas */ printf("Funções:"); for(ptr=tabela_simbolos;ptr!=NULL;ptr=ptr->prox) if(ptr->tipo==FUNCAO) printf("\t %s",ptr->nome); /* Apresenta variáveis definidas */ printf("\nVariáveis:"); for(ptr=tabela_simbolos;ptr!=NULL;ptr=ptr->prox) if(ptr->tipo==VAR) printf("\t %s(%.3f)",ptr->nome,ptr->valor.var); printf("\n"); } simbolo *getSimbolo(char *nome){ simbolo *ptr; for(ptr=tabela_simbolos;ptr!=NULL;ptr=ptr->prox) if(strcmp(nome,ptr->nome)==0) return(ptr); return(NULL); } simbolo *addSimbolo(char *nome, int tipo){ simbolo *ptr; ptr=(simbolo*)malloc(sizeof(simbolo)); if(ptr==NULL) { printf("Erro: falta de memória\n"); exit(1); } ptr->nome=(char*)malloc(strlen(nome)+1); if(ptr->nome==NULL) { printf("Erro: falta de memória\n"); exit(1); } printf("Copiando %s\n",nome); strcpy(ptr->nome,nome); ptr->tipo=tipo; ptr->valor.var=0; ptr->prox=tabela_simbolos; tabela_simbolos=ptr; return(ptr); } simbolo *addFunc(char *nome, double (*fptr)()){ simbolo *ptr; ptr=addSimbolo(nome,FUNCAO); ptr->valor.funcptr=fptr; return(ptr); }
[anterior] [seguinte]
Ultima alteração: segunda-feira, 04 de Dezembro de 2000 às 20:12