Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


APOSTILA DE PROGRAMAÇÃO EM Haskell, Exercícios de Informática

APOSTILA DE PROGRAMAÇÃO em haskell

Tipologia: Exercícios

2020

Compartilhado em 21/11/2020

lyy-1sasa
lyy-1sasa 🇧🇷

4.7

(3)

3 documentos

1 / 30

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Universidade Federal de Pernambuco
Centro de Informática
Graduação em Computação
Curso: Paradigmas de Linguagens Computacionais
(if686)
Implementação de um Interpretador em Haskell
Equipe: Daker Fernandes Pinheiro (dfp)
Rafael Alberto Gomes Pereira Lima (ragpl)
Rafael Henrique da Silva Santos (rhss)
Tarcisio Coutinho da Silva (tcs5)
Recife, 20 de novembro de 2009
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e

Pré-visualização parcial do texto

Baixe APOSTILA DE PROGRAMAÇÃO EM Haskell e outras Exercícios em PDF para Informática, somente na Docsity!

Universidade Federal de Pernambuco

Centro de Informática

Graduação em Computação

Curso: Paradigmas de Linguagens Computacionais

(if686)

Implementação de um Interpretador em Haskell

Equipe: Daker Fernandes Pinheiro (dfp)

Rafael Alberto Gomes Pereira Lima (ragpl)

Rafael Henrique da Silva Santos (rhss)

Tarcisio Coutinho da Silva (tcs5)

Recife, 20 de novembro de 2009

Índice

  1. Introdução

Este trabalho representa a documentação do projeto da disciplina de Paradigmas de Linguagens Computacionais. O projeto consiste na elaboração de um interpretador em Haskell, utilizando a ferramenta Hugs, para uma linguagem apresentada na especificação do projeto. Este documento representa o primeiro passo do projeto: dada a sintaxe abstrata de uma linguagem imperativa, elaborar uma semântica em linguagem natural para a mesma.

Este documento está divido em seis capítulos. No capítulo dois, é descrita as características da linguagem para a qual desenvolveremos o interpretador. No três, é apresentada a semântica da linguagem escrita em linguagem natural. No quatro, falamos um pouco da sintaxe abstrata, apresentando trechos do código em Haskell com a representação das produções da gramática (utilizando o tipo algébrico DATA). Alguns detalhes de implementação como a maneira que tratamos alguns conceitos como binding, memória e escopo são apresentados no capítulo cinco. No seis, o código das principais funções criadas são mostrados e no sete, alguns exemplos de programas que serão utilizados para testar o interpretador são apresentados.

  1. Características da Linguagem

A linguagem descrita neste documento, e denominada daqui em diante “DTR²”, é regida pelo paradigma imperativo, sendo considerada sua rotina principal aquela iniciada na primeira linha do código fonte. É permitido à linguagem, declaração de rotinas. Estas podem ser recursivas e parametrizadas, entretanto não podem possuir valor de retorno. Todas as rotinas, assim como variáveis, devem ser declaradas antes do uso. As variáveis não possuem escopo global, cada variável só é visível dentro do escopo onde foi declarada. Os tipos primitivos em DTR² são booleanos, strings e inteiros, incluindo apontadores para estes tipos, não sendo permitido a criação de tipos compostos e arrays.

  1. Semântica da Linguagem

3.1 Tipos básicos e valores

Sintaxe

Tipo ::= "string"

| "int"

| "boolean"

Valor ::= ValorInteiro

| ValorBooleano

| ValorString

Semântica

A linguagem possui três tipos primitivos: inteiro, booleano e string, sendo permitido a criação de apontadores para estes e vedada a criação de novos tipos e arrays.

  • string – representa uma cadeia de caracteres
  • int – representa um valor numérico inteiro de 32bits
  • boolean – representa uma informação de verdadeiro ou falso

Os valores que podem ser utilizados são os seguintes: ValorInteiro (números inteiros com sinal de 32 bits), ValorBooleano (valores booleanos: “True” ou “False”) e ValorString (cadeias de caracteres). Uma expressão sempre interpreta uma variável do tipo Valor.

Exemplo

  • “cadeia de caracteres” – string
  • 32000 – int
  • -32000 - int
  • False - boolean

Exemplo

  • “abc”
  • 12
  • &efg

3.3.1 Expressão Unária

Sintaxe

ExpUnaria ::= "-" Expressao

| "!" Expressao

Semântica

EXPUNARIA consiste em um operador seguido de EXPRESSAO. Há dois tipos de operadores possíveis, o operador menos e o operador not. O operador menos só pode ser aplicado a expressões do tipo inteiro. Ele transforma o valor da expressão no seu oposto. O operador not só pode ser aplicado a expressões do tipo booleano. Ele nega uma expressão booleana.

Exemplos

-! true

3.3.2 Expressão Binária

Sintaxe

ExpBinaria ::= Expressao "+" Expressao

| Expressao "-" Expressao

| Expressao "&&" Expressao

| Expressao "||" Expressao

| Expressao "==" Expressao

| Expressao "++" Expressao

Semântica

EXPBINARIA consiste em uma operação entre duas expressões. Os operadores possíveis são: adição(+), subtração(-), and(&&), or(||), igual(==) e concatenação(++). O operador de adição só pode ser aplicado a expressões do tipo inteiro. O seu valor final é a soma das expressões. Se as duas variáveis EXPRESSAO forem do tipo Inteiro, o valor retornado deve ser a soma dos valores da avaliação das duas variáveis EXPRESSAO. Se uma das variáveis EXPRESSAO for de qualquer outro tipo, uma mensagem de erro deve ser retornada. O operador de subtração só pode ser aplicado a expressões do tipo inteiro. O seu valor final é a subtração das expressões. Se as duas variáveis EXPRESSAO forem do tipo Inteiro, o valor retornado deve ser a diferença entre o valor da primeira expressão e o da segunda. Se uma das variáveis EXPRESSAO for de qualquer outro tipo, uma mensagem de erro deve ser retornada.

O operador and só pode ser aplicado a expressões do tipo booleano. Se as duas variáveis EXPRESSAO forem do tipo Boolean, o valor retornado deve ser o resultado da operação “e lógico” entre os valores da avaliação das duas variáveis EXPRESSAO. Se uma das variáveis EXPRESSAO for de qualquer outro tipo, uma mensagem de erro deve ser retornada. O operador or só pode ser aplicado a expressões do tipo booleano. Se as duas variáveis EXPRESSAO forem do tipo Boolean, o valor retornado deve ser o resultado da operação “ou lógico” entre os valores da avaliação das duas variáveis EXPRESSAO. Se uma das variáveis EXPRESSAO forem de qualquer outro tipo, uma mensagem de erro deve ser retornada. O operador igual só pode ser aplicado a expressões de mesmo tipo. Deve retornar sempre um valor booleano, após a avaliação dessa EXPRESSAO. Se as duas variáveis EXPRESSAO forem do mesmo tipo e os valores das avaliações das duas variáveis EXPRESSAO também forem iguais, o valor a ser retornado deve ser True. Caso contrário o valor a ser retornado deve ser False. O operador de concatenação só pode ser aplicado a expressões do tipo string. Caso as duas variáveis EXPRESSAO sejam do tipo String, o retorno deve ser a concatenação das duas cadeias de caracteres, na ordem da variável da esquerda para a variável de direita. Caso algumas das variáveis EXPRESSAO não sejam do tipo String, uma mensagem de erro deve ser retornada.

Exemplos

  • a + b
    • 3
  • true && true
  • true || false
  • “D” ++ “TR2”

3.3.3 Identificador

Sintaxe

Expressao ::= Id

Semântica O valor dessa expressão é o conteúdo do identificador, que está armazenado na memória.

Exemplo

  • abc
  • cont

3.3.4 Endereço do identificador

Sintaxe

Expressao ::= &Id

Semântica

Representa o valor do endereço no qual o ponteiro Id está armazenado.

  • IfThenElse: Representa um bloco onde, segundo a avaliação de uma expressão, será executado um dos dois subcomandos.
  • IO: representa funções de escrita de expressões e leitura de variáveis.
  • Skip: Instrução que para a execução de determinado trecho do programa.
  • ChamadaProcedimento: Corresponde a um desvio do fluxo do código para uma rotina previamente definida.
  • Comando “;” Comando : Sequência de comandos separados por “;”

Exemplos

2 var a = 0;

3 Skip

1 while a > 0 do a := a – 1

1 if identificadorA then

2 x := 1

3 else

4 x := 2

1 Skip

1 write ( x + 2 + 7 – 5 / 3)

3.4.1 Comando Declaração

Sintaxe

1 ComandoDeclaracao ::= "{" Declaracao ";" Comando "}"

3 Declaracao ::= DeclaracaoVariavel

4 | DeclaracaoProcedimento

5 | Declaracao "," Declaracao

7 DeclaracaoVariavel ::= "var" Id "=" Expressao

8 | "pointer" Id "=" "^"Tipo

10 DeclaracaoProcedimento::="proc"Id"("

[ListaDeclaracaoParametro] ")" "{" Comando "}"

13 ListaDeclaracaoParametro ::= Id ["^"]Tipo

14 | ListaDeclaracaoParametro "," ListaDeclaracaoParametro

Semântica

Toda declaração é iniciada por uma chave. Pode-se fazer declarações de variáveis (dos tipos anteriormente definidos) e de procedimentos. As declarações seqüenciais devem ser separadas por vírgula. Ao final das declarações existe um ponto e virgula e um COMANDO que finaliza com uma chave. Cada variável declarada não pode ter sido declarada previamente. As declarações de variáveis podem ser de tipos simples ou de ponteiros para os tipos simples. Pode-se fazer declaração de variáveis e procedimentos, seguidas de um novo comando, garantindo assim um maior poder de expressividade à linguagem.

Exemplo

1 {var a = 0;

2 proc soma (a int, b int){

3 a := a + b;

4 skip

3.4.2 Atribuição

Sintaxe

Atribuicao ::= Id ":=" Expressao

Semântica

Representa a mudança de valor de uma variável previamente definida. Primeiramente ele verifica se esse identificador já foi declarado, e se sim, ele avalia a expressão. Caso o tipo da expressão e do identificador forem os mesmos, o valor da expressão é calculado e armazenado na posição de memória definida para a variável correspondente. Caso os tipos sejam diferentes, será dado um erro de tipos.

Exemplos

1 casa := “casa”

1 tarci := “sio”

1 sessenta := 25 + 25

3.4.5 RepeatUntil

Sintaxe

RepeatUntil ::= “repeat” Comando “until” Expressao

Semântica

Representa um dos três tipos de laço da linguagem. Inicialmente, o trecho de código (COMANDO) é executado. Ao final de cada iteração, o valor de EXPRESSAO é avaliado. Se não for do tipo Booleano, será dado um erro. Caso resulte em TRUE, o fluxo de execução é desviado para o início do COMANDO.

Exemplo

2 var a := 0,

3 var x := 5;

5 repeat

6 a := a + 2;

7 x := x – 1

8 until x > 0

3.4.6 IfThenElse

Sintaxe

IfThenElse ::= "if" Expressao "then" Comando "else" Comando

Semântica

Inicialmente, o valor de EXPRESSAO é avaliado. Caso ela não seja do tipo Booleano, um erro será indicado. Se resultar em TRUE, o trecho de código (COMANDO) seguinte ao “then” é executado. Caso contrário, o trecho de código (COMANDO) seguinte ao “else” é executado.

Exemplo

1 if x > 0 then

2 y := x

4 else

5 y := - x

3.4.7 IO

Sintaxe

IO ::= "write" "(" Expressao ")"

| "read" "(" Id ")"

Semântica

Representam os procedimentos nativos para implementação de IO do usuário. O “write” envia a saída (EXPRESSAO) para o console. O “read” requisita a entrada de dados a partir do teclado. O valor fornecido é convertido para o tipo do destino e armazenado na variável passada na chamada do INPUT. Caso a string lida não possa ser convertida para o tipo do identificador, será dado um erro. O comando de INPUT pára a execução do programa até que o usuário digite um valor para a variável.

Exemplo

1 write (“Digite um numero”);

2 read (a);

3 write (“Digite outro numero”);

4 read (b);

5 write (“Soma:”);

6 write (a + b);

3.4.8 Skip

Sintática

Skip ::= "skip"

Semântica

Esse comando não muda o estado do programa, cujo fluxo segue normalmente após ele.

Exemplo

2 var cont = 0;

3 Skip

3.4.9 Chamada de Procedimento

4 Sintaxe Abstrata

A codificação do interpretador foi elaborada na linguagem de programação funcional Haskell. Dessa forma, na nossa sintaxe abstrata fez-se uso do tipo algébrico DATA e do tipo enumerável TYPE. O tipo algébrico DATA foi usado para representar as produções da gramática e o tipo TYPE foi usado para indicarmos qual o tipo primitivo de Haskell iremos usar para representar algum terminal da gramática. As funções Eq e Show são classes pré-definidas da linguagem Haskell. A classe Show representa todos os tipos que podem ser convertidos em listas de caracteres, em Haskell, String. Já a classe Eq representa o conjunto de tipos em que o operador (==) da linguagem Haskell está definido. Abaixo apresentamos a sintaxe abstrata que foi elaborada e que será a forma pela qual o interpretador da linguagem avaliará os programas.

4.1 Tipo

data Tipo = NONE | INT | STR | BOOL | PINT | PSTR | PBOOL deriving (Eq, Show)

4.2 Valores

data Valor = Null | PI Endereco | PS Endereco | PB Endereco | I Int | S String | B Bool deriving (Eq, Show)

4.3 Expressões

data Expressao = L Valor -- Literal | ID Id -- Valor da memoria | Soma Expressao Expressao -- Soma | Sub Expressao Expressao -- Subtracao | Igual Expressao Expressao -- Igual | And Expressao Expressao -- AND | Or Expressao Expressao -- OR | Concat Expressao Expressao -- Concatenacao | Menos Expressao -- Trocar o sinal | Not Expressao -- Trocar true/false | Ref Id -- Retorna a referencia de uma variavel | Deref Expressao -- Retorna o conteúdo da posição de memória dada deriving (Eq, Show)

4.4 Comandos

data Comando = Skip | Comandos [Comando] --lista de comandos [comando;comando]

| Chamada Id [Expressao] -- chamada procedimento [call id atributos] | Declaracao [ListaDeclaracao] Comando -- listra declaracao [declaracao;comando] | Read Id --leitura | Write Expressao --escrita | Atribuicao Id Expressao --atribuicao id = expressao | IfThenElse Expressao Comando Comando -- if then else | While Expressao Comando -- while | RepeatUntil Comando Expressao -- do while | For Id Expressao Expressao Comando -- for | Write2 Expressao -- escreve no buffer de leitura [pilha] qualquer coisa remove deriving (Eq, Show)

4.5 Lista de Declarações

data ListaDeclaracao = DeclProc Procedimento

| DeclVar Id Expressao

| DeclPointer Id Tipo

deriving (Eq, Show)

4.6 Procedimentos

data Procedimento = Proc Id Params Comando deriving (Eq, Show)

5.6 Escopo

O escopo da linguagem é apenas local. Assim, o escopo de um procedimento não é englobado pelos procedimentos que são chamados por ele.

6 Principais Funções

6.1 Função de Atribuição

Recebe o identificador juntamente com o valor a ser atribuído e o estado atual do programa, dando como resultado o novo estado do programa (tabela de símbolos e memória atualizadas). Também faz a verificação de tipos entre o valor a ser atribuído e o tipo do atributo na tabela de símbolos.

atribuicao :: Id -> Valor -> Estado -> Estado atribuicao id valor (Normal idt proc mem inp out) | tipo == NONE = (Erro ("variavel " ++ id ++ " nao declarada")) | id == varname && (tipo == (tipoValor valor)) = (Normal idt proc (sobrescreverValor add valor mem) inp out) | id == varname && (tipo /= (tipoValor valor)) = (Erro "atribuicao entre tipos diferentes") | otherwise = (Erro "erro desconhecido na atribuicao") where (varname,tipo,add) = (getVariavel id idt)

6.2 Função de Declaração

Adiciona um elemento na tabela de símbolos retornando um valor booleano representando a efetivação, ou não, da declaração. Caso o identificador já tenha sido declarado ou haja alguma inconsistência na entrada dos dados da função o retorno é falso. Caso contrário o retorna true. Esse tipo de retorno booleano é usado para um tratamento posterior de possíveis erros.

declarar :: [ListaDeclaracao] -> Estado -> Estado --metodo que faz a declaração da lista de coisas [sejam procedimentos ou variaveis] declarar [] s = s --caso lista vazia retorne estado atual declarar [(DeclProc (Proc id params cmd))] (Normal idt ptb mem inp out) --caso base [a lista contem apenas a declaracao de um procedimento] | (procDeclarado id ptb) = (Erro ("ja existe um procedimento com o id " ++ id) ) | (paramRepetido params) = (Erro ("o procedimento '" ++ id ++ "' tem parametros com o mesmo nome") ) | otherwise = (Normal idt (addProc (Proc id params cmd) ptb) mem inp out) declarar [DeclPointer id tipo] s = (declaracao id tipo s) --caso base [a lista contem apenas a declaracao de um apontador declarar [DeclVar id exp] s = (atribuicao id e (declaracao id (tipoValor e) s)) --caso base apenas uma declaracao de variavel where e = (expressao exp s) declarar ((DeclProc (Proc id params cmd)):as) (Normal idt ptb mem inp out) --caso base a cabeça da lista eh um procedimento | (procDeclarado id ptb) = (Erro ("ja existe um procedimento com o id " ++ id) ) | (paramRepetido params) = (Erro ("o procedimento '" ++ id ++ "' tem parametros com o mesmo nome") ) | otherwise = (declarar as (Normal idt (addProc (Proc id params cmd) ptb) mem inp out))