Trabalho nº 2

Propaganda
Trabalho nº 2
DESENVOLVIMENTO DE UM ANALISADOR SINTÁTICO
DESCRIÇÃO
Pretende-se implementar um analisador sintático para uma linguagem de programação muito simples,
com o nome Java+-, 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 dos tipos array de inteiros e array de valores lógicos (com uma única dimensão). 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. Os programas da linguagem Java+- são constituídos por uma única
classe (a classe principal) contendo um único método (o método main).
É possível passar parâmetros, que deverão ser literais inteiros, a um programa Java+- através da linha
de comandos. Supondo que o nome dado ao argumento do método main() é “args”, os seus valores
podem ser recuperados através da construção “Integer.parseInt(args[...])”, e o número de parâmetros
pode ser obtido através da expressão “args.length”. A construção “System.out.println(...)” permite
imprimir valores inteiros ou lógicos.
EXEMPLO
O significado de um programa em Java+- será o mesmo que o seu significado em Java. Por exemplo, o
seguinte programa calcularia o máximo divisor comum de dois inteiros, e apresentaria esse valor no
écran:
class gcd {
public static void main(String[] args) {
int[] x;
x = new int[2];
x[0] = Integer.parseInt(args[0]);
x[1] = Integer.parseInt(args[1]);
if ((x[0] <= 0) && (0 <= x[0]))
System.out.println(x[1]);
else
while (!(x[1] <= 0)) {
if (!(x[0] <= x[1]))
x[0] = x[0] - x[1];
else
x[1] = x[1] - x[0];
Compiladores 2012-2013 | Trabalho nº 2
1
}
System.out.println(x[0]);
}
}
TOKENS E GRAMÁTICA INICIAL DA LINGUAGEM JAVA+ID = [A-Za-z_][A-Za-z0-9_]*
INTLIT = [0-9]+ | “0x” [0-9a-fA-F]+
BOOLLIT = “true” | “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”
STRING = “String”
DOTLENGTH = “.length”
OCURV = “(”
CCURV = “)”
OBRACE = “{”
CBRACE = “}”
OSQUARE = “[”
CSQUARE = “]”
OP1 = “&&” | “||”
OP2 = “<” | “>” | “==” | “!=” | “<=” | “>=”
OP3 = “+” | “-”
OP4 = “*” | “/” | “%”
Compiladores 2012-2013 | Trabalho nº 2
2
NOT = “!”
ASSIGN = “=”
SEMIC = “;”
COMMA = “,”
Start → Program EOF
Program → CLASS ID OBRACE PUBLIC STATIC VOID ID OCURV STRING OSQUARE
CSQUARE ID CCURV OBRACE { VarDecl } { Statement } CBRACE CBRACE
VarDecl → Type ID { COMMA ID } SEMIC
Type → INT | BOOL | INT OSQUARE CSQUARE | BOOL OSQUARE CSQUARE
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 (OP1 | OP2 | OP3 | OP4) Exp
Exp → Exp OSQUARE Exp CSQUARE
Exp → INTLIT | ID | BOOLLIT
Exp → NEW INT OSQUARE Exp CSQUARE
Exp → NEW BOOL OSQUARE Exp CSQUARE
Exp → OCURV Exp CCURV
Exp → Exp DOTLENGTH | NOT Exp
Exp → PARSEINT OCURV ID OSQUARE Exp CSQUARE CCURV
IMPLEMENTAÇÃO
O analisador sintático deve ser implementado em Java utilizando as ferramentas JJTree e JavaCC. A
gramática dada deve ser modificada de modo a eliminar ambiguidades, a reflectir a precedência dos
operadores em Java, e a permitir a análise descendente com LOOKAHEAD=1, ou seja, a gramática
deve ser LL(1).
O analisador deverá chamar-se JavapmParser, ler o ficheiro a processar através do stdin, e emitir o
resultado da análise para o stdout. Exemplificando, no caso do ficheiro gcd.jpm conter o exemplo dado
anteriormente, a invocação
java JavapmParser < gcd.jpm ↵
deverá gerar a árvore sintática abstracta correspondente (i.e., conforme a gramática original dada) e
imprimi-la no écran. Neste caso:
Compiladores 2012-2013 | Trabalho nº 2
3
> Start
>
Program
>
CLASS
>
ID
>
OBRACE
>
PUBLIC
...
>
CSQUARE
>
ID
>
CCURV
>
OBRACE
>
VarDecl
>
Type
>
INT
>
OSQUARE
>
CSQUARE
>
ID
>
SEMIC
...
>
Statement
>
ID
>
OSQUARE
>
Exp
>
INTLIT
>
CSQUARE
>
ASSIGN
>
Exp
>
PARSEINT
>
OCURV
>
ID
>
OSQUARE
>
Exp
>
INTLIT
>
CSQUARE
>
CCURV
Compiladores 2012-2013 | Trabalho nº 2
4
>
SEMIC
...
>
CBRACE
>
CBRACE
> EOF
O analisador deve aceitar (e ignorar) comentários iniciados por // (sem incluir o caracter de fim de
linha!) e do tipo /* */, bem como detectar a existência de quaisquer erros de sintaxe no ficheiro de
entrada.
CASOS PARTICULARES
A gramática dada permite gerar certas expressões que teriam interpretação diferente em Java e Java+.
Por exemplo:

8.length
o em Java, tratar-se-ia de um literal real seguido de um identificador
o em Java+-, trata-se de um literal inteiro seguido de DOTLENGTH
(semanticamente inválido)

new int[5][2]
o em Java, tratar-se-ia de um array de dimensão 5x2
o em Java+-, tratar-se-ia da indexação de um array de dimensão 5 com o
valor 2 (semanticamente válido!!!)
De modo a garantir a compatibilidade estrita dos programas em Java+- com o Java, estes casos devem
ser tratados do seguinte modo:

Eventuais sequências do tipo <INTLIT>“.” devem ser reconhecidas como tokens de
uma categoria lexical adicional (não usada pelas regras da gramática), de modo a que
a sua ocorrência dê origem a um erro sintático.

As regras da gramática devem ser modificadas de modo a que a ocorrência de
expressões do tipo new int[...][...]... dê origem a um erro sintático.
TRATAMENTO DE ERROS SINTÁTICOS
Caso o ficheiro de entrada contenha erros sintáticos, o programa deverá imprimir a seguinte
mensagem no stdout:
*** Syntax error ***
Encountered "(t.image)" at line (line no.), column (column no.).
Last valid token: "(t.image)"
onde (t.image), (line no.) e (column no.) devem ser substituídos pelos valores correspondentes. Isto
pode ser conseguido apanhando (catch) a excepção ParseException gerada pelo analisador e
processando o seu atributo currentToken, como a seguir se indica:
try {
Compiladores 2012-2013 | Trabalho nº 2
5
rootNode = parser.Start();
rootNode.dump("> ");
} catch(ParseException e) {
Token t = e.currentToken.next;
System.out.println("*** Syntax error ***");
System.out.println(String.format("Encountered \"%s\" at line %d, column %d.",
t.image, t.beginLine, t.beginColumn));
System.out.println(String.format("Last valid token: \"%s\"",
e.currentToken.image));
}
SUBMISSÃO DO TRABALHO
O trabalho deverá ser validado no Mooshak, usando o concurso COMP1213_T2.
O relatório deve ser submetido na tutoria da disciplina e não deve conter mais de 6 páginas. Do
relatório devem constar:
1. A gramática modificada de modo a eliminar a ambiguidade e a refletir a precedência dos operadores,
em notação BNF;
2. Uma gramática equivalente à anterior, mas que seja também adequada à análise descendente com
LOOKAHEAD=1, em notação BNF;
3. A gramática, usada para implementar o analisador, gerada pelo JJDoc;
4. As descrições do analisador que permitem compreenderem a estratégia de implementação
adoptada;
5. Caso não implemente toda a funcionalidade pedida, deverá detalhar os aspectos não
implementados.
NOTA
A tarefa A do concurso COMP1213_T2 contém todos os testes parciais incluídos nas outras tarefas.
Compiladores 2012-2013 | Trabalho nº 2
6
Download