.. -- coding: utf-8 -- .. Copyright (C) Coelho e Hitoshi Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with Invariant Sections being Forward, Prefaces, and Contributor List, no Front-Cover Texts, and no Back-Cover Texts. .. shortname:: EP7 .. description:: calculadora parte A Exercício Programa 7: Calculadora - Parte B =========================================== Descrição --------- Este é o segundo de uma série de exercícios-programas que têm como objetivo a construção de um interpretador de expressões simples em *notação infixa* que, como em um programa, também poderão conter variáveis. Exemplos de expressões que o interpretador executará são: .. sourcecode:: python mp = (p1 + 2*p2 + 2*p3)/5 nota_final = 0.75*mp + 0.25*me nr = (prec + nf)/2 Como pode ser notado, as expressões serão semelhantes àquelas encontradas em linguagens de programação. Assim como em Python, variáveis poderão ser criadas por meio de atribuições e reutilizadas em expressões futuras. .. sourcecode:: python Python 3.4.3 (default, Mar 26 2015, 22:07:01) [GCC 4.9.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 1 + 2 3 >>> 3.14 * 6 18.84 >>> p1 = 4 >>> p2 = 5 >>> p3 = 6 >>> mp = (p1 + 2*p2 + 2*p3)/5 >>> mp 5.2 >>> me = 6 >>> nota_final = 0.75*mp + 0.25*me >>> nota_final 5.4 >>> >>> nota_final = 4 >>> nota_final 4 >>> prec = 5.5 >>> nr = (prec + nota_final)/2 >>> nr 4.75 >>> Durante o processo da construção desse interpretador aprenderemos e revisaremos vários conceitos de programação, algoritmos e estruturas de dados: orientação a objetos, pilhas, tabelas de símbolos, dicionários, etc. Neste exercício programa você deverá fazer escrever uma classe chamada ``Token`` e adaptar a sua função ``tokeniza()`` para retornar uma lista de objetos da classe ``Token`` em vez de uma lista de objetos da forma ``[item,tipo]`` Objetivos --------- - Continuar o desenvolvimento da habilidade de resolver problemas computacionais a partir de tipos básicos como listas, strings e dicionários. - Utilizar novas estruturas (pilhas e filas). - Motivar o uso de classes de objetos na resolução de problemas. O que você deve fazer --------------------- Primeiro, você deve baixar os arquivos `main.py `__, `operadores.py `__ e `esqueleto_tokeniza.py `__. O módulo ``main.py`` contém a função ``main()`` que é a função principal do projeto (= função que coordena o programa). A função ``main()`` está completamente escrita e **nada** no módulo ``main.py`` deve ser alterado. O módulo ``operadores.py`` contém um dicionário com uma descrição dos operadores aritméticos e parênteses. Esse módulo é utilizado apenas pela função ``main()`` e **também não** deve ser alterado. Já o módulo ``tokeniza.py`` contém: - uma função de nome ``imprima_tokens()`` que está completa e **não deve** ser alterada; .. sourcecode:: python def imprima_tokens(tokens): ''' (list) -> None Recebe uma lista tokens em que cada objeto é da classe Token e imprime a descrição de cada objeto lista. Para funcionar, está função necessita que o método __str__() da classe Token tenha sido implementado. ''' - o esqueleto da classe ``Token()`` que você deve fazer; e .. sourcecode:: python class Token: ''' Classe utilizada para representar itens léxicos. Cada objeto têm dois atributos: item e tipo. O atributo item de um objeto Token é - um float: no caso do item ser um número; ou - um string no caso do item ser um operador ou uma variável ou um abre/fecha parenteses. O componente tipo de um objeto token indica é um inteiro que indica a que categoria ele pertence. - OPERADOR = 1; - NUMERO = 2; - VARIAVEL = 3; ou - PARENTESES = 4. ''' - o cabeçalho da função ``tokeniza()`` que você também deve fazer. .. sourcecode:: python def tokeniza(exp): """(str) -> list (de Tokens) Recebe uma string exp representando uma expressão e cria e retorna uma lista de objetos da classe Token representando os itens léxicos que formam a expressão. Cada item léxico é representado por um objeto Token que possui é formado por um atributos: item e tipo. O atributo item de um token faz referência a: - um float: no caso do item ser um número; ou - um string no caso do item ser um operador ou uma variável ou um abre/fecha parenteses. O atributo tipo de um token faz referência à sua categoria (ver definição em token.py). - OPERADOR; - NUMERO; - VARIAVEL; ou - PARENTESES A funçao ignora tudo que esta na exp apos o caractere COMENTARIO (= "#"). """ Sugestão de roteiro para fazer este EP -------------------------------------- Faça o download dos arquivos do EP7 e depois escreva os métodos e função como sugeridos a seguir. ``__init__()`` '''''''''''''' Comece escrevendo o método ``__init__()`` que é o construtor da classe ``Token``. .. sourcecode:: python def __init__(self,item,tipo): '''(Token, float ou str, int) -> Token Construtor: cria e retorna um objeto Token. Magica: função retorna mas não tem return. ''' print("Vixe! Ainda não fiz esse método.") Depois de escrevê-la, execute o módulo (= ``Run -> Run Module``) e teste-a no Python Shell. .. sourcecode:: python Python 3.4.3 (default, Mar 26 2015, 22:07:01) [GCC 4.9.2] on linux Type "copyright", "credits" or "license()" for more information. >>> ================================ RESTART ================================ >>> >>> t1 = Token("+",OPERADOR) >>> t1.item '+' >>> t1.tipo 1 >>> t2 = Token(3.14,NUMERO) >>> t2.item 3.14 >>> t2.tipo 2 >>> t3 = Token("soma",VARIAVEL) >>> t3.item 'soma' >>> t3.tipo 3 >>> t4 = Token("(",PARENTESES) >>> t4.item '(' >>> t4.tipo 4 ``__str__()`` '''''''''''''' Agora, escreva o método ``__str__()`` .. sourcecode:: python def __str__(self): ''' (Token) -> str Retorna o string que print() usa para exibir um Token ''' O seu método ``__str__()`` deve produzir resultados **iguais** aos que estão a seguir. .. sourcecode:: python >>> >>> t1 = Token("+",OPERADOR) >>> str(t1) "O('+')" >>> print(t1) O('+') >>> t2 = Token(3.14,NUMERO) >>> str(t2) 'N(3.14)' >>> print(t2) N(3.14) >>> t3 = Token("soma",VARIAVEL) >>> str(t3) "V('soma')" >>> print(t3) V('soma') >>> t4 = Token("(",PARENTESES) >>> str(t4) "P('(')" >>> print(t4) P('(') >>> Depois que o seu método ``__str__()`` estiver se comportando como mostrado acima, a função ``imprima_tokens()`` poderá ser usada, pois ela utiliza a função ``str()`` para converter um objeto da classe ``Token``para um string. A função ``str()``, para fazer o seu serviço, chama o método ``__str()__`` que você escreveu. .. sourcecode:: python >>> t1 = Token("+",OPERADOR) >>> t2 = Token(3.14,NUMERO) >>> t3 = Token("soma",VARIAVEL) >>> t4 = Token("(",PARENTESES) >>> lista_de_tokens = [t1,t2,t3,t4] >>> imprima_tokens(lista_de_tokens) [O('+'), N(3.14), V('soma'), P('(')] >>> ``get_item()`` e ``get_tipo()`` ''''''''''''''''''''''''''''''' Agora, escreva os métodos ``get_item()`` e ``get_tipo()``. Com isso, a definição da classe ``Token`` estará completa. .. sourcecode:: python def get_item(self): ''' (Token) -> str ou float Retorna o conteúdo do atributo item do Token. Se o atributo tipo é OPERADOR, PARENTESES OU VARIAVEL o item retornado será um string (class str). Se o atributo tipo é NUMERO o item retornado será um float. ''' def get_tipo(self): ''' (Token) -> int Retorna o conteúdo do atributo tipo do Token. Se o valor retornado é OPERADOR, PARENTESES, VARIAVEL ou NUMERO ''' A seguir estão exemplos que mostram como os métodos ``get_item()`` e ``get_tipo()`` devem se comportar. .. sourcecode:: python >>> t1 = Token("+",OPERADOR) >>> t1.get_item() '+' >>> t1.get_tipo() 1 >>> t2 = Token(3.14,NUMERO) >>> t2.get_item() 3.14 >>> t2.get_tipo() 2 >>> t3 = Token("soma",VARIAVEL) >>> t3.get_item() 'soma' >>> t3.get_tipo() 3 >>> t4 = Token("(",PARENTESES) >>> t4.get_item() '(' >>> t4.get_tipo() 4 ``tokeniza()`` '''''''''''''' Finalmente, você deve copiar a função ``tokeniza()`` escrita para o EP6 e adaptá-la para retornar objetos do tipo ``Token`` em vez de uma lista de objetos da forma ``[item,tipo]``. Eis alguns exemplos de execução da "nova" função ``tokeniza()``. .. sourcecode:: python >>> >>> lista = tokeniza("+") >>> imprima_tokens(lista) [O('+')] >>> lista = tokeniza("=^! - +/* %") >>> imprima_tokens(lista) [O('='), O('^'), O('!'), O('-'), O('+'), O('/'), O('*'), O('%')] >>> lista = tokeniza("") >>> imprima_tokens(lista) [] >>> lista = tokeniza("123") >>> imprima_tokens(lista) [N(123)] >>> lista = tokeniza(".5") >>> imprima_tokens(lista) [N(0.5)] >>> lista = tokeniza("12.5") >>> imprima_tokens(lista) [N(12.5)] >>> lista = tokeniza("v") >>> imprima_tokens(lista) [V('v')] >>> lista = tokeniza("v_1") >>> imprima_tokens(lista) [V('v_1')] >>> lista = tokeniza("v_1 var nome_var") >>> imprima_tokens(lista) [V('v_1'), V('var'), V('nome_var')] >>> lista = tokeniza(" ") # string com espaços >>> imprima_tokens(lista) [] >>> lista = tokeniza("(()(") # string apenas com parenteses >>> imprima_tokens(lista) [P('('), P('('), P(')'), P('(')] >>> lista = tokeniza("mp = (p1 + 2*p2 + 2*p3)/ 5") >>> imprima_tokens(lista) [V('mp'), O('='), P('('), V('p1'), O('+'), N(2), O('*'), V('p2'), O('+'), N(2), O('*'), V('p3'), P(')'), O('/'), N(5)] >>> lista = tokeniza(" # esta string tem apenas comentários") >>> imprima_tokens(lista) [] >>> lista = tokeniza(" nf = 4 # nota final < 5 indica rec") >>> imprima_tokens(lista) [V('nf'), O('='), N(4)] >>> **Parte B:** entrega até 05/10 ------------------------------ A seguir esta um exemplo de execução do programa completo (= função ``main()`` do módulo ``main.py``). .. sourcecode:: python Python 3.4.3 (default, Mar 26 2015, 22:07:01) [GCC 4.9.2] on linux Type "copyright", "credits" or "license()" for more information. >>> ================================ RESTART ================================ >>> Entre como uma expressão ou tecle apenas ENTER para encerrar. expressão >>> + '+' : operador aritmético para adição expressão >>> =^! - +/* % '=' : operador para atribuição '^' : operador aritmético para exponenciacao '!' : operador aritmético 'menos unário' '-' : operador aritmético para subtração '+' : operador aritmético para adição '/' : operador aritmético para divisão '*' : operador aritmético para multiplicação '%' : operador aritmético para resto de divisão expressão >>> 123 123 : constante expressão >>> .5 0.5 : constante expressão >>> 12.5 12.5 : constante expressão >>> v_1 'v_1' : nome de variável expressão >>> v_1 var nome_var 'v_1' : nome de variável 'var' : nome de variável 'nome_var' : nome de variável expressão >>> # linha vazia expressão >>> # string apenas com espaços expressão >>> (()( '(' : abre parenteses '(' : abre parenteses ')' : fecha parenteses '(' : abre parenteses expressão >>> mp = (p1 + 2*p2 + 2*p3)/ 5 'mp' : nome de variável '=' : operador para atribuição '(' : abre parenteses 'p1' : nome de variável '+' : operador aritmético para adição 2 : constante '*' : operador aritmético para multiplicação 'p2' : nome de variável '+' : operador aritmético para adição 2 : constante '*' : operador aritmético para multiplicação 'p3' : nome de variável ')' : fecha parenteses '/' : operador aritmético para divisão 5 : constante expressão >>> # esta string tem apenas comentários expressão >>> nf = 4 # nota final < 5 indica rec 'nf' : nome de variável '=' : operador para atribuição 4 : constante expressão >>> >>>