






















Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
APOSTILA DE PROGRAMAÇÃO em haskell
Tipologia: Exercícios
1 / 30
Esta página não é visível na pré-visualização
Não perca as partes importantes!























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.
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.
3.1 Tipos básicos e valores
Sintaxe
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.
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
Exemplo
3.3.1 Expressão Unária
Sintaxe
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
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
3.3.3 Identificador
Sintaxe
Semântica O valor dessa expressão é o conteúdo do identificador, que está armazenado na memória.
Exemplo
3.3.4 Endereço do identificador
Sintaxe
Semântica
Representa o valor do endereço no qual o ponteiro Id está armazenado.
Exemplos
3.4.1 Comando Declaração
Sintaxe
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
3.4.2 Atribuição
Sintaxe
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
3.4.5 RepeatUntil
Sintaxe
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
3.4.6 IfThenElse
Sintaxe
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
Sintaxe
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
3.4.8 Skip
Sintática
Semântica
Esse comando não muda o estado do programa, cujo fluxo segue normalmente após ele.
Exemplo
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
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))