Skip to content

Commit

Permalink
Merge branch 'parser'
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandraGrass committed Jul 21, 2019
2 parents d87afe0 + 916e721 commit 0d7d4ea
Show file tree
Hide file tree
Showing 4 changed files with 344 additions and 11 deletions.
44 changes: 44 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
General
Read from file!
> Rho for vars & funs
several statements
> args really just in dictio in function body?
parser doing proper separation? -> nope

b
> basic (BasicValue)
> check if int

x
> var (Variable)
> one word, further specifications? -> check in constructor
global, local?

(op1 e)
> uadd, usub, brkt (Other)
> brackets don't need own nodes

( e1 op2 e2 )
> add, sub, mul, div
> gt, ge, lt, le, eq

( if e0 then e1 else e2 )
> if
> conditions

( e' e0 ... ek−1 )
> app
> fun has to be known
> split e0 to ek-1 correctly?
convert "39 + 3" to "39+3"

( fun x0 ... xk−1 -> e )
> fun
> differ between args and vars

( let x1 = e1 in e0 )
> let, asgn
> differ between var and fun?

( let rec x1 = e1 and ... and xn = en in e0 )
> rec, asgn
35 changes: 34 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from parser import *

if __name__ == '__main__':

from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
Expand All @@ -19,4 +21,35 @@
print(args.input)
print(args.output)

# do actual work
# own examples
print(parse_tree("let a = 17 in let f = fun b -> a + b in f (39 + 2)"))
print()
print(parse_tree("if 1 then 3 else 4"))
print()
print(parse_tree("let x3 = 4 in + x3 "))
print()
print(parse_tree("((34))"))
print()
print(parse_tree("3 / 4"))
print()
print(parse_tree("let rec f = fun x y -> if y <= 1 then x else f ( x * y ) ( y - 1 ) in f 1"))
print()
print(parse_tree("let y_x = 4 in y_x"))
print()

# from lecture slides
print(parse_tree("let rec fac = fun x -> if x <= 1 then 1 else x * fac (x-1) in fac 7")) # 102
print()

# TODO: for let f, first "in" is chosen (a in b)
# print(parse_tree("let c = 5 in let f = fun a -> let b = a * a in b + c in f c")) # 114
# print()

print(parse_tree("let a = 19 in let b = a * a in a + b")) # 131
print()

print(parse_tree("let a = 17 in let f = fun b -> a + b in f 42")) # 140
print()

print(parse_tree("let rec f = fun x y -> if y <= 1 then x else f ( x * y ) ( y - 1 ) in f 1")) # 159
print()
228 changes: 225 additions & 3 deletions parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,227 @@
from tree_nodes import *
from parse import *
import numpy as np
import re

Node("abcd")
x = Other ("abcd", "sdfsdf")
x = Other("plus", [BasicValue("basic", 3), BasicValue("basic", 6)])
def mk_rec(x, depth, dictio):
defs = x['defs'].split('and')

new_dict = dictio.copy()

children = []
for defi in defs:
y = parse("{x1} = fun {e1}", defi)
if(y == None):
raise Exception('"{}" is not a valid assignment in let rec.'.format(defi))

new_dict[y['x1']] = "fvar"

for defi in defs:
y = parse("{x1} = {e1}", defi)

x1 = Variable("fvar", y['x1'], depth+2)
e1 = parse_tree(y['e1'], depth+2, new_dict)

children.append(Other("asgn", [x1, e1], depth+1))

e0 = parse_tree(x['e0'], depth+1, new_dict)
children.append(e0)

return Other("rec", children, depth)

def mk_let(x, depth, dictio):
tag = "fvar" if x['e1'].split(' ', 1)[0] == "fun" else "var"

new_dict = dictio.copy()

x1 = Variable(tag, x['x1'], depth+2)
new_dict[x['x1']] = tag

e1 = parse_tree(x['e1'], depth+2, new_dict)

asgn = Other("asgn", [x1, e1], depth+1)
e0 = parse_tree(x['e0'], depth+1, new_dict)

return Other("let", [asgn, e0], depth)

def mk_fun(x, depth, dictio):
args = x['args'].split()

new_dict = dictio.copy()

children = []
for arg in args:
children.append(Variable("arg", arg, depth+1))
new_dict[arg] = "arg"

e = parse_tree(x['e'], depth+1, new_dict)
children.append(e)

return Other("fun", children, depth)

def split_expr(exprs):
x = parse("({e1}) {e2}", exprs)
if(x != None):
tmp = [x['e1']]
tmp.extend(split_expr(x['e2']))
return tmp

x = parse("({e})", exprs)
if(x != None):
return [x['e']]

x = exprs.split(' ', 1)

if len(x) == 1:
return [x[0]]

else:
tmp = [x[0]]
tmp.extend(split_expr(x[1]))
return tmp

def mk_app(x, depth, dictio):
children = [Variable("fvar", x[0], depth+1)]

for expr in split_expr(x[1]):
children.append(parse_tree(expr, depth+1, dictio))

return Other("app", children, depth)

def mk_if(x, depth, dictio):
e0 = parse_tree(x['e0'], depth+1, dictio)
e1 = parse_tree(x['e1'], depth+1, dictio)
e2 = parse_tree(x['e2'], depth+1, dictio)

return Other("if", [e0, e1, e2], depth)

def mk_op2(x, depth, dictio, tag):
e1 = parse_tree(x['e1'], depth+1, dictio)
e2 = parse_tree(x['e2'], depth+1, dictio)
return Other(tag, [e1, e2], depth)

def mk_op1(x, depth, dictio, tag):
e = parse_tree(x['e'], depth+1, dictio)
return Other(tag, [e], depth)

def is_known(expr, dictio, tag=""):
if tag == "":
return expr in dictio

try:
return dictio[expr] == tag
except KeyError:
return False

def is_int(expr):
try:
int(expr)
return True
except ValueError:
return False

def parse_tree(expr, depth=0, dictio={}):

# remove unnecessary whitespace
expr = re.sub(' +', ' ',expr).strip()

# (e)
x = parse("({e})", expr)
if(x != None):
return parse_tree(x['e'], depth, dictio)

# let rec x1 = e1 and ... and xn = en in e0
x = parse("let rec {defs} in {e0}", expr)
if(x != None):
return mk_rec(x, depth, dictio)

# let x1 = e1 in e0
x = parse("let {x1} = {e1} in {e0}", expr)
if(x != None):
return mk_let(x, depth, dictio)

# fun x0 ... xk-1 -> e
x = parse("fun {args} -> {e}", expr)
if(x != None):
return mk_fun(x, depth, dictio)

# e' e0 ... ek−1
x = expr.split(' ', 1)
if(is_known(x[0], dictio, "fvar")):
return mk_app(x, depth, dictio)

# if e0 then e1 else e2
x = parse("if {e0} then {e1} else {e2}", expr)
if(x != None):
return mk_if(x, depth, dictio)

# e1 >= e2
x = parse("{e1}>={e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "ge")

# e1 > e2
x = parse("{e1}>{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "gt")

# e1 <= e2
x = parse("{e1}<={e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "le")

# e1 < e2
x = parse("{e1}<{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "lt")

# e1 == e2
x = parse("{e1}=={e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "eq")

# e1 * e2
x = parse("{e1}*{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "mul")

# e1 / e2
x = parse("{e1}/{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "div")

# e1 + e2
x = parse("{e1}+{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "add")

# e1 - e2
x = parse("{e1}-{e2}", expr)
if(x != None):
return mk_op2(x, depth, dictio, "sub")

# +e
x = parse("+{e}", expr)
if(x != None):
return mk_op1(x, depth, dictio, "uadd")

# -e
x = parse("-{e}", expr)
if(x != None):
return mk_op1(x, depth, dictio, "usub")

# variable
if(is_known(expr, dictio, "var")):
return Variable("var", expr, depth)

# argument
if(is_known(expr, dictio, "arg")):
return Variable("arg", expr, depth)

# basic value
if(is_int(expr)):
return BasicValue("basic", int(expr), depth)

# default case
raise Exception('"{}" is not a valid expression.'.format(expr))
# return Variable("dummy", expr, depth)
48 changes: 41 additions & 7 deletions tree_nodes.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,56 @@
class Node(object):

def __init__(self, tag):
def __init__(self, tag, depth=0):
self.tag = tag
self.depth = depth

def __str__(self):
return " " * self.depth + self.tag

class BasicValue(Node):

def __init__(self, tag, value):
def __init__(self, tag, value, depth=0):
self.value = value
super(BasicValue, self).__init__(tag)
super(BasicValue, self).__init__(tag, depth)

def __str__(self):
super_str = super(BasicValue, self).__str__()
return super_str + ": " + str(self.value)

def check_var(var):
for char in var:
if ord(char) < 48 or ord(char) > 57 and ord(char) < 65 or ord(char) > 91 and ord(char) < 97 or ord(char) > 122:
if not char == '_':
raise Exception('"{}" is not a valid variable name.'.format(var))

try:
int(var[0])
raise Exception('"{}" is not a valid variable name.'.format(var))
except ValueError:
pass

if var[0] == '_' or var[-1] == '_':
raise Exception('"{}" is not a valid variable name.'.format(var))

class Variable(Node):

def __init__(self, tag, var):
def __init__(self, tag, var, depth=0):
if(tag != "dummy"):
check_var(var)

self.var = var
super(Variable, self).__init__(tag)
super(Variable, self).__init__(tag, depth)

def __str__(self):
super_str = super(Variable, self).__str__()
return super_str + ": " + self.var

class Other(Node):

def __init__(self, tag, children):
def __init__(self, tag, children, depth=0):
self.children = children
super(Other, self).__init__(tag)
super(Other, self).__init__(tag, depth)

def __str__(self):
super_str = super(Other, self).__str__()
return super_str + ":\n" + '\n'.join(map(str, self.children))

0 comments on commit 0d7d4ea

Please sign in to comment.