Para ler esta seção é necessário que você tenha entendido pilhas e dicionários.
A calculadora a ser implementada deve ler várias expressões na notação polonesa na forma de strings (a função input() faz o serviço) e calcular o valor de cada uma das expressões, de maneira semelhante ao Python Shell.
Para calcular o valor de uma expressão, o string de entrada deve ser processado para identificar cada elemento (token) que compõe a expressão. Essa foi a missão do EP6 e EP7.. Os tokens permitidos nesse EP são de 3 categorias: NUMERO, VARIAVEL, e OPERADOR.
O nome de uma variável é uma sequência de letras, números e _, começando por uma letra.
Por exemplo, a expressão polonesa 'abc 7 5 2 - * 4 ! / =', que equivale a expressão infixa 'abc = (7*(5-2))/!4', é composta de 10 tokens, como a função tokeniza() pode comprovar:
Python 3.4.3 (default, Mar 26 2015, 22:03:40)
[GCC 4.9.2] on linux
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
>>> lista = tokeniza("abc 7 5 2 - * 4 ! / =")
>>> imprima_tokens(lista)
[V('abc'), N(7), N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')]
>>>
Os tokens são representados como objetos da classe Token. Como foi feito no EP7, esses objetos serão instâncias da classe Token que foi definida no modulo tokeniza.py.
Uma vez convertida a expressão para uma lista de tokens pela função tokeniza(), cada token é processado da seguinte forma. Considere uma pilha de execução inicialmente vazia e um dicionário de variáveis também inicialmente vazio:
- Tokens das categorias NUMERO e VARIAVEL são empilhados na pilha de execução. A pilha de execução contém apenas objetos da classe Token que são das categorias NUMERO e VARIAVEL.
- Tokens da categoria OPERADOR exigem que desempilhemos um número apropriado de operandos (= números ou variáveis) da pilha de execução, a operação é executada utilizando os valores desses tokens como argumentos. No caso de uma variável, o valor numérico armazenado no dicionário e utilizado como argumento. O resultado da operação é empilhado na pilha de execução como um novo objeto da classe ``Token`` de categoria NUMERO.
- O operador de atribuição (símbolo '=') pode alterar o valor de uma variável já existente no dicionário de variáveis ou criar uma nova variável que está sendo criada pela primeira vez. Esse comportamento é identico ao do Python.
- Quando o último token da lista de tokens é processado, caso a expressão seja válida, o resultado deve ser o único objeto na pilha de execução, Esse elemento deve ser um token da categoria NUMERO ou VARIAVEL. Em caso contrário a expressão é inválida.
Para entender esse processamento, acompanhe a simulação a seguir.
Considere a seguinte lista de de tokens:
>>> tokens = tokeniza("var 7 5 2 -* 4 !/=")
>>> imprima_tokens(tokens)
[V('var'), N(7), N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')]
>>> >>> tokens = tokeniza("var 7 5 2 -* 4 !/=")
>>> imprima_tokens(tokens)
[V('var'), N(7), N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')]
>>>
A medida que a lista tokens é processada da esquerda para a direita:
- V('var'), N(7), N(5) e N(2) são empilhados na pilha de execução;
- O('-') exige que N(5) e N(2) sejam desempilhado e o valor de 5-2 seja calculado e token N(3) seja empilhado;
- O('*') faz que N(3) e N(7) e sejam desempilhado, o valor de 7*3 seja calculado e empilha na forma do token N(21);
- N(4) é empilhado;
- O('!') faz com que N(4) seja desempilhado , o valor de -4 seja calculado e empilha na forma do token N(-4);
- O('/') desempilha N(-4) e N(21), calcula o valor de 21/-4, e empilha o resultado na forma N(-5.25); e
- O('=') faz com que N(-5.25) e V('var') sejam desempinhados, insere chave 'var'``no dicionário de variáveis com valor ``-5.25, e empilha esse valor na forma N(-5.25).
A tabela abaixo mostra o estado da lista de tokens a serem processados, da pilha de execução e do dicionário de variáveis a cada vez que um token da lista é tratado.
lista de tokens | pilha de execução | dicionário de variáveis |
---|---|---|
[V('var'), N(7), N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')] | [] | {} |
[N(7), N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')] | [V('var')] | {} |
[N(5), N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')] | [V('var'), N(7)] | {} |
[N(2), O('-'), O('*'), N(4), O('!'), O('/'), O('=')] | [V('var'), N(7), N(5)] | {} |
[O('-'), O('*'), N(4), O('!'), O('/'), O('=')] | [V('var'), N(7), N(5), N(2)] | {} |
[O('*'), N(4), O('!'), O('/'), O('=')] | [V('var'), N(7), N(3)] | {} |
[N(4), O('!'), O('/'), O('=')] | [V('var'), N(21)] | {} |
[O('!'), O('/'), O('=')] | [V('var'), N(21), N(4)] | {} |
[O('/'), O('=')] | [V('var'), N(21), N(-4)] | {} |
[O('=')] | [V('var'), N(-5.25)] | {} |
[] | [N(-5.25)] | {'var': -5.25} |