Created
September 15, 2017 18:38
-
-
Save PraveshKoirala/88f554515768b41b90629fa2ca81926b to your computer and use it in GitHub Desktop.
Developed for /r/dailyprogrammer challenge #331
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
from operator import mul, pow, add, sub, div | |
__author__ = 'pravesh' | |
def get_simple_statement(statement): | |
template=r"((\-?\d+(?:\.\d+)?)\%s(\-?\d+(?:\.\d+)?))(?!\^)" | |
for opstr, opfunc in [("^", pow), ("*", mul), ("/", div), ("+", add), ("-", sub)]: | |
template_str = template % opstr | |
while opstr in statement: | |
#todo associativity for ^ operator | |
match = re.findall(template_str, statement) | |
if opstr=="-" and not match: break | |
eqn, a, b = match[0] | |
c = str(opfunc(float(a), float(b))) | |
statement = statement.replace(eqn, c) | |
return statement | |
replace_all = lambda st, (old, new): st.replace(old, new) | |
def get_func_call(statement, index): | |
para_index = statement.find("(", index) | |
para_count = 1 | |
while para_count!=0: | |
para_index += 1 | |
if statement[para_index] == ")": | |
para_count-= 1 | |
elif statement[para_index] == "(": | |
para_count+=1 | |
if para_count == 1 and statement[para_index] == ",": | |
statement = statement[:para_index] + "$" + statement[para_index+1:] | |
return statement[index: para_index+1] | |
def func_replace(statement, funcs): | |
# replace the function statements | |
for fname, fvalue in funcs.items(): | |
index = 0 | |
while index!=-1: | |
index = statement.find(fname+"(") | |
if index != -1: | |
func_call = get_func_call(statement, index) | |
arg_values = map(lambda w: "(" + w + ")", func_call[len(fname)+1:-1].split("$")) | |
func_call = func_call.replace("$", ",") | |
replaced_call = reduce(replace_all, zip(fvalue["args"], arg_values), fvalue["def"]) | |
statement = statement.replace(func_call, replaced_call) | |
return statement | |
def evaluate(statement, vars, funcs): | |
while "(" in statement: | |
# get all the (a+b+c...) i.e. bracketed values first | |
priority_eq = re.findall(r"\([0-9\.\+\-\^\*/_]+?\)", statement) | |
# evaluate the expressions sans the brackets .. i.e. evaluate(a+b+c) | |
values = map(get_simple_statement, [peq[1:-1] for peq in priority_eq]) | |
# replace in the equation | |
statement = reduce(replace_all, zip(priority_eq, values), statement) | |
return get_simple_statement(statement) | |
def get_results(line, vars, funcs): | |
result = None | |
var = None | |
if "=" in line: | |
func_match = re.findall(r"(\w+)\((.*)\)=(.*)", line) | |
if func_match: | |
fname, args, definition = func_match[0] | |
args = args and args.split(",") or [] | |
# sig = r"{fname}\({args}\)".format(fname=fname, args=",".join([r"(\-?\d+(?:\.\d+)?)"]*len(args))) | |
funcs[fname] = {"args": args, "def": definition} | |
return "\n" | |
# either a variable assignment or function assignment | |
var_match = re.findall(r"([a-z]\w*)=(.*)", line) | |
if var_match: | |
var, line = var_match[0] | |
# lazy replace function | |
line = func_replace(line, funcs) | |
line = reduce(replace_all, vars.items(), line) | |
result = evaluate(line, vars, funcs) | |
if var: | |
vars[var] = result | |
return result | |
def main(): | |
print "Interactive interpreter: type statements and press enter. type exit to exit" | |
vars, funcs = {}, {} | |
while True: | |
input = raw_input("").strip().replace(" ", "") | |
if input == "exit": | |
return 0 | |
print get_results(input, vars, funcs) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment