DEV Community

Alex Sandro Garzão
Alex Sandro Garzão

Posted on • Edited on

1

Compilador para um subset de Pascal

O ano era 1999 (ou 2000, não tenho mais certeza rsrsrs). Foi um dos trabalhos da disciplina de Compilação Avançada, e posso afirmar que foi um dos mais divertidos da minha graduação em Ciência da Computação 🙂

Basicamente o objetivo do projeto era implementar um compilador capaz de ler um subset de Pascal e gerar um arquivo class válido de forma a poder executá-lo na JVM. Por subset entendam um programa Pascal válido, mas com um conjunto reduzido de instruções e operações:

  • Declaração de variáveis: tipos básicos apenas;
  • Estruturas de repetição: If, For, While, Repeat;
  • Entrada e saída de dados: Write, WriteLn, Read, ReadLn;
  • Operações matemáticas com precedência de operadores: soma, subtração, divisão, multiplicação e módulo;
  • Declaração de blocos de código: procedures e funções.

Abaixo é possível ver o clássico “Hello world!” em Pascal:

program Hello;
begin
  writeln ('Hello world!');
end.
Enter fullscreen mode Exit fullscreen mode

Abaixo temos um exemplo em Pascal um pouco mais elaborado onde temos definição de variáveis, entrada e saída de dados:

program Example;
var
  MyName: String;
  MyAge : Byte;
begin
  Write('What is your name? '); Readln(MyName);
  Write('How old are you? '); Readln(MyAge);
  Writeln;
  Writeln('Hello ', MyName);
  Writeln('You are ', MyAge, ' years old');
end.
Enter fullscreen mode Exit fullscreen mode

Para facilitar o desenvolvimento do compilador, optei por utilizar um gerador de parsers. Apesar de já ter utilizado os clássicos Lex/YACC e Flex/Bison em outros momentos, eu sentia falta de uma integração maior entre a análise léxica e sintática nestes geradores. Além disso, estes geradores utilizavam BNF, e eu gostaria de utilizar EBNF para especificar a gramática da minha linguagem (subset de Pascal).

Com isso optei por utilizar o JavaCC, um gerador de parsers que, a partir da gramática EBNF que criei, gerava um parser em Java capaz de ler este subset de Pascal e, a cada etapa das análises léxicas e sintáticas, executar ações determinadas por mim. Nestas ações eu inseria código Java que realizava o que eu precisava: gerar a tabela de símbolos (que continham as strings e números existentes no programa em Pascal) e o bytecode equivalente ao programa lido. No final do parser, caso nenhum erro ocorresse, o arquivo class era gerado.

Para exemplificar o processo de tradução que o compilador realizava vamos usar o clássico “Hello world!” em Pascal abaixo:

program Hello;
begin
  writeln ('Hello world!');
end.
Enter fullscreen mode Exit fullscreen mode

A partir deste programa o compilador então traduzia para o seu equivalente em Assembly Java, similar ao exemplo abaixo:

class Hello
{ 
  method public static void main (java.lang.String[])
  max_stack 2
  { 
    getstatic java.io.PrintStream java.lang.System.out
    ldc "Hello World!"
    invokevirtual void java.io.PrintStream.println(java.lang.String)
    return
  }
}
Enter fullscreen mode Exit fullscreen mode

Posteriormente este assembly era traduzido pelo compilador para o seu formato binário (bytecode) e armazenado no arquivo class.

No fim, o trabalho foi concluído com sucesso. Eu tinha uma gramática em JavaCC que gerava um parser capaz de ler qualquer programa em Pascal (desde que respeitando o subset definido) e gerar o arquivo class, arquivo este que era executado diretamente pela JVM. Aliás, fiquei fã da JVM nesta época.

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs