Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/logic/logicparser.py
4048 views
1
r"""
2
Module that creates and modifies parse trees of well formed
3
boolean formulas.
4
5
AUTHORS:
6
-- Chris Gorecki
7
8
EXAMPLES:
9
sage: import sage.logic.logicparser as logicparser
10
sage: s = 'a|b&c'
11
sage: t = logicparser.parse(s)
12
sage: t
13
(['|', 'a', ['&', 'b', 'c']], ['a', 'b', 'c'])
14
"""
15
16
from types import *
17
import string
18
19
__symbols = '()&|~<->^'
20
__op_list = ['~', '&', '|', '^', '->', '<->']
21
22
def parse(s):
23
r"""
24
This function produces a parse tree from a boolean formula s.
25
26
INPUT:
27
s -- a string containing a boolean formula.
28
29
OUTPUT:
30
Returns the tuple (parse tree of s, variables in s).
31
32
EXAMPLES:
33
sage: import sage.logic.logicparser as logicparser
34
sage: s = 'a|b&c'
35
sage: t = logicparser.parse(s)
36
sage: t
37
(['|', 'a', ['&', 'b', 'c']], ['a', 'b', 'c'])
38
"""
39
toks, vars_order = tokenize(s)
40
tree = tree_parse(toks)
41
#special case of tree == single variable
42
if(type(tree) is StringType and len([tree]) == 1):
43
return ['&', tree, tree], vars_order
44
return tree, vars_order
45
46
def tokenize(s):
47
r"""
48
This function produces a string of tokens from s.
49
50
INPUT:
51
s -- a string containing a boolean formula.
52
53
OUTPUT:
54
Returns a tuple consisting of (tokens in s, variables in s).
55
56
EXAMPLES:
57
sage: import sage.logic.logicparser as logicparser
58
sage: s = 'a|b&c'
59
sage: t = logicparser.tokenize(s)
60
sage: t
61
(['(', 'a', '|', 'b', '&', 'c', ')'], ['a', 'b', 'c'])
62
"""
63
i = 0
64
toks = ['(']
65
vars_order = []
66
67
while(i < len(s)):
68
tok = ""
69
skip = valid = 1
70
if(s[i] in '()~&|^'):
71
tok = s[i]
72
elif(s[i:i + 2] == '->'):
73
tok = '->'
74
skip = 2
75
elif(s[i:i + 3] == '<->'):
76
tok = '<->'
77
skip = 3
78
if(len(tok) > 0):
79
toks.append(tok)
80
i += skip
81
continue
82
else:
83
#token is a variable name
84
if(s[i] == ' '):
85
i += 1
86
continue
87
88
while(i < len(s) and s[i] not in __symbols and s[i] != ' '):
89
tok += s[i]
90
i += 1
91
92
if(len(tok) > 0):
93
if(tok[0] not in string.letters):
94
valid = 0
95
for c in tok:
96
if(c not in string.letters and c not in string.digits and c != '_'):
97
valid = 0
98
99
if(valid == 1):
100
toks.append(tok)
101
if(tok not in vars_order):
102
vars_order.append(tok)
103
else:
104
msg = 'invalid variable name ' + tok
105
msg += ": identifiers must begin with a letter and contain only "
106
msg += "alphanumerics and underscores"
107
raise NameError, msg
108
109
toks.append(')')
110
return toks, vars_order
111
112
def tree_parse(toks):
113
r"""
114
This function produces a parse tree from the tokens in toks.
115
116
INPUT:
117
toks -- a list of tokens.
118
119
OUTPUT:
120
Returns a parse tree of the tokens toks.
121
122
EXAMPLES:
123
sage: import sage.logic.logicparser as logicparser
124
sage: t = ['(', 'a', '|', 'b', '&', 'c', ')']
125
sage: logicparser.tree_parse(t)
126
['|', 'a', ['&', 'b', 'c']]
127
"""
128
stack = []
129
for tok in toks:
130
stack.append(tok)
131
if(tok == ')'):
132
lrtoks = []
133
while(tok != '('):
134
tok = stack.pop()
135
lrtoks.insert(0, tok)
136
branch = parse_ltor(lrtoks[1:-1])
137
stack.append(branch)
138
return stack[0]
139
140
def parse_ltor(toks, n = 0):
141
r"""
142
This function produces a parse tree from the tokens in toks under
143
the precondition that each token in toks is atomic.
144
145
INPUT:
146
toks -- a list of tokens.
147
n -- an integer representing which order of operations
148
are occurring.
149
150
OUTPUT:
151
Returns a parse tree of the tokens toks.
152
153
EXAMPLES:
154
sage: import sage.logic.logicparser as logicparser
155
sage: t = ['a', '|', 'b', '&', 'c']
156
sage: logicparser.parse_ltor(t)
157
['|', 'a', ['&', 'b', 'c']]
158
"""
159
i = 0
160
for tok in toks:
161
if(tok == __op_list[n]):
162
if(tok == '~'):
163
#cancel double negations
164
if(toks[i] == '~' and toks[i + 1] == '~'):
165
del toks[i]
166
del toks[i]
167
return parse_ltor(toks, n)
168
args = [toks[i], toks[i + 1], None]
169
toks[i] = args
170
del toks[i + 1]
171
return parse_ltor(toks, n)
172
else:
173
args = [toks[i - 1], toks[i], toks[i + 1]]
174
toks[i - 1] = [args[1], args[0], args[2]]
175
del toks[i]
176
del toks[i]
177
return parse_ltor(toks, n)
178
i += 1
179
if(n + 1 < len(__op_list)):
180
return parse_ltor(toks, n + 1)
181
if(len(toks) > 1):
182
raise SyntaxError
183
return toks[0]
184
185
def apply_func(tree, func):
186
r"""
187
This function applies func to each node of tree.
188
189
INPUT:
190
tree -- a parse tree.
191
func -- a function to be applied to tree.
192
193
OUTPUT:
194
Returns a parse tree after func has been applied
195
to it.
196
197
EXAMPLES:
198
sage: import sage.logic.logicparser as logicparser
199
sage: t = ['|', ['&', 'a', 'b'], ['&', 'a', 'c']]
200
sage: f = lambda t: t
201
sage: logicparser.apply_func(t, f)
202
['|', ['&', 'a', 'b'], ['&', 'a', 'c']]
203
"""
204
if(type(tree[1]) is ListType and type(tree[2]) is ListType):
205
lval = apply_func(tree[1], func)
206
rval = apply_func(tree[2], func)
207
elif(type(tree[1]) is ListType):
208
lval = apply_func(tree[1], func)
209
rval = tree[2]
210
elif(type(tree[2]) is ListType):
211
lval = tree[1]
212
rval = apply_func(tree[2], func)
213
else:
214
lval = tree[1]
215
rval = tree[2]
216
return func([tree[0], lval, rval])
217
218
219
220