cdecl.py challenge
Simon Burton
simonb at webone.com.au
Tue Dec 10 02:13:39 EST 2002
OK, here it is, folks. It basically works.
The english is not great, and all function args need to be named.
$ ./cdecl.py "void (*signal(int sig, void (*func)(int a)))(int b);"
signal is function of sig is int,func is pointer to function of a
is int, returning void, returning pointer to function of b is int, returning void
#!/usr/bin/env python
import sys
from string import *
type_list = "void char signed unsigned short int long float double struct union enum".split()
qual_list = "const volatile".split()
def classify(s):
if s in type_list: return "TYPE"
if s in qual_list: return "QUAL"
else: return "ID"
class CDecl:
def __init__(self,verbose=0):
self.verbose = verbose
self.stack = []
self.explanation=[]
self.set_this("","","")
def set_this(self,tok,kind,s):
self.tok,self.kind,self.s = tok, kind, s
def get_this(self):
return self.tok,self.kind,self.s
def explain(self,s):
#print "[explain('%s')]"%s,
self.explanation.append( s )
def __str__(self):
return join( self.explanation )
def get_token(self):
i=0
tok, kind, s = "", "", self.s
while i < len(s):
if s[i].isalnum():
j=i+1
while j<len(s):
if s[j].isalnum():
j=j+1
else:
break
tok = s[i:j]
s = s[j:]
kind = classify(tok)
break
if s[i] in '*()[];,':
tok = s[i]
kind = s[i]
s=s[i+1:]
break
i=i+1
if self.verbose:
print "['%s',%s,'%s']"%(tok, kind, s)
self.set_this(tok,kind,s)
def unget_token(self):
tok,kind,s=self.get_this()
self.set_this(tok,kind,tok+s)
def find_id(self):
self.get_token()
while self.tok and self.kind!="ID":
self.push()
self.get_token()
if self.tok:
self.explain( "%s is"%self.tok )
self.get_token()
def find_array(self):
while self.tok == '[':
self.explain( "array" )
self.get_token() # a number or ']'
if self.tok.isdigit():
self.explain( "0..%s"%(int(self.tok)-1) )
self.get_token() # read the ']'
self.get_token() # read past the ']'
self.explain( "of" )
def find_args(self):
arglist = []
args = ''
self.get_token()
if self.tok != ')':
self.unget_token() # unget start of decl
while self.tok != ')':
cdecl = CDecl()
#cdecl.s = self.s
cdecl.parse(self.s)
self.set_this( *cdecl.get_this() )
arglist.append( str(cdecl) )
assert self.tok == ')' or self.tok == ','
args = "of %s, "%join(arglist, ',' )
self.explain( "function %sreturning"%args )
self.get_token()
def find_pointers(self):
#print "find_pointers"
while self:
tok, kind = self.peek()
if tok == '*':
self.pop()
self.explain( "pointer to" )
else:
return
def find_decl(self, level=0):
#print " "*level+"find_decl>>"
if self.tok == '[' :
self.find_array()
if self.tok == '(' :
self.find_args()
self.find_pointers()
while self:
tok, kind = self.peek()
if tok == '(':
self.pop()
assert self.tok == ')'
self.get_token()
self.find_decl(level+1)
else:
self.find_pointers()
self.explain( self.pop()[0] )
#print " "*level+"<<find_decl"
def parse(self,s):
if self.verbose: print "CDecl.parse('%s')"%s
self.s=s
self.find_id()
#print self.stack
self.find_decl()
if self.verbose: print '\n',self
def __len__(self):
return len(self.stack)
def push(self):
self.stack.append( (self.tok,self.kind) )
def peek(self):
return self.stack[-1]
def pop(self):
return self.stack.pop()
if __name__=="__main__":
if not sys.argv[1:]:
sys.stdout.write(">>> ")
s = sys.stdin.readline()
else:
s = join(sys.argv[1:])
cdecl=CDecl()
cdecl.parse(s)
print "%s."%cdecl
More information about the Python-list
mailing list