1. Objetivo Laboratório de Linguagens de Programação Trabalho Prático I O objetivo desse trabalho é desenvolver um interpretador para uma linguagem de programação fictícia chamada DTS (Digital Tone Synthesizer). Essa linguagem é capaz de tocar notas musicais no autofalante de beeps do computador com diversas durações. Com isso é possível emular músicas através dessa interface. A linguagem é capaz de tocar uma nota com certa duração, pausar por um determinado tempo, usar expressões e variáveis inteiras, comandos condicionais e de repetição. 2. Contextualização O beep do PC pode ser acessado por chamadas de sistema tanto no Linux quanto no Windows. Já o Macintosh não possui um autofalante de beeps, sendo necessário usar formatos de músicas como midi ou mp3. No Linux, existe a ferramenta beep (/usr/bin/beep) capaz de executar uma nota definindo sua frequência (-f) e duração (-l). Por exemplo, para tocar a nota Lá (A), frequência 440.0Hz, por 1 segundo (1000ms), basta executar o seguinte comando: $ /usr/bin/beep f 440.0 l 1000 Esse comando será usado pelo interpretador para executar comandos no Linux. Uma função em C e uma classe em Java para esse propósito podem ser encontradas na pasta do trabalho. Tabela 1. Frequências das doze (12) notas no 4 grau. Nota Frequência Frequência Nome Nota (Hz) (Hz) Nome C 261.6 Dó F# 370.0 Fá sustenido C# 277.2 Dó sustenido G 392.0 Sol D 293.7 Ré G# 415.3 Sol sustenido D# 311.1 Ré sustenido A 440.0 Lá E 329.6 Mi A# 466.2 Lá sustenido F 349.2 Fá B 493.9 Si Figura 1. Partitura da música Cai Cai Balão.
As frequências das 12 notas musicais podem ser encontradas na Tabela 1. O beep é capaz de tocar apenas uma nota por vez, portanto a linguagem DTS não suporta acordes (combinações de notas). Por exemplo, a música Cai Cai Balão cuja partitura é mostrada na Figura 1 pode ser expressa na linguagem DTS conforme programa a seguir, cujo tempo musical é de 400ms: tempo 400; musica "Cai Cai Balão"; faca i = 1; repetir (i =< 2); faca tocar(g, 1) : "Cai,"; tocar(g, 1.) : "cai,"; + meia tocar(f, %2) : "ba"; // fa colcheia se (j =< 2); faca tocar(e, 1) : "lao."; // fa seminima senao tocar(e, 1) : "lao"; // fa minima i = i + 1; tocar(g, 1) : "na"; tocar(a, 1) : "ru"; tocar(g, 1) : "a"; tocar(f, 1) : "do"; tocar(e, 1) : "sa"; tocar(d, 2) : "bao"; pausar(1); // la seminima // fa seminima // mi seminima // re minima // intervalo j = 1; repetir (j =< 3); faca tocar(d, %2) : "Nao"; // re colcheia tocar(e, %2) : "cai"; // mi colcheia se (j =< 2); faca tocar(f, 1) : "nao."; // fa seminima senao tocar(f, 2) : "nao."; // fa minima j = j + 1; tocar(g, 1) : "Cai"; tocar(a, 1) : "a"; tocar(g, 1) : "qui"; tocar(f, 1) : "na"; tocar(e, 1) : "mi"; tocar(d, 1) : "nha"; tocar(c, 2) : "mao!"; cai-cai-balao.dts // la seminima // fa seminima // mi seminima // re seminima // do minima
3. Descrição Um programa DTS possui as seguintes características: Um tempo opcional em milissegundos que deve ser informado uma única vez antes da música. Caso não seja especificado, deve-se considerar 500ms. o Ex.: tempo = 400ms; Todo programa deve obrigatoriamente conter a seção musica com seu respectivo nome, onde comandos são dados entre as palavrasreservadas faca e. o Ex.: musica "cai cai balão"; faca... Comentários de única linha, estilo C. o Ex.: int i = 1; // iniciar variável i com valor 1 Doze (12) notas musicais com letras maiúsculas e símbolo #. o Ex.: A ou C# Duração como um número que indica a quantidade de tempo em três formatos: número simples (tempo * numero), número seguido de ponto (tempo * numero * 1.5) e número prefixado com uma porcentagem (tempo / numero). o Ex: 1, 2., %4 Literais inteiras. o Ex: 5 Literais strings. o Ex: "cai" Variáveis que só podem ter um única letra minúscula. o Ex.: a ou v Expressões inteiras. o Ex: x + 1 Além disso, um programa DTS é formado por cinco (5) tipos de comandos distintos: Tocar: recebe uma nota e uma duração e tem o efeito de tocar essa nota com essa duração no autofalante de beep. Opcionalmente, podese associar uma palavra a essa nota. Deve terminar com ponto-vírgula. o Ex.: tocar(a#, 2); // tocar lá sustenido em 2 tempos o Ex: tocar(g, 1) : "cai"; // tocar sol em 1 tempo com texto "cai" Pausar: recebe uma duração e tem o efeito de interromper momentaneamente a música por essa duração. Não pode ter uma palavra associada. Deve terminar com ponto-vírgula. o Ex: pausar(1); // interromper por 1 tempo Atribuir: atribuir uma expressão aritmética simples (sempre com somente dois operandos) a uma variável. Deve terminar com pontovírgula. o Ex.: x = x+ 1;
Se: recebe uma expressão booleana entre parênteses e executa os comandos entre faca e se avaliar em verdadeiro. Opcionalmente pode incluir um bloco senao, que executa os comandos se a expressão avaliar em falso. o Ex: se (x == 1); faca... o Ex: se (x < 0); faca... senão... Repetir: recebe uma expressão booleana entre parênteses e executa os comandos entre faca e enquanto a expressão avaliar em verdadeiro. Ao avaliar em falso deve-se continuar a execução do programa executando o primeiro comando imediatamente após esse. o Ex.: repetir (x < 5); faca... A gramática para as expressões lógicas e inteiras é dada na gramática estendida de Backus-Naur Form (EBNF): <bool-expr> ::= <term> <rel_op> <term> <rel_op> ::= ==!= < > =< >= <int-expr> ::= <term> [ <arith_op> <term> ] <arith_op> ::= + - * / <term> 4. Instruções ::= <var> <num> Deve ser desenvolvido um interpretador em linha de comando que recebe um programa-fonte na linguagem DTS como argumento e executa os comandos especificados pelo programa. Os comandos Tocar e Pausar, além de suas respectivas funções, eles devem imprimir na saída do terminal conforme a seguir: Por exemplo, para o programa cai-cai-balao.dts deve-se tocar a música no beep e mostrar no terminal : $ dtsi cai-cai-balao.dts (G, 400.0) -> Cai, (G, 600.0) -> cai, (F, 200.0) -> ba (E, 400) -> lao. (G, 400) -> Cai, (G, 600) -> cai, (F, 200) -> ba (E, 400) -> lao (G, 400) -> na (A, 400) -> ru (G, 400) -> a (F, 400) -> do (E, 400) -> sa (D, 800) -> bao. (400) (D, 200) -> Nao (E, 200) -> cai (F, 400) -> nao. (D, 200) -> Nao (E, 200) -> cai (F, 400) -> nao. (D, 200) -> Nao (E, 200) -> cai (F, 800) -> nao. (G, 400) -> Cai (A, 400) -> a (G, 400) -> qui (F, 400) -> na (E, 400) -> mi (D, 400) -> nha (C, 800) -> mao!
O programa deverá abortar sua execução, em caso de qualquer erro léxico, sintático ou semântico, indicando uma mensagem de erro. As mensagens de erro são padronizadas indicando o número da linha (com no mínimo 2 dígitos) onde ocorreram: Tipo de Erro Léxico Sintático Semântico Mensagem Lexema inválido [lexema] Fim de arquivo inesperado Lexema não esperado [lexema] Fim de arquivo inesperado Operação inválida Exemplo de mensagem de erro: 5. Avaliação $ dtsi erro.dts 03: Lexema não esperado [;] O trabalho deve ser feito em grupo de até dois alunos, sendo esse limite superior estrito. O trabalho será avaliado em 15 pontos, onde essa nota será multiplicada por um fator entre 0.0 e 1.0 para compor a nota de cada aluno individualmente. Esse fator poderá estar condicionado a apresentações presenciais a critério do professor. Trabalhos copiados, parcialmente ou integralmente, serão avaliados com nota ZERO, sem direito a contestação. Você é responsável pela segurança de seu código, não podendo alegar que outro grupo o utilizou sem o seu consentimento. 6. Submissão O trabalho deverá ser submetido até as 23:55 do dia 05/10/2015 (segunda-feira) via sistema acadêmico (Moodle) em pasta específica. Não serão aceitos, em hipótese alguma, trabalhos enviados por e-mail ou por quaisquer outras fontes.
Class Diagram0 2015/10/02 powered by Astah pkg Lexema + type : Integer + token : String AnalisadorLexico - arquivo : FILE - linha : int - tabelasimbolos : Map<String,Integer> + AnalisadorLexico(nomeArquivo : String) + getlinha() : int + nexttoken() : Lexema - iniciartabelasimbolos() : void - consultartabelasimbolos(string : int) : Integer AnalisadorSintatico - lexico : AnalisadorLexico - atual : Lexema + AnalisadorSintatico(lexico : AnalisadorLexico) + init() : BlocoComandos - matchtoken(type : Integer) : void - procprogram() : BlocoComandos - proctempo() : TempoComando - proccomandos() : BlocoComandos - proccomando() : Comando - proctocar() : TocarComando - procpausar() : PausarComando - procatribuir() : AtribuirComando - procse() : SeComando - procrepetir() : RepetirComando - procexprbool() : ExprLogica - procexprint() : ExprInteira - proctermo() : Termo - procoprel() : RelOp - procoparit() : ArithOp - procnota() : Nota - procduracao() : double - procvar() : Variavel - procnum() : ConstInt - procstring() : String Comando Termo Expressao<E> <<enum>> Nota + La : double + LaSustenido : double + Si : double + Do : double + DoSustenido : double + Re : double + ReSustenido : double + Mi : double + Fa : double + FaSustenido : double + Sol : double + SolSustenido : double + nome() : String + frequencia() : double BlocoComandos TocarComando - comandos : List<Comando> - nota : Nota - duracao : double + BlocoComandos() : void - palavra : String + adicionarcomando(c : Comando) : void + TocarComando(nota : Nota, duracao : double, palavra : String) TempoComando AtribuirComando - tempo : ConstInt - var : Variavel - expr : ExprInteira Tempo + TempoComando(tempo : ConstInt) + AtribuirComando(var : Variavel, expr : ExprInteira) - tempo : int + settempo(tempo : int) : void + gettempo() : int + getvalor() : int + avaliar() : E <<Integer>> PausarComando ConstInt Variavel ExprInteira - tempo : ConstInt - valor : int - valor : int + avaliar() : Integer + PausarComando(tempo : ConstInt) + ConstInt(valor : int) + Variavel() + getvalor() : int + getvalor() : int + setvalor(valor : int) : void RepetirComando ExprIntSimples ExprIntDupla - expr : ExprLogica - termo : Termo - termo1 : Termo - comandos : BlocoComandos - op : ArithOp + ExprIntSimples(termo : Termo) + RepetirComandos(expr : ExprLogica, comandos : BlocoComandos) - termo2 : Termo + avaliar() : Integer + ExprIntDupla(termo1 : Termo, op : ArithOp, termo2 : Termo) + avaliar() : Integer <<Boolean>> ExprLogica + avaliar() : Boolean ExprLogicaDupla - termo1 : Termo - op : RelOp - termo2 : Termo + ExprLogicaDupla(termo1 : Termo, op : RelOp, termo2 : Termo) + avaliar() : Boolean SeComando - expr : ExprLogica - comandosse : BlocoComandos - comandossenao : BlocoComandos + SeComando(expr : ExprLogica, comandosse : BlocoComandos, comandossenao : BlocoComandos) <<enum>> ArithOp <<enum>> RelOp - Mais : int - Menos : int - Multiplicacao : int - Divisao : int - Igual : int - Diferente : int - Menor : int - MenorIgual : int - Maior : int - MaiorIgual : int