A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

CES-41 COMPILADORES Aulas Práticas - 2013 Capítulo III Análise Semântica no Yacc.

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Aulas Práticas - 2013 Capítulo III Análise Semântica no Yacc."— Transcrição da apresentação:

1 CES-41 COMPILADORES Aulas Práticas Capítulo III Análise Semântica no Yacc

2 Neste capítulo, será vista a construção da tabela de símbolos e a análise semântica para linguagens de programação Neste capítulo, será vista a construção da tabela de símbolos e a análise semântica para linguagens de programação A tabela de símbolos é fundamental para análise semântica e para geração do código intermediário A tabela de símbolos é fundamental para análise semântica e para geração do código intermediário Além disso pode ser devidamente aproveitada durante a interpretação e a construção do código objeto Além disso pode ser devidamente aproveitada durante a interpretação e a construção do código objeto

3 A complexidade das linguagens pode ser abordada progressivamente: 1.Inicialmente sem subprogramas, só variáveis escalares e comandos de atribuição 2.Acrescenta-se comandos condicionais, repetitivos e de entrada e saída 3.Acrescenta-se variáveis indexadas 4.Acrescenta-se subprogramas e variáveis globais 5.Acrescenta-se blocos e aninhamento de subprogramas 6.Acrescenta-se estruturas e ponteiros, etc. Abordagem do projeto

4 Estrutura de dados para a tabela de símbolos: Será usada a estrutura de hashing aberto Será usada a estrutura de hashing aberto Função para o hashing: Função para o hashing:Onde: – NCLASSHASH é o número de classes. – n é o número de caracteres de x (sem o \0)

5 Exemplo: Tabela de símbolos (hashing) do programa do fatorial (NCLASSHASH = 23)

6 Declarações para a tabela de símbolos: typedef struct celsimb celsimb; typedef celsimb *simbolo; struct celsimb { char *cadeia; int tid, tvar; logic inic, ref; simbolo prox; }; Variáveis globais: simbolo simb; simbolo tabsimb[NCLASSHASH];

7 Programa 3.1: gramática sem subprogramas, só variáveis escalares e comandos de atribuição A gramática a seguir é uma simplificação daquela da linguagem COMP-ITA 2013 A gramática a seguir é uma simplificação daquela da linguagem COMP-ITA 2013 Seja ela chamada de Sub-Set 2013 Seja ela chamada de Sub-Set 2013

8 Prog:programa ID PVIRG Decls CmdComp Decls: | var ListDecl ListDecl : Declaracao | ListDecl Declaracao Declaracao:Tipo ListElemDecl PVIRG Tipo:int | real | carac | logic ListElemDecl :ElemDecl | ListElemDecl VIRG ElemDecl ElemDecl:ID CmdComp :ABCHAV ListCmds FCHAV ListCmds: | ListCmds Comando Comando:CmdComp | CmdAtrib CmdAtrib:Variavel ATRIB Expressao PVIRG ElemDecl: Não-terminal prevendo variáveis indexadas

9 Expressao : ExprAux1 | Expressao OR ExprAux1 ExprAux1 : ExprAux2 | ExprAux1 AND ExprAux2 ExprAux2 : ExprAux3 | NOT ExprAux3 ExprAux3 : ExprAux4 | ExprAux4 OPREL ExprAux4 ExprAux4 : Termo | ExprAux4 OPAD Termo Termo : Fator | Termo OPMULT Fator Fator: Variavel | CTINT | CTREAL | CTCARAC | verdade | falso | NEG Fator | ABPAR Expressao FPAR Variavel: ID Variavel: Não-terminal prevendo variáveis indexadas

10 A seguir 3 arquivos fornecidos na aba de Códigos da página do professor: A seguir 3 arquivos fornecidos na aba de Códigos da página do professor: tsimb y (analisador sintático) tsimb y (analisador sintático) tsimb l (analisador léxico) tsimb l (analisador léxico) tsimb dat (programa a ser analisado) tsimb dat (programa a ser analisado) O primeiro deles contém declarações e funções para montagem de uma tabela de símbolos O primeiro deles contém declarações e funções para montagem de uma tabela de símbolos Depois da sua apresentação, seguem orientações para a montagem da tabela Depois da sua apresentação, seguem orientações para a montagem da tabela

11 a) Arquivo tsimb y %{ /* Inclusao de arquivos da biblioteca de C */ #include #include

12 /* Definicao dos atributos dos atomos operadores */ #define LT 1 #define LE 2 #defineGT3 #defineGE4 #defineEQ5 #defineNE6 #defineMAIS 7 #defineMENOS 8 #defineMULT 9 #defineDIV 10 #defineRESTO 11

13 /* Definicao dos tipos de identificadores */ #define IDPROG1 #define IDVAR2 /* Definicao dos tipos de variaveis */ #define NOTVAR0 #define INTEGER1 #define LOGICAL2 #define FLOAT3 #define CHAR4 /* Definicao de outras constantes */ #defineNCLASSHASH23 #defineTRUE1 #defineFALSE0 Para o caso de não ser um identificador de variável

14 /* Strings para nomes dos tipos de identificadores */ char *nometipid[3] = {" ", "IDPROG", "IDVAR"}; /* Strings para nomes dos tipos de variaveis */ char *nometipvar[5] = {"NOTVAR", "INTEGER", "LOGICAL", "FLOAT", "CHAR" }; A serem usadas na função para escrever na tela a tabela de símbolos (ImprimeTabSimb)

15 /* Declaracoes para a tabela de simbolos */ typedef struct celsimb celsimb; typedef celsimb *simbolo; struct celsimb { char *cadeia; int tid, tvar; char inic, ref; simbolo prox; }; /* Variaveis globais para a tabela de simbolos e analise semantica */ */ simbolo tabsimb[NCLASSHASH]; simbolo simb;

16 /* Prototipos das funcoes para a tabela de simbolos e analise semantica e analise semantica */ */ void InicTabSimb (void); void ImprimeTabSimb (void); simbolo InsereSimb (char *, int, int); int hash (char *); simbolo ProcuraSimb (char *); void DeclaracaoRepetida (char *); void TipoInadequado (char *); void NaoDeclarado (char *); %}

17 /* Definicao do tipo de yylval e dos atributos dos nao terminais */ %union { char cadeia[50]; int atr, valint; float valreal; char carac; }

18 /* Declaracao dos atributos dos tokens e dos nao-terminais */ %token ID %token CTCARAC %token CTINT %token CTREAL %tokenOR %tokenAND %tokenNOT %token OPREL %token OPAD %token OPMULT %tokenNEG

19 %tokenABPAR %tokenFPAR %tokenABCHAV %tokenFCHAV %tokenVIRG %tokenPVIRG %tokenATRIB %tokenCARAC %tokenFALSO %tokenINT %tokenLOGIC %tokenPROGRAMA %tokenREAL %tokenVAR %tokenVERDADE %token INVAL %

20 /* Producoes da gramatica: Os terminais sao escritos e, depois de alguns, para alguma estetica, ha mudanca de linha */ Prog:PROGRAMA ID PVIRG {printf ("programa %s ;\n", $2);} Decls CmdComp ; Decls : |VAR {printf ("var\n");} ListDecl ; ListDecl: Declaracao |ListDecl Declaracao ;

21 Declaracao:Tipo ListElemDecl PVIRG {printf (";\n");} ; Tipo: INT {printf ("int ");} | REAL {printf ("real ");} | CARAC {printf ("carac ");} | CARAC {printf ("carac ");} | LOGIC {printf ("logic ");} | LOGIC {printf ("logic ");}; ListElemDecl: ElemDecl | ListElemDecl VIRG {printf (", ");} ElemDecl; ElemDecl :ID {printf ("%s ", $1);} ;

22 CmdComp: ABCHAV {printf ("{\n");} ListCmds FCHAV {printf ("}\n");} ; ListCmds: | ListCmds Comando ; Comando : CmdComp | CmdAtrib | CmdAtrib; CmdAtrib : Variavel ATRIB {printf (:= ");} Expressao PVIRG {printf (";\n");} ;

23 Expressao : ExprAux1 | Expressao OR {printf ("|| ");} ExprAux1 ; ExprAux1 : ExprAux2 | ExprAux1 AND {printf ("&& ");} ExprAux2 ; ExprAux2 : ExprAux3 | NOT {printf ("! ");} ExprAux3 ;

24 ExprAux3 : ExprAux4 | ExprAux4 OPREL { switch ($2) { switch ($2) { case LT: printf ("< "); break; case LE: printf ("<= "); break; case EQ: printf ("= "); break; case NE: printf ("!= "); break; case GT: printf ("> "); break; case GE: printf (">= "); break; } } ExprAux4 } ExprAux4;

25 ExprAux4 : Termo | ExprAux4 OPAD { switch ($2) { case MAIS: printf ("+ "); break; case MAIS: printf ("+ "); break; case MENOS: printf ("- "); break; case MENOS: printf ("- "); break;} } Termo } Termo; Termo : Fator | Termo OPMULT { switch ($2) { case MULT: printf ("* "); break; case MULT: printf ("* "); break; case DIV: printf ("/ "); break; case DIV: printf ("/ "); break; case RESTO: printf ("% "); break; case RESTO: printf ("% "); break;} } Fator } Fator;

26 Fator: Variavel | CTINT {printf ("%d ", $1);} | CTREAL {printf ("%g ", $1);} | CTREAL {printf ("%g ", $1);} | CTCARAC {printf ("\'%c\' ", $1);} | CTCARAC {printf ("\'%c\' ", $1);} | VERDADE {printf ("verdade ");} | VERDADE {printf ("verdade ");} | FALSO {printf ("falso ");} | FALSO {printf ("falso ");} | NEG {printf ("~ ");} Fator | NEG {printf ("~ ");} Fator | ABPAR {printf ("( ");} Expressao FPAR | ABPAR {printf ("( ");} Expressao FPAR {printf (") ");} ; Variavel: ID {printf ("%s ", $1);} ;%

27 /* Inclusao do analisador lexico */ #include "lex.yy.c" /* InicTabSimb: Inicializa a tabela de simbolos */ void InicTabSimb () { int i; for (i = 0; i < NCLASSHASH; i++) tabsimb[i] = NULL; }

28 /* ProcuraSimb (cadeia): Procura cadeia na tabela de simbolos; Caso ela ali esteja, retorna um ponteiro para sua celula; Caso contrario, retorna NULL. */ */ simbolo ProcuraSimb (char *cadeia) { simbolo s; int i; i = hash (cadeia); for (s = tabsimb[i]; (s!=NULL) && strcmp(cadeia, s->cadeia); s = s->prox); return s; }

29 /* InsereSimb (cadeia, tid, tvar): Insere cadeia na tabela de simbolos, com tid como tipo de identificador e com tvar como tipo de variavel; Retorna um ponteiro para a celula inserida */ */ simbolo InsereSimb (char *cadeia, int tid, int tvar) { int i; simbolo aux, s; i = hash (cadeia); aux = tabsimb[i]; s = tabsimb[i] = (simbolo) malloc (sizeof (celsimb)); s->cadeia = (char*) malloc ((strlen(cadeia)+1) * sizeof(char)); strcpy (s->cadeia, cadeia); s->tid = tid;s->tvar = tvar; s->inic = FALSE;s->ref = FALSE; s->prox = aux;return s; }

30 /* hash (cadeia): funcao que determina e retorna a classe de cadeia na tabela de simbolos implementada por hashing */ */ int hash (char *cadeia) { int i, h; for (h = i = 0; cadeia[i]; i++) {h += cadeia[i];} h = h % NCLASSHASH; return h; }

31 /* ImprimeTabSimb: Imprime todo o conteudo da tabela de simbolos */ void ImprimeTabSimb () { int i; simbolo s; printf ("\n\n TABELA DE SIMBOLOS:\n\n"); for (i = 0; i < NCLASSHASH; i++) if (tabsimb[i]) { printf ("Classe %d:\n", i); for (s = tabsimb[i]; s!=NULL; s = s->prox){ printf (" (%s, %s", s->cadeia, nometipid[s->tid]); if (s->tid == IDVAR) printf (", %s, %d, %d", nometipvar[s->tvar], s->inic, s->ref); printf(")\n");}}}

32 /* Mensagens de erros semanticos */ void DeclaracaoRepetida (char *s) { printf ("\n\n***** Declaracao Repetida: %s *****\n\n", s); } void NaoDeclarado (char *s) { printf ("\n\n***** Identificador Nao Declarado: %s *****\n\n", s); } void TipoInadequado (char *s) { printf ("\n\n***** Identificador de Tipo Inadequado: %s *****\n\n", s); }

33 b) Arquivo tsimb l %{ void comentario (void); char tratachar (char *); %} delim[ \t\n\r] ws{delim}+ digito[0-9] letra[A-Za-z] ctint{digito}+ id{letra}({letra}|{digito})* ctreal{digito}+\.{digito}*([Ee][+-]?{digito}+)? carac1\\.|[^\\'] ctcarac'{carac1}' %

34 {ws}{ ;} "/*"{comentario ();} carac{return CARAC;} falso{return FALSO;} int{return INT;} logic{return LOGIC;} programa {return PROGRAMA;} real{return REAL;} var{return VAR;} verdade{return VERDADE;} {id}{strcpy (yylval.cadeia, yytext); return ID;} {ctcarac}{yylval.carac = tratachar (yytext); return CTCARAC;} {ctint}{yylval.valint = atoi(yytext); return CTINT;} {ctreal}{yylval.valreal = atof(yytext); return CTREAL;}

35 "||"{return OR;} "&&"{return AND;} "!"{return NOT;} "<"{yylval.atr = LT; return OPREL;} "<="{yylval.atr = LE; return OPREL;} ">"{yylval.atr = GT; return OPREL;} ">="{yylval.atr = GE; return OPREL;} "="{yylval.atr = EQ; return OPREL;} "!="{yylval.atr = NE; return OPREL;} "+"{yylval.atr = MAIS; return OPAD;} "-"{yylval.atr = MENOS; return OPAD;} "*"{yylval.atr = MULT; return OPMULT;} "/"{yylval.atr = DIV; return OPMULT;} "%"{yylval.atr = RESTO; return OPMULT;} "~"{return NEG;}

36 "("{return ABPAR;} ")"{return FPAR;} "{"{return ABCHAV;} "}"{return FCHAV;} ";"{return PVIRG;} ","{return VIRG;} :="{return ATRIB;}.{yylval.carac = yytext[0]; return INVAL;} %

37 /*comentario: le e descarta os comentarios do programa */ void comentario () { char c; int estado; estado = 1; while (estado != 3) { switch (estado) { case 1: c = input (); if (c == EOF) estado = 3; else if (c == '*') estado = 2; break; case 2: c = input (); if (c == EOF || c == '/') estado = 3; else if (c != '*') estado = 1; break; }}}

38 /* tratachar: retorna o codigo ASCII de uma constante do tipo char, eliminando os apostrofos (') e as barras invertidas (\) */ */ char tratachar (char *s) { if (s[1] != '\\') return s[1]; else switch (s[2]) { case 'a': return 7;case '\\': return 92; case 'b': return 8;case 'r': return 13; case '\"': return 34;case 'f': return 12; case 't': return 9;case 'n': return 10; case '0': return 0;case '\'': return 39; case 'v': return 11; default:return s[2]; }} 'K'\0'n'\ 'K'\ S =

39 c) Arquivo tsimb dat programa teste; var int i, jjj, h, tb; logic n, m; real v, i; carac x, y, z, w;

40 { x := n && m; v := 3.5 * v; y := { i := jjj*falso; jjj := 0; i := jjj*falso; jjj := 0;} jjj := n + 1; i := i + 1; { i := !i; i := i z; i := !i; i := i z; { i := 0; jjj := 0; i := 0; jjj := 0; } jjj := jjjj + teste; jjj := jjjj + teste;}

41 m := v + 2 > x; m := n != verdade; m := i >= n; n := m = 4; i := i + 1; n := ~ m; n := (!m && n) && (m && !n); i := n / 5; i := (!m && n) / 5; n := (!m || n) && (m || !n); n := (!m || n) && (tb + v); n := (!m || n) || (tb + v); n := (~h + v) * (tb - jjj); i := (!m || n) - 5; } Rodar tudo com o arquivo tsimb dat

42 Exercício 3.1: Inserir no programa 3.1 programação para montar a tabela dos símbolos dos programas analisados e realizar alguns testes semânticos simples, executando as seguintes tarefas: a)Inicializar a tabela de símbolos, anulando os ponteiros de todas as suas classes, e imprimir o conteúdo da tabela de símbolos (que deve ser vazio) b)Inserir o nome do programa na tabela c)Inserir os nomes das variáveis declaradas na tabela, notificando os casos de re-declaração

43 Exercício 3.1: Inserir no programa 3.1 programação para montar a tabela dos símbolos dos programas analisados e realizar alguns testes semânticos simples, executando as seguintes tarefas: d)Verificar se cada identificador usado foi declarado e)Verificar se cada identificador usado de variável é do tipo IDVAR f)Marcar as variáveis referenciadas e inicializadas pelo programa e verificar se todas as variáveis têm essa marca

44 a)Inicializar a tabela de símbolos, anulando os ponteiros de todas as suas classes, e imprimir o conteúdo da tabela de símbolos (que deve ser vazio) Colocar {InicTabSimb ();} no início da 1ª produção Colocar {InicTabSimb ();} no início da 1ª produção Colocar {ImprimeTabSimb ();} no final da mesma produção Colocar {ImprimeTabSimb ();} no final da mesma produção Trocar $2 por $3, na mesma produção Trocar $2 por $3, na mesma produção Prog: PROGRAMA ID PVIRG {printf ("programa %s ;\n", $2);} Decls CmdComp {printf ("programa %s ;\n", $2);} Decls CmdComp; Rodar com o arquivo tsimb dat

45 b)Inserir o nome do programa na tabela Na produção Prog, na ação depois de PVIRG, depois da chamada de printf, colocar Na produção Prog, na ação depois de PVIRG, depois da chamada de printf, colocar InsereSimb ($3, IDPROG, NOTVAR); Prog: { } PROGRAMA ID PVIRG {printf ("programa %s ;\n", $3); } Decls CmdComp { } Decls CmdComp { }; Rodar com o arquivo tsimb dat

46 c)Inserir os nomes das variáveis declaradas na tabela, notificando os casos de re-declaração. Declarar uma nova variável global inteira: tipocorrente Declarar uma nova variável global inteira: tipocorrente Na produção ElemDecl, na ação depois de ID, depois do printf, colocar Na produção ElemDecl, na ação depois de ID, depois do printf, colocar if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); else InsereSimb ($1, IDVAR, tipocorrente); ElemDecl : ID {printf ("%s ", $1); } ;

47 Nas produções Tipo, atribuir valor à variável tipocorrente Nas produções Tipo, atribuir valor à variável tipocorrente tipocorrente = INTEGER; tipocorrente = FLOAT; tipocorrente = CHAR tipocorrente = LOGICAL; Tipo: INT {printf (- -); | REAL {printf (- -); | CARAC {printf (- -); | LOGIC {printf (- -); }}}}}}}}} Rodar com o arquivo tsimb dat

48 d)Verificar se cada identificador usado foi declarado e)Verificar se cada identificador usado de variável é do tipo IDVAR Na produção Variavel, na ação depois de ID, depois do printf, colocar Na produção Variavel, na ação depois de ID, depois do printf, colocar simb = ProcuraSimb ($1); if (simb == NULL) NaoDeclarado ($1); else if (simb->tid != IDVAR) TipoInadequado ($1); Variavel: ID {printf ("%s ", $1); } ; Rodar com o arquivo tsimb dat

49 f)Marcar as variáveis referenciadas e inicializadas pelo programa e verificar se todas as variáveis têm essa marca Acrescentar o campo simb na declaração %union: Acrescentar o campo simb na declaração %union: /* Definicao dos campos dos tipos dos atributos */ %union { char cadeia[50]; int atr, valint; float valreal; char carac; simbolo simb; simbolo simb;} Isso possibilita que terminais e/ou não-terminais tenham como atributo um ponteiro para uma célula da tabsimb

50 Declarar que o não-terminal Variavel tem como atributo o campo simb da %union, colocando antes dos tokens: Declarar que o não-terminal Variavel tem como atributo o campo simb da %union, colocando antes dos tokens: %type Variavel /* Declaracao dos atributos dos tokens e dos nao- terminais */ %token ID %token CTCARAC %token CTINT

51 Na produção Variavel, no final da ação final, colocar: Na produção Variavel, no final da ação final, colocar: $$ = simb; Variavel: ID { printf simb = ProcuraSimb ($1); if else if }; O atributo do não-terminal Variavel é um ponteiro para a célula correspondente a ID na tabsimb

52 Na produção Fator : Variavel, colocar, no final, a ação: Na produção Fator : Variavel, colocar, no final, a ação: {if ($1 != NULL) $1->ref = TRUE;} Fator: Variavel Na produção CmdAtrib, colocar, depois de Variavel, a ação: Na produção CmdAtrib, colocar, depois de Variavel, a ação: {if ($1 != NULL) $1->inic = $1->ref = TRUE;} CmdAtrib : Variavel ATRIB {printf (<- ");} Expressao PVIRG {printf (";\n");} Rodar com o arquivo tsimb dat

53 Fazer uma função VerificaInicRef, que percorra toda a tabsimb, checando e avisando os casos de identificadores não-inicializados e não-referenciados Fazer uma função VerificaInicRef, que percorra toda a tabsimb, checando e avisando os casos de identificadores não-inicializados e não-referenciados – Não esquecer o protótipo Chamar VerificaInicRef antes de ImprimeTabSimb, na ação final da produção Prog Chamar VerificaInicRef antes de ImprimeTabSimb, na ação final da produção Prog Rodar com o arquivo tsimb dat

54 Exercício 3.2: Inserir no programa 3.1 programação para verificar a compatibilidade entre os operadores e os operandos das expressões, de acordo com a tabela

55 Numa produção contendo um operador de expressões, os operandos são não-terminais Numa produção contendo um operador de expressões, os operandos são não-terminais Exemplo: seja a produção Exemplo: seja a produção Termo : Termo OPMULT Fator No lado direito, Termo e Fator representam os operandos de OPMULT No lado direito, Termo e Fator representam os operandos de OPMULT É conveniente que esses não-terminais e todos aqueles relacionados com expressões tenham, como atributo o tipo da sub-expressão que eles representam É conveniente que esses não-terminais e todos aqueles relacionados com expressões tenham, como atributo o tipo da sub-expressão que eles representam

56 Acrescentar o campo tipoexpr na declaração %union: Acrescentar o campo tipoexpr na declaração %union: %union { char cadeia[50];int atr, valint; float valreal;char carac; simbolo simb; int tipoexpr; } Declarar que todos os não-terminais relacionados com expressões têm como atributo o campo tipoexpr: Declarar que todos os não-terminais relacionados com expressões têm como atributo o campo tipoexpr: %type Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator

57 Em cada produção relacionada com expressões, deve ser calculado o atributo do lado esquerdo ($$) Em cada produção relacionada com expressões, deve ser calculado o atributo do lado esquerdo ($$) Nas produções contendo operadores, devem ser feitos testes de compatibilidade Nas produções contendo operadores, devem ser feitos testes de compatibilidade

58 Exemplo: Teste de compatibilidade do operador NEG No não terminal Variavel, já está calculado o valor de $$: No não terminal Variavel, já está calculado o valor de $$: Variavel: ID { printf ("%s ", $1); simb = ProcuraSimb ($1); if (simb == NULL) NaoDeclarado ($1); else if (simb->tid != IDVAR) TipoInadequado ($1); $$ = simb; };

59 Calcular o valor de $$ em todas as produções de Fator e fazer teste de compatibilidade nas produções cabíveis: Calcular o valor de $$ em todas as produções de Fator e fazer teste de compatibilidade nas produções cabíveis: Fator: Variavel { if ($1 != NULL) { $1->ref = TRUE; $$ = $1->tvar; } } | CTINT {printf ("%d ", $1); $$ = INTEGER; } | CTREAL {printf ("%g ", $1); $$ = FLOAT; } | CTCARAC {printf ("%c ", $1); $$ = CHAR; } | VERDADE {printf (verdade "); $$ = LOGICAL; } | FALSO {printf ("falso "); $$ = LOGICAL; } Trocar o conteúdo da ação por

60 Calcular o valor de $$ em todas as produções de Fator e fazer teste de compatibilidade nas produções cabíveis: Calcular o valor de $$ em todas as produções de Fator e fazer teste de compatibilidade nas produções cabíveis: Fator: NEG {printf ("~ ");} Fator { if ($3 != INTEGER && $3 != FLOAT && $3 != CHAR) Incompatibilidade ("Operando improprio para menos unario"); if ($3 == FLOAT) $$ = FLOAT; else $$ = INTEGER; } | ABPAR {printf ("\( ");} Expressao FPAR { printf (") "); $$ = $3; } { printf (") "); $$ = $3; };

61 Criar a função Incompatibilidade e seu protótipo: Criar a função Incompatibilidade e seu protótipo: void Incompatibilidade (char *); void Incompatibilidade (char *s) { printf ("\n\n***** Incompatibilidade: %s *****\n\n", s); } Rodar com o arquivo tsimb dat

62 Exemplo: Teste de compatibilidade do operador OPMULT Calcular o valor de $$ em todas as produções do não-terminal Termo e fazer teste de compatibilidade nas produções cabíveis Calcular o valor de $$ em todas as produções do não-terminal Termo e fazer teste de compatibilidade nas produções cabíveis

63 Termo : Fator /* Default: $$ = $1; */ | Termo OPMULT { } Fator {switch ($2) { {switch ($2) { case MULT: case DIV: case MULT: case DIV: if ($1 != INTEGER && $1 != FLOAT && $1 != CHAR if ($1 != INTEGER && $1 != FLOAT && $1 != CHAR || $4 != INTEGER && $4!=FLOAT && $4!=CHAR) || $4 != INTEGER && $4!=FLOAT && $4!=CHAR) Incompatibilidade ("Operando improprio para operador aritmetico"); Incompatibilidade ("Operando improprio para operador aritmetico"); if ($1 == FLOAT || $4 == FLOAT) $$ = FLOAT; if ($1 == FLOAT || $4 == FLOAT) $$ = FLOAT; else $$ = INTEGER; break; else $$ = INTEGER; break; case RESTO: case RESTO: if ($1 != INTEGER && $1 != CHAR if ($1 != INTEGER && $1 != CHAR || $4 != INTEGER && $4 != CHAR) || $4 != INTEGER && $4 != CHAR) Incompatibilidade Incompatibilidade ("Operando improprio para operador resto"); ("Operando improprio para operador resto"); $$ = INTEGER; break; $$ = INTEGER; break; } } } } ; Exercício: fazer testes para os operadores OPAD, OPREL, NOT, AND e OR Rodar com o arquivo tsimb dat

64 Programa 3.2: Gramática sem subprogramas, com variáveis escalares e indexadas, comandos de atribuição, se, enquanto, ler e escrever Para os exercícios 3.3, 3.4 e 3.5, considerar os arquivos tsimb l e tsimb y da aba de Códigos da página do professor Para os exercícios 3.3, 3.4 e 3.5, considerar os arquivos tsimb l e tsimb y da aba de Códigos da página do professor Rodar esses programas com o arquivo de dados tsimb dat Rodar esses programas com o arquivo de dados tsimb dat Esses programas já fazem teste de compatibilidade de expressões Esses programas já fazem teste de compatibilidade de expressões

65 Exercício 3.3: Inserir, no programa 3.2, teste para verificar a compatibilidade entre os dois lados dos comandos de atribuição, de acordo com a tabela:

66 CmdAtrib:Variavel { if ($1 != NULL) $1->inic = $1->ref = TRUE; } ATRIB {printf (":= ");} Expressao PVIRG { printf (";\n"); printf (";\n"); if ($1 != NULL) if ((($1->tvar == INTEGER || $1->tvar == CHAR) && ($5 == FLOAT || $5 == LOGICAL)) || ($1->tvar == FLOAT && $5 == LOGICAL) || ($1->tvar == LOGICAL && $5 != LOGICAL)) Incompatibilidade ("Lado direito de comando de atribuicao improprio"); ("Lado direito de comando de atribuicao improprio");}; Testar com o arquivo de dados tsimb dat Testar com o arquivo de dados tsimb dat

67 Exercício 3.4: Inserir na gramática do programa 3.2 testes semânticos para as produções dos comandos se, enquanto, ler, escrever que aparecem na linguagem COMP-ITA 2013 Produções: Produções: Comando : CmdComp | CmdSe | CmdEnquanto | CmdLer | CmdEscrever | CmdAtrib CmdSe: se ( Expressao ) Comando CmdSenao CmdSenao: ε | senao Comando CmdEnquanto: enquanto ( Expressao ) Comando CmdLer: ler ( ListVar ) ; ListVar: Variavel | ListVar, Variavel CmdEscrever: escrever ( ListEscr ) ; ListEscr: ElemEscr | ListEscr, ElemEscr ElemEscr: CADEIA | Expressao

68 Comando : CmdComp | CmdSe | CmdEnquanto | CmdLer | CmdEscrever | CmdAtrib CmdSe: se ( Expressao ) Comando CmdSenao CmdSenao: ε | senao Comando CmdEnquanto: enquanto ( Expressao ) Comando CmdLer: ler ( ListVar ) ; ListVar: Variavel | ListVar, Variavel CmdEscrever: escrever ( ListEscr ) ; ListEscr: ElemEscr | ListEscr, ElemEscr ElemEscr: CADEIA | Expressao Marcar as variáveis lidas como inicializadas e referenciadas (tal como no lado esquerdo de atribuição) Marcar as variáveis lidas como inicializadas e referenciadas (tal como no lado esquerdo de atribuição) Verificar se as expressões dos comandos se e enquanto são lógicas Verificar se as expressões dos comandos se e enquanto são lógicas Testar o programa com o arquivo de dados tsimb dat Testar o programa com o arquivo de dados tsimb dat Abrir o arquivo tsimb dat As variáveis n e num são lidas (inic e ref) Expressões inteiras em comandos se e enquanto

69 Exercício 3.5: Inserir na gramática do programa 3.2 alterações na tabela de símbolos e testes semânticos para as produções que aparecem na linguagem COMP-ITA 2013, envolvendo variáveis indexadas Produções: Produções: ElemDecl:ID | ID [ ListDim ] ListDims: CTINT | ListDim, CTINT Variavel: ID | ID [ ListSubscr ] ListSubscr: ExprAux4 | ListSubscr, ExprAux4 Observar estas produções no arquivo tsimb y Observar estas produções no arquivo tsimb y Testar o programa com o arquivo de dados tsimb dat Testar o programa com o arquivo de dados tsimb dat

70 Preparar a tabela de símbolos para guardar informações sobre: Preparar a tabela de símbolos para guardar informações sobre: Número de dimensões de uma variável indexada Número de dimensões de uma variável indexada Número de elementos de cada dimensão Número de elementos de cada dimensão Tipo de cada elemento Tipo de cada elemento Exemplo: para a declaração Exemplo: para a declaração int A[10, 20, 5]: int A[10, 20, 5]: A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 3 ndims dims

71 /* Definicao de outras constantes */ #defineNCLASSHASH23 #defineTRUE1 #defineFALSE0 #define MAXDIMS10 /* Declaracoes para a tabela de simbolos */ typedef struct celsimb celsimb; typedef celsimb *simbolo; struct celsimb { char *cadeia; int tid, tvar, ndims, dims[MAXDIMS+1] ; char inic, ref, array ; simbolo prox; }; A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 3 ndims dims

72 /* ImprimeTabSimb: Imprime todo o conteudo da tabela de simbolos */ void ImprimeTabSimb () { int i; simbolo s; printf ("\n\n TABELA DE SIMBOLOS:\n\n"); for (i = 0; i < NCLASSHASH; i++) if (tabsimb[i]) { printf ("Classe %d:\n", i); for (s = tabsimb[i]; s!=NULL; s = s->prox){ printf ( ); if (s->tid == IDVAR) { printf ( ); if (s->array == TRUE) { int j; printf (", EH ARRAY\n\tndims = %d, dimensoes:", s->ndims); for (j = 1; j ndims; j++) printf (" %d", s->dims[j]); printf (" %d", s->dims[j]);}}printf(")\n");}}}

73 Alterar toda programação da montagem da tabela de símbolos e de testes semânticos realizados até agora Alterar toda programação da montagem da tabela de símbolos e de testes semânticos realizados até agora A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 3 ndims dims

74 Nas declarações das variáveis: Nas declarações das variáveis: ElemDecl : ID {printf ("%s ", $1); if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); else { simb = InsereSimb ($1, IDVAR, tipocorrente); simb->array = FALSE; } simb->array = FALSE; }} | ID ABCOL {printf ("%s [ ", $1); if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); else { simb = InsereSimb ($1, IDVAR, tipocorrente); simb->array = TRUE; simb->ndims = 0;} simb->array = TRUE; simb->ndims = 0;} } ListDim FCOL {printf ("] ");} } ListDim FCOL {printf ("] ");}; Ainda falta achar as dimensões das variáveis indexadas A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 3 ndims dims

75 No dimensionamento das variáveis indexadas, inclusive verificando se a constante inteira usada no dimensionamento de uma variável indexada é positiva: No dimensionamento das variáveis indexadas, inclusive verificando se a constante inteira usada no dimensionamento de uma variável indexada é positiva: ListDim : CTINT { printf ("%d ", $1); if ($1 <= 0) Esperado ("Valor inteiro positivo"); if ($1 <= 0) Esperado ("Valor inteiro positivo"); simb->ndims++; simb->dims[simb->ndims] = $1; simb->ndims++; simb->dims[simb->ndims] = $1;} | ListDim VIRG CTINT { printf (", %d ", $3); if ($3 <= 0) Esperado ("Valor inteiro positivo"); if ($3 <= 0) Esperado ("Valor inteiro positivo"); simb->ndims++; simb->dims[simb->ndims] = $3; simb->ndims++; simb->dims[simb->ndims] = $3; }; A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 3 ndims dims

76 Criar o protótipo: Criar o protótipo: void Esperado (char *); E a função: E a função: void Esperado (char *s) { printf ("\n\n***** Esperado: %s *****\n\n", s); } Rodar o programa com o arquivo tsimb dat, para verificar se as informações foram introduzidas na tabsimb Rodar o programa com o arquivo tsimb dat, para verificar se as informações foram introduzidas na tabsimb

77 Na segunda produção do não-terminal Variavel, para se determinar o atributo do lado esquerdo, foi usada a seguinte programação: Na segunda produção do não-terminal Variavel, para se determinar o atributo do lado esquerdo, foi usada a seguinte programação: Variavel : ID { $$ = simb; } | ID ABCOL { printf ("%s [ ", $1); printf ("%s [ ", $1); simb = ProcuraSimb ($1); simb = ProcuraSimb ($1); if (simb == NULL) NaoDeclarado ($1); else if (simb->tid != IDVAR) TipoInadequado ($1); $ $ = simb; $ $ = simb; } ListSubscr FCOL { printf ("] "); $$ = $ 3; } ; É a especificação do atributo de um não-terminal fictício É a especificação do atributo de um não-terminal fictício

78 Por default, o atributo de um não-terminal fictício também é do tipo inteiro Por default, o atributo de um não-terminal fictício também é do tipo inteiro Muitas vezes é desejável especificar para ele um dos campos da %union Muitas vezes é desejável especificar para ele um dos campos da %union Isso não pode ser feito por uma declaração %type Isso não pode ser feito por uma declaração %type %type só declara atributos de não-terminais não-fictícios %type só declara atributos de não-terminais não-fictícios Para tanto, coloca-se o campo escolhido entre os caracteres, tudo isso logo após o primeiro caractere $, por exemplo, $ $, $ 1, $ 2 Para tanto, coloca-se o campo escolhido entre os caracteres, tudo isso logo após o primeiro caractere $, por exemplo, $ $, $ 1, $ 2

79 Exemplo: Seja a seguinte produção: A : B {simb = InsereSimb (- - -);} C {$$ = simb->tvar;} Onde simb é uma variável global e %union {int tipoexpr; simbolo simb;} %type A Por essa programação, deseja-se que o atributo de A seja o tipo da variável da célula apontada por simb Por essa programação, deseja-se que o atributo de A seja o tipo da variável da célula apontada por simb Mas, no processamento do não-terminal C, pode ser que o valor de simb seja alterado, não se realizando o desejado Mas, no processamento do não-terminal C, pode ser que o valor de simb seja alterado, não se realizando o desejado Então a programação na produção deve mudar para Então a programação na produção deve mudar para A : B {$ $ = InsereSimb (- - -);} C {$$ = $ 2->tvar;}

80 Realizar ainda os seguintes testes semânticos: Verificar se as expressões que aparecem nos subscritos das variáveis indexadas são do tipo inteiro ou caractere Verificar se as expressões que aparecem nos subscritos das variáveis indexadas são do tipo inteiro ou caractere Verificar se uma variável de tipo escalar tem subscritos e se uma indexada não tem subscritos Verificar se uma variável de tipo escalar tem subscritos e se uma indexada não tem subscritos Verificar se o número de subscritos de uma variável indexada é igual ao seu número de dimensões declarado Verificar se o número de subscritos de uma variável indexada é igual ao seu número de dimensões declarado

81 Verificar se as expressões que aparecem nos subscritos das variáveis indexadas são do tipo inteiro ou caractere Verificar se as expressões que aparecem nos subscritos das variáveis indexadas são do tipo inteiro ou caractere Produções para este teste: ListSubscr: ExprAux4 { if ($1 != INTEGER && $1 != CHAR) if ($1 != INTEGER && $1 != CHAR) Incompatibilidade ("Tipo inadequado para subscrito"); Incompatibilidade ("Tipo inadequado para subscrito");} | ListSubscr VIRG {printf (", ");} ExprAux4 { if ($4 != INTEGER && $4 != CHAR) if ($4 != INTEGER && $4 != CHAR) Incompatibilidade ("Tipo inadequado para subscrito"); Incompatibilidade ("Tipo inadequado para subscrito");}; Rodar o programa com o arquivo tsimb dat

82 Verificar se uma variável de tipo escalar tem subscritos e se uma indexada não tem subscritos Verificar se uma variável de tipo escalar tem subscritos e se uma indexada não tem subscritos Verificar se o número de subscritos de uma variável indexada é igual ao seu número de dimensões declarado Verificar se o número de subscritos de uma variável indexada é igual ao seu número de dimensões declarado Deve-se obter o número de subscritos que aparecem depois do nome de uma variável Em seguida, deve-se comparar esse número com o número de dimensões desse nome na tabela de símbolos

83 O não-terminal ListSubscr terá como atributo o número de subscritos: O não-terminal ListSubscr terá como atributo o número de subscritos: %union { char cadeia[50]; int atr, valint; float valreal; char carac; simbolo simb; int tipoexpr; int nsubscr; int tipoexpr; int nsubscr;} %type Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator ExprAux3 ExprAux4 Termo Fator %type Variavel %type ListSubscr

84 Nas produções de ListSubscr: Nas produções de ListSubscr: ListSubscr: ExprAux4 { if ($1 != INTEGER && $1 != CHAR) Incompatibilidade ("Tipo inadequado para subscrito"); Incompatibilidade ("Tipo inadequado para subscrito"); $$ = 1; } |ListSubscr VIRG {printf (", ");} ExprAux4 { if ($4 != INTEGER && $4 != CHAR) Incompatibilidade ("Tipo inadequado para subscrito"); Incompatibilidade ("Tipo inadequado para subscrito"); $$ = $1 + 1; };

85 Nas produções de Variavel: Nas produções de Variavel: Variavel: ID { $$ = simb; if ($$ != NULL) if ($$->array == TRUE) if ($$->array == TRUE) Esperado ("Subscrito\(s)"); } |ID ABCOL { $ $ = simb; } ListSubscr FCOL { printf ("] "); $$ = $ 3; printf ("] "); $$ = $ 3; if ($$ != NULL) if ($$->array == FALSE) NaoEsperado ("Subscrito\(s)"); else if ($$->ndims != $4) else if ($$->ndims != $4) Incompatibilidade Incompatibilidade ("Numero de subscritos incompativel com declaracao"); };

86 Criar o protótipo: Criar o protótipo: void NaoEsperado (char *); E a função: E a função: void NaoEsperado (char *s) { printf ("\n\n***** Nao Esperado: %s *****\n\n", s); } Rodar o programa com o arquivo tsimb dat


Carregar ppt "CES-41 COMPILADORES Aulas Práticas - 2013 Capítulo III Análise Semântica no Yacc."

Apresentações semelhantes


Anúncios Google