CES41 COMPILADORES Aulas Prticas 2017 Captulo III Anlise

  • Slides: 88
Download presentation
CES-41 COMPILADORES Aulas Práticas - 2017 Capítulo III Análise Semântica no Yacc

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

n Neste capítulo, serão vistas a construção da tabela de símbolos e a análise

n Neste capítulo, serão vistas a construção da tabela de símbolos e a análise semântica para linguagens de programação n A tabela de símbolos é fundamental para análise semântica e para geração do código intermediário n 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

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 Abordagem do projeto 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.

Estrutura de dados para a tabela de símbolos: n Será usada a estrutura de

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

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

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

Declarações para a tabela de símbolos: typedef struct celsimb; typedef celsimb *simbolo; struct celsimb

Declarações para a tabela de símbolos: typedef struct 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 n

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

Prog : PROGRAM ID SCOLON Decls Comp. Stat Decls : | VAR Decl. List

Prog : PROGRAM ID SCOLON Decls Comp. Stat Decls : | VAR Decl. List : Declaration | Decl. List Declaration : Type Elem. List SCOLON Type : INT | FLOAT | CHAR | LOGIC Elem. List : Elem | Elem. List COMMA Elem : ID Comp. Stat : OPBRACE Stat. List CLBRACE Não-terminal prevendo Stat. List : Elem: variáveis indexadas | Stat. List Statement : Comp. Stat | Assign. Stat : Variable ASSIGN Expression SCOLON

Expression : Aux. Expr 1 | Expression OR Aux. Expr 1 : Aux. Expr

Expression : Aux. Expr 1 | Expression OR Aux. Expr 1 : Aux. Expr 2 | Aux. Expr 1 AND Aux. Expr 2 : Aux. Expr 3 | NOT Aux. Expr 3 : Aux. Expr 4 | Aux. Expr 4 RELOP Aux. Expr 4 : Term | Aux. Expr 4 ADOP Term : Factor | Term MULTOP Factor : Variable | INTCT | FLOATCT | CHARCT | TRUE | FALSE | NEG Factor | OPPAR Expression CLPAR : ID Variable: Não-terminal prevendo variáveis indexadas

n A seguir 3 arquivos fornecidos na aba de ‘Códigos’ da página do professor:

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

a) Arquivo tsimb 012017. y %{ /* Inclusao de arquivos da biblioteca de C

a) Arquivo tsimb 012017. y %{ /* Inclusao de arquivos da biblioteca de C #include <stdio. h> #include <stdlib. h> #include <string. h> */

/* Definicao dos atributos dos atomos operadores */ #define #define #define LT LE GT

/* Definicao dos atributos dos atomos operadores */ #define #define #define LT LE GT GE EQ NE MAIS MENOS MULT DIV RESTO 1 2 3 4 5 6 7 8 9 10 11

/* Definicao dos tipos de identificadores */ #define IDPROG IDVAR 1 2 /* Definicao

/* Definicao dos tipos de identificadores */ #define IDPROG IDVAR 1 2 /* Definicao dos tipos de variaveis */ #define #define NAOVAR INTEIRO LOGICO REAL CARACTERE 0 1 2 3 4 /* Definicao de outras constantes */ #define NCLASSHASH VERDADE FALSO 23 1 0 Para o caso de não ser um identificador de variável

/* Strings para nomes dos tipos de identificadores */ char *nometipid[3] = {" ",

/* Strings para nomes dos tipos de identificadores */ char *nometipid[3] = {" ", "IDPROG", "IDVAR"}; /* Strings para nomes dos tipos de variaveis */ char *nometipvar[5] = {"NAOVAR", "INTEIRO", "LOGICO", "REAL", "CARACTERE" }; A serem usadas na função para escrever na tela a tabela de símbolos (Imprime. Tab. Simb)

/* Declaracoes para a tabela de simbolos */ typedef struct celsimb; typedef celsimb *simbolo;

/* Declaracoes para a tabela de simbolos */ typedef struct 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 */ void

/* Prototipos das funcoes para a tabela de simbolos e analise semantica */ void Inic. Tab. Simb (void); void Imprime. Tab. Simb (void); simbolo Insere. Simb (char *, int); int hash (char *); simbolo Procura. Simb (char *); void Declaracao. Repetida (char *); void Tipo. Inadequado (char *); void Nao. Declarado (char *); %}

/* Definicao do tipo de yylval e dos atributos dos nao terminais */ %union

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

/* Declaracao dos atributos dos tokens e dos nao-terminais */ %token %token %token <cadeia>

/* Declaracao dos atributos dos tokens e dos nao-terminais */ %token %token %token <cadeia> <carac> <valint> <valreal> OR AND NOT <atr> NEG ID CHARCT INTCT FLOATCT RELOP ADOP MULTOP

%token %token %token %token %% OPPAR CLPAR OPBRACE CLBRACE COMMA SCOLON ASSIGN CHAR FALSE

%token %token %token %token %% OPPAR CLPAR OPBRACE CLBRACE COMMA SCOLON ASSIGN CHAR FALSE FLOAT INT LOGIC PROGRAM TRUE VAR <carac> INVAL

/* Producoes da gramatica: Os terminais sao escritos e, depois de alguns, para alguma

/* Producoes da gramatica: Os terminais sao escritos e, depois de alguns, para alguma estetica, ha mudanca de linha Prog Decls Decl. List : PROGRAM ID SCOLON {printf ("program %s ; n", $2); } Decls Comp. Stat ; : | VAR {printf ("varn"); } Decl. List ; : Declaration | Decl. List Declaration ; */

Declaration : ; Type : | | | ; Elem. List : | Elem

Declaration : ; Type : | | | ; Elem. List : | Elem : ; Type Elem. List SCOLON {printf ("; n"); } INT {printf ("int "); } FLOAT {printf ("float "); } CHAR {printf ("char "); } LOGIC {printf ("logic "); } Elem. List COMMA {printf (", "); } Elem ; ID {printf ("%s ", $1); }

Comp. Stat : ; Stat. List : | ; Statement : | ; Assign.

Comp. Stat : ; Stat. List : | ; Statement : | ; Assign. Stat : ; OPBRACE {printf ("{n"); } Stat. List CLBRACE {printf ("}n"); } Stat. List Statement Comp. Stat Assign. Stat Variable ASSIGN {printf ("= "); } Expression SCOLON {printf ("; n"); }

Expression : | Aux. Expr 1 : | Aux. Expr 2 : | Aux.

Expression : | Aux. Expr 1 : | Aux. Expr 2 : | Aux. Expr 1 Expression OR {printf ("|| "); } Aux. Expr 1 ; Aux. Expr 2 Aux. Expr 1 AND {printf ("&& "); } ; Aux. Expr 3 NOT {printf ("! "); } Aux. Expr 3 ;

Aux. Expr 3 : | ; Aux. Expr 4 RELOP { switch ($2) {

Aux. Expr 3 : | ; Aux. Expr 4 RELOP { 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; } } Aux. Expr 4

Aux. Expr 4 Term : Term | Aux. Expr 4 ADOP { switch ($2)

Aux. Expr 4 Term : Term | Aux. Expr 4 ADOP { switch ($2) { case MAIS: printf ("+ "); break; case MENOS: printf ("- "); break; } } Term ; : Factor | Term MULTOP { switch ($2) { case MULT: printf ("* "); break; case DIV: printf ("/ "); break; case RESTO: printf ("%% "); break; } } Factor ;

Factor | | | | : Variable INTCT {printf ("%d ", $1); } FLOATCT

Factor | | | | : Variable INTCT {printf ("%d ", $1); } FLOATCT {printf ("%g ", $1); } CHARCT {printf ("'%c' ", $1); } TRUE {printf ("true "); } FALSE {printf ("false "); } NEG {printf ("~ "); } Factor OPPAR {printf ("( "); } Expression {printf (") "); } ; : ; ID {printf ("%s ", $1); } CLPAR Variable %%

/* Inclusao do analisador lexico */ #include "lex. yy. c" /* Inic. Tab. Simb:

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

/* Procura. Simb (cadeia): Procura cadeia na tabela de simbolos; Caso ela ali esteja,

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

/* Insere. Simb (cadeia, tid, tvar): Insere cadeia na tabela de simbolos, com tid

/* Insere. Simb (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 Insere. Simb (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;

/* hash (cadeia): funcao que determina e retorna a classe de cadeia na tabela

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

/* Imprime. Tab. Simb: Imprime todo o conteudo da tabela de simbolos */ void

/* Imprime. Tab. Simb: Imprime todo o conteudo da tabela de simbolos */ void Imprime. Tab. Simb () { int i; simbolo s; printf ("nn TABELA DE SIMBOLOS: nn"); 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", nometipvar[s->tvar], s->inic, s->ref); printf(")n"); } } }

/* Mensagens de erros semanticos */ void Declaracao. Repetida (char *s) { printf ("nn*****

/* Mensagens de erros semanticos */ void Declaracao. Repetida (char *s) { printf ("nn***** Declaracao Repetida: %s *****nn", s); } void Nao. Declarado (char *s) { printf ("nn***** Identificador Nao Declarado: %s *****nn", s); } void Tipo. Inadequado (char *s) { printf ("nn***** Identificador de Tipo Inadequado: %s *****nn", s); }

b) Arquivo tsimb 012017. l %{ void comentario (void); char tratachar (char *); %}

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

{ws} { ; } "/*" {comentario (); } char {return CHAR; } false {return

{ws} { ; } "/*" {comentario (); } char {return CHAR; } false {return FALSE; } float {return FLOAT; } int {return INT; } logic {return LOGIC; } program {return PROGRAM; } true {return TRUE; } var {return VAR; } {id} {strcpy (yylval. cadeia, yytext); return ID; } {ctcarac} {yylval. carac = tratachar (yytext); return CHARCT; } {ctint} {yylval. valint = atoi(yytext); return INTCT; } {ctreal} {yylval. valreal = atof(yytext); return FLOATCT; }

"||" {return OR; } "&&" {return AND; } "!" {return NOT; } "<" {yylval.

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

"(" ")" "{" "}" "; " ", " "=". %% {return OPPAR; } {return

"(" ")" "{" "}" "; " ", " "=". %% {return OPPAR; } {return CLPAR; } {return OPBRACE; } {return CLBRACE; } {return SCOLON; } {return COMMA; } {return ASSIGN; } {yylval. carac = yytext[0]; return INVAL; }

/* comentario: le e descarta os comentarios do programa */ void comentario () {

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

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

c) Arquivo tsimb 012017. dat program teste; var int i, jjj, h, tb; logic

c) Arquivo tsimb 012017. dat program teste; var int i, jjj, h, tb; logic n, m; float v, i; char x, y, z, w;

{ x = n && m; v = 3. 5 * v; y =

{ x = n && m; v = 3. 5 * v; y = '@'; v = h % tb; h = jjj % 4. 2; { i = jjj*false; jjj = 0; } jjj = n + 1; i = i + 1; { i = !i; i = i + 1 + z; { i = 0; jjj = 0; } jjj = jjjj + teste; }

m m m n i n n i } = = = = v

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

Exercício 3. 1: Inserir no programa 3. 1 programação para montar a tabela dos

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

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,

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) n Colocar {Inic. Tab. Simb (); } no início da 1ª produção n Colocar {Imprime. Tab. Simb (); } no final da mesma produção n Trocar $2 por $3 , na mesma produção Prog : ; PROGRAM ID SCOLON {printf ("program %s ; n", $2); } Decls Comp. Stat Rodar com o arquivo tsimb 012017. dat

b) Inserir o nome do programa na tabela n Na produção Prog, na ação

b) Inserir o nome do programa na tabela n Na produção Prog, na ação depois de SCOLON, depois da chamada de printf, colocar Insere. Simb ($3, IDPROG, NAOVAR); Prog : ; {- - - -} PROGRAM ID SCOLON {printf ("program %sn", $3); } Decls Comp. Stat {- - - -} Rodar com o arquivo tsimb 012017. dat

c) Inserir os nomes das variáveis declaradas na tabela, notificando os casos de re-declaração.

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

n Nas produções Type, atribuir valor à variável tipocorrente Type : INT {printf (-

n Nas produções Type, atribuir valor à variável tipocorrente Type : INT {printf (- -); | FLOAT {printf (- -); | CHAR {printf (- -); | LOGIC {printf (- -); tipocorrente = INTEIRO; tipocorrente = REAL; tipocorrente = CARACTERE; tipocorrente = LOGICO; Rodar com o arquivo tsimb 012017. dat } }

d) Verificar se cada identificador usado foi declarado e) Verificar se cada identificador usado

d) Verificar se cada identificador usado foi declarado e) Verificar se cada identificador usado de variável é do tipo IDVAR n Na produção Variable, na ação depois de ID, depois do printf, colocar simb = Procura. Simb ($1); if (simb == NULL) Nao. Declarado ($1); else if (simb->tid != IDVAR) Tipo. Inadequado ($1); Variable : ID {printf ("%s ", $1); } Rodar com o arquivo tsimb 012017. dat

f) Marcar as variáveis referenciadas e inicializadas pelo programa e verificar se todas as

f) Marcar as variáveis referenciadas e inicializadas pelo programa e verificar se todas as variáveis têm essa marca n 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; } Isso possibilita que terminais e/ou não-terminais tenham como atributo um ponteiro para uma célula da tabsimb

n Declarar que o não-terminal Variable tem como atributo o campo simb da %union,

n Declarar que o não-terminal Variable tem como atributo o campo simb da %union, colocando antes dos tokens: %type <simb> Variable /* Declaracao dos atributos dos tokens e dos naoterminais */ %token <cadeia> <valint> ID CTCARAC CTINT

n Na produção Variable, no final da ação final, colocar: $$ = simb; Variable

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

n Na produção Factor : Variable, colocar, no final, a ação: {if ($1 !=

n Na produção Factor : Variable, colocar, no final, a ação: {if ($1 != NULL) $1 ->ref = VERDADE; } Factor : Variable n Na produção Assign. Stat, colocar, depois de Variable, a ação: {if ($1 != NULL) $1 ->inic = $1 ->ref = VERDADE; } Assign. Stat ("; n"); } : Variable ASSIGN {printf ("= "); } Expression SCOLON {printf Rodar com o arquivo tsimb 012017. dat

n Fazer uma função Verifica. Inic. Ref, que percorra toda a tabsimb, checando e

n Fazer uma função Verifica. Inic. Ref, 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 n Chamar Verifica. Inic. Ref antes de Imprime. Tab. Simb, na ação final da produção Prog Rodar com o arquivo tsimb 012017. dat

Exercício 3. 2: Inserir no programa 3. 1 programação para verificar a compatibilidade entre

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

n Numa produção contendo um operador de expressões, os operandos são não-terminais n Exemplo:

n Numa produção contendo um operador de expressões, os operandos são não-terminais n Exemplo: seja a produção Term : Term MULTOP Factor n No lado direito, Term e Factor representam os operandos de MULTOP n É 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

n Acrescentar o campo tipoexpr na declaração %union: %union { char cadeia[50]; int atr,

n Acrescentar o campo tipoexpr na declaração %union: %union { char cadeia[50]; int atr, valint; float valreal; char carac; simbolo simb; int tipoexpr; } n Declarar que todos os não-terminais relacionados com expressões têm como atributo o campo tipoexpr: %type <tipoexpr> Expression Aux. Expr 1 Aux. Expr 2 Aux. Expr 3 Aux. Expr 4 Term Factor

n Em cada produção relacionada com expressões, deve ser calculado o atributo do lado

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

Exemplo: Teste de compatibilidade do operador NEG n No não-terminal Variable, já está calculado

Exemplo: Teste de compatibilidade do operador NEG n No não-terminal Variable, já está calculado o valor de $$: Variable : ID { printf ("%s ", $1); simb = Procura. Simb ($1); if (simb == NULL) Nao. Declarado ($1); else if (simb->tid != IDVAR) Tipo. Inadequado ($1); $$ = simb; } ;

n Calcular o valor de $$ em todas as produções de Factor e fazer

n Calcular o valor de $$ em todas as produções de Factor e fazer teste de compatibilidade nas produções cabíveis: Factor : Variable { if ($1 != NULL) { $1 ->ref = VERDADE; $$ = $1 ->tvar; } } Trocar o conteúdo da ação por | INTCT {printf ("%d ", $1); $$ = INTEIRO; } | FLOATCT {printf ("%g ", $1); $$ = REAL; } | CHARCT {printf ("%c ", $1); $$ = CARACTERE; } | TRUE {printf (“true "); $$ = LOGICO; } | FALSE {printf ("false "); $$ = LOGICO; }

n Calcular o valor de $$ em todas as produções de Factor e fazer

n Calcular o valor de $$ em todas as produções de Factor e fazer teste de compatibilidade nas produções cabíveis: Factor : NEG {printf ("~ "); } Factor { if ($3 != INTEIRO && $3 != REAL && $3 != CARACTERE) Incompatibilidade ("Operando improprio para menos unario"); if ($3 == REAL) $$ = REAL; else $$ = INTEIRO; } | OPPAR {printf ("( "); } Expression CLPAR { printf (") "); $$ = $3; } ;

n Criar a função Incompatibilidade e seu protótipo: void Incompatibilidade (char *); void Incompatibilidade

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

Exemplo: Teste de compatibilidade do operador MULTOP n Calcular o valor de $$ em

Exemplo: Teste de compatibilidade do operador MULTOP n Calcular o valor de $$ em todas as produções do nãoterminal Term e fazer teste de compatibilidade nas produções cabíveis

Term : Factor /* Default: $$ = $1; */ Rodar com o arquivo |

Term : Factor /* Default: $$ = $1; */ Rodar com o arquivo | Term MULTOP {- - -} Factor tsimb 012017. dat {switch ($2) { case MULT: case DIV: if ($1 != INTEIRO && $1 != REAL && $1 != CARACTERE || $4 != INTEIRO && $4!=REAL && $4!=CARACTERE) Incompatibilidade ("Operando improprio para operador aritmetico"); if ($1 == REAL || $4 == REAL) $$ = REAL; else $$ = INTEIRO; break; case RESTO: if ($1 != INTEIRO && $1 != CARACTERE || $4 != INTEIRO && $4 != CARACTERE) Incompatibilidade ("Operando improprio para operador resto"); $$ = INTEIRO; break; }} ;

Exercício 3. 3: Inserir no programa 3. 1 programação para fazer testes de compatibilidade

Exercício 3. 3: Inserir no programa 3. 1 programação para fazer testes de compatibilidade para os operadores ADOP, RELOP, NOT, AND e OR Exercício 3. 4: Inserir, no programa 3. 1, teste para verificar a compatibilidade entre os dois lados comandos de atribuição, de acordo com a tabela:

Assign. Stat : Variable { if ($1 != NULL) $1 ->inic = $1 ->ref

Assign. Stat : Variable { if ($1 != NULL) $1 ->inic = $1 ->ref = VERDADE; } ASSIGN {printf ("= "); } Expression SCOLON { printf ("; n"); if ($1 != NULL) if ((($1 ->tvar == INTEIRO || $1 ->tvar == CARACTERE) && ($5 == REAL || $5 == LOGICO)) || ($1 ->tvar == REAL && $5 == LOGICO) || ($1 ->tvar == LOGICO && $5 != LOGICO)) Incompatibilidade ("Lado direito de comando de atribuicao improprio"); } ;

Programa 3. 2: Gramática sem subprogramas, com variáveis escalares e indexadas, comandos de atribuição,

Programa 3. 2: Gramática sem subprogramas, com variáveis escalares e indexadas, comandos de atribuição, if, while, read e write n Para os exercícios 3. 5 e 3. 6, considerar os arquivos tsimb 022017. l e tsimb 022017. y da aba de ‘Códigos’ da página do professor n O arquivo tsimb 022017. l tem o tratamento de cadeias análogo ao tratamento de caracteres. n Rodar inicialmente esses programas com o arquivo de dados tsimb 012017. dat n Esses arquivos já fazem teste de compatibilidade de expressões e de comandos de atribuição (conforme os 4 exercícios anteriores)

Exercício 3. 5: Inserir na gramática do programa 3. 2 testes semânticos para as

Exercício 3. 5: Inserir na gramática do programa 3. 2 testes semânticos para as produções dos comandos if, while, read, write que aparecem na linguagem COMP-ITA 2017 n Produções: Statement If. Stat Else. Stat While. Stat Read. List Write. Stat : | : Comp. Stat | If. Stat | While. Stat | Read. Stat Write. Stat | Assign. Stat IF OPPAR Expression CLPAR Statement : : : | ELSE Statement WHILE OPPAR Expression CLPAR Statement READ OPPAR Read. List CLPAR SCOLON Variable | Read. List COMMA Variable WRITE OPPAR Write. List CLPAR SCOLON

Statement: | If. Stat : Else. Stat While. Stat : Read. Stat Read. List

Statement: | If. Stat : Else. Stat While. Stat : Read. Stat Read. List Write. Stat: Write. List: Write. Elem: Comp. Stat | If. Stat | While. Stat | Read. Stat Write. Stat | Assign. Stat IF OPPAR Expression CLPAR Statement Else. Stat Abrir o arquivo : | ELSE Statement tsimb 022017. dat WHILE OPPAR Expression CLPAR Statement As variáveis n e num : READ OPPAR Read. List CLPAR SCOLON são lidas (inic e ref) : Variable | Read. List COMMA Variable Expressões inteiras em WRITE OPPAR Write. List CLPAR SCOLON comandos if e while Write. Elem | Write. List COMMA Write. Elem STRING | Expression n Marcar as variáveis lidas como inicializadas e referenciadas (tal como no lado esquerdo de atribuição) n Verificar se as expressões dos comandos if e while são lógicas n Testar o programa com o arquivo de dados tsimb 022017. dat

Exercício 3. 6: Inserir na gramática do programa 3. 2 alterações na tabela de

Exercício 3. 6: 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 2017, envolvendo variáveis indexadas n Produções: Elem Dim. List Dim Variable Subscr. List Subscript : : : ID Dim. List ε | Dim. List Dim OPBRAK INT CLBRAK ID Subscr. List ε | Subscr. List Subscript OPBRAK Expr. Aux 4 CLBRAK

n Observar a nova produção de Elem para incluir a declaração de variáveis indexadas,

n Observar a nova produção de Elem para incluir a declaração de variáveis indexadas, inserindo o nome na tabela de símbolos: Elem : ID { printf ("%s ", $1); if (Procura. Simb ($1) != NULL) Declaracao. Repetida ($1); else Insere. Simb ($1, IDVAR, tipocorrente); } Dim. List ;

n Observar a nova produção de Variavel para prever um elemento de variável indexada,

n Observar a nova produção de Variavel para prever um elemento de variável indexada, verificando se o nome está na tabela de símbolos: Variable: ID { printf ("%s ", $1); simb = Procura. Simb ($1); if (simb == NULL) Nao. Declarado ($1); else if (simb->tid != IDVAR) Tipo. Inadequado ($1); Antes era $<simb>$ = simb; $$ = simb; } Subscr. List {$$ = $<simb>2; } ; Não estava presente Mas aqui $$ não é mais o atributo do lado esquerdo

n Observar a nova produção de Variavel para incluir um elemento de variável indexada,

n Observar a nova produção de Variavel para incluir um elemento de variável indexada, verificando se o nome está na tabela de símbolos: $<simb>$ e $<simb>2: Variavel: ID { Forma de especificar o atributo de um nãoterminal fictício printf ("%s ", $1); simb = Procura. Simb ($1); if (simb == NULL) Nao. Declarado ($1); else if (simb->tid != IDVAR) Tipo. Inadequado ($1); $<simb>$ = simb; } List. Subscr {$$ = $<simb>2; } ; Porque não eliminar isso? e não colocar $$ = simb aqui?

n Por default, o atributo de um não-terminal fictício também é do tipo inteiro

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

Exemplo: Seja a seguinte produção: A : B {simb = Insere. Simb (- -

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

n Preparar a tabela de símbolos para guardar informações sobre: Número de dimensões de

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

/* Definicao de outras constantes */ #define NCLASSHASH TRUE FALSE MAXDIMS 23 1 0

/* Definicao de outras constantes */ #define NCLASSHASH TRUE FALSE MAXDIMS 23 1 0 10 /* Declaracoes para a tabela de simbolos */ typedef struct celsimb; typedef celsimb *simbolo; struct celsimb { char *cadeia; int tid, tvar , ndims, dims[MAXDIMS+1] char inic, ref , array ; simbolo prox; }; ; dims cadeia tid tvar inic ref array ndims A IDVAR INTEIRO 0 0 1 3 10 20 0 1 2 5 3 . . 10

/* Imprime. Tab. Simb: Imprime todo o conteudo da tabela de simbolos */ void

/* Imprime. Tab. Simb: Imprime todo o conteudo da tabela de simbolos */ void Imprime. Tab. Simb () { int i; simbolo s; printf ("nn TABELA DE SIMBOLOS: nn"); 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 == VERDADE) { int j; printf (", EH ARRAYntndims = %d, dimensoes: ", s->ndims); for (j = 1; j <= s->ndims; j++) printf (" %d", s->dims[j]); } } printf(")n"); } } }

n Alterar toda programação da montagem da tabela de símbolos e de testes semânticos

n Alterar toda programação da montagem da tabela de símbolos e de testes semânticos realizados até agora dims cadeia tid tvar inic ref array ndims A IDVAR INTEIRO 0 0 1 3 10 20 0 1 2 5 3 . . 10

n Nas declarações das variáveis: Ainda falta achar as dimensões das variáveis indexadas Elem:

n Nas declarações das variáveis: Ainda falta achar as dimensões das variáveis indexadas Elem: ID { printf ("%s ", $1); if (Procura. Simb ($1) != NULL) Declaracao. Repetida ($1); else { simb = Insere. Simb ($1, IDVAR, tipocorrente); simb->array = FALSO; simb->ndims = 0; } } Dim. List ; Dim. List: | Dim. List Dim {simb->array = VERDADE; } ; dims cadeia tid tvar inic ref array ndims A IDVAR INTEGER 0 0 1 3 10 20 0 1 2 5 3 . . 10

n No dimensionamento das variáveis indexadas, inclusive verificando se a constante inteira usada no

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

n Criar o protótipo: void Esperado (char *); n E a função: void Esperado

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

Realizar ainda os seguintes testes e ações semânticas: n Verificar se as expressões que

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

n Verificar se as expressões que aparecem nos subscritos das variáveis indexadas são do

n 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: Subscript: OPBRAK {printf ("[ "); } Aux. Expr 4 CLBRAK { printf ("] "); if ($3 != INTEIRO && $3 != CARACTERE) Incompatibilidade ("Tipo inadequado para subscrito"); } ; Rodar o programa com o arquivo tsimb 032017. dat

n Verificar se uma variável de tipo escalar tem subscritos n Verificar se uma

n Verificar se uma variável de tipo escalar tem subscritos n Verificar se uma variável indexada não tem subscritos n 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 verificar se esse número é

n O não-terminal Subscr. List terá como atributo o número de subscritos: %union {

n O não-terminal Subscr. List 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; } %type <simb> Variable %type <tipoexpr> Expression Aux. Expr 1 Aux. Expr 2 Aux. Expr 3 Aux. Expr 4 Term Factor %type <nsubscr> Subscr. List

n Nas produções de Subscr. List: Subscr. List ; : | {$$ = 0;

n Nas produções de Subscr. List: Subscr. List ; : | {$$ = 0; } Subscr. List Subscript {$$ = $1 + 1; }

n Na produção de Variable: ID {- - -} Subscr. List { $$ =

n Na produção de Variable: ID {- - -} Subscr. List { $$ = $<simb>2; if ($$ != NULL) { if ($$->array == FALSO && $3 > 0) Nao. Esperado ("Subscrito(s)"); else if ($$->array == VERDADE && $3 == 0) Esperado ("Subscrito(s)"); else if ($$->ndims != $3) Incompatibilidade ("Numero de subscritos incompativel com declaracao"); } } ;

n Criar o protótipo: void Nao. Esperado (char *); n E a função: void

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