CES41 COMPILADORES Aulas Prticas 2016 Captulo V Interpretao

  • Slides: 54
Download presentation
CES-41 COMPILADORES Aulas Práticas - 2016 Capítulo V Interpretação do Código Intermediário

CES-41 COMPILADORES Aulas Práticas - 2016 Capítulo V Interpretação do Código Intermediário

Código intermediário para linguagens sem subprogramas: Interpretação: Colocar um ponteiro na 1ª quádrupla executável

Código intermediário para linguagens sem subprogramas: Interpretação: Colocar um ponteiro na 1ª quádrupla executável Executar cada quádrupla, sequencialmente, até encontrar aquela de operador OPEXIT As quádruplas de desvio alteram a sequência quad

Local para valores das variáveis (temporárias ou não): n Na tabela de símbolos: Poderia

Local para valores das variáveis (temporárias ou não): n Na tabela de símbolos: Poderia ser usada union dims cadeia tid tvar inic ref array ndims n ----------vallogic valint valfloat valchar Deve-se acrescentar os seguintes campos em int *valint; celsimb : float *valfloat; Espaço para estes char *valchar, *vallogic; ponteiros serão alocados na execução da quádrupla OPENMOD

Exemplo: sejam as declarações int x; float y; int A[4][3]; Alocações na execução de

Exemplo: sejam as declarações int x; float y; int A[4][3]; Alocações na execução de float B[5]; OPENMOD dims cadeia tid tvar inic ref array ndims x ? v i n -----------------vallogic valint valfloat valchar ? ? dims cadeia tid tvar inic ref array ndims y ? v r n v i s ? 2 dims ---------vallogic valint valfloat # 4 3 valchar ? ? cadeia tid tvar inic ref array ndims B ? valchar ? cadeia tid tvar inic ref array ndims A ? valfloat v r ? s dims 1 # 5 ---------vallogic valint valfloat ? valchar

Programa 5. 1: Esqueleto do interpretador para a gramática das aulas de lab n

Programa 5. 1: Esqueleto do interpretador para a gramática das aulas de lab n Arquivos: pret 012016. y, pret 012016. l e pret 012016. dat n A seguir, o estado inicial da função principal do interpretador, no final do arquivo pret 012016. y - A ser completada durante a aula e durante a execução do projeto

void Interp. Cod. Intermed () { quadrupla quad, quadprox; char encerra; printf ("nn. INTERPRETADOR:

void Interp. Cod. Intermed () { quadrupla quad, quadprox; char encerra; printf ("nn. INTERPRETADOR: n"); encerra = FALSO; quad = codintermed->prox->listquad->prox; while (! encerra) { printf ("n%4 d) %s", quad->num, nomeoperquad[quad->oper]); quadprox = quad->prox; switch (quad->oper) { case OPEXIT: encerra = VERDADE; break; } if (! encerra) quad = quadprox; } printf ("n"); } quad

n Definição do operador de quádrupla OPEXIT: #define n OPEXIT 24 Para guardar valores

n Definição do operador de quádrupla OPEXIT: #define n OPEXIT 24 Para guardar valores das variáveis, cada célula da tabela de símbolos terá os seguintes campos: int *valint; float *valfloat; Espaço para estes ponteiros char *valchar, *vallogic; serão alocados na execução da quádrupla OPENMOD

n Protótipos de algumas funções para o interpretador (outras deverão ser construídas na elaboração

n Protótipos de algumas funções para o interpretador (outras deverão ser construídas na elaboração do projeto): void Interp. Cod. Intermed (void); void Aloca. Variaveis (void); void Exec. Quad. Write (quadrupla); void Exec. Quad. Mais (quadrupla); void Exec. Quad. LT (quadrupla); void Exec. Quad. Atrib (quadrupla); void Exec. Quad. Read (quadrupla);

n Na produção do não-terminal Programa: Programa : {- - -} ID ABCHAVE {-

n Na produção do não-terminal Programa: Programa : {- - -} ID ABCHAVE {- - -} Decl. Locs Cmds FCHAVE { printf ("}n"); Gera. Quadrupla (OPEXIT, opndidle, opndidle); Verifica. Inic. Ref (); Imprime. Tab. Simb (); Imprime. Quadruplas (); Interp. Cod. Intermed (); } ; n Rodar flex, yacc, gcc e executável n A seguir, o arquivo de dados

teste { locais: int a, b, c, i, j; real k; logico b 1;

teste { locais: int a, b, c, i, j; real k; logico b 1; int A[5][4]; comandos: escrever ("Valor 1: ", 14, "; Valor 2: ", 15. 2, "; Valor 3: ", verdade); escrever ("Valor de 3+4: ", 3+4); a : = 1; b : = 2; i : = 3; j : = 4; c : = a + b + i + j + 20; k : = 12. 6; b 1 : = verdade; escrever ("c = ", c, "; k = ", k, "; b 1 = ", b 1, "; ");

i : = 4; j : = 5; b 1 : = verdade; se

i : = 4; j : = 5; b 1 : = verdade; se (b 1) {i : = j + 6; } senao {i : = i + 15; } escrever ("i = ", i); i : = 4; j : = 5; b 1 : = verdade; enquanto (b 1) {i : = i + j; b 1 : = falso; } escrever ("i = ", i); i : = 3; k : = 20. 3; escrever ("i = ", i, "; k = ", k); /* enquanto (i < k) { i : = i + 4; escrever ("i = ", i, "; k = ", k); } */ escrever ("Valor de i+k: ", i+k); }

Exercício 5. 1: Execução da quádrupla OPENMOD n No switch da função Interp. Cod.

Exercício 5. 1: Execução da quádrupla OPENMOD n No switch da função Interp. Cod. Intermed: case OPENMOD: Aloca. Variaveis (); break; n Função Aloca. Variáveis (já tem protótipo): - Percorre todas as classes da Tab. Simb - Para cada classe, visita todas as células - Para cada célula de tipo IDVAR, aloca espaço para o valor da variável correspondente - É preciso examinar o tipo e a dimensão da variável

Exemplo: sejam as declarações int x; float A[5][4]; dims ---------vallogic cadeia tid tvar inic

Exemplo: sejam as declarações int x; float A[5][4]; dims ---------vallogic cadeia tid tvar inic ref array ndims x ? v i n valint valfloat valchar ? ? Apenas um elemento inteiro alocado para x dims cadeia tid tvar inic ref array ndims A ? v r s 2 ---------vallogic # 5 4 ? 5*4 = 20 elementos reais alocados para A valint valfloat ? valchar

void Aloca. Variaveis () { nelemaloc: número de simbolo s; int nelemaloc, i, j;

void Aloca. Variaveis () { nelemaloc: número de simbolo s; int nelemaloc, i, j; elementos alocados para printf ("ntt. Alocando as variaveis: "); cada variável for (i = 0; i < NCLASSHASH; i++) if (tabsimb[i]) { for (s = tabsimb[i]; s != NULL; s = s->prox){ if (s->tid == IDVAR) { Executar e verificar a alocação das nelemaloc = 1; variáveis na execução de OPENMOD if (s->array) for (j = 1; j <= s->ndims; j++) nelemaloc *= s->dims[j]; switch (s->tvar) { case INTEGER: s->valint = malloc ( nelemaloc * sizeof (int)); break; case FLOAT: s->valfloat = malloc ( nelemaloc * sizeof (float)); break; case CHAR: s->valchar = malloc ( nelemaloc * sizeof (char)); break; case LOGIC: s->vallogic = malloc ( nelemaloc * sizeof (char)); break; } s printf ("nttt%s: %d elemento(s) alocado(s) ", s->cadeia, nelemaloc); } dims } cadeia ----- ndims ---------valint valfloat valchar } vallogic x ------? ? } ?

Exercício 5. 2: Execução da quádrupla PARAM Exemplo: seja o comando escrever ("Valor de

Exercício 5. 2: Execução da quádrupla PARAM Exemplo: seja o comando escrever ("Valor de a+b: ", a+b, "Valor de c: ", c); n Suas quádruplas: 1) PARAM, (CADEIA, Valor de a+b: ), (IDLE) 2) MAIS, (VAR, a), (VAR, b), (VAR, ##1) 3) PARAM, (VAR, ##1), (IDLE) 4) PARAM, (CADEIA, Valor de c: ), (IDLE) 5) PARAM, (VAR, c), (IDLE) 6) WRITE, (INT, 4), (IDLE)

1) PARAM, (CADEIA, Valor de a+b: ), (IDLE) 2) MAIS, (VAR, a), (VAR, b),

1) PARAM, (CADEIA, Valor de a+b: ), (IDLE) 2) MAIS, (VAR, a), (VAR, b), (VAR, ##1) 3) PARAM, (VAR, ##1), (IDLE) 4) PARAM, (CADEIA, Valor de c: ), (IDLE) 5) PARAM, (VAR, c), (IDLE) 6) WRITE, (INT, 4), (IDLE) VAR, c CADEIA, Valor de c: VAR, ##1 CADEIA, Valor de a+b: pilhaoperando (global) pilhaopndaux Preenchida pelas 4 quádruplas PARAM A ser preenchida pela quádrupla WRITE

Execução da quádrupla: OPWRITE, (INT, 4), (IDLE) 1) Desempilhar 4 operandos de pilhaoperando, empilhando-os

Execução da quádrupla: OPWRITE, (INT, 4), (IDLE) 1) Desempilhar 4 operandos de pilhaoperando, empilhando-os em pilhaopndaux VAR, c CADEIA, Valor de c: VAR, ##1 CADEIA, Valor de a+b: pilhaoperando (global) pilhaopndaux Preenchida pelas 4 quádruplas PARAM A ser preenchida pela quádrupla WRITE

Execução da quádrupla: OPWRITE, (INT, 4), (IDLE) 2) Desempilhar 4 operandos de pilhaopndaux, imprimindo

Execução da quádrupla: OPWRITE, (INT, 4), (IDLE) 2) Desempilhar 4 operandos de pilhaopndaux, imprimindo seus atributos CADEIA, Valor de a+b: VAR, ##1 CADEIA, Valor de c: VAR, c pilhaoperando (global) pilhaopndaux Esvaziada pela quádrupla WRITE Preenchida pela quádrupla WRITE

n Declarações para pilhas de operandos (já no arquivo pret 012016. y): typedef struct

n Declarações para pilhas de operandos (já no arquivo pret 012016. y): typedef struct nohopnd; struct nohopnd { operando opnd; nohopnd *prox; }; typedef nohopnd *pilhaoperando; pilhaoperando pilhaopnd;

n Funções para manipular pilhas de operandos (já têm protótipos): void Empilhar. Opnd (operando

n Funções para manipular pilhas de operandos (já têm protótipos): void Empilhar. Opnd (operando x, pilhaoperando *P) { nohopnd *temp; temp = *P; *P = (nohopnd *) malloc (sizeof (nohopnd)); (*P)->opnd = x; (*P)->prox = temp; } void Desempilhar. Opnd (pilhaoperando *P) { nohopnd *temp; if (! Vazia. Opnd (*P)) { temp = *P; *P = (*P)->prox; free (temp); } else printf ("nt. Delecao em pilha vazian"); }

operando Topo. Opnd (pilhaoperando P) { if (! Vazia. Opnd (P)) return P->opnd; else

operando Topo. Opnd (pilhaoperando P) { if (! Vazia. Opnd (P)) return P->opnd; else printf ("nt. Topo de pilha vazian"); } void Inic. Pilha. Opnd (pilhaoperando *P) { *P = NULL; } char Vazia. Opnd (pilhaoperando P) { if (P == NULL) return 1; else return 0; }

Programação para executar quádruplas PARAM n No início da função Interp. Cod. Intermed: printf

Programação para executar quádruplas PARAM n No início da função Interp. Cod. Intermed: printf ("nn. INTERPRETADOR: n"); Inic. Pilha. Opnd (&pilhaopnd); encerra = FALSE; quad = codintermed->listquad->prox; n No switch da função Interp. Cod. Intermed: case PARAM: Empilhar. Opnd (quad->opnd 1, &pilhaopnd); break;

Exercício 5. 3: Execução da quádrupla OPWRITE n Exemplo: WRITE, (INT, 4), (IDLE) n

Exercício 5. 3: Execução da quádrupla OPWRITE n Exemplo: WRITE, (INT, 4), (IDLE) n A execução compreende os passos: - Inicializar a pilha auxiliar de operandos Transportar os operandos da pilha oficial para a auxiliar Desempilhar cada operando da pilha auxiliar, imprimindo seu atributo

Escrita dos valores dos operandos: n O problema é encontrar o paradeiro do valor

Escrita dos valores dos operandos: n O problema é encontrar o paradeiro do valor a ser escrito n Depende do tipo do operando, que pode ser: - Uma variável Uma constante inteira, real, caractere, lógica ou cadeia de caracteres

n Se for uma variável, ela pode ser inteira, real, caractere ou lógica: -

n Se for uma variável, ela pode ser inteira, real, caractere ou lógica: - O valor do operando fica então guardado na Tab. Simb dims cadeia tid tvar inic ref array ndims x ? v i n valint valfloat valchar ? ? cadeia tid tvar inic ref array ndims A ? ---------vallogic v r ? s 3 dims ----------vallogic # 5 4 valint valfloat ? valchar

Programação para executar quádruplas OPWRITE: n No switch da função Interp. Cod. Intermed: case

Programação para executar quádruplas OPWRITE: n No switch da função Interp. Cod. Intermed: case OPWRITE: Exec. Quad. Write (quad); break; n Função Exec. Quad. Write (já tem protótipo): void Exec. Quad. Write (quadrupla quad) { int i; operando opndaux; pilhaoperando pilhaopndaux; printf ("ntt. Escrevendo: nn"); Inic. Pilha. Opnd (&pilhaopndaux); for (i = 1; i <= quad->opnd 1. atr. valint; i++) { Empilhar. Opnd (Topo. Opnd (pilhaopnd), &pilhaopndaux); Desempilhar. Opnd (&pilhaopnd); }

for (i = 1; i <= quad->opnd 1. atr. valint; i++) { opndaux =

for (i = 1; i <= quad->opnd 1. atr. valint; i++) { opndaux = Topo. Opnd (pilhaopndaux); Desempilhar. Opnd (&pilhaopndaux); switch (opndaux. tipo) { case INTOPND: printf ("%d", opndaux. atr. valint); break; case REALOPND: printf ("%g", opndaux. atr. valfloat); break; case CHAROPND: printf ("%c", opndaux. atr. valchar); break; case LOGICOPND: if (opndaux. atr. vallogic == 1) printf ("VERDADE"); else printf ("FALSO"); break; case CADOPND: printf ("%s", opndaux. atr. valcad); break ;

case VAROPND: switch (opndaux. atr. simb->tvar) { case INTEGER: printf ("%d", *(opndaux. atr. simb>valint));

case VAROPND: switch (opndaux. atr. simb->tvar) { case INTEGER: printf ("%d", *(opndaux. atr. simb>valint)); break; case FLOAT: printf ("%g", *(opndaux. atr. simb>valfloat)); break; case LOGIC: if (*(opndaux. atr. simb->vallogic) == 1) printf ("VERDADE"); dims else printf ("FALSO"); break; cadeia tid tvar inic ref array ---------valint valfloat valchar ndims vallogic case CHAR: x v i n ? printf ("%c", ? ? *(opndaux. atr. simb->valchar)); break; } Executar observando os valores escritos pelas quádruplas OPWRITE } printf ("n");

Exercício 5. 4: Execução da quádrupla OPMAIS n Exemplo: MAIS, (VAR, a), (REAL, 12.

Exercício 5. 4: Execução da quádrupla OPMAIS n Exemplo: MAIS, (VAR, a), (REAL, 12. 5), (VAR, ##1) n O problema agora é encontrar o paradeiro dos elementos a serem somados e onde guardar o resultado da soma n Tudo depende do tipo do operando e da temporária que vai receber o resultado, que podem ser: - Uma variável Uma constante inteira, real, caractere

Programação para executar quádruplas OPMAIS: n No switch da função Interp. Cod. Intermed: case

Programação para executar quádruplas OPMAIS: n No switch da função Interp. Cod. Intermed: case OPMAIS: Exec. Quad. Mais (quad); break; n Função Exec. Quad. Mais (já tem protótipo): void Exec. Quad. Mais (quadrupla quad) { int tipo 1, tipo 2, valint 1, valint 2; float valfloat 1, valfloat 2; Guardam os tipos dos valores a serem somados Guardam os valores a serem somados, conforme os tipos

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 =

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 = quad->opnd 1. atr. valint; break; case REALOPND: tipo 1 = REALOPND; valfloat 1 = quad->opnd 1. atr. valfloat; break; case CHAROPND: tipo 1 = INTOPND; valint 1 = quad->opnd 1. atr. valchar; break; case VAROPND: switch (quad->opnd 1. atr. simb->tvar) { case INTEGER: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case FLOAT: tipo 1 = REALOPND; valfloat 1=*(quad->opnd 1. atr. simb>valfloat); break; case CHAR: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valchar); break;

switch (quad->opnd 2. tipo) { case INTOPND: tipo 2 = INTOPND; valint 2 =

switch (quad->opnd 2. tipo) { case INTOPND: tipo 2 = INTOPND; valint 2 = quad->opnd 2. atr. valint; break; case REALOPND: tipo 2 = REALOPND; valfloat 2 = quad->opnd 2. atr. valfloat; break; case CHAROPND: tipo 2 = INTOPND; valint 2 = quad->opnd 2. atr. valchar; break; case VAROPND: switch (quad->opnd 2. atr. simb->tvar) { case INTEGER: tipo 2 = INTOPND; valint 2 = *(quad->opnd 2. atr. simb->valint); break; case FLOAT: tipo 2 = REALOPND; valfloat 2=*(quad->opnd 2. atr. simb>valfloat); break; case CHAR: tipo 2 = INTOPND; valint 2=*(quad->opnd 2. atr. simb>valchar); break;

switch (quad->result. atr. simb->tvar) { case INTEGER: *(quad->result. atr. simb->valint) = valint 1 +

switch (quad->result. atr. simb->tvar) { case INTEGER: *(quad->result. atr. simb->valint) = valint 1 + valint 2; break; case FLOAT: if (tipo 1 == INTOPND && tipo 2 == INTOPND) *(quad->result. atr. simb->valfloat) = valint 1 + valint 2; if (tipo 1 == INTOPND && tipo 2 == REALOPND) *(quad->result. atr. simb->valfloat) = valint 1 + valfloat 2; if (tipo 1 == REALOPND && tipo 2 == INTOPND) *(quad->result. atr. simb->valfloat) = valfloat 1 + valint 2; if (tipo 1 == REALOPND && tipo 2 == REALOPND) *(quad->result. atr. simb->valfloat) = valfloat 1 + valfloat 2; break; } Executar observando os valores } escritos de resultados de somas

Exercício 5. 5: Execução da quádrupla OPATRIB n Exemplo: seja a atribuição: b 1

Exercício 5. 5: Execução da quádrupla OPATRIB n Exemplo: seja a atribuição: b 1 : = (i+3 >= j-2) && b 2 Suas quádruplas podem ser: MAIS, (VAR, i), (INT, 3), (VAR, ##1) MENOS, (VAR, j), (INT, 2), (VAR, ##2) GE, (VAR, ##1), (VAR, ##2), (VAR, ##3) AND, (VAR, ##3), (VAR, b 2), (VAR, ##4) ATRIB, (VAR, ##4), (IDLE), (VAR, b 1) n O problema agora é encontrar o paradeiro do valor a ser atribuído e onde guardá-lo n Tudo depende dos tipos dos operandos envolvidos

Programação para executar quádruplas OPATRIB: n No switch da função Interp. Cod. Intermed: case

Programação para executar quádruplas OPATRIB: n No switch da função Interp. Cod. Intermed: case OPATRIB: Exec. Quad. Atrib (quad); break; n Função Exec. Quad. Atrib (já tem protótipo): void Exec. Quad. Atrib (quadrupla quad) { int tipo 1, valint 1; float valfloat 1; char valchar 1, vallogic 1; Guarda o tipo do valor a ser atribuído Guardam os valores a serem atribuídos, conforme os tipos

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 =

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 = quad->opnd 1. atr. valint; break; case REALOPND: tipo 1 = REALOPND; valfloat 1 = quad->opnd 1. atr. valfloat; break; case CHAROPND: tipo 1 = CHAROPND; valchar 1 = quad->opnd 1. atr. valchar; break; case LOGICOPND: tipo 1 = LOGICOPND; vallogic 1 = quad->opnd 1. atr. vallogic; break;

case VAROPND: switch (quad->opnd 1. atr. simb->tvar) { case INTEGER: tipo 1 = INTOPND;

case VAROPND: switch (quad->opnd 1. atr. simb->tvar) { case INTEGER: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case FLOAT: tipo 1 = REALOPND; valfloat 1=*(quad->opnd 1. atr. simb>valfloat); break; case CHAR: tipo 1 = CHAROPND; valchar 1=*(quad->opnd 1. atr. simb>valchar); break; case LOGIC: tipo 1 = LOGICOPND; vallogic 1 = *(quad->opnd 1. atr. simb->vallogic); break; }

switch (quad->result. atr. simb->tvar) { case INTEGER: if (tipo 1 == INTOPND) *(quad->result. atr.

switch (quad->result. atr. simb->tvar) { case INTEGER: if (tipo 1 == INTOPND) *(quad->result. atr. simb->valint) = valint 1; if (tipo 1 == CHAROPND)*(quad->result. atr. simb>valint)=valchar 1; break; case CHAR: if (tipo 1 == INTOPND) *(quad->result. atr. simb->valchar) = valint 1; if (tipo 1==CHAROPND)*(quad->result. atr. simb>valchar)=valchar 1; break; case LOGIC: *(quad->result. atr. simb->vallogic) = vallogic 1; break; case FLOAT: if (tipo 1 == INTOPND) *(quad->result. atr. simb->valfloat) = valint 1; if (tipo 1 == REALOPND) *(quad->result. atr. simb->valfloat) = valfloat 1; Executar observando os valores das if (tipo 1 == CHAROPND) variáveis que recebem atribuição *(quad->result. atr. simb->valfloat) = valchar 1;

Exercício 5. 6: Execução das quádruplas OPJUMP e OPJF n Exemplo: seja o comando

Exercício 5. 6: Execução das quádruplas OPJUMP e OPJF n Exemplo: seja o comando enquanto (i < j) i : = j + h; Suas quádruplas: 2) NOP, (IDLE), (IDLE) 3) LT, (VAR, i), (VAR, j), (VAR, ##1) 4) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 5) MAIS, (VAR, j), (VAR, h), (VAR, ##2) 6) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 7) JUMP, (IDLE), (ROTULO, 2) 8) NOP, (IDLE), (IDLE)

n Nova declaração na função Interp. Cod. Intermed: char condicao; n No switch da

n Nova declaração na função Interp. Cod. Intermed: char condicao; n No switch da função Interp. Cod. Intermed: case OPJUMP: quadprox = quad->result. atr. rotulo; break; case OPJF: if (quad->opnd 1. tipo == LOGICOPND) condicao = quad->opnd 1. atr. vallogic; if (quad->opnd 1. tipo == VAROPND) condicao = *(quad->opnd 1. atr. simb->vallogic); if (! condicao) quadprox = quad->result. atr. rotulo; break; Executar observando os desvios efetuados pelos comandos if-else e while

Exercício 5. 7: Execução da quádrupla OPLT n No switch da função Interp. Cod.

Exercício 5. 7: Execução da quádrupla OPLT n No switch da função Interp. Cod. Intermed: case OPLT: Exec. Quad. LT (quad); break; n Função Exec. Quad. LT (já tem protótipo): void Exec. Quad. LT (quadrupla quad) { int tipo 1, tipo 2, valint 1, valint 2; float valfloat 1, valfloat 2;

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 =

switch (quad->opnd 1. tipo) { case INTOPND: tipo 1 = INTOPND; valint 1 = quad->opnd 1. atr. valint; break; case REALOPND: tipo 1 = REALOPND; valfloat 1=quad>opnd 1. atr. valfloat; break; case CHAROPND: tipo 1 = INTOPND; valint 1 = quad->opnd 1. atr. valchar; break; case VAROPND: switch (quad->opnd 1. atr. simb->tvar) { case INTEGER: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case FLOAT: tipo 1 = REALOPND; valfloat 1 = *(quad->opnd 1. atr. simb>valfloat); break; case CHAR: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valchar); break; }

switch (quad->opnd 2. tipo) { case INTOPND: tipo 2 = INTOPND; valint 2 =

switch (quad->opnd 2. tipo) { case INTOPND: tipo 2 = INTOPND; valint 2 = quad->opnd 2. atr. valint; break; case REALOPND: tipo 2=REALOPND; valfloat 2 = quad>opnd 2. atr. valfloat; break; case CHAROPND: tipo 2 = INTOPND; valint 2 = quad->opnd 2. atr. valchar; break; case VAROPND: switch (quad->opnd 2. atr. simb->tvar) { case INTEGER: tipo 2 = INTOPND; valint 2 = *(quad->opnd 2. atr. simb->valint); break; case FLOAT: tipo 2 = REALOPND; valfloat 2 = *(quad->opnd 2. atr. simb>valfloat); break; case CHAR: tipo 2 = INTOPND; valint 2 = *(quad->opnd 2. atr. simb->valchar); break; } break;

if (tipo 1 == INTOPND && tipo 2 == INTOPND) *(quad->result. atr. simb->vallogic) =

if (tipo 1 == INTOPND && tipo 2 == INTOPND) *(quad->result. atr. simb->vallogic) = valint 1 < valint 2; if (tipo 1 == INTOPND && tipo 2 == REALOPND) *(quad->result. atr. simb->vallogic) = valint 1 < valfloat 2; if (tipo 1 == REALOPND && tipo 2 == INTOPND) *(quad->result. atr. simb->vallogic) = valfloat 1 < valint 2; if (tipo 1 == REALOPND && tipo 2 == REALOPND) *(quad->result. atr. simb->vallogic) = valfloat 1 < valfloat 2; } n Eliminar os comentários de pret 012016. dat e rodar

Exercício 5. 8: Execução da quádrupla READ Exemplo: seja o comando ler (a, b,

Exercício 5. 8: Execução da quádrupla READ Exemplo: seja o comando ler (a, b, c); n Suas quádruplas: 1) PARAM, (VAR, a), (IDLE 2) PARAM, (VAR, b), (IDLE) 3) PARAM, (VAR, c), (IDLE) 4) READ, (INT, 3), (IDLE)

1) PARAM, (VAR, a), (IDLE 2) PARAM, (VAR, b), (IDLE) 3) PARAM, (VAR, c),

1) PARAM, (VAR, a), (IDLE 2) PARAM, (VAR, b), (IDLE) 3) PARAM, (VAR, c), (IDLE) 4) READ, (INT, 3), (IDLE)) VAR, c VAR, b VAR, a pilhaoperando (global) pilhaopndaux Preenchida pelas 3 quádruplas PARAM A ser preenchida pela quádrupla READ

Execução da quádrupla: OPREAD, (INT, 3), (IDLE) 1) Desempilhar 3 operandos de pilhaoperando, empilhando-os

Execução da quádrupla: OPREAD, (INT, 3), (IDLE) 1) Desempilhar 3 operandos de pilhaoperando, empilhando-os em pilhaopndaux VAR, c VAR, b VAR, a pilhaoperando (global) pilhaopndaux Preenchida pelas 3 quádruplas PARAM A ser preenchida pela quádrupla READ

Execução da quádrupla: OPREAD, (INT, 3), (IDLE) 2) Desempilhar 3 operandos de pilhaopndaux, lendo

Execução da quádrupla: OPREAD, (INT, 3), (IDLE) 2) Desempilhar 3 operandos de pilhaopndaux, lendo valores para seus atributos VAR, a VAR, b VAR, c pilhaoperando (global) pilhaopndaux Esvaziada pela quádrupla READ Preenchida pela quádrupla READ

Leitura dos valores dos operandos: n O problema é encontrar o local para guardar

Leitura dos valores dos operandos: n O problema é encontrar o local para guardar o valor lido n É uma variável e depende do tipo, que pode ser: - Inteiro, real, caractere ou lógico

n O valor lido deve ser guardado na Tab. Simb dims ---------vallogic cadeia tid

n O valor lido deve ser guardado na Tab. Simb dims ---------vallogic cadeia tid tvar inic ref array ndims x ? v i n valint valfloat valchar ? ? dims cadeia tid tvar inic ref array ndims A ? v r ? s 3 ----------vallogic # 5 4 valint valfloat ? valchar

Programação para executar quádruplas OPREAD: n No switch da função Interp. Cod. Intermed: case

Programação para executar quádruplas OPREAD: n No switch da função Interp. Cod. Intermed: case OPREAD: Exec. Quad. Read (quad); break; n Os dados de entrada para a execução do programa ficarão num arquivo denominado “entrada 2016” n Nova variável global: FILE *finput; n Associação com o arquivo de entrada, no início da função Interp. Cod. Intermed: finput = fopen ("entrada 2016", "r");

n Função Exec. Quad. Read (já tem protótipo): void Exec. Quad. Read (quadrupla quad)

n Função Exec. Quad. Read (já tem protótipo): void Exec. Quad. Read (quadrupla quad) { int i; operando opndaux; pilhaoperando pilhaopndaux; printf ("ntt. Lendo: n"); Inic. Pilha. Opnd (&pilhaopndaux); for (i = 1; i <= quad->opnd 1. atr. valint; i++) { Empilhar. Opnd (Topo. Opnd (pilhaopnd), &pilhaopndaux); Desempilhar. Opnd (&pilhaopnd); }

for (i = 1; i <= quad->opnd 1. atr. valint; i++) { opndaux =

for (i = 1; i <= quad->opnd 1. atr. valint; i++) { opndaux = Topo. Opnd (pilhaopndaux); Desempilhar. Opnd (&pilhaopndaux); switch (opndaux. atr. simb->tvar) { case INTEGER: fscanf (finput, "%d", opndaux. atr. simb->valint); break; case FLOAT: fscanf (finput, "%g", opndaux. atr. simb->valfloat); break; case LOGIC: fscanf (finput, "%d", opndaux. atr. simb->vallogic); break; case CHAR: fscanf (finput, "%c", opndaux. atr. simb->valchar); break; } } } Executar com o arquivo pret 022016. dat Seu conteúdo e o do arquivo entrada 2016 vem a seguir

n Arquivo pret 022016. dat: Arquivo entrada 2016: 50 43 3. 14 1 W

n Arquivo pret 022016. dat: Arquivo entrada 2016: 50 43 3. 14 1 W teste { locais: int i, j, k; real x, y; logico a, b; carac m, n; comandos: ler (i, j, x, b); escrever ("i: ", i, "; j: ", j, "; x: ", x, "; b: ", b); k : = i + j; y : = x + 3. 4; a : = i < j; escrever ("k: ", k, "; y: ", y, "; a: ", a); ler (m); n : = m + ' '; escrever ("m: ", m, "; n: ", n); }