[anterior] [seguinte]


Enunciado

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.


Gramática

Para se implementar o parser no bison é necessário rescrever a gramática para obedecer às precedências entre os operadores..

S → ID '=' E
SE
S
→ DECL L
S
→ HELP
L → ID  R
R → ',' ID | ε 
E
E '+' T
EE '-' T
ET
TT '*' F
TT '/' F
TF
F → '-' F
F → '(' E ')'
F → ID
F → ID  '(' E ')'
F → INT
F → REAL


Programa flex (exercicio9.lex)

%{

#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 () {

}

Programa bison (exercicio9.y)

%{
	#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);

}

Header file (exercicio9.codigo.h)


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();

Código (exercicio9.codigo.c)

#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