Construção de Compiladores.
Primeiro Semestre de 2001.
Prof. José de Oliveira Guimarães.

Segundo Trabalho.
Prazo de Entrega: 18 de Maio.

Entregue este trabalho com a folha de correção disponível na página da disciplina.
Nesta página, veja as observações sobre correção de trabalho.

Faça um compilador para a seguinte gramática:

Program ::= FunList
FunList ::= FunDec | FunDec FunList
FunDec ::= '(' "fun" IDENT '(' ParamList ')' Expr ')'
ParamList ::= | IDENT ParamList
Expr ::= Number | IDENT | '(' OperCall ')'
OperCall ::= Oper Expr Expr | IDENT ArgList
ArgList ::= | Expr ArgList
Oper ::= '+' | '-' | '*' | '/' | '>' | '>=' | '<' | '<='
| '==' | '!='

Um programa poderia ser
(fun previous (n) (- n 1) )
(fun fat(n) (if (> n 1) (* n (fat (- n 1))) 1))
(fun first() (fat (previous 6)))

Algumas observações:
* há uma função pré-definida chamada "if" que toma três parâmetros :
    (if expr exprThen exprElse)
Esta função retorna exprThen se expr é true e exprElse se expr é false;
* a execução do programa é a chamada da função "first" sem parâmetros, que obrigatoriamente deve ser definida no programa. O resultado da chamada a first é impresso na saída padrão;
* a análise semântica deve ser feita. Deve ser conferido se o número de argumentos passados a uma função é igual ao número de parâmetros que ela declara, entre outras coisas. Não termine a execução do programa ao sinalizar um erro semântico;
* os parâmetros são todos inteiros e todas as funções retornam inteiros;
* identificadores devem ser compostos por qualquer quantidade de letras e números, começando por letra;
* números podem ter qualquer número de dígitos, mas devem estar entre 0 e 32767;
* o compilador deve construir a ASA e gerar código a partir dela, em C. A geração de código deve ser feita para um arquivo;
* a leitura da entrada deve ser feita de um arquivo;
* possivelmente alguns alunos serão chamados para esclarecimentos sobre o seus respectivos trabalhos.

A tradução do programa acima para C deve ser:

#include <stdio.h>

/* esta funcao sempre deve ser incluída */
int ifExpr( int expr, int exprThen, int exprElse ) {
  if ( expr )
    return exprThen;
  else
    return exprElse;
}

int previous( int n ) {
  return (n - 1);
}

int fat(int n) {
  return ifExpr( (n > 1),
     (n*fat((n - 1))), 1);
}

int first() {
  return fat(previous(6));
}

void main() {
  printf("%d\n", first() );
}
 

O trabalho pode ser individual. Neste caso, o trabalho é aquele descrito acima. Se for em grupo, este deve ter no máximo duas pessoas e o trabalho deve ter as seguintes extensões:
1. variáveis e funções devem ter tipos:
    (fun int previous (int n) (- n 1) )
    (fun char greater( char ch1 char ch2 )
    (if (>= ch1 ch2) ch1 ch2 ) )
Os tipos permitidos são int e char. Sobre char apenas são permitidas as operações de comparação. Naturalmente, faça todas as conferências semânticas  associadas a tipos. Um caráter deve ser representado como em Java;
2. quando houver um erro sintático, deve-se tentar continuar a compilação. Isto é, deve-se saltar todos os tokens até que se encontre um ponto de continuação, que pode ser um ')' ou a declaração de uma nova função.