#! /usr/bin/python3

import fsint

def principal():
  """Le comandos, um por linha; executa e mostra o resultado.
  Cada comando eh "<formula>" ou "<variavel> = <formula>". """
  D = {} # Dicionario com valores das variaveis.
  while True:
    C = le_comando()
    if C == "":
      # Acabaram os comandos
      print("Hasta la vista.")
      return
    A = fsint.analisa_comando(C)
    executa_comando(A, D)
  ##----------------------------------------------------------------------
  
def le_comando():
  """Le um comando (uma linha), devolve na forma de uma cadeia de caracteres.
  O usuario pode digitar uma linha vazia para indicar que nao ha mais comandos."""
  cmd = str(input("? "))
  return cmd.strip()  # Remove brancos do inicio e fim da cadeia.
  ##----------------------------------------------------------------------
  
def executa_comando(A,D):
  """Supoe que {A} eh uma arvore de comando, e {D}
  um dicionario que associa nomes de variaveis aos seus valores.
  Executa o comando com arvore {A} usando e/ou atualizando os 
  valores de variaveis em {D}."""
  
  # Determina o {valor} da formumula, atribuindo se for atribuicao:
  if (type(A) is dict) and (A["op"] == '='):
    # Comando de atribuicao. Pega o nome da variavel:
    nomevar = A["arg1"]
    assert type(nomevar) is str # Paranoia
    # Calcula o valod da formula:
    valor = calcula_formula(A["arg2"],D)
    # Guarda no dicionario {D}:
    D[nomevar] = valor
  else:
    # Apenas a formula. Obtem o valor:
    valor = calcula_formula(A,D)
    
  # Mostra o valor:
  print(valor)

  ##----------------------------------------------------------------------
    
def calcula_formula(A,D):
  """Supoe que {A} eh {None} ou uma arvore de formula, e {D}
  um dicionario que associa nomes de variaveis aos seus valores.
  Calcula o valor numerico da formula (como float),
  usando os valores de variaveis em {D}.  Em caso de erro,
  escreve mensagem de avso e devolve {None}.  Se {A} for {None},
  nao escreve nada e devolve {None}"""
    
  if A == None:
    return None
  elif type(A) is float:
    return A
  elif type(A) is int:
    return float(A)
  elif type(A) is str:
    nomevar = A;
    if nomevar in D:
      return D[nomevar]
    else:
      print("** Variavel '" + nomevar + "' nao definida")
      return None
  elif type(A) is dict:
    # Obtem valores dos operandos:
    op = A["op"]
    arg1 = calcula_formula(A["arg1"],D)
    arg2 = calcula_formula(A["arg2"],D)
    arg3 = calcula_formula(A["arg3"],D)
    # Executa a operacao:
    valor = calcula_operacao(op,arg1,arg2,arg3)
    return valor
  else:
    # Arvore de formula mal formada - nao deveria chegar aqui nunca.
    assert False
    
  ##----------------------------------------------------------------------
  
def calcula_operacao(op,arg1,arg2,arg3):
  """Supoe que {op} eh um caracter que indica a operacao a executar,
  e {arg1,arg2,arg3} sao os valores numericos dos operandos, ou {None}
  caso nao sejam necessarios para a operacao. Devolve o valor numerico 
  do resultado.  Se algum dos argumentos necessarios
  for {None}, devolve {None} sem reclamar."""
  
  # Operadores ternarios:
  pass
  
  #Operadores binarios:
  assert arg3 == None # Paranoia
  if op in ("+","-","*","/"):
    if arg1 == None or arg2 == None:
      return None
    assert type(arg1) is float and type(arg2) is float
    if op == "+":
      return arg1 + arg2
    elif op == "-":
      return arg1 - arg2
    elif op == "*":
      return arg1 * arg2
    elif op == "/":
      if arg2 == 0:
        print("** Divisao por zero")
        return None
      else:
        return arg1/arg2
    else:
      assert False
      
  # Operadores unarios:
  assert arg2 == None # Paranoia
  
  # Operador desconhecido:
  assert False 
  
  ##----------------------------------------------------------------------


principal()

# Last edited on 2018-10-16 20:04:15 by stolfilocal
