450 likes | 607 Views
CES-41 COMPILADORES. Capítulo VII Código Intermediário. Capítulo VII Código Intermediário. 7.1 – Um programa com subprogramas 7.2 – Estruturas de dados 7.3 – Quádruplas para alguns comandos 7.4 – Quádruplas para ponteiros 7.5 – Quádruplas para subprogramação.
E N D
CES-41 COMPILADORES Capítulo VII Código Intermediário
Capítulo VIICódigo Intermediário 7.1 – Um programa com subprogramas 7.2 – Estruturas de dados 7.3 – Quádruplas para alguns comandos 7.4 – Quádruplas para ponteiros 7.5 – Quádruplas para subprogramação
7.1 – Um Programa com Subprogramas global:int comb; functions: int fat (int n;) { local:inti, fat; statements: if (n < 0 || n > 7) fat = ~1; else { fat = 1; i = 2; while (i <= n) {fat = fat * i;i = i + 1;} } return fat; } Seja o seguinte programa para calcular o número de combinações de m elementos tomados n a n:
void main () { local: char c; int m, n; statements: do { write ("Combinacao de m elementos tomados n a n? (s/n): "); do read (c); while (c!='s' && c!='n'); if (c == 's') { write ("m: "); read (m); write ("n: "); read (n); if (m <= 0 || m > 7 || n <= 0 || m < n) write ("Dados incompativeis"); else { comb = fat(m) / (fat(m-n) * fat(n)); write ("Num. de combinacoes: ", comb); } } } while (c == 's'); }
Quádruplas do escopo global: 1) OPENMOD, (FUNCAO, ##global), (IDLE), (IDLE) 2) CALLOP, (FUNCAO, main), (INT, 0), (IDLE) 3) EXITOP, (IDLE) , (IDLE) , (IDLE) • A quádrupla OPENMOD aloca memória para as variáveis globais • A quádrupla CALLOP chama a função main, passando-lhe zero argumentos • A função main, como é do tipo void, não produz resultado • A função main, depois de executada, retorna o controle para o escopo global • A quádrupla EXITOPencerra a execução do programa
Quádruplas da funçãomain: void main () { local: char c; int m, n; - - - - - } 1) OPENMOD, (FUNCAO, main), (IDLE), (IDLE) - - - - - 51) RETURNOP, (IDLE), (IDLE), (IDLE) OPENMOD aloca na memória as variáveis locais da função main RETURNOP: Desaloca da memória as variáveis locais da função main Retorna o controle da execução para o escopo global Sendo main do tipo void, a quádrupla RETURNOP não tem operando para retornar
do { - - - - - } while (c == 's'); 2) NOP, (IDLE), (IDLE), (IDLE) - - - - - 49) EQOP, (VAR, c), (CHAR, s), (VAR, ##25) 50) JTOP, (VAR, ##25), (IDLE), (ROTULO, 2) --------------------------------------------------------------------------- write ("Combinacao de m elementos tomados n a n? (s/n): "); 3) PARAM, (CADEIA, Combinacao de m elementos tomados n a n? (s/n): ), (IDLE), (IDLE) 4) WRITEOP, (INT, 1), (IDLE), (IDLE)
do read (c); while (c!='s' && c!='n'); 5) NOP, (IDLE), (IDLE), (IDLE) 6) PARAM, (VAR, c), (IDLE), (IDLE) 7) READOP, (INT, 1), (IDLE), (IDLE) 8) NEOP, (VAR, c), (CHAR, s), (VAR, ##8) 9) NEOP, (VAR, c), (CHAR, n), (VAR, ##9) 10) ANDOP, (VAR, ##8), (VAR, ##9), (VAR, ##10) 11) JTOP, (VAR, ##10), (IDLE), (ROTULO, 5) ------------------------------------------------------------------------------------- if (c == 's') { - - - - - } 12) EQOP, (VAR, c), (CHAR, s), (VAR, ##11) 13) JFOP, (VAR, ##11), (IDLE), (ROTULO, 48) - - - - - 48) NOP, (IDLE), (IDLE), (IDLE)
write ("m: "); read (m); write ("n: "); read (n); 14) PARAM, (CADEIA, m: ), (IDLE), (IDLE) 15) WRITEOP, (INT, 1), (IDLE), (IDLE) 16) PARAM, (VAR, m), (IDLE), (IDLE) 17) READOP, (INT, 1), (IDLE), (IDLE) 18) PARAM, (CADEIA, n: ), (IDLE), (IDLE) 19) WRITEOP, (INT, 1), (IDLE), (IDLE) 20) PARAM, (VAR, n), (IDLE), (IDLE) 21) READOP, (INT, 1), (IDLE), (IDLE)
if (m <= 0 || m > 7 || n <= 0 || m < n) write ("Dados incompativeis"); else { - - - - - } 22) LEOP, (VAR, m), (INT, 0), (VAR, ##12) 23) GTOP, (VAR, m), (INT, 7), (VAR, ##13) 24) OROP, (VAR, ##12), (VAR, ##13), (VAR, ##14) 25) LEOP, (VAR, n), (INT, 0), (VAR, ##15) 26) OROP, (VAR, ##14), (VAR, ##15), (VAR, ##16) 27) LTOP, (VAR, m), (VAR, n), (VAR, ##17) 28) OROP, (VAR, ##16), (VAR, ##17), (VAR, ##18) 29) JFOP, (VAR, ##18), (IDLE), (ROTULO, 33) 30) PARAM, (CADEIA, Dados incompativeis), (IDLE), (IDLE) 31) WRITEOP, (INT, 1), (IDLE), (IDLE) 32) JUMPOP, (IDLE), (IDLE), (ROTULO, 47) 33) NOP, (IDLE), (IDLE), (IDLE) - - - - - 47) NOP, (IDLE), (IDLE), (IDLE)
comb = fat(m) / (fat(m-n) * fat(n)); 34) PARAM, (VAR, m), (IDLE), (IDLE) 35) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##19) 36) MENOSOP, (VAR, m), (VAR, n), (VAR, ##20) 37) PARAM, (VAR, ##20), (IDLE), (IDLE) 38) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##21) 39) PARAM, (VAR, n), (IDLE), (IDLE) 40) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##22) 41) MULTOP, (VAR, ##21), (VAR, ##22), (VAR, ##23) 42) DIVOP, (VAR, ##19), (VAR, ##23), (VAR, ##24) 43) ATRIBOP, (VAR, ##24), (IDLE), (VAR, comb) write ("Num. de combinacoes: ", comb); 44) PARAM, (CADEIA, Num. de combinacoes: ), (IDLE), (IDLE) 45) PARAM, (VAR, comb), (IDLE), (IDLE) 46) WRITEOP, (INT, 2), (IDLE), (IDLE)
34) PARAM, (VAR, m), (IDLE), (IDLE) 35) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##19) 36) MENOSOP, (VAR, m), (VAR, n), (VAR, ##20) 37) PARAM, (VAR, ##20), (IDLE), (IDLE) 38) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##21) 39) PARAM, (VAR, n), (IDLE), (IDLE) 40) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##22) 41) MULTOP, (VAR, ##21), (VAR, ##22), (VAR, ##23) 42) DIVOP, (VAR, ##19), (VAR, ##23), (VAR, ##24) 43) ATRIBOP, (VAR, ##24), (IDLE), (VAR, comb) CALLOP chama a função fat Retira 1 argumento da pilha de parâmetros Deposita o argumento no parâmetro n da função fat O parâmetro n da função fat é localizado na lista de parâmetros do identificador fat na TabSmb
34) PARAM, (VAR, m), (IDLE), (IDLE) 35) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##19) 36) MENOSOP, (VAR, m), (VAR, n), (VAR, ##20) 37) PARAM, (VAR, ##20), (IDLE), (IDLE) 38) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##21) 39) PARAM, (VAR, n), (IDLE), (IDLE) 40) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##22) 41) MULTOP, (VAR, ##21), (VAR, ##22), (VAR, ##23) 42) DIVOP, (VAR, ##19), (VAR, ##23), (VAR, ##24) 43) ATRIBOP, (VAR, ##24), (IDLE), (VAR, comb) Pela TabSimb, a função fat é do tipo int Ela deve retornar um valor no 3º operando da quádrupla ##19, ##21 e ##22 são novas temporárias para guardar o valor retornado de suas respectivas chamadas Essas temporárias de retorno são usadas para o cálculo de comb Como pode haver chamadas embutidas de funções, as temporárias de retorno devem ser introduzidas numa pilha
Quádruplas da funçãofat: int fat (int n) { local: int i, fat; - - - - - returnfat; } 1) OPENMOD, (FUNCAO, fat), (IDLE), (IDLE) - - - - - 22) RETURNOP, (VAR, fat), (IDLE), (IDLE) OPENMOD aloca na memória as variáveis locais da função fat RETURNOP: Desaloca da memória as variáveis locais e os parâmetros da função fat Retorna o controle da execução para a função main Pela TabSimb, a função fat do tipo int Então, RETURNOP deve retirar da pilha de variáveis de retorno uma para guardar o valor a ser retornado Essa variável deve ter sido empilhada pela função que a chamou
2) LTOP, (VAR, n), (INT, 0), (VAR, ##1) 3) GTOP, (VAR, n), (INT, 7), (VAR, ##2) 4) OROP, (VAR, ##1), (VAR, ##2), (VAR, ##3) 5) JFOP, (VAR, ##3), (IDLE), (ROTULO, 9) 6) MENUNOP, (INT, 1), (IDLE), (VAR, ##4) 7) ATRIBOP, (VAR, ##4), (IDLE), (VAR, fat) 8) JUMPOP, (IDLE), (IDLE), (ROTULO, 21) 9) NOP, (IDLE), (IDLE), (IDLE) 10) ATRIBOP, (INT, 1), (IDLE), (VAR, fat) 11) ATRIBOP, (INT, 2), (IDLE), (VAR, i) 12) NOP, (IDLE), (IDLE), (IDLE) 13) LEOP, (VAR, i), (VAR, n), (VAR, ##5) 14) JFOP, (VAR, ##5), (IDLE), (ROTULO, 20) 15) MULTOP, (VAR, fat), (VAR, i), (VAR, ##6) 16) ATRIBOP, (VAR, ##6), (IDLE), (VAR, fat) 17) MAISOP, (VAR, i), (INT, 1), (VAR, ##7) 18) ATRIBOP, (VAR, ##7), (IDLE), (VAR, i) 19) JUMPOP, (IDLE), (IDLE), (ROTULO, 12) 20) NOP, (IDLE), (IDLE), (IDLE) 21) NOP, (IDLE), (IDLE), (IDLE) if (n < 0 || n > 7) fat = ~1; else { fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } }
7.2 – Estruturas de Dados As listas de quádruplas de cada subprograma:
Estrutura de uma quádrupla: • Estrutura de um operando: • Estrutura de um cabeçalho de função (funchead): As declarações foram vistas no lab
Protótipos das funções para construir o código intermediário: void InicCodIntermed (void); voidInicCodIntermFunc (simbolo); voidImprimeQuadruplas (void); quadruplaGeraQuadrupla (int, operando, operando, operando); simboloNovaTemp (int);
Função InicCodIntermed: inicializa a estrutura do código intermediário, deixando-a assim:
Função InicCodIntermFunc (simbolosimb): inicializa o código intermediário da função cujo nome está na tabela de símbolos apontada por simb; Deixa a estrutura do código intermediário assim:
7.3 – Quádruplas para Alguns Comandos • Apresentada a seguir, programação para construir o código intermediário de comandos não abordados nas aulas de laboratório: • Comando do-while • Comando for • Comando case
7.3.1 – Quádruplas para o comando do-while Seja o seguinte trecho de programa: local: inti, j, h; statements: - - - - - do {i = i + h; j = j - h; } while (i < j); i = 0; - - - - - • A programação para isso está na produção do não terminal CmdDo a seguir Suas possíveis quádruplas: 2) NOP, (IDLE), (IDLE), (IDLE) 3) MAISOP, (VAR, i), (VAR, h), (VAR, ##1) 4) ATRIBOP, (VAR, ##1), (IDLE), (VAR, i) 5) MENOSOP, (VAR, j), (VAR, h), (VAR, ##2) 6) ATRIBOP, (VAR, ##2), (IDLE), (VAR, j) 7) LTOP, (VAR, i), (VAR, j), (VAR, ##3) 8) JTOP, (VAR, ##3), (IDLE), (ROTULO, 2) 9) ATRIBOP, (INT, 0), (IDLE), (VAR, i)
CmdDo : DO { $<quad>$ = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } Comando WHILE ABPAR Expressao { - - - - - opndaux.tipo = ROTOPND; opndaux.atr.rotulo = $<quad>2; GeraQuadrupla (JTOP, $6.opnd, opndidle, opndaux); } FPAR PVIRG ; Comando $2 JTOP ##n ---- ROT NOP ----- ----- ----- ----- ----- ----- ##n Expressão
2) ATRIBOP, (INT, 0), (IDLE), (VAR, s) 3) ATRIBOP, (INT, 1), (IDLE), (VAR, p) 4) ATRIBOP, (INT, 1), (IDLE), (VAR, i) 5) NOP, (IDLE), (IDLE), (IDLE) 6) LEOP, (VAR, i), (VAR, n), (VAR, ##1) 7) JFOP, (VAR, ##1), (IDLE), (ROTULO, 17) 8) NOP, (IDLE), (IDLE), (IDLE) 9) MAISOP, (VAR, s), (VAR, i), (VAR, ##3) 10) ATRIBOP, (VAR, ##3), (IDLE), (VAR, s) 11) MULTOP, (VAR, p), (VAR, i), (VAR, ##4) 12) ATRIBOP, (VAR, ##4), (IDLE), (VAR, p) 13) NOP, (IDLE), (IDLE), (IDLE) 14) MAISOP, (VAR, i), (INT, 1), (VAR, ##2) 15) ATRIBOP, (VAR, ##2), (IDLE), (VAR, i) 16) JUMPOP, (IDLE), (IDLE), (ROTULO, 5) 17) NOP, (IDLE), (IDLE), (IDLE) 18) ATRIBOP, (INT, 0), (IDLE), (VAR, i) 7.3.2 – Quádruplas para o comando for Seja o seguinte trecho de programa: local: int i, n, s, p; statements: - - - - - s = 0; p = 1; for (i = 1; i <= n; i = i + 1) { s = s + i; p = p * i; } i = 0; Possíveis quádruplas
A ordem das quádruplas deve ser corrigida CmdFor : FOR ABPAR CmdAtrib PVIRG { $<quad>$ = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } Expressao { - - - - - opndaux.tipo = ROTOPND; $<quad>$ = GeraQuadrupla (JFOP, $6.opnd, opndidle, opndaux); } PVIRG { $<quad>$ = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } CmdAtrib FPAR { $<quad>$ = quadcorrente; } { $<quad>$ = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); } Comando { quadaux = quadcorrente; opndaux.tipo = ROTOPND; opndaux.atr.rotulo = $<quad>5; quadaux2 = GeraQuadrupla (JUMPOP, opndidle, opndidle, opndaux); $<quad>7->result.atr.rotulo = GeraQuadrupla (NOP, opndidle, opndidle, opndidle); - - - - - Correcao da ordem das quadruplas - - - - - } ;
CmdAtrib 1 Comando CmdAtrib 2 $5 NOP Ordem na qual as quádruplas foram geradas: Expressão $7 JFOP, ##expr, --- , rot $9 NOP $12 $13 NOP Comando deve ser executado antes de CmdAtrib2 quadaux quadaux2 JUMP, --- , --- , rot NOP
CmdAtrib 1 Comando CmdAtrib 2 • Correção da ordem das quádruplas: • $<quad>7->prox = $<quad>13; • quadaux->prox = $<quad>9; • $<quad>12->prox = quadaux2; • RenumQuadruplas ($<quad>7, quadcorrente); $5 NOP Expressão $7 JFOP, ##expr, --- , rot $9 NOP $12 $13 NOP quadaux Agora Comando será executado antes de CmdAtrib2 quadaux2 JUMP, --- , --- , rot NOP
7.3.3 – Quádruplas para o comando case Seja o seguinte trecho de programa: local: inti, n, s; statements: - - - - - case (i + j) { 1, 2, 3: {i = i + 1; j = j + 2;} 4, 5: {i = i + 3; j = j - 1;} 6: case (i - j) {1, 2: i = i * j;3: j = j + i;} 7: j = i - j; default: i = 0; } - - - - - Aninhamento de dois comandos case A seguir possíveis quádruplas para ele
case (i + j) 1, 2, 3: 2) MAISOP, (VAR, i), (VAR, j), (VAR, ##1) 3) EQOP, (VAR, ##1), (INT, 1), (VAR, ##2) 4) JTOP, (VAR, ##2), (IDLE), (ROTULO, 10) 5) EQOP, (VAR, ##1), (INT, 2), (VAR, ##3) 6) JTOP, (VAR, ##3), (IDLE), (ROTULO, 10) 7) EQOP, (VAR, ##1), (INT, 3), (VAR, ##4) 8) JTOP, (VAR, ##4), (IDLE), (ROTULO, 10) 9) JUMPOP, (IDLE), (IDLE), (ROTULO, 16) 10) NOP, (IDLE), (IDLE), (IDLE) 11) MAISOP, (VAR, i), (INT, 1), (VAR, ##5) 12) ATRIBOP, (VAR, ##5), (IDLE), (VAR, i) 13) MAISOP, (VAR, j), (INT, 2), (VAR, ##6) 14) ATRIBOP, (VAR, ##6), (IDLE), (VAR, j) 15) JUMPOP, (IDLE), (IDLE), (ROTULO, 64) 4, 5: { i = i + 1; j = j + 2; } Final do case externo
4, 5: 6: 16) NOP, (IDLE), (IDLE), (IDLE) 17) EQOP, (VAR, ##1), (INT, 4), (VAR, ##7) 18) JTOP, (VAR, ##7), (IDLE), (ROTULO, 22) 19) EQOP, (VAR, ##1), (INT, 5), (VAR, ##8) 20) JTOP, (VAR, ##8), (IDLE), (ROTULO, 22) 21) JUMPOP, (IDLE), (IDLE), (ROTULO, 28) 22) NOP, (IDLE), (IDLE), (IDLE) 23) MAISOP, (VAR, i), (INT, 3), (VAR, ##9) 24) ATRIBOP, (VAR, ##9), (IDLE), (VAR, i) 25) MENOSOP, (VAR, j), (INT, 1), (VAR, ##10) 26) ATRIBOP, (VAR, ##10), (IDLE), (VAR, j) 27) JUMPOP, (IDLE), (IDLE), (ROTULO, 64) { i = i + 3; j = j - 1; } Final do case externo
6: 7: 28) NOP, (IDLE), (IDLE), (IDLE) 29) EQOP, (VAR, ##1), (INT, 6), (VAR, ##11) 30) JTOP, (VAR, ##11), (IDLE), (ROTULO, 32) 31) JUMPOP, (IDLE), (IDLE), (ROTULO, 54) 32) NOP, (IDLE), (IDLE), (IDLE) 33) MENOSOP, (VAR, i), (VAR, j), (VAR, ##12) 34) EQOP, (VAR, ##12), (INT, 1), (VAR, ##13) 35) JTOP, (VAR, ##13), (IDLE), (ROTULO, 39) 36) EQOP, (VAR, ##12), (INT, 2), (VAR, ##14) 37) JTOP, (VAR, ##14), (IDLE), (ROTULO, 39) 38) JUMPOP, (IDLE), (IDLE), (ROTULO, 43) 39) NOP, (IDLE), (IDLE), (IDLE) 40) MULTOP, (VAR, i), (VAR, j), (VAR, ##15) 41) ATRIBOP, (VAR, ##15), (IDLE), (VAR, i) 42) JUMPOP, (IDLE), (IDLE), (ROTULO, 52) case (i – j) 1, 2: 3: i = i * j Final do case interno
3: 43) NOP, (IDLE), (IDLE), (IDLE) 44) EQOP, (VAR, ##12), (INT, 3), (VAR, ##16) 45) JTOP, (VAR, ##16), (IDLE), (ROTULO, 47) 46) JUMPOP, (IDLE), (IDLE), (ROTULO, 51) 47) NOP, (IDLE), (IDLE), (IDLE) 48) MAISOP, (VAR, j), (VAR, i), (VAR, ##17) 49) ATRIBOP, (VAR, ##17), (IDLE), (VAR, j) 50) JUMPOP, (IDLE), (IDLE), (ROTULO, 52) 51) NOP, (IDLE), (IDLE), (IDLE) 52) NOP, (IDLE), (IDLE), (IDLE) 53) JUMPOP, (IDLE), (IDLE), (ROTULO, 64) j = j + i; default vazio Final do case interno Final do case externo
7: 54) NOP, (IDLE), (IDLE), (IDLE) 55) EQOP, (VAR, ##1), (INT, 7), (VAR, ##18) 56) JTOP, (VAR, ##18), (IDLE), (ROTULO, 58) 57) JUMPOP, (IDLE), (IDLE), (ROTULO, 62) 58) NOP, (IDLE), (IDLE), (IDLE) 59) MENOSOP, (VAR, i), (VAR, j), (VAR, ##19) 60) ATRIBOP, (VAR, ##19), (IDLE), (VAR, j) 61) JUMPOP, (IDLE), (IDLE), (ROTULO, 64) 62) NOP, (IDLE), (IDLE), (IDLE) 63) ATRIBOP, (INT, 0), (IDLE), (VAR, i) 64) NOP, (IDLE), (IDLE), (IDLE) j = j + i; default: i = 0; Final do case externo
Nesse exemplo, observa-se que o rótulo das quádruplas de desvio 4, 6, e 8 somente serão preenchidos, quando a quádrupla 10 for gerada; o mesmo vale para: • Quádruplas de desvio 18, 20 e quádrupla 22 • Quádruplas de desvio 30 e quádrupla 32 • Quádruplas de desvio 35, 37 e quádrupla 39 • Quádrupla de desvio 45 e quádrupla 47 • Quádruplas de desvio 15, 27, 53 e quádrupla 64 • Quádruplas de desvio 42, 50 e quádrupla 52 Para esse preenchimento, essas quádruplas podem ser colocadas numa lista de quádruplas a fazer parte do atributo dos não-terminais da formação do comando case Quando a quádrupla destino dos desvios for gerada, tais rótulos serão preenchidos
Observa-se também que o resultado da expressão central do case será o primeiro operando de várias quádruplas: • No 1o case: operando (VAR, ##1) nas quádruplas 3, 5, 7, 17, 19, 29 e 55 • No 2o case: operando (VAR, ##12) nas quádruplas 34, 36 e 44 • É conveniente que esses operandos sejam colocados numa pilha apropriada, no momento em que a expressão central de seu case é analisada, e sejam dela retirados no final da análise do seu case • As estruturas para tais listas de quádruplas e tal pilha de operandos bem como as declarações e programação para a geração de quádruplas para comandos case ficam como exercício
7.4 – Quádruplas para Ponteiros Seja o seguinte trecho de programa: local: int a, b, x, @y; statements: y := &x; x := #y + a; #y := a + b; Suas possíveis quádruplas: 2) ENDEROP, (VAR, x), (IDLE), (VAR, ##1) 3) ATRIBOP, (VAR, ##1), (IDLE), (VAR, y) 4) CONTAPONT, (VAR, y), (IDLE), (VAR, ##2) 5) MAISOP, (VAR, ##2), (VAR, a), (VAR, ##3) 6) ATRIBOP, (VAR, ##3), (IDLE), (VAR, x) 7) MAISOP, (VAR, a), (VAR, b), (VAR, ##4) 8) ATRIBPONT, (VAR, ##4), (IDLE), (VAR, y)
Produções para referências a ponteiros: Fator : Variavel | CTINT | CTREAL | CTCHAR | TRUE | FALSE | ~ Fator | ( Expressao ) | CallFunc | # Variavel CmdAtrib : LadoEsquerdo := Expressao ; | LadoEsquerdo := & Variavel ; LadoEsquerdo: Variavel | # Variavel A programação para a geração de quádruplas envolvendo ponteiros fica como exercício
7.5 – Quádruplas para Subprogramação Produções envolvidas: Comando : CallMod CallMod : CALL CallFunc PVIRG CallFunc : ID ABPAR Argumentos FPAR Argumentos : | ListExpr ListExpr : Expressao | ListExpr VIRG Expressao CmdReturn : RETURN PVIRG | RETURN Expressao PVIRG Fator : CallFunc
7.5.1 – Chamada de subprogramas Exemplo: na função main do programa inicial, o comando comb = fat(m) / (fat(m-n) * fat(n)); tem as seguintes quádruplas: 34) PARAM, (VAR, m), (IDLE), (IDLE) 35) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##19) 36) MENOSOP, (VAR, m), (VAR, n), (VAR, ##20) 37) PARAM, (VAR, ##20), (IDLE), (IDLE) 38) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##21) 39) PARAM, (VAR, n), (IDLE), (IDLE) 40) CALLOP, (FUNCAO, fat), (INT, 1), (VAR, ##22) 41) MULTOP, (VAR, ##21), (VAR, ##22), (VAR, ##23) 42) DIVOP, (VAR, ##19), (VAR, ##23), (VAR, ##24) 43) ATRIBOP, (VAR, ##24), (IDLE), (VAR, comb)
Nas produções dos não-terminais ListExpre Argumentos: ListExpr : Expressao { $$.nargs = 1; $$.listtipo = InicListTipo ($1.tipo); GeraQuadrupla (PARAM, $1.opnd, opndidle, opndidle); } | ListExpr VIRG Expressao { $$.narg = $1.narg + 1; $$.listtipo = ConcatListTipo ($1.listtipo, InicListTipo ($3.tipo)); GeraQuadrupla (PARAM, $3.opnd, opndidle, opndidle); } ; Argumentos : {$$.nargs = 0; $$.listtipo = NULL;} | ListExpr /* default: $$ = $1; */
O não-terminal CallFuncpode ter o mesmo atributo que o não-terminal Variavel: %type <infovar> VariavelCallFunc • Onde: • E também: • Então o atributo de CallFunc tem dois campos: simb e opnd %union { - - - - - infovariavel infovar; - - - - - } typedef struct infovariavel infovariavel; struct infovariavel { simbolo simb; operando opnd; };
Mais um campo na TabSimb: um ponteiro para um funchead Na produção do não-terminal CallFunc: CallFunc : ID ABPAR { simb = ProcuraSimb ($1, escopo->escopo); $<simb>$ = simb;if (! simb) NaoDeclarado ($1); } Argumentos FPAR { $$.simb = $<simb>3; - - - - - Testes de compatibilidade - - - - - opnd1.tipo = FUNCOPND;opnd1.atr.func = $$.simb->fhead; opnd2.tipo = INTOPND;opnd2.atr.valint = $4.nargs; if ($$.simb->tvar == NAOVAR) result = opndidle; else {result.tipo = VAROPND; result.atr.simb = NovaTemp ($$.simb->tvar);} GeraQuadrupla (CALLOP, opnd1, opnd2, result); $$.opnd = result; } ;
Na produção do não-terminal Fator: Fator : CallFunc { if ($1.simb != NULL) { $$.tipo = $1.simb->tvar; $$.opnd = $1.opnd; } } ; • Não há programação especial para a produção: CallMod : CALL CallFunc PVIRG ;
7.5.3 – Retorno de subprogramas • Nas produções do não-terminal CmdReturn CmdReturn : RETURN { GeraQuadrupla (RETURNOP, opndidle, opndidle, opndidle); } | RETURN Expressao { GeraQuadrupla (RETURNOP, $2.opnd, opndidle, opndidle); } ;
Para o caso de uma função não ter retorno explícito, deve-se gerar uma quádrupla com a operação de retornar • Isso é feito na produção do não terminal Cmds: Cmds : STATEMENTS ABCHAV ListCmds FCHAV { if (quadcorrente->oper != RETURNOP) GeraQuadrupla (RETURNOP, opndidle, opndidle, opndidle); - - - - - } ; • Lembrando o contexto do não-terminal Cmds: Modulo : CabecalhoDeclLocsCmds Garante que a última quádrupla de qualquer função é um RETURN Mesmo que a função tenha RETURN fora do final