Skip to content

Instantly share code, notes, and snippets.

@monkstone
Created June 10, 2011 15:35
Show Gist options
  • Save monkstone/1019068 to your computer and use it in GitHub Desktop.
Save monkstone/1019068 to your computer and use it in GitHub Desktop.
Context Sensitive Grammar in python
axiom = 'baa[a]aaaa'
IGNORE='[]'
RULES = {
'b': 'a',
'b<a': 'b'
}
LEFT = -1
RIGHT = 1
def __context(a):
"""
Private helper function returns a tuple of value, index and context from key 'a'
Valid direction setters are '>' or '<' else no direction is set
"""
index = 0
before = a[1] == '<' if len(a) == 3 else False # python ternary operator
after = a[1] == '>' if len(a) == 3 else False # python ternary operator
cont = a[0] if (before or after) else None
if (before):
index += LEFT
if (after):
index += RIGHT
value = a[2] if len(a) == 3 else a[0]
return (value, index, cont)
def __getContext(path, index, direction, ignore):
"""
Private helper returns context character from path[index + direction],
skipping any ignore characters
"""
skip = 0
while path[direction + index + skip] in ignore:
skip += direction
return path[direction + index + skip]
def hasContext(a, b, index):
"""
from a given key, axiom/production string and index returns
has context boolean (ignoring characters in IGNORED)
"""
cont = False
if __context(a)[0] == b[index] and __context(a)[1] != 0:
if __context(a)[1] == LEFT and index > 0: # guard negative index
cont = __context(a)[2] == __getContext(b, index, LEFT, IGNORE)
elif __context(a)[1] == RIGHT and index < len(b) - 1: # guard out of range index
cont = __context(a)[2] == __getContext(b, index, RIGHT, IGNORE)
return cont
def produce(ax, rules):
"""
generate production from axiom and rules
"""
str_buf = [] # initialize string buffer
csrule = {} # initialize context sensitive dict
for key in rules.keys():
if len(key) == 3:
csrule[key[2]] = key
for i, a in enumerate(ax):
r = csrule.get(a, a)
if (r == a): # handle as a cf rule
str_buf.append(rules.get(a, a))
else: # handle as a cs rule
if hasContext(r, ax, i):
str_buf.append(rules.get(r))
else:
str_buf.append(r[2])
return ''.join(str_buf) # join str_buf list as a single string
def repeat(rpx, axiom, rules):
"""
Repeat rule substitution in a recursive fashion rpx times
"""
production = axiom
from itertools import repeat
for _ in repeat(None, rpx):
production = produce(production, rules)
return production
def test():
"""
simple test
"""
for i in range(0, 8):
print(repeat(i, axiom, RULES))
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment