Ações semânticas para gramática ZooG1 – Compiladores 2006-1 (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: variavel/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 (valor inicial = 3) 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 TI: tabela de identificadores (ou tabela de símbolos) Tabela de Strings: vetor que conterá todos os strings do programa, sequencialmente, indexados pelo deslocString. EG – endereço de geração. EG deve conter o endereço onde será gerada a próxima instrução. Valor inicial de EG-> 0 (se considerar que a área de geração é um vetor cujo primeiro elemento tem índice 0). Sempre que se gera uma instrução, o EG é incrementado Área de geração de código: pode-se imaginar um vetor de triplas (Operador, operando1, operando2), indexado sequencialmente e controlado por EG 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] <ZooG> ::= #0 <import> programa ID #1 "{" <corpo> "}" #2 ; Incluir ID na TI com atributos adequados (categoria=nome programa, escopo=0) [2] <ZooG> ::= #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 1 #10 ; Sempre 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 [11] tipo = nada [12] <declara> ::= <tiponada> ID #12 <declrotvar> se existe ID na TI no mesmo escopo então ERRO(“Já declarado”) senão reúne mais informações para incluir na TI (ainda não sabe se categoria é variável ou função ou vetor) – dados disponíveis: ID, escopo e tipo [13] <declrotvar> ::= ';' #13 (é declaração de variável) se tipo =int gera instrução AMEM 1 incluir na TI os dados reunidos em #11, completando categoria=”variável simples” e end.relativo=deslocamento deslocamento++ senão se tipo =flutuante ou caracter ou bool NÃO FAZ NADA – excluídos 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 [15] <declrotvar> ::= #14 '=' <inicial> #15 ';' Gerar PUSHK (valor da inicialização) (o valor da inicialização virá da ação #16) Gerar POP 0, deslocamento, utilizando o end.relativo da última variável incluída na TI (que é igual ao valor atual da variável deslocamento, menos 1) <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 #17 para caracter [19] <inicial>::= ID #19 ; RETIRADA A POSSIBILIDADE DE INICIALIZAÇÂO COM CONSTANTE NESTE SEMESTRE. Gerar ERRO(“Constante não suportada neste ponto”) [21] <declrotvar> ::= '[' #21 cteint #22 ']' ';' [22] <declrotvar> ::= '[' #21 cteint #22 ']' ';' OBS: SINTAXE E SEMÂNTICA DE VETOR DEFINIDAS POR VOCÊS. ISTO AQUI É SÓ UM EXEMPLO... [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 esta instrução para resolver ao final da sub-rotina (empilhe na pilha de desvios para Principal) incluir na TI os dados reunidos em #12, completando categoria (definida acima) e 7 endereço (posição do início de geração de código da sub-rotina = endereço seguinte ao DSVS recém-gerado) escopo++ contaParametros = 0 guardar posição onde a tupla foi incluída na TI para, no futuro, 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> #52 atualizar entrada na TI correspondente à subrotina (cuja posição foi salva), 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 [25] <listaargs> ::= <tipo> ID #25 <repargs> se tipo == nada, bool, caracter ou flutuante: ERRO(Estes tipos não são admitidos como parâmetros – NESTE SEMESTRE) senão se a ID já existe na TI no mesmo escopo: ERRO(Já declarado) senão inserir na TI: ID, categoria=parâmetro, tipo, escopo contaParâmetros++ [26] <declara> ::= final #26 <tipo> ID #27 '=' <inicial> #28 ';' [27] <declara> ::= final #26 <tipo> ID #27 '=' <inicial> #28 ';' [28] <declara> ::= final #26 <tipo> ID #27 '=' <inicial> #28 ';' NÃO UTILIZADO NESTE SEMESTRE (não haverá geração de código para constantes) [29] <declara> ::= string ID #29 '=' litstring #30 ';' se a ID já existe na TI no mesmo escopo: ERRO(Já declarado) senão incluir na TI: ID, categoria=variável, tipo=string, escopo, 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> resolver desvios pendentes gerados em #23 (pilha de desvios para Principal), usando para isso o endereço que corresponderá à primeira instrução de 'Principal'. Comando SE [32] <cmdse> ::= se '(' <cond> ')' #32 <bloco> <cmdse2> #34 Empilhar EG na pilhaSE (EG é onde o DSVF abaixo será gerado) Gerar DSVF ? (o endereço de destino pendente será resolvido em #33 ou #34) [33] <cmdse2> ::= senão #33 <bloco> Gerar DSVS ? (o endereço de destino pendente será resolvido em #34) Resolver referência pendente (pendência está situada na posição indicada pelo endereço que estiver no topo da pilhaIF) usando EG atual. Desempilhar o endereço da pilhaIF Empilhar EG-1 (referente ao DSVS gerado acima) na pilhaIF 7 [34] <cmdse> ::= se '(' <cond> ')' #32 <bloco> <cmdse2> #34 Resolver referência pendente (cujo endereço está no topo da pilhaIF) usando EG e desempilhar (pode ter sido empilhado em #32 ou em #33) Comando FAÇA: [35] <cmdfaca> ::= faça #35 <bloco> enquanto '(' <cond> ')' #36 Empilhar EG na pilhaFaça [36] <cmdfaca> ::= faça #35 <bloco> enquanto '(' <cond> ')' #36 Gerar (DSVT endereço) usando o valor que estiver no topo da pilhaEnquanto como endereço e desempilhar Comando ENQUANTO: [37] <cmdeqto> ::= enquanto #37 '(' <cond> #38 ')' <bloco> #39 Empilhar EG na pilhaEnquanto [38] <cmdeqto> ::= enquanto #37 '(' <cond> #38 ')' <bloco> #39 Empilhar EG na pilhaEnquanto (endereço onde o DSVF abaixo será gerado) Gerar DSVF ? (endereço ficará pendente para resolução futura – na ação #39) [39] <cmdeqto> ::= enquanto #37 '(' <cond> #38 ')' <bloco> #39 Resolver referência pendente do topo da pilhaEnquanto usando EG+1 e desempilhar Gerar (DSVS endereço), 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 não serão utilizadas neste semestre. As posições de ações definidas acima são apenas sugestões. [46] <cmdatrib> ::= ID #46 <contatrib> Se ID não está na TI: ERRO(Não declarado: Não se pode chamar PROCEDIMENTO que não tenha sido declarado anteriormente) senão Se ID está na TI como função/nome de prog/const: ERRO(deve ser variável, parâmetro ou procedimento) senão Recuperar os dados da TI correspondentes ao ID e salvar em tupla temporária [47] <contatrib> ::= '=' <cond> #47 Gerar (POP dif.nível, 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 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> 7 <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) Gerar (RET K) (K é o nº de parâmetros do procedimento) [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(Cláusula 'resultado' só pode ser utilizada dentro de funções) senão Gerar POP 0,0 -> 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) 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] 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 de pilhaOP="maior" – Gerar CMMA -, se topo de pilhaOP=”menor” - Gerar CMME -, se topo de pilhaOP="igual" – Gerar CMIG -,etc, etc. [67] <optermo> ::= '+' #67 | '-' #68 7 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 PUSHK cteint Fazer tipo="int" [76] <litnum> ::= cteflutuante #76 Flutuante retirado da linguagem neste semestre. Só faz: tipo="flutuante" [77] <fator> ::= litcar #77 DESNECESSÁRIO IMPLEMENTAR NESTE SEMESTRE Gerar PUSHK 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 PUSHK 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 TI e não for variável, parametro, função ou cte: ERRO(uso indevido) senão Recuperar da TI os dados do ID e salvar em uma tupla temporária para usar em #80/81 [80] <contid> ::= @ #80 Se ID é constante (esta opção não terá utilidade neste semestre) Gerar PUSHK x (x é o valor pré-declarado – está na tupla temporária) Fazer tipo="int" senão se ID é var.string Gerar PUSHK deslocString (está na tupla temporária) 7 Fazer tipo="string" se ID é outro tipo de variável ou parâmetro Gerar PUSH 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 salva em #79) não é função: ERRO(Esperava-se função) Senão Zerar contaParam Fazer tipo=(ver tipo definido na tupla temporária salva em #79) [82] <contid> ::= #81 '(' <listaparam> #82 ')' Se contaParam <> nºparametros declarados (ver tupla temporária): ERRO(nº parâmetros incorreto) Gerar CALL base, end Gerar PUSH 0, 0 <- 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 Falso ou Verdade, respectivamente) Se tipo é "int" Gerar instrução IMPR _,_ Outros: ERRO(Não implementado nesta versão) 7