blob: 53da22c1cea424fe76391402738d955b35596901 [file] [log] [blame]
Jack Jansen5ccd8261995-07-17 11:43:20 +00001"""
2gensuitemodule - Generate an AE suite module from an aete/aeut resource
3
4Based on aete.py
5"""
6
7import MacOS
8import os
9import string
10import sys
11import types
12import StringIO
13import macfs
14
15from Res import *
16
17def main():
Jack Jansen9d19a911995-08-14 12:14:55 +000018 fss, ok = macfs.PromptGetFile('Select file with aeut/aete resource:')
Jack Jansen5ccd8261995-07-17 11:43:20 +000019 if not ok:
20 sys.exit(0)
21 process(fss.as_pathname())
22
23def process(fullname):
24 """Process all resources in a single file"""
25 cur = CurResFile()
26 print fullname
27 rf = OpenRFPerm(fullname, 0, 1)
28 try:
29 UseResFile(rf)
30 resources = []
31 for i in range(Count1Resources('aete')):
32 res = Get1IndResource('aete', 1+i)
33 resources.append(res)
34 for i in range(Count1Resources('aeut')):
35 res = Get1IndResource('aeut', 1+i)
36 resources.append(res)
37 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
38 for res in resources:
39 print "decoding", res.GetResInfo(), "..."
40 data = res.data
41 aete = decode(data)
Jack Jansen66544221997-08-08 14:49:02 +000042 # switch back (needed for dialogs in Python)
43 UseResFile(cur)
Jack Jansen5ccd8261995-07-17 11:43:20 +000044 compileaete(aete, fullname)
Jack Jansen66544221997-08-08 14:49:02 +000045 UseResFile(rf)
Jack Jansen5ccd8261995-07-17 11:43:20 +000046 finally:
47 if rf <> cur:
48 CloseResFile(rf)
49 UseResFile(cur)
50
51def decode(data):
52 """Decode a resource into a python data structure"""
53 f = StringIO.StringIO(data)
54 aete = generic(getaete, f)
55 aete = simplify(aete)
56 processed = f.tell()
57 unprocessed = len(f.read())
58 total = f.tell()
59 if unprocessed:
60 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
61 (processed, unprocessed, total))
62 return aete
63
64def simplify(item):
65 """Recursively replace singleton tuples by their constituent item"""
66 if type(item) is types.ListType:
67 return map(simplify, item)
68 elif type(item) == types.TupleType and len(item) == 2:
69 return simplify(item[1])
70 else:
71 return item
72
73
74# Here follows the aete resource decoder.
75# It is presented bottom-up instead of top-down because there are direct
76# references to the lower-level part-decoders from the high-level part-decoders.
77
78def getbyte(f, *args):
79 c = f.read(1)
80 if not c:
81 raise EOFError, 'in getbyte' + str(args)
82 return ord(c)
83
84def getword(f, *args):
85 getalign(f)
86 s = f.read(2)
87 if len(s) < 2:
88 raise EOFError, 'in getword' + str(args)
89 return (ord(s[0])<<8) | ord(s[1])
90
91def getlong(f, *args):
92 getalign(f)
93 s = f.read(4)
94 if len(s) < 4:
95 raise EOFError, 'in getlong' + str(args)
96 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
97
98def getostype(f, *args):
99 getalign(f)
100 s = f.read(4)
101 if len(s) < 4:
102 raise EOFError, 'in getostype' + str(args)
103 return s
104
105def getpstr(f, *args):
106 c = f.read(1)
107 if len(c) < 1:
108 raise EOFError, 'in getpstr[1]' + str(args)
109 nbytes = ord(c)
110 if nbytes == 0: return ''
111 s = f.read(nbytes)
112 if len(s) < nbytes:
113 raise EOFError, 'in getpstr[2]' + str(args)
114 return s
115
116def getalign(f):
117 if f.tell() & 1:
118 c = f.read(1)
119 ##if c <> '\0':
120 ## print 'align:', `c`
121
122def getlist(f, description, getitem):
123 count = getword(f)
124 list = []
125 for i in range(count):
126 list.append(generic(getitem, f))
127 getalign(f)
128 return list
129
130def alt_generic(what, f, *args):
131 print "generic", `what`, args
132 res = vageneric(what, f, args)
133 print '->', `res`
134 return res
135
136def generic(what, f, *args):
137 if type(what) == types.FunctionType:
138 return apply(what, (f,) + args)
139 if type(what) == types.ListType:
140 record = []
141 for thing in what:
142 item = apply(generic, thing[:1] + (f,) + thing[1:])
143 record.append((thing[1], item))
144 return record
145 return "BAD GENERIC ARGS: %s" % `what`
146
147getdata = [
148 (getostype, "type"),
149 (getpstr, "description"),
150 (getword, "flags")
151 ]
152getargument = [
153 (getpstr, "name"),
154 (getostype, "keyword"),
155 (getdata, "what")
156 ]
157getevent = [
158 (getpstr, "name"),
159 (getpstr, "description"),
160 (getostype, "suite code"),
161 (getostype, "event code"),
162 (getdata, "returns"),
163 (getdata, "accepts"),
164 (getlist, "optional arguments", getargument)
165 ]
166getproperty = [
167 (getpstr, "name"),
168 (getostype, "code"),
169 (getdata, "what")
170 ]
171getelement = [
172 (getostype, "type"),
173 (getlist, "keyform", getostype)
174 ]
175getclass = [
176 (getpstr, "name"),
177 (getostype, "class code"),
178 (getpstr, "description"),
179 (getlist, "properties", getproperty),
180 (getlist, "elements", getelement)
181 ]
182getcomparison = [
183 (getpstr, "operator name"),
184 (getostype, "operator ID"),
185 (getpstr, "operator comment"),
186 ]
187getenumerator = [
188 (getpstr, "enumerator name"),
189 (getostype, "enumerator ID"),
190 (getpstr, "enumerator comment")
191 ]
192getenumeration = [
193 (getostype, "enumeration ID"),
194 (getlist, "enumerator", getenumerator)
195 ]
196getsuite = [
197 (getpstr, "suite name"),
198 (getpstr, "suite description"),
199 (getostype, "suite ID"),
200 (getword, "suite level"),
201 (getword, "suite version"),
202 (getlist, "events", getevent),
203 (getlist, "classes", getclass),
204 (getlist, "comparisons", getcomparison),
205 (getlist, "enumerations", getenumeration)
206 ]
207getaete = [
208 (getword, "major/minor version in BCD"),
209 (getword, "language code"),
210 (getword, "script code"),
211 (getlist, "suites", getsuite)
212 ]
213
214def compileaete(aete, fname):
215 """Generate code for a full aete resource. fname passed for doc purposes"""
216 [version, language, script, suites] = aete
217 major, minor = divmod(version, 256)
218 for suite in suites:
219 compilesuite(suite, major, minor, language, script, fname)
220
221def compilesuite(suite, major, minor, language, script, fname):
222 """Generate code for a single suite"""
223 [name, desc, code, level, version, events, classes, comps, enums] = suite
224
225 modname = identify(name)
226 fss, ok = macfs.StandardPutFile('Python output file', modname+'.py')
227 if not ok:
228 return
229 fp = open(fss.as_pathname(), 'w')
Jack Jansen18a99f51996-03-18 13:35:00 +0000230 fss.SetCreatorType('Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000231
232 fp.write('"""Suite %s: %s\n' % (name, desc))
233 fp.write("Level %d, version %d\n\n" % (level, version))
234 fp.write("Generated from %s\n"%fname)
235 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
236 (major, minor, language, script))
237 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000238
239 fp.write('import aetools\n')
240 fp.write('import MacOS\n\n')
241 fp.write("_code = %s\n\n"% `code`)
242
Jack Jansen5ccd8261995-07-17 11:43:20 +0000243 compileclassheader(fp, modname)
Jack Jansen66544221997-08-08 14:49:02 +0000244
245 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000246 if events:
247 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000248 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000249 else:
250 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000251
252 objc = ObjectCompiler(fp)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000253 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000254 objc.compileclass(cls)
255 for cls in classes:
256 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000257 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000258 objc.compilecomparison(comp)
259 for enum in enums:
260 objc.compileenumeration(enum)
261
262 for enum in enumsneeded.keys():
263 objc.checkforenum(enum)
264
265 objc.dumpindex()
Jack Jansen5ccd8261995-07-17 11:43:20 +0000266
267def compileclassheader(fp, name):
268 """Generate class boilerplate"""
269 fp.write("class %s:\n\n"%name)
270
Jack Jansen66544221997-08-08 14:49:02 +0000271def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000272 """Generate code for a single event"""
273 [name, desc, code, subcode, returns, accepts, arguments] = event
274 funcname = identify(name)
275 #
276 # generate name->keyword map
277 #
278 if arguments:
279 fp.write("\t_argmap_%s = {\n"%funcname)
280 for a in arguments:
281 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
282 fp.write("\t}\n\n")
283
284 #
285 # Generate function header
286 #
287 has_arg = (not is_null(accepts))
288 opt_arg = (has_arg and is_optional(accepts))
289
Jack Jansen84264771995-10-03 14:35:58 +0000290 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000291 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000292 if not opt_arg:
293 fp.write("_object, ") # Include direct object, if it has one
294 else:
295 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000296 else:
Jack Jansen84264771995-10-03 14:35:58 +0000297 fp.write("_no_object=None, ") # For argument checking
298 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000299 #
300 # Generate doc string (important, since it may be the only
301 # available documentation, due to our name-remaping)
302 #
303 fp.write('\t\t"""%s: %s\n'%(name, desc))
304 if has_arg:
305 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
306 elif opt_arg:
307 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
308 for arg in arguments:
309 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
310 getdatadoc(arg[2])))
311 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
312 if not is_null(returns):
313 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
314 fp.write('\t\t"""\n')
315 #
316 # Fiddle the args so everything ends up in 'arguments' dictionary
317 #
318 fp.write("\t\t_code = %s\n"% `code`)
319 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000320 #
321 # Do keyword name substitution
322 #
323 if arguments:
324 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
325 else:
326 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
327 #
328 # Stuff required arg (if there is one) into arguments
329 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000330 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000331 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000332 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000333 fp.write("\t\tif _object:\n")
334 fp.write("\t\t\t_arguments['----'] = _object\n")
335 else:
336 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000337 fp.write("\n")
338 #
Jack Jansen73215141995-10-09 23:09:23 +0000339 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000340 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000341 for a in arguments:
342 if is_enum(a[2]):
343 kname = a[1]
344 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000345 if ename <> '****':
346 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen5ccd8261995-07-17 11:43:20 +0000347 (`kname`, ename))
Jack Jansen66544221997-08-08 14:49:02 +0000348 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000349 fp.write("\n")
350 #
351 # Do the transaction
352 #
Jack Jansen84264771995-10-03 14:35:58 +0000353 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
354 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000355 #
356 # Error handling
357 #
Jack Jansen84264771995-10-03 14:35:58 +0000358 fp.write("\t\tif _arguments.has_key('errn'):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000359 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000360 fp.write("\t\t# XXXX Optionally decode result\n")
361 #
362 # Decode result
363 #
Jack Jansen84264771995-10-03 14:35:58 +0000364 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000365 if is_enum(returns):
366 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000367 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000368 fp.write("\n")
369
370# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
371# print "# returns", compiledata(returns)
372# print "# accepts", compiledata(accepts)
373# for arg in arguments:
374# compileargument(arg)
375
376def compileargument(arg):
377 [name, keyword, what] = arg
378 print "# %s (%s)" % (name, `keyword`), compiledata(what)
379
Jack Jansen66544221997-08-08 14:49:02 +0000380class ObjectCompiler:
381 def __init__(self, fp):
382 self.fp = fp
383 self.propnames = {}
384 self.classnames = {}
385 self.propcodes = {}
386 self.classcodes = {}
387 self.compcodes = {}
388 self.enumcodes = {}
389 self.othersuites = []
390
391 def findcodename(self, type, code):
392 while 1:
393 if type == 'property':
394 if self.propcodes.has_key(code):
395 return self.propcodes[code], self.propcodes[code], None
396 for s in self.othersuites:
397 if s._propdeclarations.has_key(code):
398 name = s._propdeclarations[code].__name__
399 return name, '%s.%s' % (s.__name__, name), s.__name__
400 if type == 'class':
401 if self.classcodes.has_key(code):
402 return self.classcodes[code], self.classcodes[code], None
403 for s in self.othersuites:
404 if s._classdeclarations.has_key(code):
405 name = s._classdeclarations[code].__name__
406 return name, '%s.%s' % (s.__name__, name), s.__name__
407 if type == 'enum':
408 if self.enumcodes.has_key(code):
409 return self.enumcodes[code], self.enumcodes[code], None
410 for s in self.othersuites:
411 if s._enumdeclarations.has_key(code):
412 name = '_Enum_' + identify(code)
413 return name, '%s.%s' % (s.__name__, name), s.__name__
414 if type == 'comparison':
415 if self.compcodes.has_key(code):
416 return self.compcodes[code], self.compcodes[code], None
417 for s in self.othersuites:
418 if s._compdeclarations.has_key(code):
419 name = s._compdeclarations[code].__name__
420 return name, '%s.%s' % (s.__name__, name), s.__name__
421
422 m = self.askdefinitionmodule(type, code)
423 if not m: return None, None, None
424 self.othersuites.append(m)
425
426 def askdefinitionmodule(self, type, code):
427 fss, ok = macfs.PromptGetFile('Where is %s %s declared?'%(type, code))
428 if not ok: return
429 path, file = os.path.split(fss.as_pathname())
430 modname = os.path.splitext(file)[0]
431 if not path in sys.path:
432 sys.path.insert(0, path)
433 m = __import__(modname)
434 self.fp.write("import %s\n"%modname)
435 return m
436
437 def compileclass(self, cls):
438 [name, code, desc, properties, elements] = cls
439 pname = identify(name)
440 if self.classcodes.has_key(code):
441 # plural forms and such
442 self.fp.write("\n%s = %s\n"%(pname, self.classcodes[code]))
443 self.classnames[pname] = code
444 else:
445 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
446 self.fp.write('\t"""%s - %s"""\n' % (name, desc))
447 self.fp.write('\twant = %s\n' % `code`)
448 self.classnames[pname] = code
449 self.classcodes[code] = pname
450 for prop in properties:
451 self.compileproperty(prop)
452 for elem in elements:
453 self.compileelement(elem)
454
455 def compileproperty(self, prop):
456 [name, code, what] = prop
457 if code == 'c@#!':
458 # Something silly with plurals. Skip it.
459 return
460 pname = identify(name)
461 if self.propcodes.has_key(code):
462 self.fp.write("# repeated property %s %s\n"%(pname, what[1]))
463 else:
464 self.fp.write("class %s(aetools.NProperty):\n" % pname)
465 self.fp.write('\t"""%s - %s"""\n' % (name, what[1]))
466 self.fp.write("\twhich = %s\n" % `code`)
467 self.fp.write("\twant = %s\n" % `what[0]`)
468 self.propnames[pname] = code
469 self.propcodes[code] = pname
470
471 def compileelement(self, elem):
472 [code, keyform] = elem
473 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000474
Jack Jansen66544221997-08-08 14:49:02 +0000475 def fillclasspropsandelems(self, cls):
476 [name, code, desc, properties, elements] = cls
477 cname = identify(name)
478 if self.classcodes[code] != cname:
479 # This is an other name (plural or so) for something else. Skip.
480 return
481 plist = []
482 elist = []
483 for prop in properties:
484 [pname, pcode, what] = prop
485 if pcode == 'c@#!':
486 continue
487 pname = identify(pname)
488 plist.append(pname)
489 for elem in elements:
490 [ecode, keyform] = elem
491 if ecode == 'c@#!':
492 continue
493 name, ename, module = self.findcodename('class', ecode)
494 if not name:
495 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
496 else:
497 elist.append(name, ename)
498
499 self.fp.write("%s._propdict = {\n"%cname)
500 for n in plist:
501 self.fp.write("\t'%s' : %s,\n"%(n, n))
502 self.fp.write("}\n")
503 self.fp.write("%s._elemdict = {\n"%cname)
504 for n, fulln in elist:
505 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
506 self.fp.write("}\n")
507
508 def compilecomparison(self, comp):
509 [name, code, comment] = comp
510 iname = identify(name)
511 self.compcodes[code] = iname
512 self.fp.write("class %s(aetools.NComparison):\n" % iname)
513 self.fp.write('\t"""%s - %s"""\n' % (name, comment))
514
515 def compileenumeration(self, enum):
516 [code, items] = enum
517 name = "_Enum_%s" % identify(code)
518 self.fp.write("%s = {\n" % name)
519 for item in items:
520 self.compileenumerator(item)
521 self.fp.write("}\n\n")
522 self.enumcodes[code] = name
523 return code
524
525 def compileenumerator(self, item):
526 [name, code, desc] = item
527 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, desc))
528
529 def checkforenum(self, enum):
530 """This enum code is used by an event. Make sure it's available"""
531 name, fullname, module = self.findcodename('enum', enum)
532 if not name:
533 self.fp.write("# XXXX enum %s not found!!\n"%(enum))
534 return
535 if module:
536 self.fp.write("from %s import %s\n"%(module, name))
537
538 def dumpindex(self):
539 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
540 self.fp.write("_classdeclarations = {\n")
541 for k in self.classcodes.keys():
542 self.fp.write("\t%s : %s,\n" % (`k`, self.classcodes[k]))
543 self.fp.write("}\n")
544 self.fp.write("\n_propdeclarations = {\n")
545 for k in self.propcodes.keys():
546 self.fp.write("\t%s : %s,\n" % (`k`, self.propcodes[k]))
547 self.fp.write("}\n")
548 self.fp.write("\n_compdeclarations = {\n")
549 for k in self.compcodes.keys():
550 self.fp.write("\t%s : %s,\n" % (`k`, self.compcodes[k]))
551 self.fp.write("}\n")
552 self.fp.write("\n_enumdeclarations = {\n")
553 for k in self.enumcodes.keys():
554 self.fp.write("\t%s : %s,\n" % (`k`, self.enumcodes[k]))
555 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000556
557def compiledata(data):
558 [type, description, flags] = data
559 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
560
561def is_null(data):
562 return data[0] == 'null'
563
564def is_optional(data):
565 return (data[2] & 0x8000)
566
567def is_enum(data):
568 return (data[2] & 0x2000)
569
570def getdatadoc(data):
571 [type, descr, flags] = data
572 if descr:
573 return descr
574 if type == '****':
575 return 'anything'
576 if type == 'obj ':
577 return 'an AE object reference'
578 return "undocumented, typecode %s"%`type`
579
580dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
581def compiledataflags(flags):
582 bits = []
583 for i in range(16):
584 if flags & (1<<i):
585 if i in dataflagdict.keys():
586 bits.append(dataflagdict[i])
587 else:
588 bits.append(`i`)
589 return '[%s]' % string.join(bits)
590
591# XXXX Do we have a set of python keywords somewhere?
Jack Jansen66544221997-08-08 14:49:02 +0000592illegal_ids = [ "for", "in", "from", "and", "or", "not", "print", "class", "return",
593 "def" ]
Jack Jansen5ccd8261995-07-17 11:43:20 +0000594
595def identify(str):
596 """Turn any string into an identifier:
597 - replace space by _
598 - replace other illegal chars by _xx_ (hex code)
599 - prepend _ if the result is a python keyword
600 """
Jack Jansen66544221997-08-08 14:49:02 +0000601 if not str:
602 return "_empty_ae_name"
Jack Jansen5ccd8261995-07-17 11:43:20 +0000603 rv = ''
604 ok = string.letters + '_'
605 ok2 = ok + string.digits
606 for c in str:
607 if c in ok:
608 rv = rv + c
609 elif c == ' ':
610 rv = rv + '_'
611 else:
612 rv = rv + '_%02.2x_'%ord(c)
613 ok = ok2
614 if rv in illegal_ids:
615 rv = '_' + rv
616 return rv
617
618# Call the main program
619
620if __name__ == '__main__':
621 main()
622 sys.exit(1)