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