#!/usr/bin/env python
#
# unresistricted grammar with dictionary interface
# v.11
# Written by Shea Kauffman
#
# based upon the thue langauage by:
# John Colagioia
# and the interpreter by:
# Frederic van der plancke
#
#
import string, re
def find_all(s, pattern):
"""
return ordered list of indexes where [pattern] appears in [s];
"""
shift_on_match = 1
indexes = []
i = re.search(pattern, s)
if i:
i, j, k = i.start(), i.end(), i.groups()
indexes.append((i,j,k))
return indexes
class Rule:
def __init__(self, lhs, rhs, output=None):
self.lhs = lhs
self.rhs = rhs
def __str__(self):
return "%s :- %s" % (self.lhs, self.rhs)
def __repr__(self):
return "Rule(%s,%s)" % (repr(self.lhs), repr(self.rhs))
class grammar(object):
rulebase = ()
def __init__(self, rules=()):
self.rulebase = tuple(rules)
self.trace = False
def __call__(self, item):
prev = None
while prev != item:
prev = item
item = self[item]
return item
def __getitem__(self, tape):
(match, rule) = self._matches(tape)
if not match:
'''If there are no matches then we're done'''
if self.trace: print tape
return tape
startpos, endpos, matched = match
middledata = self._transform(matched, rule)
dataspace = tape[ : startpos] + middledata + tape[endpos : ]
if self.trace:
print tape, '->', dataspace, '\t\t::\t', rule
return dataspace
def __setitem__(self, lhs, rhs):
self.rulebase = self.rulebase + (Rule(lhs, rhs), )
def __repr__(self):
return '\n'.join([rule.__str__() for rule in self.rulebase])
def __add__(self, other):
newg = grammar(self.rulebase+other.rulebase)
newg.trace = self.trace and other.trace
return newg
def _matches(self, tape):
'''iterate through rules returning first match'''
for rule in self.rulebase:
for i in find_all(tape, rule.lhs):
return i, rule
return False, None
def _transform(self, matched, rule):
if not matched:
return rule.rhs
return rule.rhs(*matched) if callable(rule.rhs) else rule.rhs % matched
if __name__ == '__main__':
TRACES = True
#TESTS:
#lengthdiv3
lengthdiv3 = grammar()
lengthdiv3['ZZZ'] = '...'
lengthdiv3.trace = TRACES
assert lengthdiv3('ZZZZZZZZZZZZ') == '............'
#bitshift
bitshift = grammar()
bitshift['0_']='0--'
bitshift['1_']='0'
bitshift['10--']='01'
bitshift['00--']='0--1'
bitshift['_1--']='@'
bitshift['_0--']='1'
bitshift['_0']=''
bitshift.trace = TRACES
assert bitshift('_1000000000000_') == '111111111111'
#helloworld
helloworld = grammar()
helloworld['__']='Hello, World!'
helloworld.trace = TRACES
assert helloworld('__') == 'Hello, World!'
#binarysucc
binarysucc = grammar()
binarysucc['1_']='1++'
binarysucc['0_']='1'
binarysucc['01\+\+']='10'
binarysucc['11\+\+']='1++0'
binarysucc['_0']='_'
binarysucc['_1\+\+']='10'
binarysucc.trace = TRACES
assert binarysucc('_1111111111_') == '10000000000'
#binaryadd
binaryadd = grammar()
binaryadd[r'_\+_'] = '<+|+>'
binaryadd[r'\+\>0'] = '0?+>'
binaryadd[r'\+\>1'] = '1?+>'
binaryadd[r'\+\>_'] = '<@0C_'
binaryadd[r'0\<\+'] = '<+0?'
binaryadd[r'1\<\+'] = '<+1?'
binaryadd[r'_\<\+'] = '_'
binaryadd[r'0\@0\?'] = '0?0@'
binaryadd[r'0\@1\?'] = '1?0@'
binaryadd[r'1\@0\?'] = '0?1@'
binaryadd[r'1\@1\?'] = '1?1@'
binaryadd[r'0\@\|'] = '|0@'
binaryadd[r'1\@\|'] = '|1@'
binaryadd[r'0\@0\@0C'] = '<@0C0'
binaryadd[r'0\@0\@1C'] = '<@0C1'
binaryadd[r'0\@1\@0C'] = '<@0C1'
binaryadd[r'0\@1\@1C'] = '<@1C0'
binaryadd[r'1\@0\@0C'] = '<@0C1'
binaryadd[r'1\@0\@1C'] = '<@1C0'
binaryadd[r'1\@1\@0C'] = '<@1C0'
binaryadd[r'1\@1\@1C'] = '<@1C1'
binaryadd[r'0\?\<\@'] = '<?0@'
binaryadd[r'1\?\<\@'] = '<?1@'
binaryadd[r'0\?\<\?'] = '<?0?'
binaryadd[r'1\?\<\?'] = '<?1?'
binaryadd[r'\|\<\?'] = '<@|'
binaryadd[r'_\<\?'] = '_'
binaryadd[r'0\?\|\<\@'] = '|0@0@'
binaryadd[r'1\?\|\<\@'] = '|1@0@'
binaryadd[r'_\<\@\|'] = '_|0@'
binaryadd[r'_\|\<\@'] = '_'
binaryadd[r'_0C'] = '_'
binaryadd[r'_1C'] = '_1'
binaryadd.trace = TRACES
assert binaryadd('_111100_+_10010_') == '_1001110_'
palindrome = grammar()
palindrome[r'(?:^1)([01]*)(?:1$)'] = '%s'
palindrome[r'(?:^0)([01]*)(?:0$)'] = '%s'
palindrome[r'^1$'] = ''
palindrome[r'^0$'] = ''
palindrome.trace = True
assert palindrome('000111000') == ''
assert palindrome('000101000') == ''
assert palindrome('0001110') == '00111'
assert palindrome('101100101') == '100'
dictionary = grammar()
dictionary["database"]="master"
dictionary["server"]="mpilgrim"
dictionary.trace = TRACES
assert dictionary["server"] == 'mpilgrim'
assert dictionary["database"] == 'master'
assert dictionary["server is offline"] == 'mpilgrim is offline'
assert dictionary["database server is offline"] == 'master server is offline'
assert dictionary("database server is offline") == 'master mpilgrim is offline'
#print re.search(r"(\w+)\+(\w+)", "3+6", 1).groups()
addition = grammar()
addition.trace = TRACES
addition[r'(\w+)\+(\w+)'] = '+(%s, %s)'
addition[r'\+\((\w+), (\w+)\)'] = lambda x,y: str(int(x)+int(y))
assert addition('2+3') == '5'
assert int(addition('26435+33333')) == 26435+33333
multiply = grammar()
multiply.trace = TRACES
multiply[r'(\w+)\s*\*\s*(\w+)'] = '*(%s, %s)'
multiply[r'\*\((\w+),\s*(\w+)\)'] = lambda x,y: str(int(x)*int(y))
assert multiply('2*3') == '6'
assert int(multiply('26435*33333')) == 26435*33333
math = multiply+addition
math['\((\w+)\)'] = lambda x: math(x) #recursive step
math.trace = TRACES
assert int(math('26435*33333')) == 26435*33333
assert int(math('(26435+26435)*33333')) == (26435+26435)*33333
assert int(math('26435+(26435*33333)')) == 26435+(26435*33333)
assert math('26435+(26435*33333)') == math('26435+26435*33333')
whitespace = grammar()
whitespace.trace = TRACES
whitespace['\n(?P<ws>\s+)(.*)(?P=ws)'] = lambda x,y: ',%s' % y
whitespace['\|,(.*)'] = lambda x: 'where(%s)' % x
assert whitespace('''
z = y |
baz = bar
foo = blurk
moo = cow
''').strip() == 'z = y where(baz = bar,foo = blurk,moo = cow)'
assert whitespace('''
z = y |
baz = bar |
foo = blurk
moo = cow
''').strip() == 'z = y where(baz = bar where(foo = blurk,moo = cow))'
assert whitespace('''
z = y |
baz = bar
foo = blurk
moo = cow
z = y |
baz = bar |
foo = blurk
moo = cow
''').strip() == '''
z = y where(baz = bar,foo = blurk,moo = cow)
z = y where(baz = bar where(foo = blurk,moo = cow))'''.strip()