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

Slides:



Advertisements
Apresentações semelhantes
Funções em C.
Advertisements

1 Estruturas de Controle Márcia J. N. Rodrigues Lucena Especialização em Técnicas e Ferramentas de Apoio à Decisão Departamento.
Procedimentos e Funções
Implementando um Montador com LEX e YACC
Grupo Paralelismo – Unesp RC
FORTRAN 90 Denise Yumi Takamura.
SQL Procedural Junho/2006.
Subconsultas em SQL. Subconsulta Estrutura geral SELECT.... FROM.... WHERE [at] OPERADOR ( SELECT... FROM... [WHERE... ]) Declaração SELECT localizada.
Sintaxe de Fortran 25/abril/2006. Comandos Fortran PROGRAM PRINT READ STOP END.
Introdução ao Fortran 4/abril/2006. Pseudocódigo Compreensão do problema Elaboração da lógica de resolução Tradução da lógica para pseudocódigo.
Teste Estrutural de Software
1 Tradução Dirigida à Sintaxe Prof. Ricardo Santos.
Agregado Homogêneo e Heterogêneo
CE-262 Ontologia e Web Semântica Prof. José M Parente de Oliveira
CES-41 COMPILADORES Capítulo IV Complementos de Análise Léxica.
Capítulo VII – Tipos Enumerativos e Estruturas 7.1 – Tipos enumerativos 7.2 – A necessidade de estruturas 7.3 – Manipulação dos campos de uma estrutura.
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo III Comandos de Controle.
5.6 – Complementos de Yacc – Usando Yacc com gramáticas ambíguas
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013
1.3 – Interpretadores – Compiladores versus Interpretadores
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013
CES-10 INTRODUÇÃO À COMPUTAÇÃO Capítulo III Declarações e Comandos de Atribuição.
CES-41 COMPILADORES Capítulo VII Código Intermediário.
CES-41 COMPILADORES Aulas Práticas
CES-10 INTRODUÇÃO À COMPUTAÇÃO
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo VII Variáveis Indexadas Numéricas.
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo XI Encadeamento de Estruturas por Ponteiros.
Capítulo IX – Ponteiros 9.1 – Introdução 9.2 – Relação entre ponteiros e variáveis indexadas 9.3 – Alocação dinâmica de memória 9.4 – Variáveis indexadas,
CES-41 COMPILADORES Aulas Práticas Capítulo III Análise Semântica no Yacc.
Capítulo III Diagramas de Transições
CES-41 COMPILADORES Aulas Práticas Capítulo IV Código Intermediário no Yacc.
Capítulo V Análise Sintática
1 Definição de Dicionário Dicionário é um sistema de informações: Equivalente a um conjunto de elementos não repetidos Equivalente a um conjunto de elementos.
CES-41 COMPILADORES Capítulo I Introdução.
C/C++.
Laboratório de Programação Prof. Oscar Luiz Monteiro de Farias
Gerador de Analisadores Léxicos
Prof. Giovanny Lucero Introdução Prof. Giovanny Lucero
Linguagens Formais e Tradutores Análise Sintática - 1
Tecnologia para Web JavaScript Enrique Pimentel Leite de Oliveira
Marco Antonio Montebello Júnior
Curso de Programação em C++ Universidade Federal do Ceará Departamento de Engenharia Estrutural e Construção Civil Prof: Evandro Parente Junior Monitor:
LINGUAGENS DE PROGRAMAÇÃO
Slides: Prof. SIMÃO Revisão: Prof. João Fabro
Slides: Prof. João Fabro UTFPR - Curitiba
Fundamentos de Programação 1
exercícios listas encadeadas
Lex Linguagem (e compilador) para especificar analisadores léxicos.
Funções ou procedures Professor Esp. Diego André Sant’Ana
CES-41 COMPILADORES Aulas Práticas Capítulo V Interpretação do Código Intermediário.
Estruturas de Dados Aula 6: Cadeias de Caracteres
CES-41 COMPILADORES Aulas Práticas Capítulo III Análise Semântica no Yacc.
Capítulo VI Análise Semântica
CES-41 COMPILADORES Aulas Práticas
Fundamentos de Programação 1 Slides 21 Prof.ª Fabiany e Prof. SIMÃO Linguagem C “Lista Encadeada”.
Fundamentos de Programação 1 Slides 22 Prof.ª Fabiany e Prof. SIMÃO Linguagem C “Lista Duplamente Encadeada - Projeto com vários Arquivos”.
CES-41 COMPILADORES Aulas Práticas Capítulo III Análise Semântica no Yacc.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2017
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2016
CES-41 COMPILADORES Aulas Práticas
CES-41 COMPILADORES Aulas Práticas
CES-41 COMPILADORES Aulas Práticas
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas
CES-41 COMPILADORES Aulas Práticas
FUNDAMENTO DE PROGRAMAÇÃO PROF. BRUNO DE CASTRO H. SILVA
FUNDAMENTO DE PROGRAMAÇÃO PROF. BRUNO DE CASTRO H. SILVA
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2017
Fundamentos de Programação 1
CES-41 COMPILADORES Aulas Práticas
Transcrição da apresentação:

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

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

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

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)

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

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];

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

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

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

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

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

/* 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

/* 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

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

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

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

/* Definicao dos campos dos tipos dos atributos */ %union { char cadeia[50]; int atr, valint; float valreal; char carac; }

/* 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

%tokenABPAR %tokenFPAR %tokenABCHAVE %tokenFCHAVE %tokenVIRG %tokenPVIRG %tokenDPONTS %tokenATRIB %tokenCARAC %tokenCOMANDOS %tokenFALSO %tokenINT %tokenLOCAIS %tokenLOGICO %tokenREAL %tokenVERDADE %token INVAL %

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

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

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");} ;

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

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;

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;

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);} ;%

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

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

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

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

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

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

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}' %

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

"||"{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;}

"("{return ABPAR;} ")"{return FPAR;} "{"{return ABCHAVE;} "}"{return FCHAVE;} ";"{return PVIRG;} ","{return VIRG;} ":"{return DPONTS;} "<-"{return ATRIB;}.{yylval.carac = yytext[0]; return INVAL;} %

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

/* 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 =

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

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

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 tsimb dat

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

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

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 tsimb dat

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 tsimb dat

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

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 tsimb dat

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

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

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

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

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

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 tsimb dat

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

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

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

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

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

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

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

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

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

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

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

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:

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 tsimb dat Testar com o arquivo de dados tsimb dat

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

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 tsimb dat Testar o programa com o arquivo de dados tsimb dat Abrir o arquivo tsimb dat A variável n é lida (inic e ref) Expressões inteiras em comandos se e enquanto

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 tsimb dat Testar o programa com o arquivo de dados tsimb dat

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

/* 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

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

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

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

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

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

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

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

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

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

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

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 tsimb dat

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

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

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

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");};

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 tsimb dat