domingo, 3 de outubro de 2010

Conversão de código com ANTLR

Olá povo,

Estou no processo final do meu mestrado escrevendo minha dissertação e meu tema aborda a conversão automática de aplicações iPhone para Android. Devo admitir que uma das mais legais foi a conversão do código-fonte de Objective-C (do iPhone) para Java (do Android).
Para realizar essa etapa, utilizei o ANTLR (lê-se Antler), "um a sofisticado gerador de parser que pode ser utilizado para criar interpretadores de linguagens, compiladores e outros tradutores". Ele foi criado e é mantido por Terence Parr.

Essa ferramenta está disponível para download, inclusive com um plugin do Eclipse. O desenvolvedor especifica um arquivo de dicionário, que determina a sintaxe da linguagem especificada. A partir desse arquivo, é gerado o lexer que determina se as sentenças descritas em um arquivo de código-fonte estão em conformidade com a linguagem especificada. Feita essa validação sintática, o lexer passa a árvore com os tokens extraídos do arquivo para o parser. O ANTLR permite que sejam adicionados alguns trechos de código à gramática, tornando o parser gerado pela ferramenta, um tradutor.

Abaixo temos um exemplo da criação de uma linguagem chamada "T". Essa linguagem tem apenas uma regra chamada "r", que pode conter fantásticos DOIS comandos!!! :) Sendo assim, em um arquivo de código-fonte escrito em "T" podemos ter várias (indicada pelo sinal de "+" no arquivo de dicionário) instruções do tipo "print" e/ou "sum". A instrução print recebe um ID que foi definido como sendo qualquer sequência de letras maiúsculas ou minúsculas (número não são aceitos). Já a instrução sum recebe dois INT, que são definidos como qualquer sequência de números.
Notem que as instruções são terminadas com ";" e que temos o código Java para cada instrução, esse código é que será executado quando mandarmos executar um código que esteja de acordo com a linguagem "T".

grammar T;

// Regra r tem os comandos "print" | "sum"
r : ('print' ID ';' {
System.out.println("imprima "+$ID.text);}

| 'sum' id1=INT id2=INT {
int x = Integer.parseInt($id1.text);
int y = Integer.parseInt($id2.text);
int z = x + y;
System.out.println("soma "+ z) ; }
)+
;

ID: ('a'..'z' | 'A'..'Z') + ;

INT: '0'..'9' + ;

// Ignore espaços em branco
WS: (' ' |'\n' |'\r' )+ {$channel=HIDDEN;} ;

Uma vez criado esse dicionário, a ferramenta gera o parser e o lexer em Java. Podemos então finalmente screver nosso primeiro programa em "T" :)

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;

public class AmazingCompiler {
public static void main(String[] args)
throws Exception {

// Código fonte (poderia estar em um arquivo)
String codigoFonte = "print Glauber; sum 2 2;";

// criando stream com o código-fonte
ANTLRStringStream input =
new ANTLRStringStream(codigoFonte);

// Cria uma intância do Lexer que lê as instruções
TLexer lexer = new TLexer(input);

// Cria lista de tokens geradas a partir do lexer
CommonTokenStream tokens =
new CommonTokenStream(lexer);

// Cria o parser pra executar as instruções
TParser parser = new TParser(tokens);

// Manda executar a regra "r".
parser.r();
}
}


O código acima, passa o código-fonte em forma de um stream para o Lexer que o valida e gera os tokens que são repassados para o Parser. Esse último, por sua vez, manda excutar a regra "r", que como já foi dito, pode conter várias instruções "print" e "sum". Uma vez executado esse código, a saída no console será:

imprima Glauber
soma 4

Muito bacana! Agora você pode criar suas liguagens de programação e entrar no hall da fama :)

Tem muita coisa que podemos falar sobre essa fantástica ferramenta. Quem quiser mais informações sobre o ANTLR segue alguns links que foram de grande valia pra mim no meu mestrado.
- Site Oficial (http://www.antlr.org/)
- Vídeos explicativos sobre a ferramenta (http://javadude.com/articles/antlr3xtut/)
- Livro de Referência do ANTLR que é fonte desse artigo.

4br4ç05,
nglauber

2 comentários:

Anônimo disse...

quando vou colocar o codigo java no eclipse da erro nos imports (:

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;

como faço para funcionar?

Nelson Glauber disse...

Olá Anônimo,

Você tem que conigurar o plugin do ANTLR para Eclipse (veja aqui http://antlreclipse.sourceforge.net/). Depois, você baixa o JAR do ANTLR aqui http://www.antlr.org/download/antlr-runtime-3.2.jar e adiciona no Build Path.

4br4ç05,
nglauber