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

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

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

Apresentações semelhantes


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

1 CES-41 COMPILADORES Aulas Práticas - 2012 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 2012 A gramática a seguir é uma simplificação daquela da linguagem COMP-ITA 2012 Seja ela chamada de Sub-Set 2012 Seja ela chamada de Sub-Set 2012

8 Programa:ID ABCHAVE DeclLocs Cmds FCHAVE DeclLocs: | locais DPONTS ListDecl ListDecl : Declaracao | ListDecl Declaracao Declaracao:Tipo ListElemDecl PVIRG Tipo:int | real | carac | logico ListElemDecl :ElemDecl | ListElemDecl VIRG ElemDecl ElemDecl:ID Cmds:comandos DPONTS ListCmds ListCmds:Comando | ListCmds Comando Comando:CmdComposto | CmdAtrib CmdComposto :ABCHAVE ListCmds FCHAVE 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: tsimb012012.y (analisador sintático) tsimb012012.y (analisador sintático) tsimb012012.l (analisador léxico) tsimb012012.l (analisador léxico) tsimb012012.dat (programa a ser analisado) tsimb012012.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 tsimb012012.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 LOGIC2 #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", "LOGIC", "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 dos campos dos tipos dos atributos */ %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 %tokenABCHAVE %tokenFCHAVE %tokenVIRG %tokenPVIRG %tokenDPONTS %tokenATRIB %tokenCARAC %tokenCOMANDOS %tokenFALSO %tokenINT %tokenLOCAIS %tokenLOGICO %tokenREAL %tokenVERDADE %token INVAL %

20 /* Producoes da gramatica: Os terminais sao escritos e, depois de alguns, para alguma estetica, ha mudanca de linha */ Programa:ID ABCHAVE {printf (\n%s {\n", $1);} DeclLocs Cmds FCHAVE {printf ("}\n");} ; DeclLocs: |LOCAIS DPONTS {printf ("locais :\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 ");} | LOGICO {printf ("logico ");} | LOGICO {printf ("logico ");}; ListElemDecl: ElemDecl | ListElemDecl VIRG {printf (", ");} ElemDecl; ElemDecl :ID {printf ("%s ", $1);} ;

22 Cmds:COMANDOS DPONTS {printf ("comandos :\n");} ListCmds ; ListCmds: Comando | ListCmds Comando ; Comando : CmdComposto | CmdAtrib | CmdAtrib; CmdComposto: ABCHAVE {printf ("{\n");} ListCmds FCHAVE {printf ("}\n");} ; 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 tsimb012012.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;} comandos{return COMANDOS;} falso{return FALSO;} int{return INT;} locais{return LOCAIS;} logico{return LOGICO;} real{return REAL;} 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 ABCHAVE;} "}"{return FCHAVE;} ";"{return PVIRG;} ","{return VIRG;} ":"{return DPONTS;} "<-"{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]; }} 01234 'K'\0'n'\ 'K'\ S =

39 c) Arquivo tsimb012012.dat teste { locais: int i, jjj, h, tb; logico n, m; real v, i; carac x, y, z, w;

40 comandos: x <- n && m; v <- 3.5 * v; y <- '@'; { i <- jjj*falso; jjj <- 0; } jjj <- n + 1; i <- i + 1; { i <- !i; i <- i + 1 + z; { i <- 0; jjj <- 0; } jjj <- jjjj + teste; }

41 m x; m <- n != verdade; m = n; n <- m = 4; i <- i + 1; n <- ~ m; n <- (!m && n) && (m && !n); 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 tsimb012012.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 última ação da mesma produção Colocar ImprimeTabSimb (); no final última ação da mesma produção Trocar $1 por $2, na mesma produção Trocar $1 por $2, na mesma produção Programa:ID ABCHAVE {printf ("%s {\n", $1);} DeclLocs Cmds FCHAVE {printf ("}\n"); } ; Rodar com o arquivo tsimb012012.dat

45 b)Inserir o nome do programa na tabela Na produção Programa, na ação depois de ABCHAVE, depois da chamada de printf, colocar Na produção Programa, na ação depois de ABCHAVE, depois da chamada de printf, colocar InsereSimb ($2, IDPROG, NOTVAR); Programa: {- - - -} ID ABCHAVE {printf (\n%s {\n", $2); } DeclLocs Cmds FCHAVE {- - - -} DeclLocs Cmds FCHAVE {- - - -}; Rodar com o arquivo tsimb012012.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 = LOGIC; Tipo: INT {printf (- -); | REAL {printf (- -); | CARAC {printf (- -); | LOGICO {printf (- -); }}}}}}}}} Rodar com o arquivo tsimb012012.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 tsimb012012.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 tsimb012012.dat

53 Fazer uma função VerificaInicRef, que percorre toda a tabsimb, checando e avisando os casos de identificadores não-inicializados e não-referenciados Fazer uma função VerificaInicRef, que percorre toda a tabsimb, checando e avisando os casos de identificadores não-inicializados e não-referenciados Chamar VerificaInicRef antes de ImprimeTabSimb, na ação final da produção Programa Chamar VerificaInicRef antes de ImprimeTabSimb, na ação final da produção Programa Rodar com o arquivo tsimb012012.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 "); $$ = LOGIC; } | FALSO {printf ("falso "); $$ = LOGIC; } 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 tsimb012012.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 tsimb012012.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 tsimb022012.l e tsimb022012.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 tsimb022012.l e tsimb022012.y da aba de Códigos da página do professor Rodar esses programas com o arquivo de dados tsimb012012.dat Rodar esses programas com o arquivo de dados tsimb012012.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 == LOGIC)) || ($1->tvar == FLOAT && $5 == LOGIC) || ($1->tvar == LOGIC && $5 != LOGIC)) Incompatibilidade ("Lado direito de comando de atribuicao improprio"); ("Lado direito de comando de atribuicao improprio");}; Testar com o arquivo de dados tsimb012012.dat Testar com o arquivo de dados tsimb012012.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 2012 Produções: Produções: Comando : CmdComposto | 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 : CmdComposto | 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 tsimb022012.dat Testar o programa com o arquivo de dados tsimb022012.dat Abrir o arquivo tsimb022012.dat A variável n é lida (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 2012, envolvendo variáveis indexadas Produções: Produções: ElemDecl:ID ListDims ListDims: ε | Dimensao | Dimensao Dimensao Dimensao:[ CTINT ] Variavel: ID ListSubscr ListSubscr: ε | Subscrito | Subscrito Subscrito Subscrito:[ ExprAux4 ] Testar o programa com o arquivo de dados tsimb032012.dat Testar o programa com o arquivo de dados tsimb032012.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]: int A[10][20]: A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 2 ndims 1020 dims 012

71 /* Declaracoes para a tabela de simbolos */ typedef struct celsimb celsimb; typedef celsimb *simbolo; struct celsimb { char *cadeia; int tid, tvar, ndims, dims[3] ; char inic, ref, array ; simbolo prox; }; A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 2 ndims 1020 dims 012

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 Na declaração das variáveis: Na declaração das variáveis: ElemDecl :ID { printf ("%s ", $1); if (ProcuraSimb ($1) != NULL) if (ProcuraSimb ($1) != NULL) DeclaracaoRepetida ($1); else { simb = InsereSimb ($1, IDVAR, tipocorrente); simb->array = FALSE; } } } ListDims ; Ainda falta achar as dimensões das variáveis indexadas

74 Acrescentar o campo dim na declaração %union: Acrescentar o campo dim na declaração %union: %union { char cadeia[50];int atr, valint;float valreal; char carac; simbolo simb;int tipoexpr; int dim; } Declarar que o não-terminal Dimensao tem como atributo o campo dim: Declarar que o não-terminal Dimensao tem como atributo o campo dim: %type Dimensao

75 No não-terminal Dimensao: No não-terminal Dimensao: Verificando se a constante inteira usada no dimensionamento de uma variável indexada é positiva Verificando se a constante inteira usada no dimensionamento de uma variável indexada é positiva Calculando o atributo do lado esquerdo Calculando o atributo do lado esquerdo Dimensao: ABCOL CTINT FCOL { printf ("[ %d ] ", $2); if ($2 <= 0) Esperado ("Valor inteiro positivo"); if ($2 <= 0) Esperado ("Valor inteiro positivo"); $$ = $2; $$ = $2;};

76 No não-terminal ListDims: No não-terminal ListDims:ListDims: | Dimensao { simb->array = TRUE; simb->ndims = 1; simb->array = TRUE; simb->ndims = 1; simb->dims[1] = $1; simb->dims[1] = $1; } | Dimensao Dimensao { simb->array = TRUE; simb->ndims = 2; simb->array = TRUE; simb->ndims = 2; simb->dims[1] = $1; simb->dims[2] = $2; simb->dims[1] = $1; simb->dims[2] = $2;}; A cadeia IDVAR tid INTEGER tvar 0 inic 0 ref 1 array 2 ndim 1020 dims 012

77 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 tsimb032012.dat, para verificar se as informações foram introduzidas na tabsimb Rodar o programa com o arquivo tsimb032012.dat, para verificar se as informações foram introduzidas na tabsimb

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

79 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

80 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;}

81 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

82 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ção para este teste: Subscrito:ABCOL {printf ("[ ");} ExprAux4 { if ($3 != INTEGER && $3 != CHAR) if ($3 != INTEGER && $3 != CHAR) Incompatibilidade ("Tipo inadequado para subscrito"); Incompatibilidade ("Tipo inadequado para subscrito"); } FCOL {printf ("] ");} ; Rodar o programa com o arquivo tsimb032012.dat

83 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

84 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; int tipoexpr; int dim; simbolo simb; int nsubscr; } %type Variable %type Expression AuxExpr1 AuxExpr2 AuxExpr3 AuxExpr4 Term Factor %type Dimensao %type ListSubscr

85 Obtenção do número de subscritos que seguem um identificador de variável: Obtenção do número de subscritos que seguem um identificador de variável: Produções para este teste: ListSubscr: {$$ = 0;} | Subscrito {$$ = 1;} | Subscrito Subscrito {$$ = 2;} | Subscrito Subscrito {$$ = 2;} ;

86 Na produção de Variavel: Na produção de Variavel: Variavel: ID {- - - - -} ListSubscr { $$ = $ 2; if ($$ != NULL) if ($$ != NULL) if ($$->array == FALSE && $3 != 0) NaoEsperado ("Subscrito\(s)"); NaoEsperado ("Subscrito\(s)"); else if ($$->array == TRUE && $3 == 0) else if ($$->array == TRUE && $3 == 0) Esperado ("Subscrito\(s)"); Esperado ("Subscrito\(s)"); else if ($$->array == TRUE && else if ($$->array == TRUE && $$->ndims != $3) Incompatibilidade Incompatibilidade ("Numero de subscritos incompativel com declaracao"); ("Numero de subscritos incompativel com declaracao");};

87 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***** Não Esperado: %s *****\n\n", s); } Rodar o programa com o arquivo tsimb032012.dat


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

Apresentações semelhantes


Anúncios Google