Parsing C Preprocessor files

Pierre-Frédéric Caillaud peufeu at free.fr
Thu Jun 24 09:27:16 CEST 2004


	I thought about it and...

	Here's a stackless version with #include and #if. 20 minutes in the  
making...
	You'll need a pen and paper to figure how the stack works though :) but  
it's fun.
	It uses references...


file1 = """Top level line
#if foo
on foo level
#if bar
on bar level
#endif
re foo level
#include file2
#else
not foo
#endif
top level
#ifdef bla
on bla level
#ifdef q
q
#else
not q
#endif
check
#if r
r
#endif
#endif"""

file2 = """included file:
#ifdef stuff
stuff level
#endif
"""

# simple class to process included files
class myreader( object ):
	def __init__(self):
		self.queue = []	# queue of iterables to be played
	
	def __iter__(self):
		return self
	
	# insert an iterable into the current flow
	def insert( self, iterator ):
		self.queue.append( iterator )
		
	def next(self):
		while self.queue:
			try:
				return self.queue[-1].next()
			except StopIteration:
				self.queue.pop()	# this iterable is finished, throw it away
		raise StopIteration

reader = myreader()
reader.insert( iter( file1.split("\n") ))

# stackless parser !
result = []
stack = [result]
stacktop = stack[-1]

for line in reader:
	ls = line.strip()
	if ls.startswith( "#" ):		# factor all # cases for speed
		keyword = ls.split(" \t\r\n",1)[0]
		if keyword == "#if":
			next = []	
			stacktop.append( [line, next] )
			stack.append( next )
			stacktop = next
		elif keyword == "#else":
			stack.pop()
			stack[-1][-1].append(line)
			next = []	
			stack[-1][-1].append( next )
			stack.append( next )
			stacktop = next
		elif keyword == "#endif":
			stack.pop()
			stack[-1][-1] = tuple( stack[-1][-1] + [line] )
		elif keyword == "#include":
			# I don't parse the filename... replace the iter() below by something  
like open(filename)
			reader.insert( iter(file2.split("\n")) )
	else:
		stacktop.append(line)

def printblock(block, indent=0) :
	ind = "\t"*indent
	for elem in block:
		if type( elem ) == list:
			printblock( elem, indent+1 )
		elif type( elem ) == tuple:
			printblock( elem, indent )
		else:
			print ind, elem
			
print result
printblock(result)



More information about the Python-list mailing list