Carregar apresentação
A apresentação está carregando. Por favor, espere
1
Capítulo III Diagramas de Transições
CES-41 COMPILADORES Capítulo III Diagramas de Transições
2
Capítulo III – Diagramas de Transições
3.1 – Considerações iniciais 3.2 – Uma linguagem ilustrativa: Mini-Pascal 3.3 – Análise léxica por diagramas de transições 3.4 – Análise sintática por diagramas de transições 3.5 – Tabela de símbolos em diagramas de transições 3.6 – Testes semânticos em diagramas de transições 3.7 – Geração de código intermediário
3
3.1 – Considerações Iniciais
Diagramas de transições: usados na construção do front-end de um compilador Forma didática de concepção de um front-end Há outros métodos mais eficientes, porém menos didáticos A seguir, análises léxica, sintática e semântica e geração de código intermediário por diagramas de transições Diagrama de transições léxicas é um autômato finito determinístico
4
Exemplo: Diagrama de transições para reconhecer constantes numéricas em Fortran
d é um dígito genérico
5
Arcos de qualquer vértice para o vértice Erro não são mostrados, mas existem
d é um dígito genérico
6
Estado não final Estado final d é um dígito genérico
7
São reconhecidas constantes como: 13, +13, -13, 13. , 1. 25,. 25, -
São reconhecidas constantes como: 13, +13, -13, 13., 1.25, .25, -.25, , 13E-15, 13.E-15, E+72, .75E5 d é um dígito genérico
8
Para as transições sintáticas usa-se vários diagramas de transições; um para cada não-terminal
Existem linguagens para as quais é difícil ou até impossível a utilização de diagramas de transições sintáticas Para ilustrar será utilizada a linguagem Mini-Pascal extraída de Pascal, apresentada logo a seguir
9
3.2 – Uma linguagem ilustrativa: Mini-Pascal
3.2.1 – Gramática do Mini-Pascal A gramática do Mini-Pascal não é recursiva à esquerda, mas apresenta a ambiguidade dos comandos condicionais Não tem subprogramas, nem variáveis indexadas e seu único comando repetitivo é o while Não-terminais estão em itálico Terminais são átomos obtidos do analisador léxico; são apresentados com LETRAS MAIÚSCULAS, ou com os caracteres que os identificam
10
Produções da gramática:
Prog PROGRAM ID ; Decls CmdComp . Decls ε VAR ListDecl ListDecl DeclTip DeclTip ListDecl DeclTip ListId : Tip ; ListId ID ID , ListId Tip INTEGER BOOLEAN CmdComp BEGIN ListCmd END ListCmd Cmd Cmd ; ListCmd Cmd CmdIf CmdWhile CmdRead CmdWrite CmdAtrib CmdComp
11
Produções da gramática (continuação 1) :
CmdIf IF Expr THEN Cmd | IF Expr THEN Cmd ELSE Cmd CmdWhile WHILE Expr DO Cmd CmdRead READ ( ListId ) CmdWrite WRITE ( ListW ) ListW ElemW ElemW , ListW ElemW Expr CADEIA CmdAtrib ID := Expr
12
Produções da gramática (continuação 2) :
Expr ExprSimpl ExprSimpl OPREL ExprSimpl ExprSimpl Term Term OPAD ExprSimpl Term Fat Fat OPMULT Term Fat ID CTE ( Expr ) TRUE FALSE OPNEG Fat
13
3.2.2 – Especificações léxicas
Cada átomo tem pelo menos um atributo chamado tipo Conforme o tipo do átomo, ele poderá ter outros atributos Se o átomo é uma palavra reservada, seu tipo é a própria palavra reservada e não há outros atributos Tabela de palavras reservadas:
14
letra ( letra | dígito )*
3.2.2 – Especificações léxicas Átomo identificador: seu tipo é ID e seu outro atributo é a cadeia de seus caracteres; sua sintaxe é letra ( letra | dígito )* Caracteres de identificadores que excederem o número de 16 são ignorados Constantes inteiras: seu tipo é CTE e seu outro atributo é o seu valor inteiro; esse valor tem de caber em 2 bytes Cadeias de caracteres: vêm entre apóstrofos (‘ ’); têm como tipo, CADEIA, e, como outro atributo, a cadeia de seus caracteres sem os apóstrofos
15
Tabela dos tipos e atributos dos operadores:
OPAD : operador aditivo OPMULT : operador multiplicativo OPNEG : operador negador OPREL : operador relacional
16
Tabela dos tipos dos separadores (não possuem outros atributos):
Os programas em Mini-Pascal não têm comentários Espaços em branco entre átomos são opcionais, com a exceção das palavras reservadas Essas não podem estar concatenadas com outras e com identificadores e constantes inteiras
17
3.3 – Análise Léxica por Diagramas de Transições
3.3.1 – Objetivos da análise léxica Os caracteres do programa são grupados em átomos Os átomos têm sua validade verificada Os átomos válidos são classificados e recebem seus atributos
18
Tabela de átomos e seus atributos
Exemplo: Programa para o cálculo do fatorial de um numero lido: PROGRAM fatorial; VAR n, fat, i: INTEGER; BEGIN READ (n); fat := 1; i := 1; WHILE i <= n DO BEGIN fat := fat * i; i := i + 1 END; WRITE (‘O fatorial de’, n, ‘ eh ’, fat) END. Tabela de átomos e seus atributos
20
3.3.2 – Diagrama de transições
A estrutura de um analisador léxico pode ser montada sobre um diagrama de transições de estados O diagrama é uma só entidade, mas, por razões didáticas, está apresentado em várias figuras Uma figura para cada transição que parte do estado inicial Supõe-se que, no estado inicial, o analisador já tenha em mãos um caractere
21
a) Uma letra é o primeiro caractere
Em cada transição: Caractere(s) responsável(eis) Ações antes da transição
22
Forma Cadeia: introduz caractere numa cadeia
Pega Caractere: lê novo caractere do programa; retorna ‘\0’ para end-of-file Class Cadeia: classifica cadeia formada Forma Átomo: forma novo átomo com o tipo obtido da classificação; se for ID, o atributo será a cadeia formada Possíveis átomos: Palavra reservada OPMULT - AND OPAD - OR OPNEG - NOT ID - cadeia
23
b) Um dígito é o primeiro caractere
Forma número: obtém o número inteiro correspondente à cadeia formada Forma Átomo: forma novo átomo com o número formado e com o tipo CTE Átomo formado: CTE - número inteiro
24
c) Um apóstrofo é o primeiro caractere
Se o fecha-apóstrofo for esquecido, o resto do programa será guardado em cadeia Átomo formado: CADEIA - cadeia
25
d) Um dos caracteres + - * / ~ = é o primeiro
Class Caractere: classifica caractere lido Possíveis átomos: OPMULT - VEZES OPMULT - DIV OPAD - MAIS OPAD - MENOS OPNEG - NEG OPREL - IGUAL
26
e) O caractere < é o primeiro
Possíveis átomos: OPREL - MENIG OPREL - DIFER OPREL - MENOR
27
f) O caractere > é o primeiro
Possíveis átomos: OPREL - MAIG OPREL - MAIOR
28
g) O caractere : é o primeiro
Possíveis átomos: ATRIB DPONTS
29
h) Um dos caracteres ; . , ( ) é o primeiro
Possíveis átomos: PVIRG PONTO VIRG ABPAR FPAR
30
i) Um dos caracteres ‘\0’, ‘ ’, ‘\n’, ‘\t’, ‘\r’, ou qualquer outro é o primeiro
Átomo de tipo FINAL: artificial Possíveis átomos: FINAL INVAL
31
3.3.3 – Implementação de um diagrama de transições léxicas
Primeiramente, será apresentada uma função main para gerenciar a classificação de todos os átomos de um programa em Mini-Pascal Essa função tem a simples finalidade de testar o analisador léxico Ela não será usada quando esse analisador estiver integrado ao analisador sintático
32
nome nomearq; FILE *program, *result;
void main () { printf ("A N A L I S E L E X I C A\n\n"); printf ("Nome do arquivo: "); fflush (stdin); gets (nomearq); program = fopen (nomearq, "r"); result = fopen ("atomosmp", "w"); carac = NovoCarac (); while (carac) { NovoAtomo (); ImprimeAtomo (); } printf ("\nAnalise do arquivo '%s' encerrada", nomearq); printf ("\n\nVer atomos no arquivo 'atomosmp'"); getch (); typedef struct atomo atomo; struct atomo { int tipo; atribatomo atrib; }; typedef union atribatomo atribatomo; union atribatomo { char *cadeia; long valor; int atr; char carac; }; Variáveis globais: nome nomearq; FILE *program, *result; char carac; atomo atom; char *cadeia; NovoAtomo: coloca em atom o tipo e o atributo do próximo átomo do programa; é o centro do analisador léxico NovoCarac: retorna o próximo caractere lido do programa; retorna ‘\0’ caso seja encontrado end-of-file
33
A função NovoAtomo: Coloca na estrutura atom o tipo e o atributo do próximo átomo encontrado Implementa o caminhamento pelo diagrama de transições léxicas A seguir o esquema geral de NovoAtomo
34
if (atom.tipo == ID || atom.tipo == CADEIA) free (atom.atrib.cadeia);
void NovoAtomo () { int estado = 1; if (atom.tipo == ID || atom.tipo == CADEIA) free (atom.atrib.cadeia); cadeia = malloc(MAXCADEIA*sizeof(char)); *cadeia = 0; while (estado != 3) switch (estado) { case 1: ; break; case 2: ; break; case 4: ; break; case 5: ; break; case 6: ; break; case 7: ; break; case 8: ; break; } free (cadeia); Preparação para uma eventual formação de cadeia Caso o átomo anterior tenha como atributo uma cadeia, ela deve ser desalocada Aqui ocorrem as transições de estados e o preparo do átomo Depois de formado o átomo, a cadeia é desalocada
35
Transições a partir do Estado 1
36
case 1: switch (carac) { case '\'': ; estado = 5; break; case '+': case '-': case '*': case '/': case '~': case '=': case ';': case '.': case ',': case '(': case ')': ; estado = 3; break; case '<': ; estado = 6; break; case '>': ; estado = 7; break; case ':': ; estado = 8; break; case '\0': ; estado = 3; break; default: if (isalpha (carac)) { ; estado = 2;} else if (isdigit (carac)) { ; estado = 4;} else if ((isspace(carac) || iscntrl(carac)) && (carac != 0)) { ; estado = 1; } else { ; estado = 3; } break;
37
case 1: switch (carac) { default: if (isalpha (carac)) { FormaCadeia (); carac = NovoCarac(); estado = 2;} else if (isdigit (carac)) { estado = 4;}
38
case 1: switch (carac) { case '\'': carac = NovoCarac( ); estado = 5; break;
39
case 1: switch (carac) { case '+': case '-': case '*': case '/': case '~': case '=': case ';': case '.': case ',': case '(': case ')': atom = Classifica (); carac = NovoCarac(); estado = 3; break;
40
case 1: switch (carac) { case '<': carac = NovoCarac(); estado = 6; break; case '>': carac = NovoCarac(); estado = 7; break; case ':': carac = NovoCarac(); estado = 8; break;
41
case 1: switch (carac) { case '\0': atom.tipo = FINAL; estado = 3; break; default: if ----- else if ((isspace(carac) || iscntrl(carac)) && (carac != 0)) { carac = NovoCarac(); estado = 1;} else {atom.tipo = INVAL; atom.atrib.carac = carac; carac = NovoCarac(); estado = 3; }
42
case 2: if (isalnum (carac)) { FormaCadeia (); carac = NovoCarac(); estado = 2;} else { atom = ClassificaCadeia (); estado = 3;} break; case 4: if (isdigit (carac)) { FormaCadeia (); carac = NovoCarac();estado = 4;} else {atom = FormaNumero (); estado = 3;}
43
case 6: if (carac == '=') { atom.tipo = OPREL; atom.atrib.atr = MENIG; carac = NovoCarac();} else if (carac == '>'){ atom.tipo = OPREL; atom.atrib.atr = DIFER; else { atom.tipo = OPREL; atom.atrib.atr = MENOR; } estado = 3; break; Outros estados ficam como exercícios
44
void FormaCadeia (void):
Funções auxiliares: void FormaCadeia (void): Armazena o novo caractere lido no final da variável cadeia É chamada para formar a cadeia de um identificador, palavra reservada, número ou constante cadeia de caracteres, ou um dos operadores and, or ou not atomo ClassificaCadeia (void): Classifica uma cadeia de caracteres Possíveis classes: Identificador palavra reservada operadores and, or e not; Retorna o átomo formado (tipo e atributo)
45
atomo FormaNumero (void):
Funções auxiliares: atomo FormaNumero (void): Converte uma cadeia de dígitos decimais em seu valor numérico Retorna o átomo formado (tipo e atributo) atomo Classifica (void): Classifica átomos formados por apenas um caractere, exceto os inválidos Retorna o átomo formado (tipo e atributo se for o caso) int PalavraReserv (void): Verifica se uma cadeia é uma palavra reservada Retorna seu tipo, em caso positivo
46
Definição de constantes simbólicas para as palavras reservadas, para os outros tipos de átomos e para os atributos dos operadores (#defines):
47
3.4 – Análise Sintática por Diagramas de Transições
3.4.1 – Objetivos da análise sintática Verificar a estrutura sintática de um programa Servir de esqueleto para: Construção da tabela de símbolos Análise semântica Geração do código intermediário Exemplo: árvore sintática do programa do fatorial (várias figuras)
54
3.4.2 – Diagramas de transições
Análise sintática por diagramas de transições é um método top-down preditor: Top-down: Partindo do símbolo inicial, através de derivações diretas, vai simulando a construção do programa analisado Preditor: Um só átomo é suficiente para decidir qual produção usar para fazer uma derivação direta
55
Características de um método preditor:
Os átomos são analisados um por um, do início para o final do programa Para decidir qual produção usar numa derivação direta, não é necessário checar um átomo já analisado Não é necessário olhar para algum átomo que vai aparecer mais adiante A gramática não pode ser recursiva à esquerda A gramática deve estar fatorada à esquerda (assunto a ser estudado no capítulo sobre análise sintática)
56
A gramática do Mini-Pascal admite análise sintática preditora, tal como o método dos diagramas de transições Muitas gramáticas não admitem métodos preditores Requerem a análise de átomos futuros e/ou passados
57
Percorrer diagrama de X
Usa-se um diagrama para cada não-terminal Nas transições, usa-se terminais ou não-terminais (na análise léxica: caracteres) Exemplo para não-terminais: sejam as produções: Y → X X → X Percorrer diagrama de X Diagrama de Y Diagrama de X
58
A seguir, diagramas de transições sintáticas de cada não-terminal da gramática do Mini-Pascal
Incluídas transições para tratamento de erros sintáticos Tal tratamento é bem simples, só a título de ilustração
59
a) Prog PROGRAM ID PVIRG Decls CmdComp PONTO FINAL
60
ExecTransic (X): Percorre o diagrama de X, antes de mudar de estado Estados 9 e 10: Tratamento de erro Incondicional: Mudança incondicional de estado
61
b) Decls ε VAR ListDecl
62
ListDecl ( DeclTipo )+
c) ListDecl DeclTipo DeclTipo ListDecl Para facilitar a construção do diagrama, pode-se escrever suas produções de outra maneira: ListDecl ( DeclTipo )+
63
d) DeclTipo ListId DPONTS Tip PVIRG
64
e) ListId ID ID VIRG ListId
Pode-se escrever suas produções de outra maneira: ListId ID ( VIRG ID )*
65
f) Tip INTEGER BOOLEAN
66
g) CmdComp BEGIN ListCmd END
67
ListCmd Cmd ( PVIRG Cmd )*
h) ListCmd Cmd Cmd PVIRG ListCmd Pode-se escrever suas produções de outra maneira: ListCmd Cmd ( PVIRG Cmd )*
68
i) Cmd CmdIf CmdWhile CmdRead CmdWrite | CmdAtrib CmdComp
69
IF Expr THEN IF Expr THEN Cmd ELSE Cmd
j) CmdIf IF Expr THEN Cmd | IF Expr THEN Cmd ELSE Cmd Ambiguidade: a sub-forma sentencial IF Expr THEN IF Expr THEN Cmd ELSE Cmd tem duas árvores sintáticas Regra de solução: o ELSE corresponde ao último THEN encontrado O diagrama de transições resolve o problema
70
j) CmdIf IF Expr THEN Cmd
| IF Expr THEN Cmd ELSE Cmd
71
k) CmdWhile WHILE Expr DO Cmd
72
l) CmdRead READ ABPAR ListId FPAR
73
m) CmdWrite WRITE ABPAR ListW FPAR
74
ListW ElemW ( VIRG ElemW )*
n) ListW ElemW ElemW VIRG ListW Pode-se escrever suas produções de outra maneira: ListW ElemW ( VIRG ElemW )*
75
o) ElemW CADEIA Expr
76
p) CmdAtrib ID ATRIB Expr
77
Expr ExprSimpl ( OPREL ExprSimpl ) ?
q) Expr ExprSimpl ExprSimpl OPREL ExprSimpl Pode-se escrever suas produções de outra maneira: Expr ExprSimpl ( OPREL ExprSimpl ) ?
78
ExprSimpl Term ( OPAD Term )*
r) ExprSimpl Term Term OPAD ExprSimpl Pode-se escrever suas produções de outra maneira: ExprSimpl Term ( OPAD Term )*
79
Term Fat ( OPMULT Fat )*
s) Term Fat Fat OPMULT Term Pode-se escrever suas produções de outra maneira: Term Fat ( OPMULT Fat )*
80
t) Fat ID CTE TRUE FALSE ABPAR Expr FPAR OPNEG Fat
81
3.4.3 – Implementação dos diagramas de transições sintáticas
Primeiramente, uma função main para acionar o analisador sintático
82
Variáveis globais: logic erro nome nomearq; FILE *program, *result;
void main () { printf ("A N A L I S E S I N T A T I C A\n\n"); printf ("Nome do arquivo: "); fflush (stdin); gets (nomearq); program = fopen (nomearq, "r"); result = fopen ("atomosmp", "w"); erro = FALSE; carac = NovoCarac (); NovoAtomo (); ExecProg (); printf ("\nAnalise do arquivo '%s' encerrada", nomearq); if (erro) printf ("\n\nPrograma com erros!!!"); printf ("\n\nVer analise no arquivo 'atomosmp'"); getch (); } Variáveis globais: logic erro nome nomearq; FILE *program, *result; char carac; atomo atom; char *cadeia; ExecProg: implementa o diagrama de transições do não-terminal Prog ; é o centro do analisador sintático
83
a)A função ExecProg:
84
void ExecProg () { int estado = 1; while (estado != 8) switch (estado) { case 1: if (atom.tipo == PROGRAM) {NovoAtomo (); estado = 2;} else {Esperado ("PROGRAM"); estado = 9;} break; case 2: if (atom.tipo == ID) {NovoAtomo (); estado = 3;} else {Esperado ("IDENTIFICADOR"); estado = 9;} case 3: if (atom.tipo == PVIRG) {NovoAtomo (); estado = 4;} else {Esperado ("PONTO E VIRGULA"); estado = 9; }
85
case 4: ExecDecls (); estado = 5; break; case 5: ExecCmdComp (); estado = 6; break; case 6: if (atom.tipo == PONTO) {NovoAtomo (); estado = 7;} else {Esperado ("PONTO"); estado = 10;} break; case 7: if (atom.tipo == FINAL) estado = 8; else {Esperado ("END OF FILE"); estado = 10;} case 9: if (atom.tipo == PVIRG) {NovoAtomo (); estado = 4;} else if (atom.tipo == FINAL) estado = 8; else {NovoAtomo (); estado = 9;} case 10: else {NovoAtomo (); estado = 10;} }
86
b) A função ExecDecls: void ExecDecls () { int estado = 11;
while (estado != 13) switch (estado) { case 11: if (atom.tipo == VAR) {NovoAtomo (); estado = 12;} else estado = 13; break; case 12: ExecListDecl (); estado = 13; }
87
c) A função ExecListDecl:
void ExecListDecl () { int estado = 14; while (estado != 16) switch (estado) { case 14: ExecDeclTipo (); estado = 15; break; case 15: if (atom.tipo == ID) estado = 14; else estado = 16; }
88
d) A função DeclTipo:
89
Funções para outros não-terminais ficam como exercícios
void ExecDeclTipo () { int estado = 17; while (estado != 21) switch (estado) { case 17: ExecListId (); estado = 18; break; case 18: if (atom.tipo == DPONTS) {NovoAtomo (); estado = 19;} else {Esperado ("DOIS PONTOS"); estado = 22;} break; case 19: ExecTip (); estado = 20; break; case 20: if (atom.tipo == PVIRG) {NovoAtomo (); estado = 21;} else {Esperado ("PONTO E VIRGULA"); estado = 22;} break; case 22: if (atom.tipo == PVIRG) else if (atom.tipo == FINAL) estado = 21; else {NovoAtomo (); estado = 22;} break; } Funções para outros não-terminais ficam como exercícios
90
3.5 – Tabela de Símbolos em Diagramas de Transições
3.5.1 – Objetivos da tabela de símbolos Agregar informações sobre todos os identificadores do programa Disponibilizar essas informações para: Análise semântica Geração do código intermediário
91
Para o Mini-Pascal, considerando só a fase de análise, as informações são as seguintes:
Cadeia de caracteres do identificador Tipo do identificador: Nome de programa Nome de variável Nome de função (para o Pascal padrão) Nome de procedimento (para o Pascal padrão)
92
Se for variável: Tipo da variável (inteira, booleana) Se é indexada (para o Pascal padrão) Se tem inicialização Se é referenciada Para a fase de síntese, outras informações: Endereço de memória Número de bytes ocupados, etc.
93
3.5.2 – Estrutura de dados para a tabela de símbolos
Pode-se usar estrutura de hashing aberto Função para o hashing: Onde: NCLASSHASH é o número de classes. n é o número de caracteres de x (sem o ‘\0’)
94
Exemplo: Tabela de símbolos (hashing) do programa do fatorial (NCLASSHASH = 23)
95
Neste exemplo, as classes têm somente 0 e 1 símbolo; Em outros, as listas das classes podem ser maiores.
96
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];
97
3.5.3 – Implementação da tabela de símbolos em diagramas de transições
A geração da tabela de símbolos é feita nas ações dos diagramas de transições sintáticas O símbolo com o nome do programa é inserido na produção do não-terminal Prog
98
Ampliado a seguir:
99
InsereSimb (atom.atrib.cadeia, IDPROG);
Insere na tabela de símbolos o atributo cadeia do átomo recém-formado, como sendo do tipo identificador de programa Retorna um ponteiro para a célula inserida na tabela de símbolos Sua programação consiste em inserir numa tabela hashing
100
Os nomes de variáveis são inseridos nas transições do não terminal ListId
101
O diagrama de ListId é chamado:
No diagrama de DeclTip, na região das declarações No diagrama de CmdRead, na região dos comandos Diagrama de CmdRead Diagrama de DeclTip
102
A inserção deve ocorrer na região das declarações e não na dos comandos
aqui sim aqui não Diagrama de CmdRead Diagrama de DeclTip
103
Pode-se usar uma variável-flag de nome declarando (global):
Na região de declarações: declarando = VERDADE; Nas outras regiões: declarando = FALSO; Em ListId , só se deve inserir quando declarando == VERDADE No início da função ExecProg (início da análise sintática): void ExecProg () { int estado = 1; while (estado != 8) switch (estado) { case 1:
104
No diagrama de Decls : No início, declarando = VERDADE; No final, declarando = FALSO;
105
No diagrama de ListId , tratamento distinto para
declarando == VERDADE declarando == FALSO
107
ProcuraSimb (atom . atrib . cadeia):
Procura na tabela de símbolos a célula que guarda o atributo cadeia do átomo recém-formado
108
ProcuraSimb (atom . atrib . cadeia):
Quando encontra, retorna um ponteiro para a célula procurada; quando não, retorna NULL Sua programação consiste em procurar numa tabela hashing
109
ProcuraSimb (atom . atrib . cadeia):
Nas declarações, em caso positivo, é uma dupla declaração No comando READ, em caso negativo, é identificador usado mas não declarado
110
Nas declarações, o tipo da variável só aparece mais adiante, fora do diagrama de ListId
Podem ser várias variáveis inseridas sem o tipo
111
Solução: colocar os símbolos de uma declaração numa lista linear de símbolos (lista de ponteiros para células - global) Mais adiante, quando aparecer o tipo na declaração, percorre-se essa lista, adicionando-o em cada célula
112
Exemplo: i, fat, n: INTEGER;
listsimb: variável global
113
Para adicionar, nas células das variáveis declaradas, a informação sobre o tipo:
No diagrama de DeclTip : A lista global de símbolos é anulada e inicializada vazia, antes da chamada do diagrama de ListId Depois da chamada do diagrama de Tip , adiciona-se o tipo às referidas células, usando o valor de outra variável global: tipocorrente
114
Para adicionar, nas células das variáveis declaradas, a informação sobre o tipo:
E no diagrama de Tip :
115
AdicTipoVar adiciona, em cada símbolo da lista linear, a informação contida na variável global tipocorrente i, fat, n: INTEGER;
116
No comando READ, a célula com o nome da variável é marcada como inicializada e referenciada
117
No diagrama de CmdAtrib:
Se encontrado na tabela de símbolos, o identificador do lado esquerdo deve ser marcado como inicializado e como referenciado Se não encontrado, é identificador usado mas não declarado
118
No diagrama de Fat : Se encontrado na tabela de símbolos, o identificador deve ser marcado como referenciado Se não encontrado, é identificador usado mas não declarado
120
3.6 – Testes Semânticos em Diagramas de Transições
3.6.1 – Especificações semânticas do Mini-Pascal Qualquer identificador de variável usado nos comandos do programa deve estar declarado Nenhum identificador pode ser declarado mais de uma vez no programa Toda variável deve ser inicializada e referenciada no programa O nome do programa não pode ser usado como variável
121
Especificações relacionadas com expressões:
Num comando de atribuição, a expressão e a variável que recebe seu valor devem ser do mesmo tipo Os operadores +, -, ~, *, / e os relacionais <, <=, >, >= só admitem operandos inteiros Os operandos dos operadores = e <> devem ser de mesmo tipo Os operadores AND, OR e NOT só admitem operandos booleanos As expressões nos cabeçalhos dos comandos IF e WHILE devem ser booleanas
122
3.6.2 – Detecção de identificadores de variáveis não-declaradas
Ao ser usado num comando, um identificador deve estar na tabela de símbolos O tipo do identificador deve ser IDVAR Um identificador é usado em: Comandos READ Lado esquerdo de comandos de atribuição Fatores de expressões
123
a) Detecção em Comandos READ: no diagrama do ListId
124
b) Detecção no lado esquerdo de um comando de atribuição:
125
c) Detecção no fator de uma expressão :
126
3.6.3 – Detecção de dupla declaração de identificadores
No diagrama de ListId , ao ser declarado, um identificador não deve estar na tabela de símbolos
127
3.6.4 – Detecção de identificadores não referenciados e não inicializados
Percorrer todas as classes de TabSimb Visitar célula por célula em cada classe Reportar aquelas marcadas como não referenciadas e/ou não inicializadas TabSimb
128
3.6.5 – Determinação do tipo das expressões
Os testes semânticos relacionados com expressões requerem a determinação do tipo de expressões e sub-expressões: Os operadores +, -, ~, *, / e os relacionais <, <=, >, >= só admitem operandos inteiros Os operandos dos operadores =, <> devem ser de mesmo tipo Os operadores AND, OR e NOT só admitem operandos booleanos Num comando de atribuição, a expressão e a variável que recebe seu valor devem ser do mesmo tipo As expressões nos cabeçalhos dos comandos IF e WHILE devem ser booleanas
129
Sejam as seguintes produções contendo operadores do Mini-Pascal:
Expr ExprSimpl ( OPREL ExprSimpl )? ExprSimpl Term ( OPAD Term )* Term Fat ( OPMULT Fat )* Fat OPNEG Fat Cada OPREL é cercado por duas ExprSimpl’s Cada OPAD é cercado por dois Term’s Cada OPMULT é cercado por dois Fat’s Cada OPNEG é seguido por um Fat Esses não-terminais representam os operandos de tais operadores
130
Expr ExprSimpl ( OPREL ExprSimpl )?
ExprSimpl Term ( OPAD Term )* Term Fat ( OPMULT Fat )* Fat OPNEG Fat Os tipos dos operandos devem obedecer às especificações de compatibilidade com tais operadores Idéia: a execução dos diagramas de Expr, ExprSimpl, Term e Fat pode retornar o tipo da sub-expressão que representam
131
ret: variável de retorno
Idéia: a execução dos diagramas de Expr, ExprSimpl, Term e Fat pode retornar o tipo da sub-expressão que representam int ExecExpr () { int ret; return ret; } int ExecExprSimpl () { int ret; return ret; } int ExecTerm () { int ret; return ret; } int ExecFat () { int ret; return ret; } ret: variável de retorno Deve guardar o tipo do não-terminal do diagrama executado O valor de ret deve ser calculado durante a execução do diagrama
132
Diagrama de Fat (função ExecFat):
Seja cada um dos caminhos que levam, sem erros, ao estado 81
133
Na produção Fat ID: O tipo de Fat é o tipo da variável representada por ID
134
Nas produções Fat CTE | TRUE | FALSE
O tipos de Fat são respectivamente inteiro, booleano e booleano: FALSE
135
Na produção Fat ( Expr ):
O tipo de Fat é o tipo de Expr a ser apresentado adiante
136
Produção Fat OPNEG Fat :
O tipo de Fat do lado esquerdo deve ser o tipo admitido pelo atributo de OPNEG O atributo de OPNEG pode ser: NOT, que só admite operando booleano NEG, que só admite operando inteiro É necessário um teste de compatibilidade entre o atributo de OPNEG e o tipo de Fat do lado direito
137
Produção Fat OPNEG Fat :
Da análise sintática oper: variável local inteira, para guardar o atributo de um operador Em caso de erro, retorna-se o tipo admitido pelo atributo de OPNEG
138
Diagrama de Term: Term Fat ( OPMULT Fat )*
Ao transitar de 75 para 76 pela primeira vez, não há teste de compatibilidade Ao voltar de 76 para 75, deve haver teste entre o OPMULT e o Fat anterior Ao transitar de 75 para 76 depois da primeira vez, deve haver teste entre o Fat e o OPMULT anterior Função ExecTerm
139
oper = 0, no início de ExecTerm
Diagrama de Term: Term Fat ( OPMULT Fat )* Para não haver teste de compatibilidade, ao passar pela primeira vez: oper = 0, no início de ExecTerm
140
Diagrama de Term: Term Fat ( OPMULT Fat )*
O valor de ret veio de Fat na última transição de 75 para 76
141
ExprSimpl Term ( OPAD Term )*
Diagrama de ExprSimpl : ExprSimpl Term ( OPAD Term )* Estratégia análoga ao diagrama de Term
142
ExprSimpl Term ( OPAD Term )*
Diagrama de ExprSimpl : ExprSimpl Term ( OPAD Term )* oper = 0, no início de ExecExprSimpl
143
ExprSimpl Term ( OPAD Term )*
Diagrama de ExprSimpl : ExprSimpl Term ( OPAD Term )*
144
Expr ExprSimpl ( OPREL ExprSimpl )?
Diagrama de Expr: Expr ExprSimpl ( OPREL ExprSimpl )? Ao transitar de 68 para 69 não há teste de compatibilidade Ao transitar de 69 para 70, deve haver teste entre o OPREL e o ExprSimpl anterior Ao transitar de 70 para 71, deve haver teste entre o novo ExprSimpl e o OPREL anterior
145
Expr ExprSimpl ( OPREL ExprSimpl )?
Diagrama de Expr: Expr ExprSimpl ( OPREL ExprSimpl )?
146
Expr ExprSimpl ( OPREL ExprSimpl )?
Diagrama de Expr: Expr ExprSimpl ( OPREL ExprSimpl )?
147
Expr ExprSimpl ( OPREL ExprSimpl )?
Diagrama de Expr: Expr ExprSimpl ( OPREL ExprSimpl )? O tipo de uma expressão relacional é booleano
148
CmdAtrib ID ATRIB Expr
Diagrama de CmdAtrib: CmdAtrib ID ATRIB Expr O tipo de Expr deve ser o mesmo da variável correspondente ao ID
149
CmdAtrib ID ATRIB Expr
Diagrama de CmdAtrib: CmdAtrib ID ATRIB Expr tvar: variável local destinada a guardar o tipo da variável
150
CmdAtrib ID ATRIB Expr
Diagrama de CmdAtrib: CmdAtrib ID ATRIB Expr texpr: variável local destinada a guardar o tipo da expressão
151
CmdIf IF Expr THEN Cmd Diagrama de CmdIf:
| IF Expr THEN Cmd ELSE Cmd O tipo de Expr deve booleano
152
CmdIf IF Expr THEN Cmd Diagrama de CmdIf:
| IF Expr THEN Cmd ELSE Cmd
153
CmdWhile WHILE Expr DO Cmd
Diagrama de CmdWhile: CmdWhile WHILE Expr DO Cmd O tipo de Expr deve booleano
154
CmdWhile WHILE Expr DO Cmd
Diagrama de CmdWhile: CmdWhile WHILE Expr DO Cmd
155
3.7 – Geração de Código Intermediário
Supor que serão utilizadas quádruplas A geração das quádruplas deve estar contida nas ações dos diagramas de transições sintáticas Exemplo: Código intermediário não otimizado para o programa fatorial:
156
openmod: aloca memória para as variáveis locais e parâmetros de um módulo
A estrutura de dados para essas quádruplas será vista em capítulo específico. O código intermediário deve ser otimizado e traduzido para Assembly
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.