CES41 COMPILADORES Aulas Prticas 2018 Captulo V Interpretao

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

CES-41 COMPILADORES Aulas Práticas - 2018 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 ndim 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]; dims cadeia tid

Exemplo: sejam as declarações int x; float y; int A[4, 3]; dims cadeia tid tvar inic ref array ndim x ? v i n ? v r n ? v valint ---------vallogic valint valfloat valchar ? dims cadeia tid tvar inic ref array ndim A ? -----vallogic dims cadeia tid tvar inic ref array ndim y ? float B[5]; Alocações na execução de OPENMOD i s 2 # 4 3 valfloat valchar ? ? dims cadeia tid tvar inic ref array ndim B ? v r ? s 1 # 5 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 012018. y, pret 012018. l e pret 012018. dat n A seguir, o estado inicial da função principal do interpretador, no final do arquivo pret 012018. 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; quad } if (! encerra) quad = quadprox; } printf ("n"); }

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 Prog: Prog : {- - -} ID OPTRIP {-

n Na produção do não-terminal Prog: Prog : {- - -} ID OPTRIP {- - -} Decls Stats CLTRIP { printf (- - -); 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 {{{ var { int a, b, c, i, j; float k; logic b

teste {{{ var { int a, b, c, i, j; float k; logic b 1; int A[5, 4]; } statements { write ("Valor 1: ", 14, "; Valor 2: ", 15. 2, "; Valor 3: ", true); write ("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 : = true; write ("c = ", c, "; k = ", k, "; b 1 = ", b 1, "; ");

i : = 4; j : = 5; b 1 : = true; if

i : = 4; j : = 5; b 1 : = true; if b 1 then {i : = j + 6; } else {i : = i + 15; } write ("i = ", i); i : = 4; j : = 5; b 1 : = true; while b 1 do {i : = i + j; b 1 : = false; } write ("i = ", i); i : = 3; k : = 20. 3; write ("i = ", i, "; k = ", k); /* while i < k do { i : = i + 4; write ("i = ", i, "; k = ", k); } write ("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][3][4]; dims cadeia tid tvar inic ref

Exemplo: sejam as declarações int x; float A[5][3][4]; dims cadeia tid tvar inic ref array ndim x ? v i -----vallogic n valint valfloat valchar ? ? Apenas um elemento inteiro alocado para x dims cadeia tid tvar inic ref array ndim A ? v r s 3 # 5 3 4 -----vallogic ? 5*3*4 = 60 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 INTEIRO: s->valint = malloc ( nelemaloc * sizeof (int)); break; case REAL: s->valfloat = malloc ( nelemaloc * sizeof (float)); break; case CARACTERE: s->valchar = malloc ( nelemaloc * sizeof (char)); break; case LOGICO: 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 write ("Valor de

Exercício 5. 2: Execução da quádrupla PARAM Exemplo: seja o comando write ("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 012018. y): typedef struct

n Declarações para pilhas de operandos (já no arquivo pret 012018. 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 = FALSO; 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 ("TRUE"); else printf ("FALSE"); break; case CADOPND: printf ("%s", opndaux. atr. valcad); break ;

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

case VAROPND: switch (opndaux. atr. simb->tvar) { case INTEIRO: printf ("%d", *(opndaux. atr. simb>valint)); break; case REAL: printf ("%g", *(opndaux. atr. simb>valfloat)); break; case LOGICO: if (*(opndaux. atr. simb->vallogic) == 1) printf ("TRUE"); dims else printf ("FALSE"); break; cadeia tid tvar inic ref array -----valint valfloat valchar ndims vallogic case CARACTERE: 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 INTEIRO: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case REAL: tipo 1 = REALOPND; valfloat 1=*(quad->opnd 1. atr. simb>valfloat); break; case CARACTERE: 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 INTEIRO: tipo 2 = INTOPND; valint 2 = *(quad->opnd 2. atr. simb->valint); break; case REAL: tipo 2 = REALOPND; valfloat 2=*(quad->opnd 2. atr. simb>valfloat); break; case CARACTERE: tipo 2 = INTOPND; valint 2=*(quad->opnd 2. atr. simb>valchar); break;

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

switch (quad->result. atr. simb->tvar) { case INTEIRO: *(quad->result. atr. simb->valint) = valint 1 + valint 2; break; case REAL: 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 INTEIRO: tipo 1 = INTOPND;

case VAROPND: switch (quad->opnd 1. atr. simb->tvar) { case INTEIRO: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case REAL: tipo 1 = REALOPND; valfloat 1=*(quad->opnd 1. atr. simb>valfloat); break; case CARACTERE: tipo 1 = CHAROPND; valchar 1=*(quad->opnd 1. atr. simb>valchar); break; case LOGICO: tipo 1 = LOGICOPND; vallogic 1 = *(quad->opnd 1. atr. simb->vallogic); break; }

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

switch (quad->result. atr. simb->tvar) { case INTEIRO: if (tipo 1 == INTOPND) *(quad->result. atr. simb->valint) = valint 1; if (tipo 1 == CHAROPND)*(quad->result. atr. simb>valint)=valchar 1; break; case CARACTERE: if (tipo 1 == INTOPND) *(quad->result. atr. simb->valchar) = valint 1; if (tipo 1==CHAROPND)*(quad->result. atr. simb>valchar)=valchar 1; break; case LOGICO: *(quad->result. atr. simb->vallogic) = vallogic 1; break; case REAL: 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 while i < j do 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 INTEIRO: tipo 1 = INTOPND; valint 1 = *(quad->opnd 1. atr. simb->valint); break; case REAL: tipo 1 = REALOPND; valfloat 1 = *(quad->opnd 1. atr. simb>valfloat); break; case CARACTERE: 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 INTEIRO: tipo 2 = INTOPND; valint 2 = *(quad->opnd 2. atr. simb->valint); break; case REAL: tipo 2 = REALOPND; valfloat 2 = *(quad->opnd 2. atr. simb>valfloat); break; case CARACTERE: 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 012018. dat e rodar

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

Exercício 5. 8: Execução da quádrupla READ Exemplo: seja o comando read (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 cadeia tid tvar

n O valor lido deve ser guardado na Tab. Simb dims cadeia tid tvar inic ref array ndims x ? v i ----- valint valfloat vallogic n valchar ? ? dims cadeia tid tvar inic ref array ndims A ? v r ? s ------ 2 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 2018” 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 2018", "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 INTEIRO: fscanf (finput, "%d", opndaux. atr. simb->valint); break; case REAL: fscanf (finput, "%g", opndaux. atr. simb->valfloat); break; case LOGICO: fscanf (finput, "%d", opndaux. atr. simb->vallogic); break; case CARACTERE: fscanf (finput, "%c", opndaux. atr. simb->valchar); break; } } Executar com o arquivo pret 022018. dat } Seu conteúdo e o do arquivo entrada 2018 vem a seguir

n Arquivo pret 022018. dat: Arquivo entrada 2018: teste {{{ 30 20 3. 14

n Arquivo pret 022018. dat: Arquivo entrada 2018: teste {{{ 30 20 3. 14 1 W var { int i, j, k; float x, y; logic a, b; char m, n; } statements { read (i, j, x, b); write ("i: ", i, "; j: ", j, "; x: ", x, "; b: ", b); k : = i + j; y : = x + 3. 4; a : = i < j; write ("k: ", k, "; y: ", y, "; a: ", a); read (m); n : = m + ' '; write ("m: ", m, "; n: ", n); } }}}