#!/usr/bin/env python
import string
import types
# get the fastest implementation of StringIO
try:
        from cStringIO import StringIO
except ImportError:
        from StringIO import StringIO

trans = [' '] * 256
for i in range(256):
        if chr(i) in string.letters + string.digits + '_':
                trans[i] = chr(i)
        else:
                trans[i] = '_'
trans = string.join(trans, '')

def parse(fp):
        stack = [()]
        line = fp.readline()
        while line:
                while line:
                        line = string.lstrip(line)
                        if not line:
                                break
                        elif line[0] == '(':
                                stack.append(())
                                line = line[1:]
                        elif line[0] == ')':
                                closed = stack[-1]
                                del stack[-1]
                                stack[-1] = stack[-1] + (closed,)
                                line = line[1:]
                        elif line[0] == '"':
                                pos = string.index(line[1:], '"')
                                stack[-1] = stack[-1] + (eval(line[:pos+2]),)
                                line = line[pos+2:]
                        elif line[0] in string.digits:
                                str = ""
                                while line and line[0] in "0123456789+-.":
                                        str = str + line[0]
                                        line = line[1:]
                                stack[-1] = stack[-1] + (string.atof(str),)
                        elif line[0] == ';':
                                break
                        else:
                                str = ""
                                while line and line[0] not in " \t();\n":
                                        str = str + line[0]
                                        line = line[1:]
                                stack[-1] = stack[-1] + (str,)
                line = fp.readline()
        if len(stack) != 1:
                raise IOError, "parentheses don't match"
        return stack[0]

class Parser:
        def __init__(self, arg):
                """Argument is either a string, a parse tree, or file object"""
                if type(arg) == types.StringType:
                        self.filename = arg
                        self.parseTree = parse(open(arg))
                elif type(arg) == types.TupleType:
                        self.filename = '<none>'
                        self.parseTree = arg
                elif type(arg) == types.FileType:
                        self.filename = arg.name
                        self.parseTree = parse(arg)
                else:
                        raise TypeError, \
                              'second arg must be string, tuple or file'
        def startParsing(self, tuples=None):
                if tuples == None: tuples = self.parseTree
                for tup in tuples:
                        self.handle(tup)
        def handle(self, tup):
                cmd = string.translate(tup[0], trans)
                if hasattr(self, cmd):
                        apply(getattr(self, cmd), tup[1:])
                else:
                        self.unknown(tup)
        def unknown(self, tup):
                pass

_testString = """; a scheme file
(define-func gdk_font_load    ; a comment at end of line
  GdkFont
  ((string name)))

(define-boxed GdkEvent
  gdk_event_copy
  gdk_event_free
  "sizeof(GdkEvent)")
"""

if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
                fp = open(sys.argv[1])
        else:
                fp = StringIO(_testString)
        statements = parse(fp)
        for s in statements:
                print `s`
