A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

CES-41 COMPILADORES Aulas Práticas

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Aulas Práticas"— Transcrição da apresentação:

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)


Carregar ppt "CES-41 COMPILADORES Aulas Práticas"

Apresentações semelhantes


Anúncios Google