-
Notifications
You must be signed in to change notification settings - Fork 1
/
cyprus_parser.py
123 lines (102 loc) · 3.49 KB
/
cyprus_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
## cyprus
## parser
## PeckJ 20121121
##
from funcparserlib.parser import (some, a, maybe, many, finished, skip,
with_forward_decls, oneplus, NoParseError)
from funcparserlib.lexer import Token
from funcparserlib.util import pretty_tree
## grammar
#
# program := {env}
# env := "[", body, "]"
# membrane := "(", body, ")"
# body := <name>, {statement}
# statement := membrane | expr
# expr := exists | reaction | priority
# exists := "exists", "~", name, {name}
# reaction := "reaction", <"as", name>, "~", name, {name}, "::",
# {symbol}
# priority := "priority", "~", name, ">>", name
# name := number | atom
# atom := [A-Za-z], {[A-Za-z0-9]}
# number := [0-9], {[0-9]} | {[0-9]}, ".", [0-9], {[0-9]}
# symbol := atom | "!", name, <"!!", name> | "$", [name]
tokval = lambda tok: tok.value
toktype = lambda type: lambda tok: tok.type == type
make_number = lambda str: float(str)
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
class Grouping(object):
def __init__(self, kids):
try:
self.kids = list(flatten([kids]))
except TypeError:
self.kids = [kids]
class Program(Grouping):
pass
class Environment(Grouping):
pass
class Membrane(Grouping):
pass
class Statement(Grouping):
pass
def parse(tokens):
## building blocks
kw_priority = some(toktype("kw_priority"))
kw_probability = some(toktype("kw_probability"))
kw_reaction = some(toktype("kw_reaction"))
kw_exists = some(toktype("kw_exists"))
kw_as = some(toktype("kw_as"))
op_tilde = some(toktype("op_tilde"))
op_priority_maximal = some(toktype("op_priority_maximal"))
op_production = some(toktype("op_production"))
atom = some(toktype("name"))
number = some(toktype("number"))
dissolve = some(toktype("op_dissolve"))
osmose = some(toktype("op_osmose"))
osmose_location = some(toktype("op_osmose_location"))
env_open = some(toktype("env_open"))
env_close = some(toktype("env_close"))
membrane_open = some(toktype("membrane_open"))
membrane_close = some(toktype("membrane_close"))
## grammar from the bottom up
name = atom | number
symbol = atom | (dissolve + maybe(name)) | (osmose + name + maybe(osmose_location + name))
priority = kw_priority + op_tilde + name + op_priority_maximal + name
reaction = (kw_reaction + maybe(kw_as + name) + op_tilde +
oneplus(name) + op_production + many(symbol))
exists = kw_exists + op_tilde + oneplus(name)
expr = (exists | reaction | priority)
statement = with_forward_decls(lambda: membrane | expr) >> Statement
body = maybe(name) + many(statement)
membrane = (skip(membrane_open) + body + skip(membrane_close)) >> Membrane
env = (skip(env_open) + body + skip(env_close)) >> Environment
program = many(env) + skip(finished) >> Program
return program.parse(tokens)
# pretty print a parse tree
def ptree(tree):
def kids(x):
if isinstance(x, Grouping):
return x.kids
else:
return []
def show(x):
#print "show(%r)" % x
if isinstance(x, Program):
return '{Program}'
elif isinstance(x, Environment):
return '{Environment}'
elif isinstance(x, Membrane):
return '{Membrane}'
elif isinstance(x, Statement):
return '{Statement}'
else:
return repr(x)
return pretty_tree(tree, kids, show)