Carregar apresentação
A apresentação está carregando. Por favor, espere
1
CES-41 COMPILADORES Aulas Práticas - 2016
Capítulo IV Código Intermediário no Yacc
2
O sub-set da Linguagem COMP-ITA-2016, usado no final do capítulo anterior, contém:
Comandos de atribuição, compostos, entrada e saída, condicionais, enquanto, variáveis escalares e indexadas Seja essa linguagem chamada de Sub-Set2 2016 Seja o programa a seguir, escrito em Sub-Set2 2016, para encontrar números primos
3
primos { locais: logico achou; int n, div, resto, cont, num; comandos: ler (n); se (n > 0) { num := 1; cont := 0; enquanto (cont < n) { num := num + 1; div := 2; achou := falso; enquanto (achou = falso && div * div <= num) { resto := num % div; se (resto = 0) achou := verdade; senao div := div + 1; } se (achou = falso) { escrever (num); cont := cont + 1;
4
Um possível código intermediário não otimizado:
primos { locais: logico achou; int n, div, resto, cont, num; comandos: 1) OPENMOD, (MODULO, primos), (IDLE), (IDLE) ler (n); 2) PARAM, (VAR, n), (IDLE), (IDLE) 3) READ, (INT, 1), (IDLE), (IDLE)
5
4) GT, (VAR, n), (INT, 0), (VAR, ##1)
se (n > 0) { } 4) GT, (VAR, n), (INT, 0), (VAR, ##1) 5) JF, (VAR, ##1), (IDLE), (ROTULO, 42) 42) NOP, (IDLE), (IDLE), (IDLE) num := 0; cont := 0; 6) ATRIB, (INT, 0), (IDLE), (VAR, num) 7) ATRIB, (INT, 0), (IDLE), (VAR, cont) NOP: no operation Todos os desvios serão feitos para quádruplas com NOP’s Facilitam a programação Devem ser eliminadas na fase de otimização
6
enquanto (cont < n) { - - - - - } 8) NOP, (IDLE), (IDLE), (IDLE)
9) LT, (VAR, cont), (VAR, n), (VAR, ##2) 10) JF, (VAR, ##2), (IDLE), (ROTULO, 41) 40) JUMP, (IDLE), (IDLE), (ROTULO, 8) 41) NOP, (IDLE), (IDLE), (IDLE) num := num + 1; div := 2; achou := false; 11) MAIS, (VAR, num), (INT, 1), (VAR, ##3) 12) ATRIB, (VAR, ##3), (IDLE), (VAR, num) 13) ATRIB, (INT, 2), (IDLE), (VAR, div) 14) ATRIB, (LOGIC, 0), (IDLE), (VAR, achou) NOP: no operation Todos os desvios serão feitos para quádruplas com NOP’s Facilitam a programação Devem ser eliminadas na fase de otimização
7
enquanto (achou = falso && div * div <= num) {
} 15) NOP, (IDLE), (IDLE), (IDLE) 16) EQ, (VAR, achou), (LOGIC, 0), (VAR, ##4) 17) MULT, (VAR, div), (VAR, div), (VAR, ##5) 18) LE, (VAR, ##5), (VAR, num), (VAR, ##6) 19) AND, (VAR, ##4), (VAR, ##6), (VAR, ##7) 20) JF, (VAR, ##7), (IDLE), (ROTULO, 32) 31) JUMP, (IDLE), (IDLE), (ROTULO, 15) 32) NOP, (IDLE), (IDLE), (IDLE)
8
resto := num % div; se (resto = 0) achou := true; senao div := div + 1; 21) RESTO, (VAR, num), (VAR, div), (VAR, ##8) 22) ATRIB, (VAR, ##8), (IDLE), (VAR, resto) 23) EQ, (VAR, resto), (INT, 0), (VAR, ##9) 24) JF, (VAR, ##9), (IDLE), (ROTULO, 27) 25) ATRIB, (LOGIC, 1), (IDLE), (VAR, achou) 26) JUMP, (IDLE), (IDLE), (ROTULO, 30) 27) NOP, (IDLE), (IDLE), (IDLE) 28) MAIS, (VAR, div), (INT, 1), (VAR, ##10) 29) ATRIB, (VAR, ##10), (IDLE), (VAR, div) 30) NOP, (IDLE), (IDLE), (IDLE)
9
se (achou = falso) {escrever (num); cont := cont + 1;}
33) EQ, (VAR, achou), (LOGIC, 0), (VAR, ##11) 34) JF, (VAR, ##11), (IDLE), (ROTULO, 39) 35) PARAM, (VAR, num), (IDLE), (IDLE) 36) WRITE, 1, (IDLE), (IDLE) 37) MAIS, (VAR, cont), (INT, 1), (VAR, ##12) 38) ATRIB, (VAR, ##12), (IDLE), (VAR, cont) 39) NOP, (IDLE), (IDLE), (IDLE) Cada linha do código intermediário chama-se quádrupla
10
Estrutura de dados para o código intermediário de linguagens contendo subprogramas:
11
Cada lista de quádruplas fica acoplada a um mod-head
As quádruplas do módulo ##global destinam-se a: Alocar as variáveis globais Acionar a execução do módulo principal (principal) E encerrar tudo no final Cada lista de quádruplas tem um nó-lider
12
Estrutura de dados para código intermediário de linguagens sem subprogramas:
O primeiro mod-head seria dispensável Ele é usado prevendo a implementação do módulo global
13
A primeira quádrupla é uma quádrupla-líder, sem conteúdo
Esta estrutura será usada nas próximas aulas No projeto será usada a do slide anterior
14
Programa 4.1: O arquivo inter y tem um analisador semântico quase acabado para a linguagem Sub-Set2 2016 O arquivo inter l é seu analisador léxico O arquivo inter y contém ainda declarações e funções para auxiliar a construção do código intermediário Rodar esses arquivos com inter dat A seguir, uma descrição dessas declarações e funções
15
Estrutura de uma quádrupla:
typedef struct celquad celquad; typedef celquad *quadrupla; struct celquad { int num, oper; operando opnd1, opnd2, result; quadrupla prox; }; O campo num numera as quádruplas Não é necessário na compilação Foi colocado por razões didáticas Um operando tem dois campos: o tipo e o atributo celquad oper opnd1 opnd2 result prox num
16
Estrutura de um operando:
typedef struct operando operando; struct operando { int tipo; atribopnd atr; }; Os tipos dos operandos são: Operando vazio (idle) Nome de variável Constantes inteira, real, lógica e caractere Cadeia de caracteres Rótulo de quádruplas (ponteiro para quádruplas) Nome de módulo operando tipo atr (simb, valint, valfloat, valchar, vallogic, valcad, rotulo, modulo)
17
Estrutura do atributo de um operando:
typedef union atribopnd atribopnd; union atribopnd { simbolo simb; int valint; float valfloat; char valchar; char vallogic; char *valcad; quadrupla rotulo; modhead modulo; }; Tabela dos atributos conforme o tipo de operando: operando tipo atr (simb, valint, valfloat, valchar, vallogic, valcad, rotulo, modulo) Tipo Atributo Idle - Constante caractere valchar Nome de variável simb Cadeia de caracteres valcad Constante inteira valint Rótulo de quádrupla rotulo Constante real valfloat Nome de módulo modulo Constante lógica vallogic
18
Estrutura de um cabeçalho de módulo:
typedef struct celmodhead celmodhead; typedef celmodhead *modhead; struct celmodhead { simbolo modname; modhead prox; quadrupla listquad; }; modname celmodhead prox listquad
19
Variáveis globais: quadrupla quadcorrente, quadaux;
modhead codintermed, modcorrente; int oper, numquadcorrente; operando opnd1, opnd2, result, opndaux; int numtemp; const operando opndidle = {IDLEOPND, 0}; quadcorrente: ponteiro para a celquad recém-alocada codintermed: ponteiro que dá acesso a todo o código intermediário modcorrente: ponteiro para a última celmodhead alocada numtemp: usada para controlar a concessão de nomes a variáveis temporárias opndidle: constante do tipo operando para preencher operandos vazios nas quádruplas
20
Novas definições para os tipos dos identificadores:
Relembrando as definições para os tipos de variáveis: #define IDPROG 1 #define IDVAR 2 #define IDFUNC 3 #define IDGLOB 4 #define NOTVAR 0 #define INTEGER 1 #define LOGIC 2 #define FLOAT 3 #define CHAR 4
21
Definições de constantes para operadores de quádruplas:
Esta lista deverá aumentar durante o desenvolvimento do projeto #define OPOR 1 #define OPAND 2 #define OPLT 3 #define OPLE 4 #define OPGT 5 #define OPGE 6 #define OPEQ 7 #define OPNE 8 #define OPMAIS 9 #define OPMENOS 10 #define OPMULTIP 11 #define OPDIV 12 #define OPRESTO 13 #define OPMENUN 14 #define OPNOT 15 #define OPATRIB 16 #define OPENMOD 17 #define NOP 18 #define OPJUMP 19 #define OPJF 20
22
Definições de constantes para os tipos dos operandos:
#define IDLEOPND 0 #define VAROPND 1 #define INTOPND 2 #define REALOPND 3 #define CHAROPND 4 #define LOGICOPND 5 #define CADOPND 6 #define ROTOPND 7 #define MODOPND 8
23
Protótipos das funções para o código intermediário:
void InicCodIntermed (void); void InicCodIntermMod (simbolo); quadrupla GeraQuadrupla (int, operando, operando, operando); simbolo NovaTemp (int); void ImprimeQuadruplas (void); void RenumQuadruplas (quadrupla, quadrupla);
24
Função InicCodIntermed:
void InicCodIntermed () { codintermed = malloc (sizeof (celmodhead)); modcorrente = codintermed; modcorrente->listquad = NULL; modcorrente->prox = NULL; } codintermed modname prox listquad ● ● modcorrente
25
Função InicCodIntermMod (simbolo simb):
void InicCodIntermMod (simbolo simb) { modcorrente->prox = malloc (sizeof (celmodhead)); modcorrente = modcorrente->prox; modcorrente->prox = NULL; modcorrente->modname = simb; modcorrente->listquad = malloc (sizeof (celquad)); quadcorrente = modcorrente->listquad; quadcorrente->prox = NULL; numquadcorrente = 0; quadcorrente->num = numquadcorrente; } codintermed simb cadeia tid modname prox listquad modname prox listquad ● ● ● modcorrente num oper #### opnd #### opnd2 #### result #### prox ● quadcorrente
26
Função GeraQuadrupla (oper, opnd1, opnd2, result):
quadrupla GeraQuadrupla (int oper, operando opnd1, operando opnd2, operando result) { quadcorrente->prox = malloc (sizeof (celquad)); quadcorrente = quadcorrente->prox; quadcorrente->oper = oper; quadcorrente->opnd1 = opnd1; quadcorrente->opnd2 = opnd2; quadcorrente->result = result; quadcorrente->prox = NULL; numquadcorrente ++; quadcorrente->num = numquadcorrente; return quadcorrente; } num oper X opnd YYYY opnd2 ZZZZ result WWWW prox ● quadcorrente num oper opnd1 opnd2 result prox 453 R SSSS TTTT TTTT opnd2 valor retornado VVVV ● R oper SSSS opnd1 VVVV result
27
Função Novatemp (tip):
simbolo NovaTemp (int tip) { simbolo simb; int temp, i, j; char nometemp[10] = "##", s[10] = {0}; numtemp ++; temp = numtemp; for (i = 0; temp > 0; temp /= 10, i++) s[i] = temp % 10 + '0'; i --; for (j = 0; j <= i; j++) nometemp[2+i-j] = s[j]; simb = InsereSimb (nometemp, IDVAR, tip); simb->inic = simb->ref = VERDADE; simb->array = FALSO; return simb; } Gera um nome para uma nova variável temporária O nome começa com ## e termina com um número O número é a soma do último utilizado +1 O nome é inserido na TabSimb e marcado como inicializado e referenciado Retorna um ponteiro para a célula inserida na TabSimb O tipo da nova variável vem como argumento
28
Os operandos para as quádruplas que calculam o valor de expressões devem estar nos atributos dos não-terminais para a montagem de expressões Exemplo: seja a produção Termo : Termo OPMULT Fator Deve ser gerada a quádrupla com: operador correspondente ao atributo de OPMULT primeiro operando: no atributo de Termo do lado direito segundo operando: no atributo de Fator operando resultado: no atributo de Termo do lado esquerdo
29
Não-terminais para a montagem de expressões:
Expressao, ExprAux1, ExpxAux2, ExprAux3, ExprAux4, Termo, Fator Esses não-terminais já guardam seus tipos em seus atributos, para os testes de compatibilidade entre operadores e operandos: %type <tipoexpr> Expressao ExprAux1 ExpxAux2 ExprAux3 ExprAux4 Termo Fator Agora, o atributo desses não-terminais deverá ter dois campos: o tipo e o operando
30
Seja também a produção:
Fator : Variavel É conveniente também que o não-terminal Variavel carregue um operando em seu atributo, para que o operando de Fator receba esse operando Esse não-terminal já guarda em seu atributo um ponteiro para a TabSimb, para os testes de compatibilidade entre operadores e operandos: %type <simb> Variavel Agora, o atributo desse não-terminal deverá ter dois campos: o referido ponteiro e o operando
31
Novas declarações para atributos de expressões e variáveis:
typedef struct infoexpressao infoexpressao; struct infoexpressao { int tipo; operando opnd; }; typedef struct infovariavel infovariavel; struct infovariavel { simbolo simb; operando opnd; }; Novos campos para a declaração %union: %union { char cadeia[50]; int atr, valint; float valreal; char carac; infoexpressao infoexpr; infovariavel infovar; simbolo simb; int dim; int nsubscr; }
32
Novos campos para a declaração %union: %union {
char cadeia[50]; int atr, valint; float valreal; char carac; infoexpressao infoexpr; infovariavel infovar; simbolo simb; int dim; int nsubscr; } Novas especificações para os atributos dos não-terminais envolvidos: %type <infovar> Variavel %type <infoexpr> Expressao ExprAux1 ExprAux ExprAux3 ExprAux4 Termo Fator Antes era <simb> Antes era <tipoexpr>
33
Nas produções onde aparecem não-terminais envolvidos no cálculo de expressões foi trocado $$ por $$.tipo e $1, $2, etc. por $1.tipo, $2.tipo, etc. Nas ocorrências de atributos do não terminal Variavel, foi trocado $$ por $$.simb e $1, $2, etc. por $1.simb, $2.simb, etc.
34
Na produção do não-terminal Programa:
Exercício 4.1: Inicializar o código intermediário e a lista de quádruplas do único módulo, imprimindo-as (a lista é vazia) Na produção do não-terminal Programa: Programa : { InicTabSimb (); InicCodIntermed (); numtemp = 0; } ID ABCHAVE {printf ("%s {\n", $2); simb = InsereSimb ($2, IDPROG, NOTVAR); InicCodIntermMod (simb); } DeclLocs Cmds FCHAVE { printf ("}\n"); VerificaInicRef (); ImprimeTabSimb (); ImprimeQuadruplas (); } ; Acrescentar ao arquivo inter y o código em destaque Rodar com o arquivo inter dat
35
Exercício 4.2: Inserir a quádrupla OPENMOD
Ainda na produção do não-terminal Programa: Programa: { } ID ABCHAVE { InicCodIntermMod (simb); opnd1.tipo = MODOPND; opnd1.atr.modulo = modcorrente; GeraQuadrupla (OPENMOD, opnd1, opndidle, opndidle); } DeclLocs Cmds FCHAVE { } ; Acrescentar ao arquivo inter y o código em destaque Rodar com o arquivo inter dat
36
Exemplo: as quádruplas para a expressão: (i+3 >= j-2) && b2
Exercício 4.3: Inserir quádruplas para expressões sem variáveis indexadas Exemplo: as quádruplas para a expressão: (i+3 >= j-2) && b2 sendo: int i, j; logico b2; 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, b2), (VAR, ##4)
37
É necessária uma programação em todos os não-terminais envolvendo expressões
Em toda produção que contribui para a formação de expressões, deve-se calcular o atributo operando do não-terminal do lado esquerdo Numa produção onde aparece operador de expressões, além desse cálculo, deve-se gerar quádrupla com a operação correspondente e com os atributos operandos dos não-terminais de expressões
38
Na produção do não-terminal Variavel, calcula-se seu operando, quando não há subscritos:
Variavel: ID { } ListSubscr { $$.simb = $<simb>2; if ($$.simb != NULL) { if ($$.simb->array == FALSE && ) else if ($$.simb->array == TRUE && ) else if ($$.simb->ndims != $3) Incompatibilidade ( ); $$.opnd.tipo = VAROPND; if ($3 == 0) $$.opnd.atr.simb = $$.simb; }
39
Nas produções sem operadores do não-terminal Fator, calcula-se seu operando:
Fator : Variavel { if ($1.simb != NULL) { $$.tipo = $1.simb->tvar; $$.opnd = $1.opnd; } } | CTINT { $$.tipo = INTEGER; $$.opnd.tipo = INTOPND; $$.opnd.atr.valint = $1; | CTREAL { $$.tipo = FLOAT; $$.opnd.tipo = REALOPND; $$.opnd.atr.valfloat = $1;
40
Fator: CTCARAC { - - - - - $$.tipo = CHAR;
$$.opnd.tipo = CHAROPND; $$.opnd.atr.valchar = $1; } | VERDADE { $$.tipo = LOGIC; $$.opnd.tipo = LOGICOPND; $$.opnd.atr.vallogic = 1; | FALSO { $$.tipo = LOGIC; $$.opnd.atr.vallogic = 0; | ABPAR { } Expressao FPAR { $$.tipo = $3.tipo; $$.opnd = $3.opnd;
41
Na produção do não-terminal Fator com o operador NEG, gera-se uma quádrupla, além de calcular o operando do lado esquerdo: Fator : NEG { } Fator { if ( ) Incompatibilidade ( ); if ($3.tipo == FLOAT) $$.tipo = FLOAT; else $$.tipo = INTEGER; $$.opnd.tipo = VAROPND; $$.opnd.atr.simb = NovaTemp ($$.tipo); GeraQuadrupla (OPMENUN, $3.opnd, opndidle, $$.opnd); } ; Rodar com o arquivo inter dat
42
Produções do não-terminal Termo:
Termo : Fator /* default: $$ = $1 */ | Termo OPMULT { } Fator { switch ($2) { case MULT: case DIV: $$.opnd.tipo = VAROPND; $$.opnd.atr.simb = NovaTemp ($$.tipo); if ($2 == MULT) GeraQuadrupla (OPMULTIP, $1.opnd, $4.opnd, $$.opnd); else GeraQuadrupla (OPDIV, $1.opnd, $4.opnd, $$.opnd); break; case RESTO: GeraQuadrupla (OPRESTO, $1.opnd, $4.opnd, $$.opnd); } ; Rodar com o arquivo inter dat Fazer programação análoga para as produções dos não terminais ExprAux4, ExprAux3, ExprAux2, ExprAux1 e Expressao
43
Exercício 4.4: Inserir quádruplas para comandos de atribuição
Exemplo: as quádruplas para a atribuição: b1 := (i+3 >= j-2) && b2 sendo: int i, j; logico b1, b2; 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, b2), (VAR, ##4) ATRIB, (VAR, ##4), (IDLE), (VAR, b1)
44
Exercício 4.5: Inserir quádruplas para comandos condicionais
Primeiramente, sejam os comandos se sem senao Exemplo: as quádruplas para o comando se (i < j) { i := i+3; n := v/h; } podem ser: 2) LT, (VAR, i), (VAR, j), (VAR, ##1) 3) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 4) MAIS, (VAR, i), (INT, 3), (VAR, ##2) 5) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 6) DIV, (VAR, v), (VAR, h), (VAR, ##3) 7) ATRIB, (VAR, ##3), (IDLE), (VAR, n) 8) NOP, (IDLE), (IDLE), (IDLE) Usar os arquivos inter y, inter l e inter dat
45
Arquivo inter y: Gera quádruplas para abrir módulo, operadores de expressões e comandos de atribuição Função RenumQuadruplas (q1, q2): Algumas quádruplas serão geradas fora de ordem Sua ordem deve ser corrigida Para fins didáticos, as quádruplas serão renumeradas Abrir o arquivo inter dat Rodar flex, yacc, gcc e executável gerado A cada implementação, alterar os comentários em inter dat
46
A programação para se sem senao está na produção do não-terminal CmdSe:
CmdSe : SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (")\n");} Comando { $<quad>5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao ; É necessário acrescentar o campo quad na declaração %union: quadrupla quad;
47
A programação para se sem senao está na produção do não-terminal CmdSe:
CmdSe : SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (")\n");} Comando { $<quad>5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao ; No arquivo inter dat, tirar o comentário do se sem senao e rodar
48
CmdSe : SE ABPAR {- - - - -} Expressao {
opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (")\n");} Comando { $<quad>5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao ; $5 Expressao A quádrupla destino do desvio é gerada na produção de CmdSe NOP é eliminada na otimização do código intermediário ----- ##n ? JF ##n ----- ROT Comando NOP -----
49
Sejam agora os comandos se com senao
Exemplo: as quádruplas para os comandos se (i < j) { i := i+3; n := v/h; } senao { v := h; i := j; } n := v; podem ser: 2) LT, (VAR, i), (VAR, j), (VAR, ##1) 3) JF, (VAR, ##1), (IDLE), (ROTULO, 9) 4) MAIS, (VAR, i), (INT, 3), (VAR, ##2) 5) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 6) DIV, (VAR, v), (VAR, h), (VAR, ##3) 7) ATRIB, (VAR, ##3), (IDLE), (VAR, n) 8) JUMP, (IDLE), (IDLE), (ROTULO, 12) 9) NOP, (IDLE), (IDLE), (IDLE) 10) ATRIB, (VAR, h), (IDLE), (VAR, v) 11) ATRIB, (VAR, j), (IDLE), (VAR, i) 12) NOP, (IDLE), (IDLE), (IDLE) 13) ATRIB, (VAR, v), (IDLE), (VAR, n)
50
A programação para se com senao está nas produções dos não-terminais CmdSe e CmdSenao:
CmdSe : SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (")\n");} Comando { $<quad>$ = quadcorrente; $<quad>5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao { if ($<quad>9->prox != quadcorrente) { quadaux = $<quad>9->prox; $<quad>9->prox = quadaux->prox; quadaux->prox = $<quad>9->prox->prox; $<quad>9->prox->prox = quadaux; RenumQuadruplas ($<quad>9, quadcorrente); } ;
51
CmdSenao : | SENAO { opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { $<quad>2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } ; No arquivo inter dat, tirar o comentário do if com else e rodar
52
CmdSe : SE ABPAR { - - - - - } Expressao { - - - - -
opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (")\n");} Comando { $<quad>$ = quadcorrente; $<quad>5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao { } ; $5 Expressao $9 ----- ##n JF ##n ----- ROT Comando NOP -----
53
CmdSenao : | SENAO { - - - - -
opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { $<quad>2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } ; Expressao ? $2 JUMP ----- ROT ----- ##n $5 JF ##n ----- ROT As quádruplas NOP e JUMP foram geradas em ordem trocada Comando $9 NOP -----
54
Expressao ? $2 Comando $4 Comando $8
CmdSenao : | SENAO { opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { $<quad>2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } ; Expressao ? $2 JUMP ----- ROT ----- ##n Comando $4 JF ##n ----- ROT NOP ----- Comando $8 É preciso inverter a ordem das quádruplas NOP e JUMP NOP -----
55
CmdSe : SE ABPAR {- - - - -} Expressao {- - - - -} FPAR {- - - - -} Comando
{ } CmdSenao { if ($<quad>9->prox != quadcorrente) { quadaux = $<quad>9->prox; $<quad>9->prox = quadaux->prox; quadaux->prox = $<quad>9->prox->prox; $<quad>9->prox->prox = quadaux; RenumQuadruplas ($<quad>9, quadaux); } ; Comando $9 NOP ----- JUMP ----- ROT quadaux Comando Se a quádrupla seguinte à $9 for a quádrupla corrente, o se não tem senao – não é preciso fazer troca NOP -----
56
Exercício 4.6: Inserir quádruplas para o comando enquanto
Exemplo: as quádruplas para o comando enquanto (i < j) i := j + h; i := 0; podem ser: 2) NOP, (IDLE), (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), (IDLE), (ROTULO, 2) 8) NOP, (IDLE), (IDLE), (IDLE) 9) ATRIB, (INT, 0), (IDLE), (VAR, i)
57
Expressao Comando CmdEnquanto : ENQUANTO ABPAR Expressao FPAR Comando
; NOP ----- Expressao ----- ##n ? JF ##n ----- ROT Comando JUMP ----- ROT NOP -----
58
Exercício 4.7: Inserir quádruplas para comandos ler e escrever
Exemplo: as quádruplas para os comandos ler (a, b, c); escrever ("Valor de a+b:", a+b, "Valor de c:", c); podem ser: 2) PARAM, (VAR, a), (IDLE), (IDLE) 3) PARAM, (VAR, b), (IDLE), (IDLE) 4) PARAM, (VAR, c), (IDLE), (IDLE) 5) READ, (INT, 3), (IDLE), (IDLE) 6) PARAM, (CADEIA, Valor de a+b:), (IDLE), (IDLE) 7) MAIS, (VAR, a), (VAR, b), (VAR, ##1) 8) PARAM, (VAR, ##1), (IDLE), (IDLE) 9) PARAM, (CADEIA, Valor de c:), (IDLE), (IDLE) 10) PARAM, (VAR, c), (IDLE), (IDLE) 11) WRITE, (INT, 4), (IDLE), (IDLE) Os operadores de quádruplas PARAM, OPREAD e OPWRITE já estão declarados no programa inter y
59
São úteis contadores de argumentos para os comandos ler e escrever
2) PARAM, (VAR, a), (IDLE), (IDLE) 3) PARAM, (VAR, b), (IDLE), (IDLE) 4) PARAM, (VAR, c), (IDLE), (IDLE) 5) READ, (INT, 3), (IDLE), (IDLE) 6) PARAM, (CADEIA, Valor de a+b:), (IDLE), (IDLE) 7) MAIS, (VAR, a), (VAR, b), (VAR, ##1) 8) PARAM, (VAR, ##1), (IDLE), (IDLE) 9) PARAM, (CADEIA, Valor de c:), (IDLE), (IDLE) 10) PARAM, (VAR, c), (IDLE), (IDLE) 11) WRITE, (INT, 4), (IDLE), (IDLE) São úteis contadores de argumentos para os comandos ler e escrever Isso será feito nas produções dos não-terminais ListLeit e ListEscr Elementos de escrita também podem ser operandos de quádruplas
60
O atributo dos não-terminais ListLeit e ListEscr deve ser o número de argumentos de suas listas
Deve-se acrescentar mais um campo na declaração %union: %union { int nsubscr, nargs; } Declaração do atributo dos não terminais ListLeit e ListEscr: %type <nargs> ListLeit ListEscr
61
Tal como uma expressão, o não terminal ElemEscr terá um operando de quádrupla
Então deve haver uma declaração %type para ele: %type <infoexpr> Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator ElemEscr
62
Programação para o não-terminal ListLeit que é usado na produção do não-terminal CmdLer:
ListLeit : Variavel { $$ = 1; GeraQuadrupla (PARAM, $1.opnd, opndidle, opndidle); } | ListLeit VIRG { } Variavel { $$ = $1 + 1; GeraQuadrupla (PARAM, $4.opnd, opndidle, opndidle); ; $$ é o contador de argumentos de um comando ler
63
Programação para o não-terminal CmdLer:
CmdLer : LER ABPAR { } ListLeit { opnd1.tipo = INTOPND; opnd1.atr.valint = $4; GeraQuadrupla (OPREAD, opnd1, opndidle, opndidle); } FPAR PVIRG {printf (") ;\n");} ;
64
Programação para o não-terminal ElemEscr:
ElemEscr : CADEIA { printf ("%s ", $1); $$.opnd.tipo = CADOPND; $$.opnd.atr.valcad = malloc (strlen($1) + 1); strcpy ($$.opnd.atr.valcad, $1); } | Expressao /* default: $$ = $1 */ ; Obs.: $$.tipo da 1ª produção do não-terminal ElemEscr não é usado Portanto não é calculado
65
Programação para o não-terminal ListEscr:
ListEscr : ElemEscr { $$ = 1; GeraQuadrupla (PARAM, $1.opnd, opndidle, opndidle); } | ListEscr VIRG {printf (", ");} ElemEscr $$ = $1 + 1; GeraQuadrupla (PARAM, $4.opnd, opndidle, opndidle); ; $$ é o contador de argumentos de um comando escrever
66
Programação para o não-terminal CmdEscrever:
CmdEscrever : ESCREVER ABPAR { } ListEscr { opnd1.tipo = INTOPND; opnd1.atr.valint = $4; GeraQuadrupla (OPWRITE, opnd1, opndidle, opndidle); } FPAR PVIRG {printf (") ;\n");} ; No arquivo inter dat, tirar o comentário dos comandos ler e escrever e rodar
67
Exercício 4.8: Inserir quádruplas para indexação
Sejam as seguintes declarações e comandos: int i, j, k, A[6][5]; i := 4; j := 3; k := A[i][j-2] + 7; A[10-i][2*j+3] := i + j * k; ler (i, j, A[i+j][2*i-j]); Acesso a um elemento genérico A[i][j]: Uma vez conhecido o endereço inicial da matriz A, é necessário localizar o elemento A[i][j] Seja a seguir o mapa de A[6][5] na memória:
68
Seja m o número de linhas e n o número de colunas da matriz A
O endereço do elemento A[i][j] é dado pela fórmula: Ender (A) + i * n + j Para m = 6, n = 5, o endereço de A[4][3] é Ender (A) + 23
69
No programa, cada índice pode ser uma expressão inteira
Exemplo: A[10-i][2*j+3] Calcula-se o valor de cada índice, empilhando-o numa pilha de índices Isso pode ser feito pela execução de uma quádrupla de operador IND: IND, i , ---- , ---- IND, j , ---- , ----
70
Calcula-se o endereço de A[i][j], usando uma quádrupla de operador INDEX:
INDEX , A , 2 , temp1 Sua execução consiste em: Pegar as dimensões e o endereço de A na tabela de símbolos Desempilhar dois índices Calcular o endereço, colocando-o na variável temp1 A variável temp1 é portanto um ponteiro
71
Para isso, pode-se usar uma quádrupla de operador CONTAPONT:
Quando o elemento A[i][j] está numa expressão, necessita-se do conteúdo do local apontado por temp1 Para isso, pode-se usar uma quádrupla de operador CONTAPONT: CONTAPONT , temp1 , ---- , temp2 temp2 recebe o conteúdo do local apontado por temp1 int i, j, k, A[6][5]; i := 4; j := 3; k := A[i][j-2] + 7; A[10-i][2*j+3] := i + j * k; ler (i, j, A[i+j][2*i-j]);
72
Então, pode-se usar uma quádrupla de operador ATRIBPONT:
Quando o elemento A[i][j] vai receber uma atribuição, o local apontado por temp1 é que vai receber isso Então, pode-se usar uma quádrupla de operador ATRIBPONT: ATRIBPONT , tempexpr , ---- , temp1 O local apontado por temp1 recebe o conteúdo de tempexpr int i, j, k, A[6][5]; i := 4; j := 3; k := A[i][j-2] + 7; A[10-i][2*j+3] := i + j * k; ler (i, j, A[i+j][2*i-j]);
73
Duas quádruplas OPREAD
Quando o elemento A[i][j] vai receber um valor lido: O valor lido é guardado numa nova temporária O local apontado por temp1 recebe o valor dessa temporária PARAM , tempread , ---- , ---- OPREAD , 1 , ---- , ---- ATRIBPONT , tempread , ---- , temp1 É conveniente colocar a leitura do elemento de uma variável indexada numa quádrupla separada: Duas quádruplas OPREAD int i, j, k, A[6][5]; i := 4; j := 3; k := A[i][j-2] + 7; A[10-i][2*j+3] := i + j * k; ler (i, j, A[i+j][2*i-j]);
74
Exemplo: seja o seguinte programa:
programa teste { locais: int i, j, k, A[10][10]; Comandos: i := 7; j := 5; k := A[i-3][j+2] + 5; A[10-i][9-j] := i + j * k; ler (i, j, A[2][3], k); ler (A[1][2]); } A seguir suas possíveis quádruplas
75
programa teste { locais: int i, j, k, A[10][10]; 1) OPENMOD, (MODULO, teste), (IDLE), (IDLE) statements { i := 7; j := 5; 2) ATRIB, (INT, 7), (IDLE), (VAR, i) 3) ATRIB, (INT, 5), (IDLE), (VAR, j)
76
k := A[i-3][j+2] + 5; 4) MENOS, (VAR, i), (INT, 3), (VAR, ##1) 5) IND, (VAR, ##1), (IDLE), (IDLE) 6) MAIS, (VAR, j), (INT, 2), (VAR, ##2) 7) IND, (VAR, ##2), (IDLE), (IDLE) 8) INDEX, (VAR, A), (INT, 2), (VAR, ##3) 9) CONTAPONT, (VAR, ##3), (IDLE), (VAR, ##4) 10) MAIS, (VAR, ##4), (INT, 5), (VAR, ##5) 11) ATRIB, (VAR, ##5), (IDLE), (VAR, k)
77
A[10-i][9-j] := i + j * k; 12) MENOS, (INT, 10), (VAR, i), (VAR, ##6) 13) IND, (VAR, ##6), (IDLE), (IDLE) 14) MENOS, (INT, 9), (VAR, j), (VAR, ##7) 15) IND, (VAR, ##7), (IDLE), (IDLE) 16) INDEX, (VAR, A), (INT, 2), (VAR, ##8) 17) MULT, (VAR, j), (VAR, k), (VAR, ##9) 18) MAIS, (VAR, i), (VAR, ##9), (VAR, ##10) 19) ATRIBPONT, (VAR, ##10), (IDLE), (VAR, ##8)
78
ler (i, j, A[2][3], k); 20) PARAM, (VAR, i), (IDLE), (IDLE) 21) PARAM, (VAR, j), (IDLE), (IDLE) 22) READ, (INT, 2), (IDLE), (IDLE) 23) IND, (INT, 2), (IDLE), (IDLE) 24) IND, (INT, 3), (IDLE), (IDLE) 25) INDEX, (VAR, A), (INT, 2), (VAR, ##11) 26) PARAM, (VAR, ##12), (IDLE), (IDLE) 27) READ, (INT, 1), (IDLE), (IDLE) 28) ATRIBPONT, (VAR, ##12), (IDLE), (VAR, ##11) 29) PARAM, (VAR, k), (IDLE), (IDLE) 30) READ, (INT, 1), (IDLE), (IDLE)
79
ler (A[1][2]); } 31) IND, (INT, 1), (IDLE), (IDLE) 32) IND, (INT, 2), (IDLE), (IDLE) 33) INDEX, (VAR, A), (INT, 2), (VAR, ##13) 34) PARAM, (VAR, ##14), (IDLE), (IDLE) 35) READ, (INT, 1), (IDLE), (IDLE) 36) ATRIBPONT, (VAR, ##14), (IDLE), (VAR, ##13)
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.