Uma Ferramenta para Criação de Linguagens de Domínio Específico (DSL)
Autor: Renato | Publicado: 2009-11-26T14:49:00-03:00

Iniciarei neste post uma série que falará sobre um assunto que já existe a muito tempo, porém recentemente ganhou mais evidência: Linguagens de Domínio Específico, também conhecidas como DSL (Domain Specific Languages).

Farei uma introdução sobre as DSLs, depois mostrarei uma ferramenta para auxiliar na criação de linguagens e por fim um estudo de caso colocando em prática todo o conhecimento.

Este post foi construído com base em um trabalho de pós graduação, feito por mim em parceria com Elson Travassos, que eventualmente também escreve no meu blog "Do Windows ao Linux"

DSL - Domain Specific Languages

No mundo da computação, linguagens de programação existem para permitir que as pessoas escrevam programas que sejam compreensíveis pelas máquinas. Estas linguagens podem ser divididas em dois grandes blocos: linguagens de propósito genérico e as linguagens de domínio específico.

As linguagens de propósito genérico oferecem ao programador um conjunto de elementos, como operadores, abstrações, variáveis, etc, que permitem a ele construir programas que resolvem uma grande variedade de problemas (AABY, 2004). Elas não focam em um domínio específico do conhecimento. Exemplos deste tipo de linguagem são C, Java, Ruby, etc.

Ao contrário das linguagens de propósito genérico, existem as linguagens de domínio específico (DSL). Elas são criadas dentro de um contexto para resolver um conjunto específico de problemas (FOWLER, 2006), e tendem a ser mais naturais e próximas da linguagem humana, facilitando a manutenção de seus códigos (PARR, 2007). Muitas linguagens utilizadas hoje em dia são na verdade DSL. Alguns exemplos são as macros de planilhas eletrônicas, SQL para fazer consultas a bancos de dados, CSS para definir estilos de formatação em HTML, arquivos de configurações de aplicações como Apache, Struts, dentre diversas outras.

As DSLs podem ainda serem divididas em dois subgrupos: internas e externas. DSLs internas são formas que o programador possui de reescrever um determinado trecho de código, utilizando a mesma linguagem original, mas que esta fique de maneira mais legível (fluente) para um determinado propósito (FOWLER, 2006). Linguagens dinâmicas, normalmente as de script, são mais suscetíveis a notações mais fluentes, que exijam menos texto digitado. No entanto, é possível se beneficiar das vantagens de uma DSL interna mesmo em linguagens estruturadas como o Java (RUIZ, 2008).

Já as DSLs externas são de verdade uma linguagem. Elas possuem uma sintaxe própria e precisam de um interpretador para analisar o código e executar os comandos. Assim como as linguagens tradicionais, as DSLs externas podem ser interpretadas e executadas de imediato ou podem ser convertidas para outra linguagem (normalmente de propósito genérico) que então será executada.

O ANTLR

Para se criar uma DSL interna (ou simplesmente DSL), é necessário criar as regras de definição de uma linguagem. Deve-se definir seus átomos, criar suas regras sintáticas e semânticas além de implementar seu analisador (comumente chamado de parser). Este último é o responsável por, de posse de um código fonte escrito na linguagem em questão, analise sua sintaxe verificando por erros de escrita, sua semântica e por fim transforme este código em algo que possa ser executado (AHO, 2007). Implementar o código que executa todas estas tarefas, por mais simples que a DSL seja, não é algo simples. Requer muito conhecimento sobre compiladores.

O ANTLR (Another Tool for Language Recognition) é uma ferramenta que tem como objetivo apoiar os desenvolvedores a criarem novas linguagens, podendo ser DSLs ou não. No entanto ele é mais utilizado para construção de DSLs (PARR, 2007). Ele é um gerador de parser ou um compilador de compiladores, ou seja, é uma ferramenta usada para gerar um analisador/tradutor para uma determinada linguagem. O ANTLR gera seu código a partir da especificação de uma linguagem através de uma gramatica formal. Desenvolvedores de software podem usar o ANTLR para:


  Implementar DSLs;
  Gerar uma parte de compiladores e tradutores;
  Construir ferramentas para realizar análise sintática, por exemplo para um XML complexo.


A partir de uma linguagem definida por uma gramática, o ANTLR irá realizar as seguintes tarefas


  Gerar o código do analisador léxico – agrupa os caracteres de entrada em tokens de acordo com o padrão especificado na gramatica.
  Gerar o código do analisador sintático – combina os tokens formando sentenças para linguagem.
  Transformar a gramatica inserida em uma estrutura de dados que na maioria das vezes é disposta através de uma arvore sintática abstrata (AST – Abstract Syntax Tree). A partir desta árvore é possível adicionar funcionalidade (semântica) em cada nó reconhecido, para que o código analisado gere um resultado ao ser executado.


A linguagem da gramática utilizada pelo ANTLR é o EBNF (Extended Bakus-Naur Form). Ela é uma versão melhorada da BNF, solucionando problemas de notação para representar facilmente decisões e repetições. A EBNF utiliza notações de expressões regulares.

Os códigos gerados pelo ANTLR podem ser em C, C++, Java, Python, C# e Objective-C.

No próximo post detalharei mais os recursos do ANTLR através de uma linguagem simples porém suficiente para demonstrar o poder desta ferramenta.

 
  Referências 
  
    Aaby, Anthony. Introduction to Programming Languages. http://burks.brighton.ac.uk/burks/pcinfo/progdocs/plbook/index.htm acessado em 20/11/2009.
    Fowler, Martin. Dsl Bliki. http://martinfowler.com/bliki/dsl.html acessado em 20/11/2009
    Ruiz, Alex; Bay, Jeff. An Approach to Internal Domain-Specific Languages in Java. 2008. http://www.infoq.com/articles/internal-dsls-java acessado em 20/11/2009
    PARR, Terrance. The Definitive ANTLR Reference: Building Domain Specific Languages. Pragmatic Programmer, 2007
    AHO, Alfred. Compilers: Principles, Techniques, & Tools. Second Edition, Addison Wesley, 2007