Hacked reduction.
4 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
12 args = parse_arguments()
13 scanner = Scanner(TOKENS)
14 parser = Parser(SYNTAX, scanner)
15 #(accepted, out, tree_nodes) = parser.parse(args.formula)
16 #tree = SyntaxTree(out, tree_nodes)
21 formula = Imp([Eq([p, q]), r])
22 formula = Not([Or([p, q])])
23 formula = Not([Not([p])])
30 map = {IMP: lambda (a, b): Or([Not([a]), b]),
31 EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])]),
32 NOT: lambda (a,): not isinstance(a, Not) and a.__class__([Not([v]) for v in a.values]) or Not(a.values),
33 AND: lambda (a, b): And([a, b]),
34 OR: lambda (a, b): Or([a, b])}
36 return [reduce(v) for v in formula.values]
38 if not isinstance(formula, Operator) or formula.id not in map:
41 return map[formula.id](values())
56 class Operator(object):
57 def __init__(self, id, arity, values):
64 out = str(self.values[0])
66 out = self.id + str(self.values[0])
70 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
75 def __init__(self, values):
76 Operator.__init__(self, NOT, Not.arity, values)
82 def __init__(self, values):
83 Operator.__init__(self, AND, And.arity, values)
87 def __init__(self, values):
88 Operator.__init__(self, OR, Or.arity, values)
92 def __init__(self, values):
93 Operator.__init__(self, IMP, Imp.arity, values)
97 def __init__(self, values):
98 Operator.__init__(self, EQ, Eq.arity, values)
102 def __init__(self, values):
103 Operator.__init__(self, BOX, Box.arity, values)
105 class Diamond(Operator):
107 def __init__(self, values):
108 Operator.__init__(self, DIAMOND, Diamond.arity, values)
110 class Variable(Operator):
112 def __init__(self, values):
113 Operator.__init__(self, VARIABLE, Variable.arity, values)
117 def __init__(self, values):
118 Operator.__init__(self, LB, Lb.arity, values)
122 def __init__(self, values):
123 Operator.__init__(self, RB, Rb.arity, values)
125 class Formula(object):
129 TOKENS = {re.compile("\("): Lb,
130 re.compile("\)"): Rb,
131 re.compile("~"): Not,
132 re.compile("&"): And,
133 re.compile("\|"): Or,
134 re.compile("->"): Imp,
135 re.compile("<->"): Eq,
136 re.compile("\[\]"): Box,
137 re.compile("<>"): Diamond,
138 re.compile("[a-z]+"): Variable}
140 class Scanner(object):
141 def __init__(self, tokens, source=None):
145 while self.i < len(self.source):
147 for p, token in self.tokens.iteritems():
148 m = p.match(self.source[self.i:])
152 return (token, value)
155 def reset(self, source):
170 SYNTAX = ((Variable,),
181 def __init__(self, parent, value):
185 def addChild(self, value):
186 self.children.append(self, node)
188 class Parser(object):
189 def __init__(self, syntax, scanner):
191 self.scanner = scanner
192 def parse(self, source):
193 table = {(S, Variable): 0,
202 (A, Variable, And): 5,
203 (A, Variable, Or): 6,
204 (A, Variable, Imp): 7,
205 (A, Variable, Eq): 8,
206 (A, Not, Variable, And): 5,
207 (A, Not, Variable, Or): 6,
208 (A, Not, Variable, Imp): 7,
209 (A, Not, Variable, Eq): 8}
214 self.scanner.reset(source)
215 (token, value) = self.scanner.next()
216 (lookahead, la_value) = self.scanner.next()
217 (lookahead2, la2_value) = self.scanner.next()
219 while token and len(stack):
222 tree_nodes.append((token, value))
224 #tree_nodes.append((stack.pop(), value))
225 (token, value) = (lookahead, la_value)
226 (lookahead, la_value) = (lookahead2, la2_value)
227 #(lookahead, _) = self.scanner.next()
228 (lookahead2, la2_value) = self.scanner.next()
231 if (top, token) in table:
232 action = table[(top, token)]
233 elif (top, token, lookahead) in table:
234 action = table[(top, token, lookahead)]
235 elif (top, token, lookahead, lookahead2) in table:
236 action = table[(top, token, lookahead, lookahead2)]
243 stack.extend(reversed(self.syntax[action]))
244 accepted = accepted and not len(stack)
245 return (accepted, out, tree_nodes)
247 class SyntaxTree(object):
248 def __init__(self, seq, tree_nodes):
253 self.root = self.compile(seq, tree_nodes)[0]
255 def compile(self, seq, tree_nodes):
262 c, v = tree_nodes.pop()
264 c, v = tree_nodes.pop()
265 stack.append(Variable(v))
267 stack.append(Not(self.compile(seq, tree_nodes)))
269 stack.extend(self.compile(seq, tree_nodes))
271 stack.append(Box(self.compile(seq, tree_nodes)))
273 stack.append(Diamond(self.compile(seq, tree_nodes)))
275 stack.append(And(self.compile(seq, tree_nodes)))
277 stack.append(Or(self.compile(seq, tree_nodes)))
279 stack.append(Imp(self.compile(seq, tree_nodes)))
281 stack.append(Eq(self.compile(seq, tree_nodes)))
285 def compile_(self, tree_nodes):
290 for n, v in (tree_nodes):
294 if len(table) < n.arity:
295 print "appending unfinished ", n
298 args = table[:n.arity]
301 table = table[n.arity:]
304 if len(unfinished) and unfinished[-1].arity <= len(table):
306 print "finishing ", n
307 args = table[:n.arity]
308 table = table[n.arity:]
314 from argparse import ArgumentParser
316 def parse_arguments():
317 parser = ArgumentParser(description="Parses simple modal logic syntax.")
318 parser.add_argument("formula", help="your formula")
319 return parser.parse_args()
321 if __name__ == "__main__":