Created
June 10, 2011 15:35
-
-
Save monkstone/1019068 to your computer and use it in GitHub Desktop.
Context Sensitive Grammar in python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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