2 # -*- Mode: Python; py-indent-offset: 4 -*-
3 from __future__ import generators
7 from cStringIO import StringIO
9 class error(Exception):
10 def __init__(self, filename, lineno, msg):
11 Exception.__init__(self, msg)
12 self.filename = filename
16 return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg)
20 if chr(i) in string.letters + string.digits + '_':
24 trans = string.join(trans, '')
27 if isinstance(filename, str):
28 fp = open(filename, 'r')
29 else: # if not string, assume it is some kind of iterator
31 filename = getattr(fp, 'name', '<unknown>')
32 whitespace = ' \t\n\r\x0b\x0c'
33 nonsymbol = whitespace + '();\'"'
40 while pos < len(line):
41 if line[pos] in whitespace: # ignore whitespace
43 elif line[pos] == ';': # comment
45 elif line[pos:pos+2] == "'(":
46 pass # the open parenthesis will be handled next iteration
47 elif line[pos] == '(':
49 openlines.append(lineno)
50 elif line[pos] == ')':
52 raise error(filename, lineno, 'close parenthesis found when none open')
57 stack[-1] += (closed,)
60 elif line[pos] == '"': # quoted string
62 raise error(filename, lineno,
63 'string found outside of s-expression')
66 while endpos < len(line):
67 if endpos+1 < len(line) and line[endpos] == '\\':
69 if line[endpos] == 'n':
71 elif line[endpos] == 'r':
73 elif line[endpos] == 't':
77 chars.append(line[endpos])
78 elif line[endpos] == '"':
81 chars.append(line[endpos])
83 if endpos >= len(line):
84 raise error(filename, lineno, "unclosed quoted string")
86 stack[-1] += (''.join(chars),)
89 raise error(filename, lineno,
90 'identifier found outside of s-expression')
92 while endpos < len(line) and line[endpos] not in nonsymbol:
94 symbol = line[pos:endpos]
95 pos = max(pos, endpos-1)
96 try: symbol = int(symbol)
98 try: symbol = float(symbol)
99 except ValueError: pass
100 stack[-1] += (symbol,)
103 msg = '%d unclosed parentheses found at end of ' \
104 'file (opened on line(s) %s)' % (len(stack),
105 ', '.join(map(str, openlines)))
106 raise error(filename, lineno, msg)
109 def __init__(self, filename):
110 """Argument is either a string, a parse tree, or file object"""
111 self.filename = filename
112 def startParsing(self, filename=None):
113 statements = parse(filename or self.filename)
114 for statement in statements:
115 self.handle(statement)
116 def handle(self, tup):
117 cmd = string.translate(tup[0], trans)
118 if hasattr(self, cmd):
119 getattr(self, cmd)(*tup[1:])
122 def unknown(self, tup):
125 _testString = """; a scheme file
126 (define-func gdk_font_load ; a comment at end of line
130 (define-boxed GdkEvent
136 if __name__ == '__main__':
139 fp = open(sys.argv[1])
141 fp = StringIO(_testString)
142 statements = parse(fp)