sawine@0
|
1 |
"""
|
sawine@0
|
2 |
Name:
|
sawine@0
|
3 |
|
sawine@0
|
4 |
Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
|
sawine@0
|
5 |
"""
|
sawine@0
|
6 |
from os import path
|
sawine@0
|
7 |
import os
|
sawine@0
|
8 |
import re
|
sawine@0
|
9 |
import token
|
sawine@0
|
10 |
|
sawine@7
|
11 |
def main():
|
sawine@7
|
12 |
args = parse_arguments()
|
sawine@7
|
13 |
scanner = Scanner(TOKENS)
|
sawine@7
|
14 |
parser = Parser(SYNTAX, scanner)
|
sawine@7
|
15 |
#(accepted, out, tree_nodes) = parser.parse(args.formula)
|
sawine@7
|
16 |
#tree = SyntaxTree(out, tree_nodes)
|
sawine@7
|
17 |
#print tree.root
|
sawine@7
|
18 |
p = Variable(["p"])
|
sawine@7
|
19 |
q = Variable(["q"])
|
sawine@7
|
20 |
r = Variable(["r"])
|
sawine@7
|
21 |
formula = Imp([Eq([p, q]), r])
|
sawine@10
|
22 |
#formula = Not([Or([p, q])])
|
sawine@10
|
23 |
#formula = Not([Not([p])])
|
sawine@7
|
24 |
print formula
|
sawine@7
|
25 |
print "reduced"
|
sawine@7
|
26 |
print reduce(formula)
|
sawine@7
|
27 |
|
sawine@10
|
28 |
def reduce(formula):
|
sawine@7
|
29 |
map = {IMP: lambda (a, b): Or([Not([a]), b]),
|
sawine@7
|
30 |
EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])]),
|
sawine@10
|
31 |
NOT: lambda (a,): not isinstance(a, Not)
|
sawine@10
|
32 |
and not isinstance(a.values[0], Not)
|
sawine@10
|
33 |
and a.__class__([Not([v]) for v in a.values]) or a.values[0],
|
sawine@7
|
34 |
AND: lambda (a, b): And([a, b]),
|
sawine@8
|
35 |
OR: lambda (a, b): Or([a, b])}
|
sawine@10
|
36 |
def values():
|
sawine@7
|
37 |
return [reduce(v) for v in formula.values]
|
sawine@7
|
38 |
|
sawine@10
|
39 |
if not isinstance(formula, Operator) or formula.id not in map:
|
sawine@7
|
40 |
return formula
|
sawine@7
|
41 |
return map[formula.id](values())
|
sawine@7
|
42 |
|
sawine@7
|
43 |
|
sawine@7
|
44 |
|
sawine@0
|
45 |
NOT = "~"
|
sawine@0
|
46 |
AND = "&"
|
sawine@0
|
47 |
OR = "|"
|
sawine@0
|
48 |
IMP = "->"
|
sawine@0
|
49 |
EQ = "<->"
|
sawine@0
|
50 |
BOX = "[]"
|
sawine@0
|
51 |
DIAMOND = "<>"
|
sawine@1
|
52 |
VARIABLE = "p"
|
sawine@1
|
53 |
LB = "("
|
sawine@1
|
54 |
RB = ")"
|
sawine@0
|
55 |
|
sawine@1
|
56 |
class Operator(object):
|
sawine@6
|
57 |
def __init__(self, id, arity, values):
|
sawine@6
|
58 |
self.id = id
|
sawine@6
|
59 |
self.arity = arity
|
sawine@4
|
60 |
self.values = values
|
sawine@1
|
61 |
def __str__(self):
|
sawine@6
|
62 |
out = self.id
|
sawine@6
|
63 |
if self.arity == 0:
|
sawine@6
|
64 |
out = str(self.values[0])
|
sawine@6
|
65 |
if self.arity == 1:
|
sawine@6
|
66 |
out = self.id + str(self.values[0])
|
sawine@6
|
67 |
elif self.arity == 2:
|
sawine@6
|
68 |
#print self.id
|
sawine@6
|
69 |
#print self.values
|
sawine@6
|
70 |
out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
|
sawine@6
|
71 |
return out
|
sawine@1
|
72 |
|
sawine@1
|
73 |
class Not(Operator):
|
sawine@2
|
74 |
arity = 1
|
sawine@2
|
75 |
def __init__(self, values):
|
sawine@6
|
76 |
Operator.__init__(self, NOT, Not.arity, values)
|
sawine@1
|
77 |
def __call__(self):
|
sawine@1
|
78 |
pass
|
sawine@1
|
79 |
|
sawine@1
|
80 |
class And(Operator):
|
sawine@2
|
81 |
arity = 2
|
sawine@2
|
82 |
def __init__(self, values):
|
sawine@6
|
83 |
Operator.__init__(self, AND, And.arity, values)
|
sawine@4
|
84 |
|
sawine@1
|
85 |
class Or(Operator):
|
sawine@2
|
86 |
arity = 2
|
sawine@2
|
87 |
def __init__(self, values):
|
sawine@6
|
88 |
Operator.__init__(self, OR, Or.arity, values)
|
sawine@2
|
89 |
|
sawine@1
|
90 |
class Imp(Operator):
|
sawine@2
|
91 |
arity = 2
|
sawine@5
|
92 |
def __init__(self, values):
|
sawine@6
|
93 |
Operator.__init__(self, IMP, Imp.arity, values)
|
sawine@1
|
94 |
|
sawine@1
|
95 |
class Eq(Operator):
|
sawine@2
|
96 |
arity = 2
|
sawine@5
|
97 |
def __init__(self, values):
|
sawine@6
|
98 |
Operator.__init__(self, EQ, Eq.arity, values)
|
sawine@1
|
99 |
|
sawine@1
|
100 |
class Box(Operator):
|
sawine@2
|
101 |
arity = 1
|
sawine@2
|
102 |
def __init__(self, values):
|
sawine@6
|
103 |
Operator.__init__(self, BOX, Box.arity, values)
|
sawine@2
|
104 |
|
sawine@1
|
105 |
class Diamond(Operator):
|
sawine@2
|
106 |
arity = 1
|
sawine@5
|
107 |
def __init__(self, values):
|
sawine@6
|
108 |
Operator.__init__(self, DIAMOND, Diamond.arity, values)
|
sawine@1
|
109 |
|
sawine@1
|
110 |
class Variable(Operator):
|
sawine@2
|
111 |
arity = 0
|
sawine@2
|
112 |
def __init__(self, values):
|
sawine@6
|
113 |
Operator.__init__(self, VARIABLE, Variable.arity, values)
|
sawine@6
|
114 |
|
sawine@2
|
115 |
class Lb(Operator):
|
sawine@2
|
116 |
arity = -1
|
sawine@2
|
117 |
def __init__(self, values):
|
sawine@6
|
118 |
Operator.__init__(self, LB, Lb.arity, values)
|
sawine@2
|
119 |
|
sawine@2
|
120 |
class Rb(Operator):
|
sawine@2
|
121 |
arity = -1
|
sawine@2
|
122 |
def __init__(self, values):
|
sawine@6
|
123 |
Operator.__init__(self, RB, Rb.arity, values)
|
sawine@2
|
124 |
|
sawine@1
|
125 |
class Formula(object):
|
sawine@2
|
126 |
def __init__(self):
|
sawine@5
|
127 |
pass
|
sawine@1
|
128 |
|
sawine@2
|
129 |
TOKENS = {re.compile("\("): Lb,
|
sawine@2
|
130 |
re.compile("\)"): Rb,
|
sawine@1
|
131 |
re.compile("~"): Not,
|
sawine@1
|
132 |
re.compile("&"): And,
|
sawine@1
|
133 |
re.compile("\|"): Or,
|
sawine@1
|
134 |
re.compile("->"): Imp,
|
sawine@1
|
135 |
re.compile("<->"): Eq,
|
sawine@1
|
136 |
re.compile("\[\]"): Box,
|
sawine@1
|
137 |
re.compile("<>"): Diamond,
|
sawine@1
|
138 |
re.compile("[a-z]+"): Variable}
|
sawine@0
|
139 |
|
sawine@0
|
140 |
class Scanner(object):
|
sawine@0
|
141 |
def __init__(self, tokens, source=None):
|
sawine@0
|
142 |
self.tokens = tokens
|
sawine@0
|
143 |
self.reset(source)
|
sawine@0
|
144 |
def next(self):
|
sawine@6
|
145 |
while self.i < len(self.source):
|
sawine@6
|
146 |
re.purge()
|
sawine@0
|
147 |
for p, token in self.tokens.iteritems():
|
sawine@0
|
148 |
m = p.match(self.source[self.i:])
|
sawine@0
|
149 |
if m:
|
sawine@0
|
150 |
self.i += m.end(0)
|
sawine@6
|
151 |
value = m.group(0)
|
sawine@2
|
152 |
return (token, value)
|
sawine@0
|
153 |
self.i += 1
|
sawine@2
|
154 |
return (None, None)
|
sawine@0
|
155 |
def reset(self, source):
|
sawine@0
|
156 |
self.i = 0
|
sawine@0
|
157 |
self.source = source
|
sawine@0
|
158 |
|
sawine@1
|
159 |
S = Formula
|
sawine@1
|
160 |
A = "A"
|
sawine@2
|
161 |
#0 S: (Variable,),
|
sawine@2
|
162 |
#1 S: (Not, S),
|
sawine@2
|
163 |
#2 S: (Lb, A, Rb),
|
sawine@2
|
164 |
#3 S: (Box, S),
|
sawine@2
|
165 |
#4 S: (Diamond, S),
|
sawine@2
|
166 |
#5 A: (S, And, S),
|
sawine@2
|
167 |
#6 A: (S, Or, S),
|
sawine@2
|
168 |
#7 A: (S, Imp, S),
|
sawine@2
|
169 |
#8 A: (S, Eq, S)
|
sawine@1
|
170 |
SYNTAX = ((Variable,),
|
sawine@1
|
171 |
(Not, S),
|
sawine@2
|
172 |
(Lb, A, Rb),
|
sawine@1
|
173 |
(Box, S),
|
sawine@1
|
174 |
(Diamond, S),
|
sawine@1
|
175 |
(S, And, S),
|
sawine@1
|
176 |
(S, Or, S),
|
sawine@1
|
177 |
(S, Imp, S),
|
sawine@1
|
178 |
(S, Eq, S))
|
sawine@1
|
179 |
|
sawine@2
|
180 |
class Node(object):
|
sawine@2
|
181 |
def __init__(self, parent, value):
|
sawine@2
|
182 |
self.parent = parent
|
sawine@2
|
183 |
self.value = value
|
sawine@2
|
184 |
self.children = []
|
sawine@2
|
185 |
def addChild(self, value):
|
sawine@2
|
186 |
self.children.append(self, node)
|
sawine@2
|
187 |
|
sawine@0
|
188 |
class Parser(object):
|
sawine@1
|
189 |
def __init__(self, syntax, scanner):
|
sawine@1
|
190 |
self.syntax = syntax
|
sawine@0
|
191 |
self.scanner = scanner
|
sawine@0
|
192 |
def parse(self, source):
|
sawine@1
|
193 |
table = {(S, Variable): 0,
|
sawine@1
|
194 |
(S, Not): 1,
|
sawine@2
|
195 |
(S, Lb): 2,
|
sawine@1
|
196 |
(S, Box): 3,
|
sawine@1
|
197 |
(S, Diamond): 4,
|
sawine@1
|
198 |
(A, S, And): 5,
|
sawine@1
|
199 |
(A, S, Or): 6,
|
sawine@1
|
200 |
(A, S, Imp): 7,
|
sawine@1
|
201 |
(A, S, Eq): 8,
|
sawine@1
|
202 |
(A, Variable, And): 5,
|
sawine@1
|
203 |
(A, Variable, Or): 6,
|
sawine@1
|
204 |
(A, Variable, Imp): 7,
|
sawine@6
|
205 |
(A, Variable, Eq): 8,
|
sawine@6
|
206 |
(A, Not, Variable, And): 5,
|
sawine@6
|
207 |
(A, Not, Variable, Or): 6,
|
sawine@6
|
208 |
(A, Not, Variable, Imp): 7,
|
sawine@6
|
209 |
(A, Not, Variable, Eq): 8}
|
sawine@1
|
210 |
stack = [S]
|
sawine@3
|
211 |
tree_nodes = []
|
sawine@6
|
212 |
tree = None
|
sawine@1
|
213 |
out = []
|
sawine@0
|
214 |
self.scanner.reset(source)
|
sawine@2
|
215 |
(token, value) = self.scanner.next()
|
sawine@6
|
216 |
(lookahead, la_value) = self.scanner.next()
|
sawine@6
|
217 |
(lookahead2, la2_value) = self.scanner.next()
|
sawine@6
|
218 |
accepted = True
|
sawine@6
|
219 |
while token and len(stack):
|
sawine@4
|
220 |
top = stack[-1]
|
sawine@1
|
221 |
if top == token:
|
sawine@6
|
222 |
tree_nodes.append((token, value))
|
sawine@6
|
223 |
stack.pop()
|
sawine@6
|
224 |
#tree_nodes.append((stack.pop(), value))
|
sawine@6
|
225 |
(token, value) = (lookahead, la_value)
|
sawine@6
|
226 |
(lookahead, la_value) = (lookahead2, la2_value)
|
sawine@6
|
227 |
#(lookahead, _) = self.scanner.next()
|
sawine@6
|
228 |
(lookahead2, la2_value) = self.scanner.next()
|
sawine@1
|
229 |
else:
|
sawine@1
|
230 |
action = None
|
sawine@1
|
231 |
if (top, token) in table:
|
sawine@1
|
232 |
action = table[(top, token)]
|
sawine@1
|
233 |
elif (top, token, lookahead) in table:
|
sawine@6
|
234 |
action = table[(top, token, lookahead)]
|
sawine@6
|
235 |
elif (top, token, lookahead, lookahead2) in table:
|
sawine@6
|
236 |
action = table[(top, token, lookahead, lookahead2)]
|
sawine@1
|
237 |
if action is None:
|
sawine@1
|
238 |
accepted = False
|
sawine@1
|
239 |
break
|
sawine@6
|
240 |
|
sawine@1
|
241 |
out.append(action)
|
sawine@1
|
242 |
stack.pop()
|
sawine@1
|
243 |
stack.extend(reversed(self.syntax[action]))
|
sawine@2
|
244 |
accepted = accepted and not len(stack)
|
sawine@3
|
245 |
return (accepted, out, tree_nodes)
|
sawine@4
|
246 |
|
sawine@3
|
247 |
class SyntaxTree(object):
|
sawine@6
|
248 |
def __init__(self, seq, tree_nodes):
|
sawine@6
|
249 |
seq.reverse()
|
sawine@6
|
250 |
tree_nodes.reverse()
|
sawine@6
|
251 |
print tree_nodes
|
sawine@6
|
252 |
print seq
|
sawine@6
|
253 |
self.root = self.compile(seq, tree_nodes)[0]
|
sawine@6
|
254 |
print self.root
|
sawine@6
|
255 |
def compile(self, seq, tree_nodes):
|
sawine@6
|
256 |
stack = []
|
sawine@6
|
257 |
waiting = []
|
sawine@6
|
258 |
print seq
|
sawine@6
|
259 |
while len(seq):
|
sawine@6
|
260 |
s = seq.pop()
|
sawine@6
|
261 |
if s == 0:
|
sawine@6
|
262 |
c, v = tree_nodes.pop()
|
sawine@6
|
263 |
while c != Variable:
|
sawine@6
|
264 |
c, v = tree_nodes.pop()
|
sawine@6
|
265 |
stack.append(Variable(v))
|
sawine@6
|
266 |
elif s == 1:
|
sawine@6
|
267 |
stack.append(Not(self.compile(seq, tree_nodes)))
|
sawine@6
|
268 |
elif s == 2:
|
sawine@6
|
269 |
stack.extend(self.compile(seq, tree_nodes))
|
sawine@6
|
270 |
elif s == 3:
|
sawine@6
|
271 |
stack.append(Box(self.compile(seq, tree_nodes)))
|
sawine@6
|
272 |
elif s == 4:
|
sawine@6
|
273 |
stack.append(Diamond(self.compile(seq, tree_nodes)))
|
sawine@6
|
274 |
elif s == 5:
|
sawine@6
|
275 |
stack.append(And(self.compile(seq, tree_nodes)))
|
sawine@6
|
276 |
elif s == 6:
|
sawine@6
|
277 |
stack.append(Or(self.compile(seq, tree_nodes)))
|
sawine@6
|
278 |
elif s == 7:
|
sawine@6
|
279 |
stack.append(Imp(self.compile(seq, tree_nodes)))
|
sawine@6
|
280 |
elif s == 8:
|
sawine@6
|
281 |
stack.append(Eq(self.compile(seq, tree_nodes)))
|
sawine@6
|
282 |
print stack
|
sawine@6
|
283 |
return stack
|
sawine@6
|
284 |
|
sawine@6
|
285 |
def compile_(self, tree_nodes):
|
sawine@3
|
286 |
table = []
|
sawine@3
|
287 |
unfinished = []
|
sawine@4
|
288 |
node = None
|
sawine@6
|
289 |
print tree_nodes
|
sawine@6
|
290 |
for n, v in (tree_nodes):
|
sawine@6
|
291 |
print
|
sawine@6
|
292 |
print n
|
sawine@4
|
293 |
if n.arity >= 0:
|
sawine@3
|
294 |
if len(table) < n.arity:
|
sawine@6
|
295 |
print "appending unfinished ", n
|
sawine@3
|
296 |
unfinished.append(n)
|
sawine@3
|
297 |
else:
|
sawine@6
|
298 |
args = table[:n.arity]
|
sawine@6
|
299 |
if n.arity == 0:
|
sawine@6
|
300 |
args = [v]
|
sawine@3
|
301 |
table = table[n.arity:]
|
sawine@4
|
302 |
node = n(args)
|
sawine@3
|
303 |
table.append(node)
|
sawine@6
|
304 |
if len(unfinished) and unfinished[-1].arity <= len(table):
|
sawine@6
|
305 |
n = unfinished[-1]
|
sawine@6
|
306 |
print "finishing ", n
|
sawine@3
|
307 |
args = table[:n.arity]
|
sawine@3
|
308 |
table = table[n.arity:]
|
sawine@4
|
309 |
node = n(args)
|
sawine@3
|
310 |
table.append(node)
|
sawine@4
|
311 |
unfinished.pop()
|
sawine@3
|
312 |
return table[0]
|
sawine@0
|
313 |
|
sawine@0
|
314 |
from argparse import ArgumentParser
|
sawine@0
|
315 |
|
sawine@0
|
316 |
def parse_arguments():
|
sawine@2
|
317 |
parser = ArgumentParser(description="Parses simple modal logic syntax.")
|
sawine@0
|
318 |
parser.add_argument("formula", help="your formula")
|
sawine@0
|
319 |
return parser.parse_args()
|
sawine@0
|
320 |
|
sawine@0
|
321 |
if __name__ == "__main__":
|
sawine@0
|
322 |
main()
|