Ações semânticas para gramática ZooAZ – Compiladores 2004-2 (De Lucca) AÇÃO [0] Antes de tudo, a parte semântica deve ser inicializada. Abaixo, a lista de elementos necessários para a execução das ações semânticas. Inicializar variáveis auxiliares e contadores tipo: valores possívels: int/bool/caracter/flut/nada categoria: var.simples/vetor/procedimento/função/constante/parâmetro/nomeprograma deslocamento: controla a posição da declaração de cada identificador. Cada variável simples incrementará o deslocamento de 1 deslocString: controla a posição da declaração de strings. Cada string incrementará o deslocString de 1. O deslocString fará papel de apontador na tabela de Strings contaParâmetros: contador de parâmetros declarados escopo: controla o escopo de declaração dos identificadores geradoRET: controla se foi ou não gerada a instrução RET em uma função TS: tabela de símbolos ou de identificadores. Tabela de Strings: vetor que conterá todos os strings do programa, sequencialmente, indexados pelo deslocString. Área de geração de código: pode-se imaginar um vetor de triplas (Operador, operando1, operando2), indexado sequencialmente e controlado por um IG – índice de geração). Sempre que se gera uma instrução, o IG é incrementado. diversas pilhas para solução de referências futuras pilhas de desvios para Principal pilha de solução de enquanto (pilhaEnquanto) pilha de solução de para (pilhaPara) pilha de solução de faça-enquanto (pilhaFaça) pilhas de solução de se-senão (pilhaSE) outras que se fizerem necessárias pilhaOP: pilha de apoio à geração de código de operações aritméticas e lógicas [1] <ZooA> ::= #0 <import> programa ID #1 "{" <corpo> "}" #2 ; Incluir ID na TS com atributos adequados (categoria=nome programa, escopo=0) Gerar AMEM 0,3 [2] <ZooA> ::= #0 <import> programa ID #1 "{" <corpo> "}" #2 ; Verificar se há pendências nas pilhas (-> ERRO1) [3] <import> ::= importar ID #3 ";" <import> OBS: Não será feita importação de arquivos neste semestre <tipo> ::= int #7 | bool #8 | caracter #9 | flutuante <tiponada> ::= <tipo> | nada #11 ; [7]tipo = int [8]tipo = bool [9]tipo = caracter [10]tipo = flutuante [11]tipo = nada #10 ; [12] <declara> ::= <tiponada> ID #12 <declrotvar> 1Sempre que ocorrer um ERRO, deve ser cancelada a geração de código. A análise pode continuar, mas qualquer que seja o código gerado não deverá ser considerado correto. 7 se existe ID na TS no mesmo escopo então ERRO(“Já declarado”) senão monta tupla provisória para incluir na TS (ainda não sabe se categoria é variável ou sub-rotina ou vetor) – dados disponíveis: ID, escopo, tipo e modo [13] <declrotvar> ::= #13 ';' (é declaração de variável) se tipo =int ou caracter ou bool gera instrução AMEM (0,1) inclui a tupla provisória na TS completando categoria=”variável simples”, sem inicialização, deslocamento deslocamento++ senão se tipo =flutuante NÃO FAZ NADA – Flutuante excluído da linguagem neste semestre senão o tipo será nada: ERRO("'Nada' não permitido em declaração de variável") [14] <declrotvar> ::= #14 '=' <inicial> #15 ';' idem ação #13 mas com inicialização: Guardar a posição utilizada da TS em uma variável temporária para posteriormente a #15 possa colocar o valor da inicialização [15] <declrotvar> ::= #14 '=' <inicial> #15 ';' Atualizar a entrada da TS (posição salva na #14) com o valor da inicialização Gerar CRCT (0, valor da inicialização) Gerar ARMZ (0, deslocamento), utilizando o deslocamento da variável da entrada da TS salva em #14 <inicial> ::= cteint #16 | cteflut #17 | litcar #18 [16] se tipo <> int : ERRO(Tipos incompatíveis) senão salva valor da cteint em variável temporária para usar em #15, em #28 ou em #41 [17] FLUTUANTE retirado da linguagem neste semestre. Gerar ERRO ("Flutuante não suportado"). [18] idem #16 para caracter [19] <inicial>::= ID #19 ; se ID existe na TS e é o nome de uma constante salva valor da constante (recuperar da TS) em variável temporária para usar em #15, #28 ou em #41 senão ERRO: Constante não declarada ou identificador não declarado como constante [21] <declrotvar> ::= #21 '[' cteint #22 ']' ';' OBS: VETOR RETIRADO DA LINGUAGEM - Não fazer testes com vetores. [22] <declrotvar> ::= #21 '[' cteint #22 ']' ';' [23]<declrotvar> ::= #23 '(' <listaargs> #24 ')' #51 <bloco> #52 se tipo==nada categoria = procedimento se tipo== int ou caracter ou bool categoria = função Gerar DSVS -,? , empilhando o endereço onde foi gerada a instrução (IG) para resolver ao final da sub-rotina (use a pilha de desvios para Principal) incluir tupla provisória (criada em #12) na TS, completando categoria (definida acima) e 7 endereço (posição do início de geração de código da sub-rotina = IG seguinte ao DSVS gerado) escopo++ contaParametros = 0 guardar posição onde a tupla foi incluída na TS para retornar e colocar o nº de parâmetros (será feito em #24) geradoRET = falso (será verificado, no final do bloco, se foi gerado o return) [24]<declrotvar> ::= #23 '(' <listaargs> #24 ')' #51 <bloco> atualizar entrada na TS correspondente à subrotina, com o nº de parâmetros atualizar entradas dos parâmetros com deslocamentos negativos exemplo: nada xyz ( int a, bool b, int c) deslocamento de a = -3 deslocamento de b = -2 deslocamento de c = -1 #52 [25] <listaargs> ::= <tipo> ID #25 <repargs> se tipo == nada ou flutuante: ERRO(Tipos não admitidos como parâmetros) senão se a ID já existe na TS no mesmo escopo: ERRO(Já declarado) senão inserir na TS: ID, tipo, escopo, categoria=parâmetro contaParâmetros++ [26] <declara> ::= categoria = constante final #26 <tipo> ID #27 '=' <inicial> #28 ';' [27] <declara> ::= final #26 <tipo> ID #27 '=' <inicial> #28 ';' se tipo == nada ou flutuante: ERRO(Tipo inválido) senão se a ID já existe na TS no mesmo escopo: ERRO(Já declarado) senão inserir na TS: ID, tipo, modo, escopo, categoria [28] <declara> ::= final #26 <tipo> ID #27 '=' <inicial> #28 ';' atualizar última entrada da TS (constante) com valor da inicialização (variável temporária definida em #16, #17, #18, #19) [29] <declara> ::= string ID #29 '=' litstring #30 ';' se a ID já existe na TS no mesmo escopo: ERRO(Já declarado) senão incluir na TS: ID, modo, escopo, categoria=string, tipo=string, deslocString [30] <declara> ::= string ID #29 '=' litstring #30 ';' incluir litstring na Tab de strings, na posição definida por deslocString deslocString++ [31] <corpo> ::= principal '(' ')' #31 <bloco> #53 <corpo> incluir na TS: ID='Principal', tipo=nada, categoria=procedimento, escopo=0, nºparam=0 e endereço de geração de código correspondente ao início da função 'Principal' (IG atual) resolver desvios pendentes gerados em #23 (pilha de desvios para Principal), usando o endereço de geração de código que corresponderá ao início da função 'Principal'. Comando SE [32] <cmdse> ::= se '(' <cond> ')' #32 <bloco> <cmdse2> #34 Empilhar IG na pilhaSE (onde o DSVF abaixo será gerado) 7 Gerar DSVF -,? (com endereço de destino pendente que será resolvido em #33 ou #34) [33] <cmdse2> ::= #33 senão <bloco> Gerar DSVS -,? (com endereço de destino pendente que será resolvido em #34) Resolver referência pendente do topo da pilhaIF, usando IG atual e desempilhar Empilhar IG-1 (referente ao DSVS gerado acima) na pilhaIF [34] <cmdse> ::= se '(' <cond> ')' #32 <bloco> <cmdse2> #34 Resolver referência pendente (cujo endereço está no topo da pilhaIF) usando IG e desempilhar (pode ter sido empilhado em #32 ou em #33) Comando FAÇA: [35] <cmdfaca> ::= #35 faça <bloco> enquanto '(' <cond> ')' #36 Empilhar IG na pilhaFaça [36] <cmdfaca> ::= #35 faça <bloco> enquanto '(' <cond> ')' #36 Gerar (DSVT -,end) usando o topo da pilhaEnquanto como endereço e desempilhar Comando ENQUANTO: [37] <cmdeqto> ::= #37 enquanto '(' <cond> #38 ')' <bloco> Empilhar IG na pilhaEnquanto [38] <cmdeqto> ::= #37 enquanto '(' <cond> #38 ')' <bloco> Empilhar IG na pilhaEnquanto (endereço onde o DSVF abaixo será gerado) Gerar DSVF -,? (endereço ficará pendente para resolução futura) #39 #39 [39] <cmdeqto> ::= #37 enquanto '(' <cond> #38 ')' <bloco> #39 Resolver referência pendente do topo da pilhaEnquanto usando IG+1 e desempilhar Gerar (DSVS -,end) usando o novo topo da pilhaEnquanto como endereço Comando FOR: [40] <cmdpara> ::= para "(" ID #40 "=" <inicial> #41 ";" <cond> #42 ";" #43 <expr> #44 ")" <bloco> #45 ; As ações para o COMANDO PARA deverão ser definidas e implementadas pelo grupo. As posições de ações definidas acima são sugestões de uma possível solução. [46] <cmdatrib> ::= ID #46 <contatrib> Se ID não está na TS: ERRO(Não declarado: Não se pode chamar PROCEDIMENTO que não tenha sido declarado anteriormente) senão Se ID está na TS como função/nome de prog/const: ERRO(deve ser variável, parâmetro ou procedimento) senão Salvar, em tupla temporária, os dados da TabSimb correspondentes ao ID [47] <contatrib> ::= '=' <cond> #47 Gerar (ARMZ base, desloc) usando informações da tupla temporária salva em #46 [48] <contatrib> ::= '(' #48 <listaparam> #49 ')' Se ID não é procedimento (ver dados da tupla temporária): ERRO(Esperava-se procedimento) senão Zerar contaParam [49] <contatrib> ::= '(' #48 <listaparam> #49 ')' Se contaParam <> nº parâmetros da tupla temporária salva em [46] ERRO(Nº de 7 parâmetros incorreto) senão Gerar (CALL base, end) usando informações da tupla temporária salva em #46 base = escopo atual – escopo de declaração da sub-rotina (ver tupla) end = endereço do procedimento (ver tupla) [50] <listaparam> ::= <expr> #50 <rlista> <rlista> ::= <expr> #50 <rlista> Incrementar contaParam [51] <declrotvar> ::= #23 '(' <listaargs> #24 ')' #51 <bloco> #52 Gerar AMEM 0,3 <<reservando espaço para o registro de ativação [52] <declrotvar> ::= #23 '(' <listaargs> #24 ')' #51 <bloco> #52 Decrementar escopo Se categoria é função e se variável geradoRET=false: ERRO(falta return) Se categoria é procedimento, gerar RET -,n (n é o nº de parâmetros do procedimento) Resolver DSVS gerado em #23 (endereço guardado na pilha de desvios para Principal), usando o IG atual [53] <corpo> ::= principal '(' ')' #31 <bloco> #53 <corpo> Verificar se há pendências em aberto nas diversas pilhas. Se houver, gerar o erro equivalente. Senão Gerar PARA -,[54] <clauresult> ::= resultado <cond> #54 Se categoria não é função: ERRO(Não é função) senão Gerar ARMZ n,0 n é o escopo atual -> isto fará com que o valor de retorno seja copiado para a posição mais baixa da pilha de execução (qdo o código for executado) Gerar RET -,K (K é o nº de parâmetros do procedimento – ver TabSimb) Fazer geradoRET = true [57] <clausula> ::= '!' <valor> #57 Gerar NEGA -,[58] <cond2> ::= '&&' <clausula> #58 <cond2> Gerar CONJ -,[59] <cond2> ::= '||' <clausula> #59 <cond2> Gerar DISJ -,[60] <oprel> ::= '>' #60 | '<' #61 | '>=' #62 | '<=' #63 | '==' #64 | '!=' #65 Empilhar "maior" na pilhaOP [61] Empilhar "menor" na pilhaOP [62] Empilhar "maior-igual" na pilhaOP [63] Empilhar "menor-igual" na pilhaOP [64] 7 Empilhar "igual" na pilhaOP [65] Empilhar "dif" na pilhaOP [66] <valor> ::= <expr> <oprel> <expr> #66 Gerar instrução de comparação correspondente à operação do topo da pilhaOP e desempilhar se topo="maior" – Gerar CMMA -, se topo="igual" – Gerar CMIG -,etc [67] <optermo> ::= '+' #67 | '-' #68 Empilhar "soma" na pilhaOP [68] Empilhar "subt" na pilhaOP [69] <expr2> ::= <optermo> <termo> #69 <expr2> Gerar instrução aritmética conforme topo da pilhaOP e desempilhar se topo="soma" – Gerar SOMA -, se topo="subt" – Gerar SUB -,[70] <opfator> ::= '*' #70 | '/' #71 | '%' #72 Empilhar "mult" na pilhaOP [71] Empilhar "div" na pilhaOP [72] Empilhar "rest" na pilhaOP [73] <termo2> ::= <opfator> <fator> #73 <termo2> Gerar instrução arimética conforme topo da pilhaOP e desempilhar se topo="mult" – Gerar MULT -, se topo="div" – Gerar DIV -, se topo="rest" – Gerar MOD -,[74] <fator> ::= '-' <fator> #74 Gerar MUNARIO -,[75] <litnum> ::= cteint #75 Gerar CRCT -,cteint Fazer tipo="int" [76] <litnum> ::= cteflutuante #76 Flutuante retirado da linguagem neste semestre. Só faz: tipo="flutuante" [77] <fator> ::= litcar #77 Gerar CRCT -,código(litcar) (usar o código ASCII ou Unicode do caracter) Fazer tipo="caracter" [78] <fator> ::= litstring #78 Armazenar "litstring" na Tabela de Strings (deslocString++) Gerar CRCT -,deslocString (posição da TabString onde o litstring foi armazenado) Fazer tipo="string" [79] <fator> ::= ID #79 <contid> OBS: Não se pode chamar FUNÇÃO NÃO pré-declarada Se ID está na TS e não for variável, vetor, função ou cte: ERRO(uso indevido) 7 senão Salvar dados do ID em uma tupla temporária para usar em #80/81 [80] <contid> ::= @ #80 Se ID é constante Gerar CRCT -,x (x é o valor pré-declarado – está na tupla temporária) Fazer tipo="int" senão se ID é var.string Gerar CRCT -,deslocString (está na tupla temporária) Fazer tipo="string" se ID é outro tipo de variável ou parâmetro Gerar CRVL base, desloc (ver tupla temporária) Fazer tipo=(ver tipo definido na tupla temporária) senão ERRO(Esperava-se variável, parâmetro ou constante) [81] <contid> ::= #81 '(' <listaparam> #82 ')' Se ID (ver tupla temporária) não é função: ERRO(Esperava-se função) Senão Zerar contaParam Fazer tipo=(ver tipo definido na tupla temporária) [82] <contid> ::= #81 '(' <listaparam> #82 ')' Se contaParam <> nºparametros declarados (ver tupla temporária): ERRO(nº parâmetros incorreto) Gerar CALL base, end Gerar CRVL dif, 0 dif é o escopo atual: servirá para carregar o resultado da função que está no fundo da pilha de execução [83] <fator> ::= ler '(' ')' #83 Gerar instrução LEIT -,- (deixa o valor lido no topo da pilha – se for lido um caracter, deve-se utilizar o valor do código correspondente (Unicode ou Ascii)) [84] <cmdsaida> ::= escrever "(" <expr> #84 ")"; Se tipo da <expr> for "string" (consultar variável "tipo") Gerar instrução IMPRLIT _,_ (utilizará o valor do topo da pilha de execução para acessar a TabStrings e colocar o string na tela) Se tipo é "caracter" Gerar instrução IMPRCH _,_ (o valor do topo da pilha é um código ASCII ou Unicode. Deverá ser convertido p/o caracter adequado e depois exibido) Se tipo é "booleano" Gerar instrução IMPRBL _,_ (o valor do topo da pilha é 0 (false) ou 1 (true). IMPRBL imprimirá a F ou V, respectivamente) Se tipo é "int" Gerar instrução IMPR _,_ Outros: ERRO(Não implementado nesta versão) 7