# -*- coding: utf-8 -*-

import ply.lex as lex
import ply.yacc as yacc
import math

variables = {}

#      _
#     | |
#     | |     _____  _____ _ __
#     | |    / _ \ \/ / _ \ '__|
#     | |___|  __/>  <  __/ |
#     \_____/\___/_/\_\___|_|
#
multiplier = {'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'm': 1e-3, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15}
constants = {'PI': math.pi, 'E': math.e, 'C': 300e8}

class VariableError(Exception): pass
class LexError(Exception): pass
class ConstantError(Exception): pass
class GrammarError(Exception): pass

reserved = {
    'sin': 'SIN', 'cos': 'COS', 'tan': 'TAN',
    'asin': 'ASIN', 'acos': 'ACOS', 'atan': 'ATAN',
    'sqr': 'SQR',
    'rad': 'RAD', 'deg': 'DEG',
    'log': 'LOG', 'ln': 'LN',
    }
tokens = ['ASSIGN', 'NUMBER',
    'PLUS', 'MINUS', 'TIMES', 'DIVIDE',
    'LPAREN', 'RPAREN',
    'POWER',
    # 'ESCAPE',
    'FILTER', 'EOL',
    'ID', 'CONST',
    ]+list(reserved.values())

t_ignore     = " \t"
t_PLUS       = r'\+'
t_MINUS      = r'-'
t_TIMES      = r'\*'
t_DIVIDE     = r'/'
t_LPAREN     = r'\('
t_RPAREN     = r'\)'
t_POWER      = r'\^'
t_ASSIGN     = r'='
# t_ESCAPE     = r'!'
t_FILTER     = r'\|'
t_CONST      = r'[A-Z]+'

def t_comment(t):
    r'\#[^\n]*'
    pass

def t_EOL(t):
    r'\n'
    t.lexer.lineno += t.value.count("\n")
    return t

def t_ID(t):
    r'[a-z][a-z0-9]*'
    t.type = reserved.get(t.value, 'ID')
    return t

def t_NUMBER(t):
    r'(?:(?:\d+(?:[.,]\d+)?)|(?:[.,]\d+))(?:(?:[Ee][+-]?\d+)|T|G|M|k|m|u|n|p|f)?'
    try:
        v = t.value.translate({ord(','): '.'})
        if v[-1] in multiplier.keys():
            t.value = float(v[:-1])*multiplier[v[-1]]
        else:
            t.value = float(v)
    except ValueError:
        print("Integer value too large %d", t.value)
        t.value = 0
    return t

def t_error(t):
    raise LexError(t)


#     ______
#     | ___ \
#     | |_/ /_ _ _ __ ___  ___ _ __
#     |  __/ _` | '__/ __|/ _ \ '__|
#     | | | (_| | |  \__ \  __/ |
#     \_|  \__,_|_|  |___/\___|_|
#
precedence = (
    ('right', 'ASSIGN'),
    # ('right', 'ID'),
    ('left', 'PLUS', 'MINUS'),
    ('right', 'SIN', 'COS', 'TAN', 'ASIN', 'ACOS', 'ATAN'),
    ('right', 'DEG', 'RAD'),
    ('left', 'TIMES', 'DIVIDE'),
    # ('left', 'SQR'),
    ('left', 'POWER'),
    ('right', 'UMINUS', 'FILTER'),
    # ('nonassoc', 'ESCAPE'),
    )

def p_result(p):
    'result : list'
    p[0] = p[1]

def p_list_null(p):
    '''list : EOL'''
    s = (p.lexer.lineno, None)
    p[0] = [s]

def p_list(p):
    '''list : statment EOL'''
    s = (p.lexer.lineno, p[1])
    p[0] = [s]

def p_list_stat(p):
    '''list : list statment EOL'''
    s = (p.lexer.lineno, p[2])
    p[0] = p[1]+[s]

def p_statement_none(p):
    '''statment :'''
    p[0] = None

def p_statement(p):
    '''statment : value'''
    p[0] = p[1]

def p_assign(p):
    '''value : ID ASSIGN value'''
    p[0] = p[3]
    variables[p[1]] = p[3]

def p_val_binop(p):
    '''value : value PLUS value
             | value MINUS value
             | value TIMES value
             | value DIVIDE value'''
    if   p[2] == '+': p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]

def p_val_uminus(p):
    'value : MINUS value %prec UMINUS'
    p[0] = -p[2]

def p_val_angle(p):
    '''value : RAD value
             | DEG value'''
    if p[1] == 'rad': p[0] = p[2]*math.pi/180.0
    else: p[0] = p[2]*180.0/math.pi

def p_val_trig(p):
    '''value : SIN value
             | COS value
             | TAN value'''
    if   p[1] == 'sin': p[0] = math.sin(p[2])
    elif p[1] == 'cos': p[0] = math.cos(p[2])
    elif p[1] == 'tan' : p[0] = math.tan(p[2])

def p_val_atrig(p):
    '''value : ASIN value
             | ACOS value
             | ATAN value'''
    if   p[1] == 'asin': p[0] = math.asin(p[2])
    elif p[1] == 'acos': p[0] = math.acos(p[2])
    elif p[1] == 'atan' : p[0] = math.atan(p[2])

def p_val_power(p):
    '''value : value POWER value'''
    p[0] = math.pow(p[1], p[3])

def p_val_square(p):
    '''value : SQR value'''
    p[0] = math.sqrt(p[2])

def p_val_square_ex(p):
    '''value : SQR value value'''
    p[0] = math.pow(p[3], 1./p[2])

def p_val_ln(p):
    'value : LN value'
    p[0] = math.log(p[2])

def p_val_log(p):
    'value : LOG value'
    p[0] = math.log10(p[2])

def p_val_log_ex(p):
    'value : LOG value value'
    p[0] = math.log(p[3], p[2])

def p_val_group(p):
    'value : LPAREN value RPAREN'
    p[0] = p[2]

def p_val_number(p):
    'value : NUMBER'
    p[0] = p[1]

def p_variable(p):
    'value : ID'
    p[0] = variables.get(p[1], 0)
    # TODO avisar se nao existir

def p_constant(p):
    'value : CONST'
    if p[1] in constants:
        p[0] = constants[p[1]]
    else:
        raise ConstantError( (p[1], p.lexer.lineno) )

def p_error(p):
    # print("Syntax line %d, at '%s'" % (p.lineno, p.value))
    raise GrammarError(p)

# def p_error(p):
#     global flag_for_error
#     flag_for_error = 1

#     if p is not None:
#         errors_list.append("Erreur de syntaxe à la ligne %s"%(p.lineno))
#         yacc.errok()
#     else:
#         print("Unexpected end of input")


#      _   _      _
#     | | | |    | |
#     | |_| | ___| |_ __   ___ _ __
#     |  _  |/ _ \ | '_ \ / _ \ '__|
#     | | | |  __/ | |_) |  __/ |
#     \_| |_/\___|_| .__/ \___|_|
#                  | |
#                  |_|
optimized = True
debug = False

lexer = lex.lex(lextab='solver_lex', optimize=optimized, debug=debug)
parser = yacc.yacc(tabmodule='solver_tab', optimize=optimized, debug=debug)


def solve(text):
    global variables
    variables = {}
    lexer.lineno = 0
    return parser.parse(text+'\n', lexer=lexer, debug=debug, tracking=True)

#      _____         _
#     |_   _|       | |
#       | | ___  ___| |_ ___ _ __
#       | |/ _ \/ __| __/ _ \ '__|
#       | |  __/\__ \ ||  __/ |
#       \_/\___||___/\__\___|_|
#
if __name__ == '__main__':

    import cmd

    class MeuTeste(cmd.Cmd):
        """MeuTeste """

        def __init__(self):
            cmd.Cmd.__init__(self)
            self.prompt = "mt> "
            self.intro  = "Executando o MeuTeste"

        def do_exit(self, args):
            return -1

        def do_EOF(self, args):
            return self.do_exit(args)

        def emptyline(self):
            pass

        def default(self, line):
            print('>>>> ', parser.parse(line+'\n', debug=debug))

    mt = MeuTeste()
    mt.cmdloop()

# -*- coding: utf-8 -*-

import ply.lex as lex
import ply.yacc as yacc
import math

variables = {}

#      _
#     | |
#     | |     _____  _____ _ __
#     | |    / _ \ \/ / _ \ '__|
#     | |___|  __/>  <  __/ |
#     \_____/\___/_/\_\___|_|
#
multiplier = {'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'm': 1e-3, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15}
constants = {'PI': math.pi, 'E': math.e, 'C': 300e8}

class VariableError(Exception): pass
class LexError(Exception): pass
class ConstantError(Exception): pass
class GrammarError(Exception): pass

reserved = {
    'sin': 'SIN', 'cos': 'COS', 'tan': 'TAN',
    'asin': 'ASIN', 'acos': 'ACOS', 'atan': 'ATAN',
    'sqr': 'SQR',
    'rad': 'RAD', 'deg': 'DEG',
    'log': 'LOG', 'ln': 'LN',
    }
tokens = ['ASSIGN', 'NUMBER',
    'PLUS', 'MINUS', 'TIMES', 'DIVIDE',
    'LPAREN', 'RPAREN',
    'POWER',
    # 'ESCAPE',
    'FILTER', 'EOL',
    'ID', 'CONST',
    ]+list(reserved.values())

t_ignore     = " \t"
t_PLUS       = r'\+'
t_MINUS      = r'-'
t_TIMES      = r'\*'
t_DIVIDE     = r'/'
t_LPAREN     = r'\('
t_RPAREN     = r'\)'
t_POWER      = r'\^'
t_ASSIGN     = r'='
# t_ESCAPE     = r'!'
t_FILTER     = r'\|'
t_CONST      = r'[A-Z]+'

def t_comment(t):
    r'\#[^\n]*'
    pass

def t_EOL(t):
    r'\n'
    t.lexer.lineno += t.value.count("\n")
    return t

def t_ID(t):
    r'[a-z][a-z0-9]*'
    t.type = reserved.get(t.value, 'ID')
    return t

def t_NUMBER(t):
    r'(?:(?:\d+(?:[.,]\d+)?)|(?:[.,]\d+))(?:(?:[Ee][+-]?\d+)|T|G|M|k|m|u|n|p|f)?'
    try:
        v = t.value.translate({ord(','): '.'})
        if v[-1] in multiplier.keys():
            t.value = float(v[:-1])*multiplier[v[-1]]
        else:
            t.value = float(v)
    except ValueError:
        print("Integer value too large %d", t.value)
        t.value = 0
    return t

def t_error(t):
    raise LexError(t)


#     ______
#     | ___ \
#     | |_/ /_ _ _ __ ___  ___ _ __
#     |  __/ _` | '__/ __|/ _ \ '__|
#     | | | (_| | |  \__ \  __/ |
#     \_|  \__,_|_|  |___/\___|_|
#
precedence = (
    ('right', 'ASSIGN'),
    # ('right', 'ID'),
    ('left', 'PLUS', 'MINUS'),
    ('right', 'SIN', 'COS', 'TAN', 'ASIN', 'ACOS', 'ATAN'),
    ('right', 'DEG', 'RAD'),
    ('left', 'TIMES', 'DIVIDE'),
    # ('left', 'SQR'),
    ('left', 'POWER'),
    ('right', 'UMINUS', 'FILTER'),
    # ('nonassoc', 'ESCAPE'),
    )

def p_result(p):
    'result : list'
    p[0] = p[1]

def p_list_null(p):
    '''list : EOL'''
    s = (p.lexer.lineno, None)
    p[0] = [s]

def p_list(p):
    '''list : statment EOL'''
    s = (p.lexer.lineno, p[1])
    p[0] = [s]

def p_list_stat(p):
    '''list : list statment EOL'''
    s = (p.lexer.lineno, p[2])
    p[0] = p[1]+[s]

def p_statement_none(p):
    '''statment :'''
    p[0] = None

def p_statement(p):
    '''statment : value'''
    p[0] = p[1]

def p_assign(p):
    '''value : ID ASSIGN value'''
    p[0] = p[3]
    variables[p[1]] = p[3]

def p_val_binop(p):
    '''value : value PLUS value
             | value MINUS value
             | value TIMES value
             | value DIVIDE value'''
    if   p[2] == '+': p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]

def p_val_uminus(p):
    'value : MINUS value %prec UMINUS'
    p[0] = -p[2]

def p_val_angle(p):
    '''value : RAD value
             | DEG value'''
    if p[1] == 'rad': p[0] = p[2]*math.pi/180.0
    else: p[0] = p[2]*180.0/math.pi

def p_val_trig(p):
    '''value : SIN value
             | COS value
             | TAN value'''
    if   p[1] == 'sin': p[0] = math.sin(p[2])
    elif p[1] == 'cos': p[0] = math.cos(p[2])
    elif p[1] == 'tan' : p[0] = math.tan(p[2])

def p_val_atrig(p):
    '''value : ASIN value
             | ACOS value
             | ATAN value'''
    if   p[1] == 'asin': p[0] = math.asin(p[2])
    elif p[1] == 'acos': p[0] = math.acos(p[2])
    elif p[1] == 'atan' : p[0] = math.atan(p[2])

def p_val_power(p):
    '''value : value POWER value'''
    p[0] = math.pow(p[1], p[3])

def p_val_square(p):
    '''value : SQR value'''
    p[0] = math.sqrt(p[2])

def p_val_square_ex(p):
    '''value : SQR value value'''
    p[0] = math.pow(p[3], 1./p[2])

def p_val_ln(p):
    'value : LN value'
    p[0] = math.log(p[2])

def p_val_log(p):
    'value : LOG value'
    p[0] = math.log10(p[2])

def p_val_log_ex(p):
    'value : LOG value value'
    p[0] = math.log(p[3], p[2])

def p_val_group(p):
    'value : LPAREN value RPAREN'
    p[0] = p[2]

def p_val_number(p):
    'value : NUMBER'
    p[0] = p[1]

def p_variable(p):
    'value : ID'
    p[0] = variables.get(p[1], 0)
    # TODO avisar se nao existir

def p_constant(p):
    'value : CONST'
    if p[1] in constants:
        p[0] = constants[p[1]]
    else:
        raise ConstantError( (p[1], p.lexer.lineno) )

def p_error(p):
    # print("Syntax line %d, at '%s'" % (p.lineno, p.value))
    raise GrammarError(p)

# def p_error(p):
#     global flag_for_error
#     flag_for_error = 1

#     if p is not None:
#         errors_list.append("Erreur de syntaxe à la ligne %s"%(p.lineno))
#         yacc.errok()
#     else:
#         print("Unexpected end of input")


#      _   _      _
#     | | | |    | |
#     | |_| | ___| |_ __   ___ _ __
#     |  _  |/ _ \ | '_ \ / _ \ '__|
#     | | | |  __/ | |_) |  __/ |
#     \_| |_/\___|_| .__/ \___|_|
#                  | |
#                  |_|
optimized = True
debug = False

lexer = lex.lex(lextab='solver_lex', optimize=optimized, debug=debug)
parser = yacc.yacc(tabmodule='solver_tab', optimize=optimized, debug=debug)


def solve(text):
    global variables
    variables = {}
    lexer.lineno = 0
    return parser.parse(text+'\n', lexer=lexer, debug=debug, tracking=True)

#      _____         _
#     |_   _|       | |
#       | | ___  ___| |_ ___ _ __
#       | |/ _ \/ __| __/ _ \ '__|
#       | |  __/\__ \ ||  __/ |
#       \_/\___||___/\__\___|_|
#
if __name__ == '__main__':

    import cmd

    class MeuTeste(cmd.Cmd):
        """MeuTeste """

        def __init__(self):
            cmd.Cmd.__init__(self)
            self.prompt = "mt> "
            self.intro  = "Executando o MeuTeste"

        def do_exit(self, args):
            return -1

        def do_EOF(self, args):
            return self.do_exit(args)

        def emptyline(self):
            pass

        def default(self, line):
            print('>>>> ', parser.parse(line+'\n', debug=debug))

    mt = MeuTeste()
    mt.cmdloop()

# -*- coding: utf-8 -*- #      _ #     | | #     | |     _____  _____ _ __ #     | |    / _ \ \/ / _ \ '__| #     | |___|  __/>  <  __/ | #     \_____/\___/_/\_\___|_| # # 'ESCAPE', # t_ESCAPE     = r'!' #[^\n]*' #     ______ #     | ___ \ #     | |_/ /_ _ _ __ ___  ___ _ __ #     |  __/ _` | '__/ __|/ _ \ '__| #     | | | (_| | |  \__ \  __/ | #     \_|  \__,_|_|  |___/\___|_| # # ('right', 'ID'), # ('left', 'SQR'), # ('nonassoc', 'ESCAPE'), list : EOL list : statment EOL list : list statment EOL statment : statment : value value : ID ASSIGN value value : value PLUS value              | value MINUS value              | value TIMES value              | value DIVIDE value value : RAD value              | DEG value value : SIN value              | COS value              | TAN value value : ASIN value              | ACOS value              | ATAN value value : value POWER value value : SQR value value : SQR value value # TODO avisar se nao existir # print("Syntax line %d, at '%s'" % (p.lineno, p.value)) # def p_error(p): #     global flag_for_error #     flag_for_error = 1 #     if p is not None: #         errors_list.append("Erreur de syntaxe à la ligne %s"%(p.lineno)) #         yacc.errok() #     else: #         print("Unexpected end of input") #      _   _      _ #     | | | |    | | #     | |_| | ___| |_ __   ___ _ __ #     |  _  |/ _ \ | '_ \ / _ \ '__| #     | | | |  __/ | |_) |  __/ | #     \_| |_/\___|_| .__/ \___|_| #                  | | #                  |_| #      _____         _ #     |_   _|       | | #       | | ___  ___| |_ ___ _ __ #       | |/ _ \/ __| __/ _ \ '__| #       | |  __/\__ \ ||  __/ | #       \_/\___||___/\__\___|_| # MeuTeste