Cleaned up.
4 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
15 formula1 = Imp([Eq([p, q]), r])
16 formula2 = Not([Or([p, q])])
17 formula3 = Not([Not([p])])
20 args = parse_arguments()
22 scanner = Scanner(TOKENS)
23 parser = Parser(SYNTAX, scanner)
24 (accepted, out, tree_nodes) = parser.parse(args.formula)
28 tree = SyntaxTree(out, tree_nodes)
37 map = {IMP: lambda (a, b): Or([Not([a]), b]),
38 EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])]),
39 NOT: lambda (a,): not isinstance(a, Not)
40 and not isinstance(a.values[0], Not)
41 and a.__class__([Not([v]) for v in a.values]) or a.values[0],
42 AND: lambda (a, b): And([a, b]),
43 OR: lambda (a, b): Or([a, b])}
45 return [reduce(v) for v in formula.values]
47 if not isinstance(formula, Operator) or formula.id not in map:
49 return map[formula.id](values())
62 class Operator(object):
63 def __init__(self, id, arity, values):
70 out = str(self.values[0])
72 out = self.id + str(self.values[0])
74 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
79 def __init__(self, values):
80 Operator.__init__(self, NOT, Not.arity, values)
86 def __init__(self, values):
87 Operator.__init__(self, AND, And.arity, values)
91 def __init__(self, values):
92 Operator.__init__(self, OR, Or.arity, values)
96 def __init__(self, values):
97 Operator.__init__(self, IMP, Imp.arity, values)
101 def __init__(self, values):
102 Operator.__init__(self, EQ, Eq.arity, values)
106 def __init__(self, values):
107 Operator.__init__(self, BOX, Box.arity, values)
109 class Diamond(Operator):
111 def __init__(self, values):
112 Operator.__init__(self, DIAMOND, Diamond.arity, values)
114 class Variable(Operator):
116 def __init__(self, values):
117 Operator.__init__(self, VARIABLE, Variable.arity, values)
121 def __init__(self, values):
122 Operator.__init__(self, LB, Lb.arity, values)
126 def __init__(self, values):
127 Operator.__init__(self, RB, Rb.arity, values)
129 class Formula(object):
133 TOKENS = {re.compile("\("): Lb,
134 re.compile("\)"): Rb,
135 re.compile("~"): Not,
136 re.compile("&"): And,
137 re.compile("\|"): Or,
138 re.compile("->"): Imp,
139 re.compile("<->"): Eq,
140 re.compile("\[\]"): Box,
141 re.compile("<>"): Diamond,
142 re.compile("[a-z]+"): Variable}
144 class Scanner(object):
145 def __init__(self, tokens, source=None):
149 while self.i < len(self.source):
151 for p, token in self.tokens.iteritems():
152 m = p.match(self.source[self.i:])
156 return (token, value)
159 def reset(self, source):
174 SYNTAX = ((Variable,),
185 def __init__(self, parent, value):
189 def addChild(self, value):
190 self.children.append(self, node)
192 class Parser(object):
193 def __init__(self, syntax, scanner):
195 self.scanner = scanner
196 def parse(self, source):
197 table = {(S, Variable): 0,
206 (A, Variable, And): 5,
207 (A, Variable, Or): 6,
208 (A, Variable, Imp): 7,
209 (A, Variable, Eq): 8,
210 (A, Not, Variable, And): 5,
211 (A, Not, Variable, Or): 6,
212 (A, Not, Variable, Imp): 7,
213 (A, Not, Variable, Eq): 8}
218 self.scanner.reset(source)
219 (token, value) = self.scanner.next()
220 (lookahead, la_value) = self.scanner.next()
221 (lookahead2, la2_value) = self.scanner.next()
223 while token and len(stack):
226 tree_nodes.append((token, value))
228 #tree_nodes.append((stack.pop(), value))
229 (token, value) = (lookahead, la_value)
230 (lookahead, la_value) = (lookahead2, la2_value)
231 #(lookahead, _) = self.scanner.next()
232 (lookahead2, la2_value) = self.scanner.next()
235 if (top, token) in table:
236 action = table[(top, token)]
237 elif (top, token, lookahead) in table:
238 action = table[(top, token, lookahead)]
239 elif (top, token, lookahead, lookahead2) in table:
240 action = table[(top, token, lookahead, lookahead2)]
247 stack.extend(reversed(self.syntax[action]))
248 accepted = accepted and not len(stack)
249 return (accepted, out, tree_nodes)
251 class SyntaxTree(object):
252 def __init__(self, seq, tree_nodes):
255 self.root = self.compile(seq, tree_nodes)[0]
256 def compile(self, seq, tree_nodes):
261 c, v = tree_nodes.pop()
263 c, v = tree_nodes.pop()
264 stack.append(Variable(v))
266 stack.append(Not(self.compile(seq, tree_nodes)))
268 stack.extend(self.compile(seq, tree_nodes))
270 stack.append(Box(self.compile(seq, tree_nodes)))
272 stack.append(Diamond(self.compile(seq, tree_nodes)))
274 stack.append(And(self.compile(seq, tree_nodes)))
276 stack.append(Or(self.compile(seq, tree_nodes)))
278 stack.append(Imp(self.compile(seq, tree_nodes)))
280 stack.append(Eq(self.compile(seq, tree_nodes)))
283 from argparse import ArgumentParser
285 def parse_arguments():
286 parser = ArgumentParser(description="Parses simple modal logic syntax.")
287 parser.add_argument("-f", "--formula", help="your formula")
288 return parser.parse_args()
290 EXCUSE = """The formula was not accepted by the parser, because the parser doesn't like you or the rest of the world. It seems to have some real issues with formulae with inner nesting and generally suffers from its hasty implementation. The parser would like to thank you for your coorporation by providing the formula within the code file itself. Thank you."""
292 if __name__ == "__main__":