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, "\n"); cont := cont + 1; }}} senao escrever ("O valor de entrada deveria ser maior que zero"); senao escrever ("O valor de entrada deveria ser maior que zero");}">

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

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

CES-41 COMPILADORES Aulas Práticas - 2013 Capítulo IV Código Intermediário no Yacc.

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Aulas Práticas - 2013 Capítulo IV Código Intermediário no Yacc."— Transcrição da apresentação:

1 CES-41 COMPILADORES Aulas Práticas Capítulo IV Código Intermediário no Yacc

2 O sub-set da Linguagem COMP-ITA-2013, usado no final do capítulo anterior, contém: O sub-set da Linguagem COMP-ITA-2013, 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 Comandos de atribuição, compostos, entrada e saída, condicionais, enquanto, variáveis escalares e indexadas Seja essa linguagem chamada de Sub-Set Seja essa linguagem chamada de Sub-Set Seja o programa a seguir, escrito em Sub-Set2 2013, para encontrar números primos Seja o programa a seguir, escrito em Sub-Set2 2013, para encontrar números primos

3 programa primos; var logic achou; int n, div, resto, cont, num; { ler (n); escrever (n, " primeiros numeros naturais primos:\n\n"); escrever (n, " primeiros numeros naturais primos:\n\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, "\n"); cont := cont + 1; }}} senao escrever ("O valor de entrada deveria ser maior que zero"); senao escrever ("O valor de entrada deveria ser maior que zero");}

4 Um possível código intermediário não otimizado: Um possível código intermediário não otimizado: programa primos; var logic achou; int n, div, resto, cont, num; 1) OPENMOD, (MODULO, primos), (IDLE), (IDLE) ler (n); 2) PARAM, (VAR, n), (IDLE), (IDLE) 3) READ, (INT, 1), (IDLE), (IDLE)

5 se (n > 0) { } 4) GT, (VAR, n), (INT, 0), (VAR, ##1) 5) JF, (VAR, ##1), (IDLE), (ROTULO, 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 NOPs 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) ) JUMP, (IDLE), (IDLE), (ROTULO, 8) 41) NOP, (IDLE), (IDLE), (IDLE) num := num + 1; div := 2; achou := falso; 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 NOPs 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) ) JUMP, (IDLE), (IDLE), (ROTULO, 15) 32) NOP, (IDLE), (IDLE), (IDLE)

8 resto := num % div; se (resto = 0) achou := verdade; 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 prog destinam-se a: alocar as variáveis do programa principal (globais) executar o programa principal e encerrar tudo no final

12 A lista de mod-heads tem um nó-líder e cada lista de quádruplas também tem

13 Estrutura de dados para código intermediário de linguagens sem subprogramas: 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-Set O arquivo inter y tem um analisador semântico quase acabado para a linguagem Sub-Set O arquivo inter l é seu analisador léxico 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 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 Rodar esses arquivos com inter dat A seguir, uma descrição dessas declarações e funções A seguir, uma descrição dessas declarações e funções

15 Estrutura de uma quádrupla: 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 O campo num numera as quádruplas Não é necessário na compilação Não é necessário na compilação Foi colocado por razões didáticas Foi colocado por razões didáticas Um operando tem dois campos: o tipo e o atributo Um operando tem dois campos: o tipo e o atributo operopnd1 opnd2result prox num celquad

16 Estrutura de um operando: Estrutura de um operando: typedef struct operando operando; struct operando { int tipo; atribopnd atr; }; Os tipos dos operandos são: Os tipos dos operandos são: Operando vazio (idle) Operando vazio (idle) Nome de variável Nome de variável Constantes inteira, real, lógica e caractere Constantes inteira, real, lógica e caractere Cadeia de caracteres Cadeia de caracteres Rótulo de quádruplas (ponteiro para quádruplas) Rótulo de quádruplas (ponteiro para quádruplas) Nome de módulo Nome de módulo tipo atr (simb, valint, valfloat, valchar, vallogic, valcad, rotulo, modulo) operando

17 Estrutura do atributo de um operando: 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: Tabela dos atributos conforme o tipo de operando: TipoAtributoTipoAtributo Idle-Constante caracterevalchar Nome de variávelsimbCadeia de caracteresvalcad Constante inteiravalintRótulo de quádruplarotulo Constante realvalfloatNome de módulomodulo Constante lógicavallogic tipo atr (simb, valint, valfloat, valchar, vallogic, valcad, rotulo, modulo) operando

18 Estrutura de um cabeçalho de módulo: Estrutura de um cabeçalho de módulo: typedef struct celmodhead celmodhead; typedef celmodhead *modhead; struct celmodhead { simbolo modname; modhead prox; int modtip; quadrupla listquad; }; modname modtip celmodhead prox listquad

19 Variáveis globais: 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 quadcorrente: ponteiro para a celquad recém-alocada codintermed: ponteiro que dá acesso a todo o código intermediário codintermed: ponteiro que dá acesso a todo o código intermediário modcorrente: ponteiro para a última celmodhead alocada modcorrente: ponteiro para a última celmodhead alocada numtemp: usada para controlar a concessão de nomes a variáveis temporárias 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 opndidle: constante do tipo operando para preencher operandos vazios nas quádruplas

20 Novas definições para os tipos dos identificadores: Novas definições para os tipos dos identificadores: Relembrando as definições para os tipos de variáveis: Relembrando as definições para os tipos de variáveis: #define IDPROG1 #define IDVAR2 #define IDFUNC3 #define IDPROC4 #define NOTVAR0 #define INTEGER1 #define LOGIC2 #define FLOAT3 #define CHAR4

21 Definições de constantes para operadores de quádruplas: Definições de constantes para operadores de quádruplas: #defineOPOR1 #defineOPAND2 #define OPLT 3 #define OPLE 4 #defineOPGT 5 #defineOPGE6 #defineOPEQ7 #defineOPNE8 #defineOPMAIS9 #defineOPMENOS10 #defineOPMULTIP11 #defineOPDIV12 #defineOPRESTO13 #defineOPMENUN14 #defineOPNOT15 #defineOPATRIB16 #defineOPENMOD17 #defineNOP18 #defineOPJUMP19 #defineOPJF20

22 Definições de constantes para os tipos dos operandos: Definições de constantes para os tipos dos operandos: #defineIDLEOPND0 #defineVAROPND1 #defineINTOPND2 #defineREALOPND3 #defineCHAROPND4 #defineLOGICOPND5 #defineCADOPND6 #defineROTOPND7 #defineMODOPND8

23 Protótipos das funções para o código intermediário: 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: Função InicCodIntermed: void InicCodIntermed () { codintermed = malloc (sizeof (celmodhead)); modcorrente = codintermed; modcorrente->listquad = NULL; modcorrente->listquad = NULL; modcorrente->prox = NULL; } codintermed modname modtip prox listquad modcorrente

25 Função InicCodIntermMod (simbolo simb): Função InicCodIntermMod (simbolo simb): void InicCodIntermMod (simbolo simb) { modcorrente->prox = malloc (sizeof (celmodhead)); modcorrente = modcorrente->prox; modcorrente->prox = NULL; modcorrente->modname = simb; modcorrente->modtip = simb->tid; modcorrente->listquad = malloc (sizeof (celquad)); quadcorrente = modcorrente->listquad; quadcorrente->prox = NULL; numquadcorrente = 0; quadcorrente->num = numquadcorrente; } codintermed simb num oper #### opnd1 #### opnd2 #### result #### prox quadcorrente 0 modname modtip prox listquad modname modtip prox listquad modcorrente cadeiatid

26 Função GeraQuadrupla (oper, opnd1, opnd2, result): 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; quadcorrente->num = numquadcorrente; return quadcorrente; return quadcorrente;} num 452 oper X opnd1 YYYY opnd2 ZZZZ result WWWW prox quadcorrente 453 R oper SSSS opnd1 TTTT opnd2 VVVV result TTTT SSSS VVVV R num oper opnd1 opnd2 result prox valor retornado

27 Função Novatemp (tip): 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 = TRUE; simb->array = FALSE; 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 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 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: Não-terminais para a montagem de expressões: Expressao, ExprAux1, ExprAux2, ExprAux3, ExprAux4, Termo, Fator Esses não-terminais já guardam seus tipos em seus atributos, para os testes de compatibilidade entre operadores e operandos: Esses não-terminais já guardam seus tipos em seus atributos, para os testes de compatibilidade entre operadores e operandos: %type Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator Agora, o atributo desses não-terminais deverá ter dois campos: Agora, o atributo desses não-terminais deverá ter dois campos: o tipo e o operando

30 Seja também a produção: 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 É 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: Esse não-terminal já guarda em seu atributo um ponteiro para a TabSimb, para os testes de compatibilidade entre operadores e operandos: %type Variavel %type Variavel Agora, o atributo desse não-terminal deverá ter dois campos: 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: 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: 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: 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; simbolo simb; int dim; int nsubscr;} Novas especificações para os atributos dos não-terminais envolvidos: Novas especificações para os atributos dos não-terminais envolvidos: %type Variavel %type Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator Antes era

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 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. 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 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 Prog: Na produção do não-terminal Prog: Prog:{ InicTabSimb (); InicCodIntermed (); numtemp = 0; } PROGRAMA ID PVIRG { printf ("programa %s ;\n", $3); simb = InsereSimb ($3, IDPROG, NOTVAR); simb = InsereSimb ($3, IDPROG, NOTVAR); InicCodIntermMod (simb); InicCodIntermMod (simb); } Decls CmdComp { VerificaInicRef (); ImprimeTabSimb (); VerificaInicRef (); ImprimeTabSimb (); ImprimeQuadruplas (); 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 Prog: Ainda na produção do não-terminal Prog: Prog:{ } PROGRAMA ID PVIRG { InicCodIntermMod (simb); InicCodIntermMod (simb); opnd1.tipo = MODOPND; opnd1.tipo = MODOPND; opnd1.atr.modulo = modcorrente; opnd1.atr.modulo = modcorrente; GeraQuadrupla (OPENMOD, opnd1, opndidle, opndidle); GeraQuadrupla (OPENMOD, opnd1, opndidle, opndidle); } Decls CmdComp { }; Acrescentar ao arquivo inter y o código em destaque Rodar com o arquivo inter dat

36 Exercício 4.3: Inserir quádruplas para expressões sem variáveis indexadas Exemplo: as quádruplas para a expressão: Exemplo: as quádruplas para a expressão: (i+3 >= j-2) && b2 sendo: int i, j; logic 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 É 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 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 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 1ª produção do não-terminal Variavel (sem subscritos), calcula-se seu operando: Na 1ª produção do não-terminal Variavel (sem subscritos), calcula-se seu operando: Variavel: ID { $$.simb = simb; $$.simb = simb; if ($$.simb != NULL) { if ($$.simb != NULL) { if ( ) Esperado ("Subscrito\(s)"); $$.opnd.tipo = VAROPND; $$.opnd.atr.simb = $$.simb; $$.opnd.atr.simb = $$.simb; }};

39 Nas produções sem operadores do não-terminal Fator, calcula-se seu operando: 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.tipo = INTOPND; $$.opnd.atr.valint = $1; } | CTREAL { $$.tipo = FLOAT; | CTREAL { $$.tipo = FLOAT; $$.opnd.tipo = REALOPND; $$.opnd.tipo = REALOPND; $$.opnd.atr.valfloat = $1; }

40 Fator: CTCARAC { $$.tipo = CHAR; Fator: CTCARAC { $$.tipo = CHAR; $$.opnd.tipo = CHAROPND; $$.opnd.tipo = CHAROPND; $$.opnd.atr.valchar = $1; } | VERDADE { $$.tipo = LOGICAL; | VERDADE { $$.tipo = LOGICAL; $$.opnd.tipo = LOGICOPND; $$.opnd.tipo = LOGICOPND; $$.opnd.atr.vallogic = 1; } | FALSO { $$.tipo = LOGICAL; | FALSO { $$.tipo = LOGICAL; $$.opnd.tipo = LOGICOPND; $$.opnd.tipo = LOGICOPND; $$.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: 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.tipo = VAROPND; $$.opnd.atr.simb = NovaTemp ($$.tipo); GeraQuadrupla (OPMENUN, $3.opnd, opndidle, $$.opnd); GeraQuadrupla (OPMENUN, $3.opnd, opndidle, $$.opnd);}; Rodar com o arquivo inter dat

42 Produções do não-terminal Termo: 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); GeraQuadrupla (OPMULTIP, $1.opnd, $4.opnd, $$.opnd); else GeraQuadrupla (OPDIV, $1.opnd, $4.opnd, $$.opnd); break; case RESTO: $$.opnd.tipo = VAROPND; $$.opnd.atr.simb = NovaTemp ($$.tipo); GeraQuadrupla (OPRESTO, $1.opnd, $4.opnd, $$.opnd); break;}}; 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: Exemplo: as quádruplas para a atribuição: b1 := (i+3 >= j-2) && b2 sendo: int i, j; logic 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 Primeiramente, sejam os comandos se sem senao Exemplo: as quádruplas para o comando 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) 2) LT, (VAR, i), (VAR, j), (VAR, ##1) 3) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 3) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 4) MAIS, (VAR, i), (INT, 3), (VAR, ##2) 4) MAIS, (VAR, i), (INT, 3), (VAR, ##2) 5) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 5) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 6) DIV, (VAR, v), (VAR, h), (VAR, ##3) 6) DIV, (VAR, v), (VAR, h), (VAR, ##3) 7) ATRIB, (VAR, ##3), (IDLE), (VAR, n) 7) ATRIB, (VAR, ##3), (IDLE), (VAR, n) 8) NOP, (IDLE), (IDLE), (IDLE) 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 Gera quádruplas para abrir módulo, operadores de expressões e comandos de atribuição Função RenumQuadruplas (q1, q2): Função RenumQuadruplas (q1, q2): Algumas quádruplas serão geradas fora de ordem Algumas quádruplas serão geradas fora de ordem Sua ordem deve ser corrigida Sua ordem deve ser corrigida Para fins didáticos, as quádruplas serão renumeradas Para fins didáticos, as quádruplas serão renumeradas Abrir o arquivo inter dat Abrir o arquivo inter dat Rodar flex, yacc, gcc e executável gerado Rodar flex, yacc, gcc e executável gerado A cada implementação, alterar os comentários em inter dat 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: A programação para se sem senao está na produção do não- terminal CmdSe: CmdSe: SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (") ");} Comando { $ 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: A programação para se sem senao está na produção do não- terminal CmdSe: CmdSe: SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (") ");} Comando { $ 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; $ $ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (") ");} Comando { $ 5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao ; Expressao ##nJF##n-----ROT $5 Comando NOP----- A quádrupla destino do desvio é gerada na produção de CmdSe NOP é eliminada na otimização do código intermediário ?

49 Sejam agora os comandos se com senao Sejam agora os comandos se com senao Exemplo: as quádruplas para os comandos 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: 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; opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR {printf (") ");} Comando { $ $ = quadcorrente; $ $ = quadcorrente; $ 5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao { if ($ 9->prox != quadcorrente) { quadaux = $ 9->prox; $ 9->prox = quadaux->prox; quadaux->prox = $ 9->prox->prox; $ 9->prox->prox = quadaux; RenumQuadruplas ($ 9, quadcorrente); }};

51 CmdSenao: | SENAO { opndaux.tipo = ROTOPND; opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { } Comando { $ 2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); }; No arquivo inter dat, tirar o comentário do se com senao e rodar

52 CmdSe: SE ABPAR { } Expressao { opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJF, $4.opnd, opndidle, opndaux); } FPAR { } Comando { $ $ = quadcorrente; $ 5->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdSenao { } ; Expressao ##nJF##n-----ROT Comando NOP----- $5 $9

53 CmdSenao:| SENAO { opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { $ 2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); }; Expressao ##nJF##n-----ROT Comando NOP----- $5 $9 JUMP----- ROT $2 As quádruplas NOP e JUMP foram geradas em ordem trocada ?

54 CmdSenao:| SENAO { opndaux.tipo = ROTOPND; $ $ = GeraQuadrupla (OPJUMP, opndidle, opndidle, opndaux); } Comando { $ 2->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); }; Expressao ##nJF##n-----ROT Comando NOP----- $5 $9 JUMP----- ROT $2 Comando NOP----- É preciso inverter a ordem das quádruplas NOP e JUMP ?

55 CmdSe: SE ABPAR { } Expressao { } FPAR { } Comando { } CmdSenao { if ($ 9->prox != quadcorrente) { quadaux = $ 9->prox; $ 9->prox = quadaux->prox; quadaux->prox = $9->prox->prox; $ 9->prox->prox = quadaux; RenumQuadruplas ($ 9, quadcorrente); }}; Comando NOP----- $9 JUMP----- ROT Comando NOP----- Se a quádrupla seguinte à $9 for a quádrupla corrente, o se não tem senao – não é preciso fazer troca quadaux

56 Exercício 4.6: Inserir quádruplas para o comando enquanto Exemplo: as quádruplas para o comando Exemplo: as quádruplas para o comando enquanto (i < j) i := j + h; i := 0; podem ser: 2) NOP, (IDLE), (IDLE), (IDLE) 2) NOP, (IDLE), (IDLE), (IDLE) 3) LT, (VAR, i), (VAR, j), (VAR, ##1) 3) LT, (VAR, i), (VAR, j), (VAR, ##1) 4) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 4) JF, (VAR, ##1), (IDLE), (ROTULO, 8) 5) MAIS, (VAR, j), (VAR, h), (VAR, ##2) 5) MAIS, (VAR, j), (VAR, h), (VAR, ##2) 6) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 6) ATRIB, (VAR, ##2), (IDLE), (VAR, i) 7) JUMP, (IDLE), (IDLE), (ROTULO, 2) 7) JUMP, (IDLE), (IDLE), (ROTULO, 2) 8) NOP, (IDLE), (IDLE), (IDLE) 8) NOP, (IDLE), (IDLE), (IDLE) 9) ATRIB, (INT, 0), (IDLE), (VAR, i) 9) ATRIB, (INT, 0), (IDLE), (VAR, i)

57 CmdEnquanto: ENQUANTO ABPAR Expressao FPAR Comando ; Expressao ##nJF##n-----ROT Comando NOP----- NOP----- JUMP----- ROT ?

58 Exercício 4.7: Inserir quádruplas para comandos ler e escrever Exemplo: as quádruplas para os comandos 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 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) Elementos de escrita também podem ser operandos de quádruplas São úteis contadores de argumentos para os comandos ler e escrever Isso será feito nas produções dos não-terminais ListVar e ListEscr

60 O atributo dos não-terminais ListVar e ListEscr deve ser o número de argumentos de suas listas O atributo dos não-terminais ListVar e ListEscr deve ser o número de argumentos de suas listas Deve-se acrescentar mais um campo na declaração %union: Deve-se acrescentar mais um campo na declaração %union: %union { int nsubscr, nargs; } Declaração do atributo dos não terminais ListVar e ListEscr: Declaração do atributo dos não terminais ListVar e ListEscr: %type ListVar ListEscr

61 Tal como uma expressão, o não terminal ElemEscr deve ter um operando de quádrupla Tal como uma expressão, o não terminal ElemEscr deve ter um operando de quádrupla Então deve haver uma declaração %type para ele: Então deve haver uma declaração %type para ele: %type Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator ElemEscr

62 Programação para o não-terminal ListVar que é usado na produção do não-terminal CmdLer: Programação para o não-terminal ListVar que é usado na produção do não-terminal CmdLer: ListVar: Variavel { $$ = 1; GeraQuadrupla (PARAM, $1.opnd, opndidle, opndidle); } | ListVar 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: Programação para o não-terminal CmdLer: CmdLer: LER ABPAR { } ListVar{ 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: 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: 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: 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: 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]: 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] 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: 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 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: 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] é 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 No programa, cada índice pode ser uma expressão inteira Calcula-se o valor de cada índice, empilhando-o numa pilha de índices 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: Isso pode ser feito pela execução de uma quádrupla de operador IND: IND, i, ----, ---- IND, i, ----, ---- IND, j, ----, ---- IND, j, ----, ----

70 Calcula-se o endereço de A[i,j], usando uma quádrupla de operador INDEX: 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: Sua execução consiste em: Pegar as dimensões e o endereço de A na tabela de símbolos Pegar as dimensões e o endereço de A na tabela de símbolos Desempilhar dois índices Desempilhar dois índices Calcular o endereço, colocando-o na variável temp1 Calcular o endereço, colocando-o na variável temp1 A variável temp1 é portanto um ponteiro A variável temp1 é portanto um ponteiro

71 Quando o elemento A[i,j] está numa expressão, necessita-se do conteúdo do local apontado por temp1 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: Para isso, pode-se usar uma quádrupla de operador CONTAPONT: CONTAPONT, temp1, ----, temp2 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]); temp2 recebe o conteúdo do local apontado por temp1

72 Quando o elemento A[i,j] vai receber uma atribuição, o local apontado por temp1 é que vai receber isso 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: Então, pode-se usar uma quádrupla de operador ATRIBPONT: ATRIBPONT, tempexpr, ----, 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]); O local apontado por temp1 recebe o conteúdo de tempexpr

73 Quando o elemento A[i,j] vai receber um valor lido: Quando o elemento A[i,j] vai receber um valor lido: O valor lido é guardado numa temporária O valor lido é guardado numa temporária O local apontado por temp1 recebe o valor dessa temporária O local apontado por temp1 recebe o valor dessa temporária É 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]); PARAM, tempread, ----, ---- OPREAD, 1, ----, ---- ATRIBPONT, tempread, ----, temp1

74 Exemplo: seja o seguinte programa: Exemplo: seja o seguinte programa: programa teste; var int i, j, k, A[10,10]; { 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; var int i, j, k, A[10,10]; 1) OPENMOD, (MODULO, teste), (IDLE), (IDLE) { 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 - 2013 Capítulo IV Código Intermediário no Yacc."

Apresentações semelhantes


Anúncios Google