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