Whitespace normalization.
diff --git a/Parser/spark.py b/Parser/spark.py
index 00d9733..2c18623 100644
--- a/Parser/spark.py
+++ b/Parser/spark.py
@@ -1,5 +1,5 @@
 #  Copyright (c) 1998-2002 John Aycock
-#  
+#
 #  Permission is hereby granted, free of charge, to any person obtaining
 #  a copy of this software and associated documentation files (the
 #  "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
 #  distribute, sublicense, and/or sell copies of the Software, and to
 #  permit persons to whom the Software is furnished to do so, subject to
 #  the following conditions:
-#  
+#
 #  The above copyright notice and this permission notice shall be
 #  included in all copies or substantial portions of the Software.
-#  
+#
 #  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 #  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 #  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -26,651 +26,651 @@
 import string
 
 def _namelist(instance):
-	namelist, namedict, classlist = [], {}, [instance.__class__]
-	for c in classlist:
-		for b in c.__bases__:
-			classlist.append(b)
-		for name in c.__dict__.keys():
-			if not namedict.has_key(name):
-				namelist.append(name)
-				namedict[name] = 1
-	return namelist
+    namelist, namedict, classlist = [], {}, [instance.__class__]
+    for c in classlist:
+        for b in c.__bases__:
+            classlist.append(b)
+        for name in c.__dict__.keys():
+            if not namedict.has_key(name):
+                namelist.append(name)
+                namedict[name] = 1
+    return namelist
 
 class GenericScanner:
-	def __init__(self, flags=0):
-		pattern = self.reflect()
-		self.re = re.compile(pattern, re.VERBOSE|flags)
+    def __init__(self, flags=0):
+        pattern = self.reflect()
+        self.re = re.compile(pattern, re.VERBOSE|flags)
 
-		self.index2func = {}
-		for name, number in self.re.groupindex.items():
-			self.index2func[number-1] = getattr(self, 't_' + name)
+        self.index2func = {}
+        for name, number in self.re.groupindex.items():
+            self.index2func[number-1] = getattr(self, 't_' + name)
 
-	def makeRE(self, name):
-		doc = getattr(self, name).__doc__
-		rv = '(?P<%s>%s)' % (name[2:], doc)
-		return rv
+    def makeRE(self, name):
+        doc = getattr(self, name).__doc__
+        rv = '(?P<%s>%s)' % (name[2:], doc)
+        return rv
 
-	def reflect(self):
-		rv = []
-		for name in _namelist(self):
-			if name[:2] == 't_' and name != 't_default':
-				rv.append(self.makeRE(name))
+    def reflect(self):
+        rv = []
+        for name in _namelist(self):
+            if name[:2] == 't_' and name != 't_default':
+                rv.append(self.makeRE(name))
 
-		rv.append(self.makeRE('t_default'))
-		return string.join(rv, '|')
+        rv.append(self.makeRE('t_default'))
+        return string.join(rv, '|')
 
-	def error(self, s, pos):
-		print "Lexical error at position %s" % pos
-		raise SystemExit
+    def error(self, s, pos):
+        print "Lexical error at position %s" % pos
+        raise SystemExit
 
-	def tokenize(self, s):
-		pos = 0
-		n = len(s)
-		while pos < n:
-			m = self.re.match(s, pos)
-			if m is None:
-				self.error(s, pos)
+    def tokenize(self, s):
+        pos = 0
+        n = len(s)
+        while pos < n:
+            m = self.re.match(s, pos)
+            if m is None:
+                self.error(s, pos)
 
-			groups = m.groups()
-			for i in range(len(groups)):
-				if groups[i] and self.index2func.has_key(i):
-					self.index2func[i](groups[i])
-			pos = m.end()
+            groups = m.groups()
+            for i in range(len(groups)):
+                if groups[i] and self.index2func.has_key(i):
+                    self.index2func[i](groups[i])
+            pos = m.end()
 
-	def t_default(self, s):
-		r'( . | \n )+'
-		print "Specification error: unmatched input"
-		raise SystemExit
+    def t_default(self, s):
+        r'( . | \n )+'
+        print "Specification error: unmatched input"
+        raise SystemExit
 
 #
 #  Extracted from GenericParser and made global so that [un]picking works.
 #
 class _State:
-	def __init__(self, stateno, items):
-		self.T, self.complete, self.items = [], [], items
-		self.stateno = stateno
+    def __init__(self, stateno, items):
+        self.T, self.complete, self.items = [], [], items
+        self.stateno = stateno
 
 class GenericParser:
-	#
-	#  An Earley parser, as per J. Earley, "An Efficient Context-Free
-	#  Parsing Algorithm", CACM 13(2), pp. 94-102.  Also J. C. Earley,
-	#  "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis,
-	#  Carnegie-Mellon University, August 1968.  New formulation of
-	#  the parser according to J. Aycock, "Practical Earley Parsing
-	#  and the SPARK Toolkit", Ph.D. thesis, University of Victoria,
-	#  2001, and J. Aycock and R. N. Horspool, "Practical Earley
-	#  Parsing", unpublished paper, 2001.
-	#
+    #
+    #  An Earley parser, as per J. Earley, "An Efficient Context-Free
+    #  Parsing Algorithm", CACM 13(2), pp. 94-102.  Also J. C. Earley,
+    #  "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis,
+    #  Carnegie-Mellon University, August 1968.  New formulation of
+    #  the parser according to J. Aycock, "Practical Earley Parsing
+    #  and the SPARK Toolkit", Ph.D. thesis, University of Victoria,
+    #  2001, and J. Aycock and R. N. Horspool, "Practical Earley
+    #  Parsing", unpublished paper, 2001.
+    #
 
-	def __init__(self, start):
-		self.rules = {}
-		self.rule2func = {}
-		self.rule2name = {}
-		self.collectRules()
-		self.augment(start)
-		self.ruleschanged = 1
+    def __init__(self, start):
+        self.rules = {}
+        self.rule2func = {}
+        self.rule2name = {}
+        self.collectRules()
+        self.augment(start)
+        self.ruleschanged = 1
 
-	_NULLABLE = '\e_'
-	_START = 'START'
-	_BOF = '|-'
+    _NULLABLE = '\e_'
+    _START = 'START'
+    _BOF = '|-'
 
-	#
-	#  When pickling, take the time to generate the full state machine;
-	#  some information is then extraneous, too.  Unfortunately we
-	#  can't save the rule2func map.
-	#
-	def __getstate__(self):
-		if self.ruleschanged:
-			#
-			#  XXX - duplicated from parse()
-			#
-			self.computeNull()
-			self.newrules = {}
-			self.new2old = {}
-			self.makeNewRules()
-			self.ruleschanged = 0
-			self.edges, self.cores = {}, {}
-			self.states = { 0: self.makeState0() }
-			self.makeState(0, self._BOF)
-		#
-		#  XXX - should find a better way to do this..
-		#
-		changes = 1
-		while changes:
-			changes = 0
-			for k, v in self.edges.items():
-				if v is None:
-					state, sym = k
-					if self.states.has_key(state):
-						self.goto(state, sym)
-						changes = 1
-		rv = self.__dict__.copy()
-		for s in self.states.values():
-			del s.items
-		del rv['rule2func']
-		del rv['nullable']
-		del rv['cores']
-		return rv
+    #
+    #  When pickling, take the time to generate the full state machine;
+    #  some information is then extraneous, too.  Unfortunately we
+    #  can't save the rule2func map.
+    #
+    def __getstate__(self):
+        if self.ruleschanged:
+            #
+            #  XXX - duplicated from parse()
+            #
+            self.computeNull()
+            self.newrules = {}
+            self.new2old = {}
+            self.makeNewRules()
+            self.ruleschanged = 0
+            self.edges, self.cores = {}, {}
+            self.states = { 0: self.makeState0() }
+            self.makeState(0, self._BOF)
+        #
+        #  XXX - should find a better way to do this..
+        #
+        changes = 1
+        while changes:
+            changes = 0
+            for k, v in self.edges.items():
+                if v is None:
+                    state, sym = k
+                    if self.states.has_key(state):
+                        self.goto(state, sym)
+                        changes = 1
+        rv = self.__dict__.copy()
+        for s in self.states.values():
+            del s.items
+        del rv['rule2func']
+        del rv['nullable']
+        del rv['cores']
+        return rv
 
-	def __setstate__(self, D):
-		self.rules = {}
-		self.rule2func = {}
-		self.rule2name = {}
-		self.collectRules()
-		start = D['rules'][self._START][0][1][1]	# Blech.
-		self.augment(start)
-		D['rule2func'] = self.rule2func
-		D['makeSet'] = self.makeSet_fast
-		self.__dict__ = D
+    def __setstate__(self, D):
+        self.rules = {}
+        self.rule2func = {}
+        self.rule2name = {}
+        self.collectRules()
+        start = D['rules'][self._START][0][1][1]        # Blech.
+        self.augment(start)
+        D['rule2func'] = self.rule2func
+        D['makeSet'] = self.makeSet_fast
+        self.__dict__ = D
 
-	#
-	#  A hook for GenericASTBuilder and GenericASTMatcher.  Mess
-	#  thee not with this; nor shall thee toucheth the _preprocess
-	#  argument to addRule.
-	#
-	def preprocess(self, rule, func):	return rule, func
+    #
+    #  A hook for GenericASTBuilder and GenericASTMatcher.  Mess
+    #  thee not with this; nor shall thee toucheth the _preprocess
+    #  argument to addRule.
+    #
+    def preprocess(self, rule, func):       return rule, func
 
-	def addRule(self, doc, func, _preprocess=1):
-		fn = func
-		rules = string.split(doc)
+    def addRule(self, doc, func, _preprocess=1):
+        fn = func
+        rules = string.split(doc)
 
-		index = []
-		for i in range(len(rules)):
-			if rules[i] == '::=':
-				index.append(i-1)
-		index.append(len(rules))
+        index = []
+        for i in range(len(rules)):
+            if rules[i] == '::=':
+                index.append(i-1)
+        index.append(len(rules))
 
-		for i in range(len(index)-1):
-			lhs = rules[index[i]]
-			rhs = rules[index[i]+2:index[i+1]]
-			rule = (lhs, tuple(rhs))
+        for i in range(len(index)-1):
+            lhs = rules[index[i]]
+            rhs = rules[index[i]+2:index[i+1]]
+            rule = (lhs, tuple(rhs))
 
-			if _preprocess:
-				rule, fn = self.preprocess(rule, func)
+            if _preprocess:
+                rule, fn = self.preprocess(rule, func)
 
-			if self.rules.has_key(lhs):
-				self.rules[lhs].append(rule)
-			else:
-				self.rules[lhs] = [ rule ]
-			self.rule2func[rule] = fn
-			self.rule2name[rule] = func.__name__[2:]
-		self.ruleschanged = 1
+            if self.rules.has_key(lhs):
+                self.rules[lhs].append(rule)
+            else:
+                self.rules[lhs] = [ rule ]
+            self.rule2func[rule] = fn
+            self.rule2name[rule] = func.__name__[2:]
+        self.ruleschanged = 1
 
-	def collectRules(self):
-		for name in _namelist(self):
-			if name[:2] == 'p_':
-				func = getattr(self, name)
-				doc = func.__doc__
-				self.addRule(doc, func)
+    def collectRules(self):
+        for name in _namelist(self):
+            if name[:2] == 'p_':
+                func = getattr(self, name)
+                doc = func.__doc__
+                self.addRule(doc, func)
 
-	def augment(self, start):
-		rule = '%s ::= %s %s' % (self._START, self._BOF, start)
-		self.addRule(rule, lambda args: args[1], 0)
+    def augment(self, start):
+        rule = '%s ::= %s %s' % (self._START, self._BOF, start)
+        self.addRule(rule, lambda args: args[1], 0)
 
-	def computeNull(self):
-		self.nullable = {}
-		tbd = []
+    def computeNull(self):
+        self.nullable = {}
+        tbd = []
 
-		for rulelist in self.rules.values():
-			lhs = rulelist[0][0]
-			self.nullable[lhs] = 0
-			for rule in rulelist:
-				rhs = rule[1]
-				if len(rhs) == 0:
-					self.nullable[lhs] = 1
-					continue
-				#
-				#  We only need to consider rules which
-				#  consist entirely of nonterminal symbols.
-				#  This should be a savings on typical
-				#  grammars.
-				#
-				for sym in rhs:
-					if not self.rules.has_key(sym):
-						break
-				else:
-					tbd.append(rule)
-		changes = 1
-		while changes:
-			changes = 0
-			for lhs, rhs in tbd:
-				if self.nullable[lhs]:
-					continue
-				for sym in rhs:
-					if not self.nullable[sym]:
-						break
-				else:
-					self.nullable[lhs] = 1
-					changes = 1
+        for rulelist in self.rules.values():
+            lhs = rulelist[0][0]
+            self.nullable[lhs] = 0
+            for rule in rulelist:
+                rhs = rule[1]
+                if len(rhs) == 0:
+                    self.nullable[lhs] = 1
+                    continue
+                #
+                #  We only need to consider rules which
+                #  consist entirely of nonterminal symbols.
+                #  This should be a savings on typical
+                #  grammars.
+                #
+                for sym in rhs:
+                    if not self.rules.has_key(sym):
+                        break
+                else:
+                    tbd.append(rule)
+        changes = 1
+        while changes:
+            changes = 0
+            for lhs, rhs in tbd:
+                if self.nullable[lhs]:
+                    continue
+                for sym in rhs:
+                    if not self.nullable[sym]:
+                        break
+                else:
+                    self.nullable[lhs] = 1
+                    changes = 1
 
-	def makeState0(self):
-		s0 = _State(0, [])
-		for rule in self.newrules[self._START]:
-			s0.items.append((rule, 0))
-		return s0
+    def makeState0(self):
+        s0 = _State(0, [])
+        for rule in self.newrules[self._START]:
+            s0.items.append((rule, 0))
+        return s0
 
-	def finalState(self, tokens):
-		#
-		#  Yuck.
-		#
-		if len(self.newrules[self._START]) == 2 and len(tokens) == 0:
-			return 1
-		start = self.rules[self._START][0][1][1]
-		return self.goto(1, start)
+    def finalState(self, tokens):
+        #
+        #  Yuck.
+        #
+        if len(self.newrules[self._START]) == 2 and len(tokens) == 0:
+            return 1
+        start = self.rules[self._START][0][1][1]
+        return self.goto(1, start)
 
-	def makeNewRules(self):
-		worklist = []
-		for rulelist in self.rules.values():
-			for rule in rulelist:
-				worklist.append((rule, 0, 1, rule))
+    def makeNewRules(self):
+        worklist = []
+        for rulelist in self.rules.values():
+            for rule in rulelist:
+                worklist.append((rule, 0, 1, rule))
 
-		for rule, i, candidate, oldrule in worklist:
-			lhs, rhs = rule
-			n = len(rhs)
-			while i < n:
-				sym = rhs[i]
-				if not self.rules.has_key(sym) or \
-				   not self.nullable[sym]:
-					candidate = 0
-					i = i + 1
-					continue
+        for rule, i, candidate, oldrule in worklist:
+            lhs, rhs = rule
+            n = len(rhs)
+            while i < n:
+                sym = rhs[i]
+                if not self.rules.has_key(sym) or \
+                   not self.nullable[sym]:
+                    candidate = 0
+                    i = i + 1
+                    continue
 
-				newrhs = list(rhs)
-				newrhs[i] = self._NULLABLE+sym
-				newrule = (lhs, tuple(newrhs))
-				worklist.append((newrule, i+1,
-						 candidate, oldrule))
-				candidate = 0
-				i = i + 1
-			else:
-				if candidate:
-					lhs = self._NULLABLE+lhs
-					rule = (lhs, rhs)
-				if self.newrules.has_key(lhs):
-					self.newrules[lhs].append(rule)
-				else:
-					self.newrules[lhs] = [ rule ]
-				self.new2old[rule] = oldrule
-	
-	def typestring(self, token):
-		return None
+                newrhs = list(rhs)
+                newrhs[i] = self._NULLABLE+sym
+                newrule = (lhs, tuple(newrhs))
+                worklist.append((newrule, i+1,
+                                 candidate, oldrule))
+                candidate = 0
+                i = i + 1
+            else:
+                if candidate:
+                    lhs = self._NULLABLE+lhs
+                    rule = (lhs, rhs)
+                if self.newrules.has_key(lhs):
+                    self.newrules[lhs].append(rule)
+                else:
+                    self.newrules[lhs] = [ rule ]
+                self.new2old[rule] = oldrule
 
-	def error(self, token):
-		print "Syntax error at or near `%s' token" % token
-		raise SystemExit
+    def typestring(self, token):
+        return None
 
-	def parse(self, tokens):
-		sets = [ [(1,0), (2,0)] ]
-		self.links = {}
-		
-		if self.ruleschanged:
-			self.computeNull()
-			self.newrules = {}
-			self.new2old = {}
-			self.makeNewRules()
-			self.ruleschanged = 0
-			self.edges, self.cores = {}, {}
-			self.states = { 0: self.makeState0() }
-			self.makeState(0, self._BOF)
+    def error(self, token):
+        print "Syntax error at or near `%s' token" % token
+        raise SystemExit
 
-		for i in xrange(len(tokens)):
-			sets.append([])
+    def parse(self, tokens):
+        sets = [ [(1,0), (2,0)] ]
+        self.links = {}
 
-			if sets[i] == []:
-				break				
-			self.makeSet(tokens[i], sets, i)
-		else:
-			sets.append([])
-			self.makeSet(None, sets, len(tokens))
+        if self.ruleschanged:
+            self.computeNull()
+            self.newrules = {}
+            self.new2old = {}
+            self.makeNewRules()
+            self.ruleschanged = 0
+            self.edges, self.cores = {}, {}
+            self.states = { 0: self.makeState0() }
+            self.makeState(0, self._BOF)
 
-		#_dump(tokens, sets, self.states)
+        for i in xrange(len(tokens)):
+            sets.append([])
 
-		finalitem = (self.finalState(tokens), 0)
-		if finalitem not in sets[-2]:
-			if len(tokens) > 0:
-				self.error(tokens[i-1])
-			else:
-				self.error(None)
+            if sets[i] == []:
+                break
+            self.makeSet(tokens[i], sets, i)
+        else:
+            sets.append([])
+            self.makeSet(None, sets, len(tokens))
 
-		return self.buildTree(self._START, finalitem,
-				      tokens, len(sets)-2)
+        #_dump(tokens, sets, self.states)
 
-	def isnullable(self, sym):
-		#
-		#  For symbols in G_e only.  If we weren't supporting 1.5,
-		#  could just use sym.startswith().
-		#
-		return self._NULLABLE == sym[0:len(self._NULLABLE)]
+        finalitem = (self.finalState(tokens), 0)
+        if finalitem not in sets[-2]:
+            if len(tokens) > 0:
+                self.error(tokens[i-1])
+            else:
+                self.error(None)
 
-	def skip(self, (lhs, rhs), pos=0):
-		n = len(rhs)
-		while pos < n:
-			if not self.isnullable(rhs[pos]):
-				break
-			pos = pos + 1
-		return pos
+        return self.buildTree(self._START, finalitem,
+                              tokens, len(sets)-2)
 
-	def makeState(self, state, sym):
-		assert sym is not None
-		#
-		#  Compute \epsilon-kernel state's core and see if
-		#  it exists already.
-		#
-		kitems = []
-		for rule, pos in self.states[state].items:
-			lhs, rhs = rule
-			if rhs[pos:pos+1] == (sym,):
-				kitems.append((rule, self.skip(rule, pos+1)))
-		core = kitems
+    def isnullable(self, sym):
+        #
+        #  For symbols in G_e only.  If we weren't supporting 1.5,
+        #  could just use sym.startswith().
+        #
+        return self._NULLABLE == sym[0:len(self._NULLABLE)]
 
-		core.sort()
-		tcore = tuple(core)
-		if self.cores.has_key(tcore):
-			return self.cores[tcore]
-		#
-		#  Nope, doesn't exist.  Compute it and the associated
-		#  \epsilon-nonkernel state together; we'll need it right away.
-		#
-		k = self.cores[tcore] = len(self.states)
-		K, NK = _State(k, kitems), _State(k+1, [])
-		self.states[k] = K
-		predicted = {}
+    def skip(self, (lhs, rhs), pos=0):
+        n = len(rhs)
+        while pos < n:
+            if not self.isnullable(rhs[pos]):
+                break
+            pos = pos + 1
+        return pos
 
-		edges = self.edges
-		rules = self.newrules
-		for X in K, NK:
-			worklist = X.items
-			for item in worklist:
-				rule, pos = item
-				lhs, rhs = rule
-				if pos == len(rhs):
-					X.complete.append(rule)
-					continue
+    def makeState(self, state, sym):
+        assert sym is not None
+        #
+        #  Compute \epsilon-kernel state's core and see if
+        #  it exists already.
+        #
+        kitems = []
+        for rule, pos in self.states[state].items:
+            lhs, rhs = rule
+            if rhs[pos:pos+1] == (sym,):
+                kitems.append((rule, self.skip(rule, pos+1)))
+        core = kitems
 
-				nextSym = rhs[pos]
-				key = (X.stateno, nextSym)
-				if not rules.has_key(nextSym):
-					if not edges.has_key(key):
-						edges[key] = None
-						X.T.append(nextSym)
-				else:
-					edges[key] = None
-					if not predicted.has_key(nextSym):
-						predicted[nextSym] = 1
-						for prule in rules[nextSym]:
-							ppos = self.skip(prule)
-							new = (prule, ppos)
-							NK.items.append(new)
-			#
-			#  Problem: we know K needs generating, but we
-			#  don't yet know about NK.  Can't commit anything
-			#  regarding NK to self.edges until we're sure.  Should
-			#  we delay committing on both K and NK to avoid this
-			#  hacky code?  This creates other problems..
-			#
-			if X is K:
-				edges = {}
+        core.sort()
+        tcore = tuple(core)
+        if self.cores.has_key(tcore):
+            return self.cores[tcore]
+        #
+        #  Nope, doesn't exist.  Compute it and the associated
+        #  \epsilon-nonkernel state together; we'll need it right away.
+        #
+        k = self.cores[tcore] = len(self.states)
+        K, NK = _State(k, kitems), _State(k+1, [])
+        self.states[k] = K
+        predicted = {}
 
-		if NK.items == []:
-			return k
+        edges = self.edges
+        rules = self.newrules
+        for X in K, NK:
+            worklist = X.items
+            for item in worklist:
+                rule, pos = item
+                lhs, rhs = rule
+                if pos == len(rhs):
+                    X.complete.append(rule)
+                    continue
 
-		#
-		#  Check for \epsilon-nonkernel's core.  Unfortunately we
-		#  need to know the entire set of predicted nonterminals
-		#  to do this without accidentally duplicating states.
-		#
-		core = predicted.keys()
-		core.sort()
-		tcore = tuple(core)
-		if self.cores.has_key(tcore):
-			self.edges[(k, None)] = self.cores[tcore]
-			return k
+                nextSym = rhs[pos]
+                key = (X.stateno, nextSym)
+                if not rules.has_key(nextSym):
+                    if not edges.has_key(key):
+                        edges[key] = None
+                        X.T.append(nextSym)
+                else:
+                    edges[key] = None
+                    if not predicted.has_key(nextSym):
+                        predicted[nextSym] = 1
+                        for prule in rules[nextSym]:
+                            ppos = self.skip(prule)
+                            new = (prule, ppos)
+                            NK.items.append(new)
+            #
+            #  Problem: we know K needs generating, but we
+            #  don't yet know about NK.  Can't commit anything
+            #  regarding NK to self.edges until we're sure.  Should
+            #  we delay committing on both K and NK to avoid this
+            #  hacky code?  This creates other problems..
+            #
+            if X is K:
+                edges = {}
 
-		nk = self.cores[tcore] = self.edges[(k, None)] = NK.stateno
-		self.edges.update(edges)
-		self.states[nk] = NK
-		return k
+        if NK.items == []:
+            return k
 
-	def goto(self, state, sym):
-		key = (state, sym)
-		if not self.edges.has_key(key):
-			#
-			#  No transitions from state on sym.
-			#
-			return None
+        #
+        #  Check for \epsilon-nonkernel's core.  Unfortunately we
+        #  need to know the entire set of predicted nonterminals
+        #  to do this without accidentally duplicating states.
+        #
+        core = predicted.keys()
+        core.sort()
+        tcore = tuple(core)
+        if self.cores.has_key(tcore):
+            self.edges[(k, None)] = self.cores[tcore]
+            return k
 
-		rv = self.edges[key]
-		if rv is None:
-			#
-			#  Target state isn't generated yet.  Remedy this.
-			#
-			rv = self.makeState(state, sym)
-			self.edges[key] = rv
-		return rv
+        nk = self.cores[tcore] = self.edges[(k, None)] = NK.stateno
+        self.edges.update(edges)
+        self.states[nk] = NK
+        return k
 
-	def gotoT(self, state, t):
-		return [self.goto(state, t)]
+    def goto(self, state, sym):
+        key = (state, sym)
+        if not self.edges.has_key(key):
+            #
+            #  No transitions from state on sym.
+            #
+            return None
 
-	def gotoST(self, state, st):
-		rv = []
-		for t in self.states[state].T:
-			if st == t:
-				rv.append(self.goto(state, t))
-		return rv
+        rv = self.edges[key]
+        if rv is None:
+            #
+            #  Target state isn't generated yet.  Remedy this.
+            #
+            rv = self.makeState(state, sym)
+            self.edges[key] = rv
+        return rv
 
-	def add(self, set, item, i=None, predecessor=None, causal=None):
-		if predecessor is None:
-			if item not in set:
-				set.append(item)
-		else:
-			key = (item, i)
-			if item not in set:
-				self.links[key] = []
-				set.append(item)
-			self.links[key].append((predecessor, causal))
+    def gotoT(self, state, t):
+        return [self.goto(state, t)]
 
-	def makeSet(self, token, sets, i):
-		cur, next = sets[i], sets[i+1]
+    def gotoST(self, state, st):
+        rv = []
+        for t in self.states[state].T:
+            if st == t:
+                rv.append(self.goto(state, t))
+        return rv
 
-		ttype = token is not None and self.typestring(token) or None
-		if ttype is not None:
-			fn, arg = self.gotoT, ttype
-		else:
-			fn, arg = self.gotoST, token
+    def add(self, set, item, i=None, predecessor=None, causal=None):
+        if predecessor is None:
+            if item not in set:
+                set.append(item)
+        else:
+            key = (item, i)
+            if item not in set:
+                self.links[key] = []
+                set.append(item)
+            self.links[key].append((predecessor, causal))
 
-		for item in cur:
-			ptr = (item, i)
-			state, parent = item
-			add = fn(state, arg)
-			for k in add:
-				if k is not None:
-					self.add(next, (k, parent), i+1, ptr)
-					nk = self.goto(k, None)
-					if nk is not None:
-						self.add(next, (nk, i+1))
+    def makeSet(self, token, sets, i):
+        cur, next = sets[i], sets[i+1]
 
-			if parent == i:
-				continue
+        ttype = token is not None and self.typestring(token) or None
+        if ttype is not None:
+            fn, arg = self.gotoT, ttype
+        else:
+            fn, arg = self.gotoST, token
 
-			for rule in self.states[state].complete:
-				lhs, rhs = rule
-				for pitem in sets[parent]:
-					pstate, pparent = pitem
-					k = self.goto(pstate, lhs)
-					if k is not None:
-						why = (item, i, rule)
-						pptr = (pitem, parent)
-						self.add(cur, (k, pparent),
-							 i, pptr, why)
-						nk = self.goto(k, None)
-						if nk is not None:
-							self.add(cur, (nk, i))
+        for item in cur:
+            ptr = (item, i)
+            state, parent = item
+            add = fn(state, arg)
+            for k in add:
+                if k is not None:
+                    self.add(next, (k, parent), i+1, ptr)
+                    nk = self.goto(k, None)
+                    if nk is not None:
+                        self.add(next, (nk, i+1))
 
-	def makeSet_fast(self, token, sets, i):
-		#
-		#  Call *only* when the entire state machine has been built!
-		#  It relies on self.edges being filled in completely, and
-		#  then duplicates and inlines code to boost speed at the
-		#  cost of extreme ugliness.
-		#
-		cur, next = sets[i], sets[i+1]
-		ttype = token is not None and self.typestring(token) or None
+            if parent == i:
+                continue
 
-		for item in cur:
-			ptr = (item, i)
-			state, parent = item
-			if ttype is not None:
-				k = self.edges.get((state, ttype), None)
-				if k is not None:
-					#self.add(next, (k, parent), i+1, ptr)
-					#INLINED --v
-					new = (k, parent)
-					key = (new, i+1)
-					if new not in next:
-						self.links[key] = []
-						next.append(new)
-					self.links[key].append((ptr, None))
-					#INLINED --^
-					#nk = self.goto(k, None)
-					nk = self.edges.get((k, None), None)
-					if nk is not None:
-						#self.add(next, (nk, i+1))
-						#INLINED --v
-						new = (nk, i+1)
-						if new not in next:
-							next.append(new)
-						#INLINED --^
-			else:
-				add = self.gotoST(state, token)
-				for k in add:
-					if k is not None:
-						self.add(next, (k, parent), i+1, ptr)
-						#nk = self.goto(k, None)
-						nk = self.edges.get((k, None), None)
-						if nk is not None:
-							self.add(next, (nk, i+1))
+            for rule in self.states[state].complete:
+                lhs, rhs = rule
+                for pitem in sets[parent]:
+                    pstate, pparent = pitem
+                    k = self.goto(pstate, lhs)
+                    if k is not None:
+                        why = (item, i, rule)
+                        pptr = (pitem, parent)
+                        self.add(cur, (k, pparent),
+                                 i, pptr, why)
+                        nk = self.goto(k, None)
+                        if nk is not None:
+                            self.add(cur, (nk, i))
 
-			if parent == i:
-				continue
+    def makeSet_fast(self, token, sets, i):
+        #
+        #  Call *only* when the entire state machine has been built!
+        #  It relies on self.edges being filled in completely, and
+        #  then duplicates and inlines code to boost speed at the
+        #  cost of extreme ugliness.
+        #
+        cur, next = sets[i], sets[i+1]
+        ttype = token is not None and self.typestring(token) or None
 
-			for rule in self.states[state].complete:
-				lhs, rhs = rule
-				for pitem in sets[parent]:
-					pstate, pparent = pitem
-					#k = self.goto(pstate, lhs)
-					k = self.edges.get((pstate, lhs), None)
-					if k is not None:
-						why = (item, i, rule)
-						pptr = (pitem, parent)
-						#self.add(cur, (k, pparent),
-						#	 i, pptr, why)
-						#INLINED --v
-						new = (k, pparent)
-						key = (new, i)
-						if new not in cur:
-							self.links[key] = []
-							cur.append(new)
-						self.links[key].append((pptr, why))
-						#INLINED --^
-						#nk = self.goto(k, None)
-						nk = self.edges.get((k, None), None)
-						if nk is not None:
-							#self.add(cur, (nk, i))
-							#INLINED --v
-							new = (nk, i)
-							if new not in cur:
-								cur.append(new)
-							#INLINED --^
+        for item in cur:
+            ptr = (item, i)
+            state, parent = item
+            if ttype is not None:
+                k = self.edges.get((state, ttype), None)
+                if k is not None:
+                    #self.add(next, (k, parent), i+1, ptr)
+                    #INLINED --v
+                    new = (k, parent)
+                    key = (new, i+1)
+                    if new not in next:
+                        self.links[key] = []
+                        next.append(new)
+                    self.links[key].append((ptr, None))
+                    #INLINED --^
+                    #nk = self.goto(k, None)
+                    nk = self.edges.get((k, None), None)
+                    if nk is not None:
+                        #self.add(next, (nk, i+1))
+                        #INLINED --v
+                        new = (nk, i+1)
+                        if new not in next:
+                            next.append(new)
+                        #INLINED --^
+            else:
+                add = self.gotoST(state, token)
+                for k in add:
+                    if k is not None:
+                        self.add(next, (k, parent), i+1, ptr)
+                        #nk = self.goto(k, None)
+                        nk = self.edges.get((k, None), None)
+                        if nk is not None:
+                            self.add(next, (nk, i+1))
 
-	def predecessor(self, key, causal):
-		for p, c in self.links[key]:
-			if c == causal:
-				return p
-		assert 0
+            if parent == i:
+                continue
 
-	def causal(self, key):
-		links = self.links[key]
-		if len(links) == 1:
-			return links[0][1]
-		choices = []
-		rule2cause = {}
-		for p, c in links:
-			rule = c[2]
-			choices.append(rule)
-			rule2cause[rule] = c
-		return rule2cause[self.ambiguity(choices)]
+            for rule in self.states[state].complete:
+                lhs, rhs = rule
+                for pitem in sets[parent]:
+                    pstate, pparent = pitem
+                    #k = self.goto(pstate, lhs)
+                    k = self.edges.get((pstate, lhs), None)
+                    if k is not None:
+                        why = (item, i, rule)
+                        pptr = (pitem, parent)
+                        #self.add(cur, (k, pparent),
+                        #        i, pptr, why)
+                        #INLINED --v
+                        new = (k, pparent)
+                        key = (new, i)
+                        if new not in cur:
+                            self.links[key] = []
+                            cur.append(new)
+                        self.links[key].append((pptr, why))
+                        #INLINED --^
+                        #nk = self.goto(k, None)
+                        nk = self.edges.get((k, None), None)
+                        if nk is not None:
+                            #self.add(cur, (nk, i))
+                            #INLINED --v
+                            new = (nk, i)
+                            if new not in cur:
+                                cur.append(new)
+                            #INLINED --^
 
-	def deriveEpsilon(self, nt):
-		if len(self.newrules[nt]) > 1:
-			rule = self.ambiguity(self.newrules[nt])
-		else:
-			rule = self.newrules[nt][0]
-		#print rule
+    def predecessor(self, key, causal):
+        for p, c in self.links[key]:
+            if c == causal:
+                return p
+        assert 0
 
-		rhs = rule[1]
-		attr = [None] * len(rhs)
+    def causal(self, key):
+        links = self.links[key]
+        if len(links) == 1:
+            return links[0][1]
+        choices = []
+        rule2cause = {}
+        for p, c in links:
+            rule = c[2]
+            choices.append(rule)
+            rule2cause[rule] = c
+        return rule2cause[self.ambiguity(choices)]
 
-		for i in range(len(rhs)-1, -1, -1):
-			attr[i] = self.deriveEpsilon(rhs[i])
-		return self.rule2func[self.new2old[rule]](attr)
+    def deriveEpsilon(self, nt):
+        if len(self.newrules[nt]) > 1:
+            rule = self.ambiguity(self.newrules[nt])
+        else:
+            rule = self.newrules[nt][0]
+        #print rule
 
-	def buildTree(self, nt, item, tokens, k):
-		state, parent = item
+        rhs = rule[1]
+        attr = [None] * len(rhs)
 
-		choices = []
-		for rule in self.states[state].complete:
-			if rule[0] == nt:
-				choices.append(rule)
-		rule = choices[0]
-		if len(choices) > 1:
-			rule = self.ambiguity(choices)
-		#print rule
+        for i in range(len(rhs)-1, -1, -1):
+            attr[i] = self.deriveEpsilon(rhs[i])
+        return self.rule2func[self.new2old[rule]](attr)
 
-		rhs = rule[1]
-		attr = [None] * len(rhs)
+    def buildTree(self, nt, item, tokens, k):
+        state, parent = item
 
-		for i in range(len(rhs)-1, -1, -1):
-			sym = rhs[i]
-			if not self.newrules.has_key(sym):
-				if sym != self._BOF:
-					attr[i] = tokens[k-1]
-					key = (item, k)
-					item, k = self.predecessor(key, None)
-			#elif self.isnullable(sym):
-			elif self._NULLABLE == sym[0:len(self._NULLABLE)]:
-				attr[i] = self.deriveEpsilon(sym)
-			else:
-				key = (item, k)
-				why = self.causal(key)
-				attr[i] = self.buildTree(sym, why[0],
-							 tokens, why[1])
-				item, k = self.predecessor(key, why)
-		return self.rule2func[self.new2old[rule]](attr)
+        choices = []
+        for rule in self.states[state].complete:
+            if rule[0] == nt:
+                choices.append(rule)
+        rule = choices[0]
+        if len(choices) > 1:
+            rule = self.ambiguity(choices)
+        #print rule
 
-	def ambiguity(self, rules):
-		#
-		#  XXX - problem here and in collectRules() if the same rule
-		#	 appears in >1 method.  Also undefined results if rules
-		#	 causing the ambiguity appear in the same method.
-		#
-		sortlist = []
-		name2index = {}
-		for i in range(len(rules)):
-			lhs, rhs = rule = rules[i]
-			name = self.rule2name[self.new2old[rule]]
-			sortlist.append((len(rhs), name))
-			name2index[name] = i
-		sortlist.sort()
-		list = map(lambda (a,b): b, sortlist)
-		return rules[name2index[self.resolve(list)]]
+        rhs = rule[1]
+        attr = [None] * len(rhs)
 
-	def resolve(self, list):
-		#
-		#  Resolve ambiguity in favor of the shortest RHS.
-		#  Since we walk the tree from the top down, this
-		#  should effectively resolve in favor of a "shift".
-		#
-		return list[0]
+        for i in range(len(rhs)-1, -1, -1):
+            sym = rhs[i]
+            if not self.newrules.has_key(sym):
+                if sym != self._BOF:
+                    attr[i] = tokens[k-1]
+                    key = (item, k)
+                    item, k = self.predecessor(key, None)
+            #elif self.isnullable(sym):
+            elif self._NULLABLE == sym[0:len(self._NULLABLE)]:
+                attr[i] = self.deriveEpsilon(sym)
+            else:
+                key = (item, k)
+                why = self.causal(key)
+                attr[i] = self.buildTree(sym, why[0],
+                                         tokens, why[1])
+                item, k = self.predecessor(key, why)
+        return self.rule2func[self.new2old[rule]](attr)
+
+    def ambiguity(self, rules):
+        #
+        #  XXX - problem here and in collectRules() if the same rule
+        #        appears in >1 method.  Also undefined results if rules
+        #        causing the ambiguity appear in the same method.
+        #
+        sortlist = []
+        name2index = {}
+        for i in range(len(rules)):
+            lhs, rhs = rule = rules[i]
+            name = self.rule2name[self.new2old[rule]]
+            sortlist.append((len(rhs), name))
+            name2index[name] = i
+        sortlist.sort()
+        list = map(lambda (a,b): b, sortlist)
+        return rules[name2index[self.resolve(list)]]
+
+    def resolve(self, list):
+        #
+        #  Resolve ambiguity in favor of the shortest RHS.
+        #  Since we walk the tree from the top down, this
+        #  should effectively resolve in favor of a "shift".
+        #
+        return list[0]
 
 #
 #  GenericASTBuilder automagically constructs a concrete/abstract syntax tree
@@ -681,32 +681,32 @@
 #
 
 class GenericASTBuilder(GenericParser):
-	def __init__(self, AST, start):
-		GenericParser.__init__(self, start)
-		self.AST = AST
+    def __init__(self, AST, start):
+        GenericParser.__init__(self, start)
+        self.AST = AST
 
-	def preprocess(self, rule, func):
-		rebind = lambda lhs, self=self: \
-				lambda args, lhs=lhs, self=self: \
-					self.buildASTNode(args, lhs)
-		lhs, rhs = rule
-		return rule, rebind(lhs)
+    def preprocess(self, rule, func):
+        rebind = lambda lhs, self=self: \
+                        lambda args, lhs=lhs, self=self: \
+                                self.buildASTNode(args, lhs)
+        lhs, rhs = rule
+        return rule, rebind(lhs)
 
-	def buildASTNode(self, args, lhs):
-		children = []
-		for arg in args:
-			if isinstance(arg, self.AST):
-				children.append(arg)
-			else:
-				children.append(self.terminal(arg))
-		return self.nonterminal(lhs, children)
+    def buildASTNode(self, args, lhs):
+        children = []
+        for arg in args:
+            if isinstance(arg, self.AST):
+                children.append(arg)
+            else:
+                children.append(self.terminal(arg))
+        return self.nonterminal(lhs, children)
 
-	def terminal(self, token):	return token
+    def terminal(self, token):      return token
 
-	def nonterminal(self, type, args):
-		rv = self.AST(type)
-		rv[:len(args)] = args
-		return rv
+    def nonterminal(self, type, args):
+        rv = self.AST(type)
+        rv[:len(args)] = args
+        return rv
 
 #
 #  GenericASTTraversal is a Visitor pattern according to Design Patterns.  For
@@ -719,57 +719,57 @@
 #
 
 class GenericASTTraversalPruningException:
-	pass
+    pass
 
 class GenericASTTraversal:
-	def __init__(self, ast):
-		self.ast = ast
+    def __init__(self, ast):
+        self.ast = ast
 
-	def typestring(self, node):
-		return node.type
+    def typestring(self, node):
+        return node.type
 
-	def prune(self):
-		raise GenericASTTraversalPruningException
+    def prune(self):
+        raise GenericASTTraversalPruningException
 
-	def preorder(self, node=None):
-		if node is None:
-			node = self.ast
+    def preorder(self, node=None):
+        if node is None:
+            node = self.ast
 
-		try:
-			name = 'n_' + self.typestring(node)
-			if hasattr(self, name):
-				func = getattr(self, name)
-				func(node)
-			else:
-				self.default(node)
-		except GenericASTTraversalPruningException:
-			return
+        try:
+            name = 'n_' + self.typestring(node)
+            if hasattr(self, name):
+                func = getattr(self, name)
+                func(node)
+            else:
+                self.default(node)
+        except GenericASTTraversalPruningException:
+            return
 
-		for kid in node:
-			self.preorder(kid)
+        for kid in node:
+            self.preorder(kid)
 
-		name = name + '_exit'
-		if hasattr(self, name):
-			func = getattr(self, name)
-			func(node)
+        name = name + '_exit'
+        if hasattr(self, name):
+            func = getattr(self, name)
+            func(node)
 
-	def postorder(self, node=None):
-		if node is None:
-			node = self.ast
+    def postorder(self, node=None):
+        if node is None:
+            node = self.ast
 
-		for kid in node:
-			self.postorder(kid)
+        for kid in node:
+            self.postorder(kid)
 
-		name = 'n_' + self.typestring(node)
-		if hasattr(self, name):
-			func = getattr(self, name)
-			func(node)
-		else:
-			self.default(node)
+        name = 'n_' + self.typestring(node)
+        if hasattr(self, name):
+            func = getattr(self, name)
+            func(node)
+        else:
+            self.default(node)
 
 
-	def default(self, node):
-		pass
+    def default(self, node):
+        pass
 
 #
 #  GenericASTMatcher.  AST nodes must have "__getitem__" and "__cmp__"
@@ -779,62 +779,62 @@
 #
 
 class GenericASTMatcher(GenericParser):
-	def __init__(self, start, ast):
-		GenericParser.__init__(self, start)
-		self.ast = ast
+    def __init__(self, start, ast):
+        GenericParser.__init__(self, start)
+        self.ast = ast
 
-	def preprocess(self, rule, func):
-		rebind = lambda func, self=self: \
-				lambda args, func=func, self=self: \
-					self.foundMatch(args, func)
-		lhs, rhs = rule
-		rhslist = list(rhs)
-		rhslist.reverse()
+    def preprocess(self, rule, func):
+        rebind = lambda func, self=self: \
+                        lambda args, func=func, self=self: \
+                                self.foundMatch(args, func)
+        lhs, rhs = rule
+        rhslist = list(rhs)
+        rhslist.reverse()
 
-		return (lhs, tuple(rhslist)), rebind(func)
+        return (lhs, tuple(rhslist)), rebind(func)
 
-	def foundMatch(self, args, func):
-		func(args[-1])
-		return args[-1]
+    def foundMatch(self, args, func):
+        func(args[-1])
+        return args[-1]
 
-	def match_r(self, node):
-		self.input.insert(0, node)
-		children = 0
+    def match_r(self, node):
+        self.input.insert(0, node)
+        children = 0
 
-		for child in node:
-			if children == 0:
-				self.input.insert(0, '(')
-			children = children + 1
-			self.match_r(child)
+        for child in node:
+            if children == 0:
+                self.input.insert(0, '(')
+            children = children + 1
+            self.match_r(child)
 
-		if children > 0:
-			self.input.insert(0, ')')
+        if children > 0:
+            self.input.insert(0, ')')
 
-	def match(self, ast=None):
-		if ast is None:
-			ast = self.ast
-		self.input = []
+    def match(self, ast=None):
+        if ast is None:
+            ast = self.ast
+        self.input = []
 
-		self.match_r(ast)
-		self.parse(self.input)
+        self.match_r(ast)
+        self.parse(self.input)
 
-	def resolve(self, list):
-		#
-		#  Resolve ambiguity in favor of the longest RHS.
-		#
-		return list[-1]
+    def resolve(self, list):
+        #
+        #  Resolve ambiguity in favor of the longest RHS.
+        #
+        return list[-1]
 
 def _dump(tokens, sets, states):
-	for i in range(len(sets)):
-		print 'set', i
-		for item in sets[i]:
-			print '\t', item
-			for (lhs, rhs), pos in states[item[0]].items:
-				print '\t\t', lhs, '::=',
-				print string.join(rhs[:pos]),
-				print '.',
-				print string.join(rhs[pos:])
-		if i < len(tokens):
-			print
-			print 'token', str(tokens[i])
-			print
+    for i in range(len(sets)):
+        print 'set', i
+        for item in sets[i]:
+            print '\t', item
+            for (lhs, rhs), pos in states[item[0]].items:
+                print '\t\t', lhs, '::=',
+                print string.join(rhs[:pos]),
+                print '.',
+                print string.join(rhs[pos:])
+        if i < len(tokens):
+            print
+            print 'token', str(tokens[i])
+            print