blob: d358e28dea1ebff04b5c83365495069b5cfd6507 [file] [log] [blame]
Guido van Rossumb6775db1994-08-01 11:34:53 +00001########################################################################
Guido van Rossum524b5881995-01-04 19:10:35 +00002# Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3# The Netherlands.
4#
Guido van Rossumb6775db1994-08-01 11:34:53 +00005# All Rights Reserved
Guido van Rossum524b5881995-01-04 19:10:35 +00006#
7# Permission to use, copy, modify, and distribute this software and its
8# documentation for any purpose and without fee is hereby granted,
Guido van Rossumb6775db1994-08-01 11:34:53 +00009# provided that the above copyright notice appear in all copies and that
Guido van Rossum524b5881995-01-04 19:10:35 +000010# both that copyright notice and this permission notice appear in
Guido van Rossumb6775db1994-08-01 11:34:53 +000011# supporting documentation, and that the names of Stichting Mathematisch
12# Centrum or CWI not be used in advertising or publicity pertaining to
13# distribution of the software without specific, written prior permission.
Guido van Rossum524b5881995-01-04 19:10:35 +000014#
Guido van Rossumb6775db1994-08-01 11:34:53 +000015# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22########################################################################
23
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000024# Python script to parse cstubs file for gl and generate C stubs.
Guido van Rossum670690e1991-08-16 08:57:40 +000025# usage: python cgen.py <cstubs >glmodule.c
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000026#
Guido van Rossum1242f1d1991-10-20 20:28:02 +000027# NOTE: You must first make a python binary without the "GL" option
28# before you can run this, when building Python for the first time.
29# See comments in the Makefile.
30#
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000031# XXX BUG return arrays generate wrong code
32# XXX need to change error returns into gotos to free mallocked arrays
33
34
35import string
36import sys
37
38
39# Function to print to stderr
40#
Guido van Rossum064a62b1995-07-07 22:39:14 +000041def err(*args):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000042 savestdout = sys.stdout
43 try:
44 sys.stdout = sys.stderr
45 for i in args:
46 print i,
47 print
48 finally:
49 sys.stdout = savestdout
50
51
52# The set of digits that form a number
53#
54digits = '0123456789'
55
56
57# Function to extract a string of digits from the front of the string.
58# Returns the leading string of digits and the remaining string.
59# If no number is found, returns '' and the original string.
60#
61def getnum(s):
62 n = ''
Guido van Rossum3f5da241990-12-20 15:06:42 +000063 while s and s[0] in digits:
64 n = n + s[0]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000065 s = s[1:]
66 return n, s
67
68
69# Function to check if a string is a number
70#
71def isnum(s):
72 if not s: return 0
73 for c in s:
74 if not c in digits: return 0
75 return 1
76
77
78# Allowed function return types
79#
80return_types = ['void', 'short', 'long']
81
82
83# Allowed function argument types
84#
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +000085arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000086
87
88# Need to classify arguments as follows
89# simple input variable
90# simple output variable
91# input array
92# output array
93# input giving size of some array
94#
95# Array dimensions can be specified as follows
96# constant
97# argN
98# constant * argN
99# retval
100# constant * retval
101#
102# The dimensions given as constants * something are really
103# arrays of points where points are 2- 3- or 4-tuples
104#
105# We have to consider three lists:
106# python input arguments
107# C stub arguments (in & out)
108# python output arguments (really return values)
109#
110# There is a mapping from python input arguments to the input arguments
111# of the C stub, and a further mapping from C stub arguments to the
112# python return values
113
114
115# Exception raised by checkarg() and generate()
116#
117arg_error = 'bad arg'
118
119
120# Function to check one argument.
121# Arguments: the type and the arg "name" (really mode plus subscript).
122# Raises arg_error if something's wrong.
123# Return type, mode, factor, rest of subscript; factor and rest may be empty.
124#
125def checkarg(type, arg):
126 #
127 # Turn "char *x" into "string x".
128 #
Guido van Rossum28178751992-01-12 17:18:12 +0000129 if type == 'char' and arg[0] == '*':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000130 type = 'string'
131 arg = arg[1:]
132 #
133 # Check that the type is supported.
134 #
135 if type not in arg_types:
136 raise arg_error, ('bad type', type)
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000137 if type[:2] == 'u_':
138 type = 'unsigned ' + type[2:]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000139 #
140 # Split it in the mode (first character) and the rest.
141 #
142 mode, rest = arg[:1], arg[1:]
143 #
144 # The mode must be 's' for send (= input) or 'r' for return argument.
145 #
146 if mode not in ('r', 's'):
147 raise arg_error, ('bad arg mode', mode)
148 #
149 # Is it a simple argument: if so, we are done.
150 #
151 if not rest:
152 return type, mode, '', ''
153 #
154 # Not a simple argument; must be an array.
155 # The 'rest' must be a subscript enclosed in [ and ].
156 # The subscript must be one of the following forms,
157 # otherwise we don't handle it (where N is a number):
158 # N
159 # argN
160 # retval
161 # N*argN
162 # N*retval
163 #
164 if rest[:1] <> '[' or rest[-1:] <> ']':
165 raise arg_error, ('subscript expected', rest)
166 sub = rest[1:-1]
167 #
168 # Is there a leading number?
169 #
170 num, sub = getnum(sub)
171 if num:
172 # There is a leading number
173 if not sub:
174 # The subscript is just a number
175 return type, mode, num, ''
Guido van Rossum28178751992-01-12 17:18:12 +0000176 if sub[:1] == '*':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000177 # There is a factor prefix
178 sub = sub[1:]
179 else:
180 raise arg_error, ('\'*\' expected', sub)
Guido van Rossum28178751992-01-12 17:18:12 +0000181 if sub == 'retval':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000182 # size is retval -- must be a reply argument
183 if mode <> 'r':
184 raise arg_error, ('non-r mode with [retval]', mode)
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000185 elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000186 raise arg_error, ('bad subscript', sub)
187 #
188 return type, mode, num, sub
189
190
191# List of functions for which we have generated stubs
192#
193functions = []
194
195
196# Generate the stub for the given function, using the database of argument
197# information build by successive calls to checkarg()
198#
199def generate(type, func, database):
200 #
201 # Check that we can handle this case:
202 # no variable size reply arrays yet
203 #
204 n_in_args = 0
205 n_out_args = 0
206 #
207 for a_type, a_mode, a_factor, a_sub in database:
Guido van Rossum28178751992-01-12 17:18:12 +0000208 if a_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000209 n_in_args = n_in_args + 1
Guido van Rossum28178751992-01-12 17:18:12 +0000210 elif a_mode == 'r':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000211 n_out_args = n_out_args + 1
212 else:
213 # Can't happen
214 raise arg_error, ('bad a_mode', a_mode)
Guido van Rossum28178751992-01-12 17:18:12 +0000215 if (a_mode == 'r' and a_sub) or a_sub == 'retval':
Guido van Rossum064a62b1995-07-07 22:39:14 +0000216 err('Function', func, 'too complicated:',
217 a_type, a_mode, a_factor, a_sub)
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000218 print '/* XXX Too complicated to generate code for */'
219 return
220 #
221 functions.append(func)
222 #
223 # Stub header
224 #
225 print
226 print 'static object *'
227 print 'gl_' + func + '(self, args)'
228 print '\tobject *self;'
229 print '\tobject *args;'
230 print '{'
231 #
232 # Declare return value if any
233 #
234 if type <> 'void':
235 print '\t' + type, 'retval;'
236 #
237 # Declare arguments
238 #
239 for i in range(len(database)):
240 a_type, a_mode, a_factor, a_sub = database[i]
241 print '\t' + a_type,
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000242 brac = ket = ''
243 if a_sub and not isnum(a_sub):
244 if a_factor:
245 brac = '('
246 ket = ')'
247 print brac + '*',
248 print 'arg' + `i+1` + ket,
249 if a_sub and isnum(a_sub):
250 print '[', a_sub, ']',
251 if a_factor:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000252 print '[', a_factor, ']',
253 print ';'
254 #
255 # Find input arguments derived from array sizes
256 #
257 for i in range(len(database)):
258 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000259 if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000260 # Sending a variable-length array
261 n = eval(a_sub[3:])
262 if 1 <= n <= len(database):
263 b_type, b_mode, b_factor, b_sub = database[n-1]
Guido van Rossum28178751992-01-12 17:18:12 +0000264 if b_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000265 database[n-1] = b_type, 'i', a_factor, `i`
266 n_in_args = n_in_args - 1
267 #
268 # Assign argument positions in the Python argument list
269 #
270 in_pos = []
271 i_in = 0
272 for i in range(len(database)):
273 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000274 if a_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000275 in_pos.append(i_in)
276 i_in = i_in + 1
277 else:
278 in_pos.append(-1)
279 #
280 # Get input arguments
281 #
282 for i in range(len(database)):
283 a_type, a_mode, a_factor, a_sub = database[i]
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000284 if a_type[:9] == 'unsigned ':
285 xtype = a_type[9:]
286 else:
287 xtype = a_type
Guido van Rossum28178751992-01-12 17:18:12 +0000288 if a_mode == 'i':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000289 #
290 # Implicit argument;
291 # a_factor is divisor if present,
292 # a_sub indicates which arg (`database index`)
293 #
294 j = eval(a_sub)
295 print '\tif',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000296 print '(!geti' + xtype + 'arraysize(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000297 print `n_in_args` + ',',
298 print `in_pos[j]` + ',',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000299 if xtype <> a_type:
300 print '('+xtype+' *)',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000301 print '&arg' + `i+1` + '))'
302 print '\t\treturn NULL;'
303 if a_factor:
304 print '\targ' + `i+1`,
305 print '= arg' + `i+1`,
306 print '/', a_factor + ';'
Guido van Rossum28178751992-01-12 17:18:12 +0000307 elif a_mode == 's':
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000308 if a_sub and not isnum(a_sub):
309 # Allocate memory for varsize array
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000310 print '\tif ((arg' + `i+1`, '=',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000311 if a_factor:
312 print '('+a_type+'(*)['+a_factor+'])',
313 print 'NEW(' + a_type, ',',
314 if a_factor:
315 print a_factor, '*',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000316 print a_sub, ')) == NULL)'
317 print '\t\treturn err_nomem();'
318 print '\tif',
319 if a_factor or a_sub: # Get a fixed-size array array
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000320 print '(!geti' + xtype + 'array(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000321 print `n_in_args` + ',',
322 print `in_pos[i]` + ',',
323 if a_factor: print a_factor,
324 if a_factor and a_sub: print '*',
325 if a_sub: print a_sub,
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000326 print ',',
327 if (a_sub and a_factor) or xtype <> a_type:
328 print '('+xtype+' *)',
329 print 'arg' + `i+1` + '))'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000330 else: # Get a simple variable
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000331 print '(!geti' + xtype + 'arg(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000332 print `n_in_args` + ',',
333 print `in_pos[i]` + ',',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000334 if xtype <> a_type:
335 print '('+xtype+' *)',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000336 print '&arg' + `i+1` + '))'
337 print '\t\treturn NULL;'
338 #
339 # Begin of function call
340 #
341 if type <> 'void':
342 print '\tretval =', func + '(',
343 else:
344 print '\t' + func + '(',
345 #
346 # Argument list
347 #
348 for i in range(len(database)):
349 if i > 0: print ',',
350 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000351 if a_mode == 'r' and not a_factor:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000352 print '&',
353 print 'arg' + `i+1`,
354 #
355 # End of function call
356 #
357 print ');'
358 #
359 # Free varsize arrays
360 #
361 for i in range(len(database)):
362 a_type, a_mode, a_factor, a_sub = database[i]
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000363 if a_mode == 's' and a_sub and not isnum(a_sub):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000364 print '\tDEL(arg' + `i+1` + ');'
365 #
366 # Return
367 #
368 if n_out_args:
369 #
370 # Multiple return values -- construct a tuple
371 #
372 if type <> 'void':
373 n_out_args = n_out_args + 1
Guido van Rossum28178751992-01-12 17:18:12 +0000374 if n_out_args == 1:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000375 for i in range(len(database)):
376 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000377 if a_mode == 'r':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000378 break
379 else:
380 raise arg_error, 'expected r arg not found'
381 print '\treturn',
382 print mkobject(a_type, 'arg' + `i+1`) + ';'
383 else:
384 print '\t{ object *v = newtupleobject(',
385 print n_out_args, ');'
386 print '\t if (v == NULL) return NULL;'
387 i_out = 0
388 if type <> 'void':
389 print '\t settupleitem(v,',
390 print `i_out` + ',',
391 print mkobject(type, 'retval') + ');'
392 i_out = i_out + 1
393 for i in range(len(database)):
394 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000395 if a_mode == 'r':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000396 print '\t settupleitem(v,',
397 print `i_out` + ',',
398 s = mkobject(a_type, 'arg' + `i+1`)
399 print s + ');'
400 i_out = i_out + 1
401 print '\t return v;'
402 print '\t}'
403 else:
404 #
405 # Simple function return
406 # Return None or return value
407 #
Guido van Rossum28178751992-01-12 17:18:12 +0000408 if type == 'void':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000409 print '\tINCREF(None);'
410 print '\treturn None;'
411 else:
412 print '\treturn', mkobject(type, 'retval') + ';'
413 #
414 # Stub body closing brace
415 #
416 print '}'
417
418
419# Subroutine to return a function call to mknew<type>object(<arg>)
420#
421def mkobject(type, arg):
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000422 if type[:9] == 'unsigned ':
423 type = type[9:]
424 return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000425 return 'mknew' + type + 'object(' + arg + ')'
426
427
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000428defined_archs = []
429
430# usage: cgen [ -Dmach ... ] [ file ]
431for arg in sys.argv[1:]:
432 if arg[:2] == '-D':
433 defined_archs.append(arg[2:])
434 else:
435 # Open optional file argument
436 sys.stdin = open(arg, 'r')
Guido van Rossum5c850621992-09-11 23:55:51 +0000437
438
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000439# Input line number
440lno = 0
441
442
443# Input is divided in two parts, separated by a line containing '%%'.
444# <part1> -- literally copied to stdout
445# <part2> -- stub definitions
446
447# Variable indicating the current input part.
448#
449part = 1
450
451# Main loop over the input
452#
453while 1:
454 try:
455 line = raw_input()
456 except EOFError:
457 break
458 #
459 lno = lno+1
460 words = string.split(line)
461 #
Guido van Rossum28178751992-01-12 17:18:12 +0000462 if part == 1:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000463 #
464 # In part 1, copy everything literally
465 # except look for a line of just '%%'
466 #
Guido van Rossum28178751992-01-12 17:18:12 +0000467 if words == ['%%']:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000468 part = part + 1
469 else:
470 #
471 # Look for names of manually written
472 # stubs: a single percent followed by the name
473 # of the function in Python.
474 # The stub name is derived by prefixing 'gl_'.
475 #
Guido van Rossum28178751992-01-12 17:18:12 +0000476 if words and words[0][0] == '%':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000477 func = words[0][1:]
478 if (not func) and words[1:]:
479 func = words[1]
480 if func:
481 functions.append(func)
482 else:
483 print line
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000484 continue
485 if not words:
486 continue # skip empty line
487 elif words[0] == 'if':
488 # if XXX rest
489 # if !XXX rest
490 if words[1][0] == '!':
491 if words[1][1:] in defined_archs:
492 continue
493 elif words[1] not in defined_archs:
494 continue
495 words = words[2:]
496 if words[0] == '#include':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000497 print line
Guido van Rossum28178751992-01-12 17:18:12 +0000498 elif words[0][:1] == '#':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000499 pass # ignore comment
500 elif words[0] not in return_types:
501 err('Line', lno, ': bad return type :', words[0])
502 elif len(words) < 2:
503 err('Line', lno, ': no funcname :', line)
504 else:
505 if len(words) % 2 <> 0:
506 err('Line', lno, ': odd argument list :', words[2:])
507 else:
508 database = []
509 try:
510 for i in range(2, len(words), 2):
511 x = checkarg(words[i], words[i+1])
512 database.append(x)
513 print
514 print '/*',
515 for w in words: print w,
516 print '*/'
517 generate(words[0], words[1], database)
518 except arg_error, msg:
519 err('Line', lno, ':', msg)
520
521
522print
523print 'static struct methodlist gl_methods[] = {'
524for func in functions:
525 print '\t{"' + func + '", gl_' + func + '},'
526print '\t{NULL, NULL} /* Sentinel */'
527print '};'
528print
529print 'initgl()'
530print '{'
531print '\tinitmodule("gl", gl_methods);'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000532print '}'