UNIVERSIDADE DO ALGARVE Faculdade de Ciências e Tecnologia Disciplina de Compiladores Relatório do Trabalho Prático 3: DESENVOLVIMENTO DE UM INTERPRETADOR Discentes: Renato Santos nº 24143 Ricardo Cruz nº 22937 Introdução O objectivo deste nosso trabalho é elaborar um interpretador para uma linguagem de programação muito simples, a que se irá dar o nome de MiniJava, e que é um subconjunto da linguagem Java. Nesta linguagem é possível utilizar variáveis e constantes dos tipos lógico e inteiro (de 32 bits) com sinal. Podem também ser utilizadas variáveis do tipo array de inteiros. A linguagem aceita expressões aritméticas e lógicas e operações relacionais simples, construções condicionais do tipo if-else, e construções while. Definição dos tokens Foram dados os seguintes tokens com as respectivas expressões regulares ID = [A-Za-z][A-Za-z0-9_]* INT_LIT = [0-9]+ TRUE = “true” FALSE = “false” INT = “int” BOOL = “boolean” NEW = “new” IF = “if” ELSE = “else” WHILE = “while” PRINT = “System.out.println” PARSEINT = “Integer.parseInt” CLASS = “class” PUBLIC = “public” STATIC = “static” VOID = “void” MAIN = “main” STRING = “String” LENGTH = “length” ARGS = “args” DOT = “.” OCURV = “(” CCURV = “)” OBRACE = “{” CBRACE = “}” OSQUARE = “[” CSQUARE = “]” OP = “&&” | “<” | “+” | “-” | “*” NOT = “!” ASSIGN = “=” SEMIC = “;” COMMENT = “//[^\n]*” Gramática Inicialmente foi dada a seguinte gramática: Program CLASS ID OBRACE PUBLIC STATIC VOID -> MAIN OCURV STRING OSQUARE CSQUARE ARGS CCURV OBRACE { VarDecl } { Statement } CBRACE CBRACE VarDecl -> Type ID SEMIC Type-> INT OSQUARE CSQUARE | BOOL | INT Statement ->OBRACE { Statement } CBRACE Statement -> IF OCURV Exp CCURV Statement ELSE Statement Statement -> WHILE OCURV Exp CCURV Statement Statement->PRINT OCURV Exp CCURV SEMIC Statement->ID ASSIGN Exp SEMIC Statement->ID OSQUARE Exp CSQUARE ASSIGN Exp SEMIC Exp->Exp OP Exp Exp-> Exp OSQUARE Exp CSQUARE Exp->INT_LIT | ID | TRUE | FALSE Exp->NEW INT OSQUARE Exp CSQUARE Exp->OCURV Exp CCURV Exp->NOT Exp Exp->Exp DOT LENGTH Exp->ARGS DOT LENGTH Exp->PARSEINT OCURV ARGS OSQUARE Exp CSQUARE CCURV Após esta gramática efectuamos algumas alterações às regras para permitir a análise descendente. Assim sendo, tivemos de implementar novas regras de forma a eliminar a recursividade á esquerda e ambiguidade nas regras: Exp->Exp OP Exp Exp-> Exp OSQUARE Exp CSQUARE Exp->Exp DOT LENGTH Consultando [2] na página 52, efectuámos as alterações gramaticais lá indicadas e obtivemos a seguinte gramática: Program -> CLASS ID OBRACE PUBLIC STATIC VOID -> MAIN OCURV STRING OSQUARE CSQUARE ARGS CCURV OBRACE { VarDecl } { Statement } CBRACE CBRACE VarDecl -> Type ID SEMIC Type-> INT OSQUARE CSQUARE | BOOL | INT Statement ->OBRACE { Statement } CBRACE Statement -> IF OCURV Exp CCURV Statement ELSE Statement Statement -> WHILE OCURV Exp CCURV Statement Statement->PRINT OCURV Exp CCURV SEMIC Statement->ID ASSIGN Exp SEMIC Statement->ID OSQUARE Exp CSQUARE ASSIGN Exp SEMIC Exp->(INT_LIT | ID | TRUE | FALSE) Exp’ Exp->NEW INT OSQUARE Exp CSQUARE Exp’ Exp->OCURV Exp CCURV Exp’ Exp->NOT Exp Exp’ Exp->ARGS DOT LENGTH Exp’ Exp->PARSEINT OCURV ARGS OSQUARE Exp CSQUARE CCURV Exp’ Exp’-> OP Exp Exp’ > Exp’-> OSQUARE Exp CSQUARE Exp’ Exp’->DOT LENGTH Exp’ Exp’->E Código Implementado Neste trabalho infelizmente não nos foi possível a realização de todas as funcionalidades inicialmente previstas. Implementámos apenas a elaboração da análise sintáctica da gramática e a impressão da árvore sintáctica correspondente. Já as interpretações pedidas não conseguimos implementar. Criámos um ficheiro Minijava.jjt que contém a implementação dos tokens e das regras da gramática modificada. Para compilar o código implementado usa-se em primeiro lugar o comando: jjtree Minijava.jjt Para de seguida gerar o código Java com o JavaCC: javacc Minijava.jj E por último compilar o código Java gerado: Javac *.java Para correr o programa deve-se especificar o ficheiro a analisar na linha de comandos: java Minijava <input.java> Todos os ficheiros produzidos são enviados juntamente com este relatório. Testes Foram criados quatro ficheiros de teste: 2 válidos: contador.java, maximo.java 2 inválidos: contador2.java, maximo2.java No contador.java tentámos utilizar a gramática para a elaboração de um programa que imprime no ecrã uma listagem de números inteiros que se inicia em 0 e termina em 10. No maximo.java é um programa que dados dois números á escolha do utilizador ele indica qual o maior número dos dois números inseridos. No contador2.java foi alterada a expressão “ numero= numero +1 “ para “ numero++ “ e verificamos que o programa irá dar erro pelo facto de esta expressão não estar de acordo com a gramática existente, o que não é aceite pela gramática. No maximo2.java tentámos fazer algo como if ( num1 <= num2 ) mas tal não é permitido pela nossa gramática. Devidos às limitações descritas no ponto anterior não podemos interpretar os ficheiros de teste criados. Testámos apenas se a análise sintáctica de cada um dos ficheiros dá erro ou não. Verificámos que ambos os ficheiros válidos completavam a análise sintáctica e imprimiam a respectiva árvore sintáctica. Já os dois ficheiros inválidos deram erro de sintaxe. Bibliografia [1] http://w3.ualg.pt/%7Ejmcardo/ensino/compiladores/ [2] Andrew W. Appel. Modern Compiler Implementation in Java, Cambridge University Press, 2002. [3] http://www.engr.mun.ca/~theo/JavaCC-Tutorial/