blob: c0329628e6d8b8904f94434a0a01cf8b365b7fe5 [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
Guido van Rossumd266eb41996-10-25 14:44:06 +000012# Centrum or CWI or Corporation for National Research Initiatives or
13# CNRI not be used in advertising or publicity pertaining to
14# distribution of the software without specific, written prior
15# permission.
16#
17# While CWI is the initial source for this software, a modified version
18# is made available by the Corporation for National Research Initiatives
19# (CNRI) at the Internet address ftp://ftp.python.org.
20#
21# STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23# MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24# CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28# PERFORMANCE OF THIS SOFTWARE.
Guido van Rossumb6775db1994-08-01 11:34:53 +000029########################################################################
30
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000031# Python script to parse cstubs file for gl and generate C stubs.
Guido van Rossum670690e1991-08-16 08:57:40 +000032# usage: python cgen.py <cstubs >glmodule.c
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000033#
Guido van Rossum1242f1d1991-10-20 20:28:02 +000034# NOTE: You must first make a python binary without the "GL" option
35# before you can run this, when building Python for the first time.
36# See comments in the Makefile.
37#
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000038# XXX BUG return arrays generate wrong code
39# XXX need to change error returns into gotos to free mallocked arrays
40
41
42import string
43import sys
44
45
46# Function to print to stderr
47#
Guido van Rossum064a62b1995-07-07 22:39:14 +000048def err(*args):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000049 savestdout = sys.stdout
50 try:
51 sys.stdout = sys.stderr
52 for i in args:
53 print i,
54 print
55 finally:
56 sys.stdout = savestdout
57
58
59# The set of digits that form a number
60#
61digits = '0123456789'
62
63
64# Function to extract a string of digits from the front of the string.
65# Returns the leading string of digits and the remaining string.
66# If no number is found, returns '' and the original string.
67#
68def getnum(s):
69 n = ''
Guido van Rossum3f5da241990-12-20 15:06:42 +000070 while s and s[0] in digits:
71 n = n + s[0]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000072 s = s[1:]
73 return n, s
74
75
76# Function to check if a string is a number
77#
78def isnum(s):
79 if not s: return 0
80 for c in s:
81 if not c in digits: return 0
82 return 1
83
84
85# Allowed function return types
86#
87return_types = ['void', 'short', 'long']
88
89
90# Allowed function argument types
91#
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +000092arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000093
94
95# Need to classify arguments as follows
96# simple input variable
97# simple output variable
98# input array
99# output array
100# input giving size of some array
101#
102# Array dimensions can be specified as follows
103# constant
104# argN
105# constant * argN
106# retval
107# constant * retval
108#
109# The dimensions given as constants * something are really
110# arrays of points where points are 2- 3- or 4-tuples
111#
112# We have to consider three lists:
113# python input arguments
114# C stub arguments (in & out)
115# python output arguments (really return values)
116#
117# There is a mapping from python input arguments to the input arguments
118# of the C stub, and a further mapping from C stub arguments to the
119# python return values
120
121
122# Exception raised by checkarg() and generate()
123#
124arg_error = 'bad arg'
125
126
127# Function to check one argument.
128# Arguments: the type and the arg "name" (really mode plus subscript).
129# Raises arg_error if something's wrong.
130# Return type, mode, factor, rest of subscript; factor and rest may be empty.
131#
132def checkarg(type, arg):
133 #
134 # Turn "char *x" into "string x".
135 #
Guido van Rossum28178751992-01-12 17:18:12 +0000136 if type == 'char' and arg[0] == '*':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000137 type = 'string'
138 arg = arg[1:]
139 #
140 # Check that the type is supported.
141 #
142 if type not in arg_types:
143 raise arg_error, ('bad type', type)
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000144 if type[:2] == 'u_':
145 type = 'unsigned ' + type[2:]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000146 #
147 # Split it in the mode (first character) and the rest.
148 #
149 mode, rest = arg[:1], arg[1:]
150 #
151 # The mode must be 's' for send (= input) or 'r' for return argument.
152 #
153 if mode not in ('r', 's'):
154 raise arg_error, ('bad arg mode', mode)
155 #
156 # Is it a simple argument: if so, we are done.
157 #
158 if not rest:
159 return type, mode, '', ''
160 #
161 # Not a simple argument; must be an array.
162 # The 'rest' must be a subscript enclosed in [ and ].
163 # The subscript must be one of the following forms,
164 # otherwise we don't handle it (where N is a number):
165 # N
166 # argN
167 # retval
168 # N*argN
169 # N*retval
170 #
171 if rest[:1] <> '[' or rest[-1:] <> ']':
172 raise arg_error, ('subscript expected', rest)
173 sub = rest[1:-1]
174 #
175 # Is there a leading number?
176 #
177 num, sub = getnum(sub)
178 if num:
179 # There is a leading number
180 if not sub:
181 # The subscript is just a number
182 return type, mode, num, ''
Guido van Rossum28178751992-01-12 17:18:12 +0000183 if sub[:1] == '*':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000184 # There is a factor prefix
185 sub = sub[1:]
186 else:
187 raise arg_error, ('\'*\' expected', sub)
Guido van Rossum28178751992-01-12 17:18:12 +0000188 if sub == 'retval':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000189 # size is retval -- must be a reply argument
190 if mode <> 'r':
191 raise arg_error, ('non-r mode with [retval]', mode)
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000192 elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000193 raise arg_error, ('bad subscript', sub)
194 #
195 return type, mode, num, sub
196
197
198# List of functions for which we have generated stubs
199#
200functions = []
201
202
203# Generate the stub for the given function, using the database of argument
204# information build by successive calls to checkarg()
205#
206def generate(type, func, database):
207 #
208 # Check that we can handle this case:
209 # no variable size reply arrays yet
210 #
211 n_in_args = 0
212 n_out_args = 0
213 #
214 for a_type, a_mode, a_factor, a_sub in database:
Guido van Rossum28178751992-01-12 17:18:12 +0000215 if a_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000216 n_in_args = n_in_args + 1
Guido van Rossum28178751992-01-12 17:18:12 +0000217 elif a_mode == 'r':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000218 n_out_args = n_out_args + 1
219 else:
220 # Can't happen
221 raise arg_error, ('bad a_mode', a_mode)
Guido van Rossum28178751992-01-12 17:18:12 +0000222 if (a_mode == 'r' and a_sub) or a_sub == 'retval':
Guido van Rossum064a62b1995-07-07 22:39:14 +0000223 err('Function', func, 'too complicated:',
224 a_type, a_mode, a_factor, a_sub)
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000225 print '/* XXX Too complicated to generate code for */'
226 return
227 #
228 functions.append(func)
229 #
230 # Stub header
231 #
232 print
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000233 print 'static PyObject *'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000234 print 'gl_' + func + '(self, args)'
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000235 print '\tPyObject *self;'
236 print '\tPyObject *args;'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000237 print '{'
238 #
239 # Declare return value if any
240 #
241 if type <> 'void':
242 print '\t' + type, 'retval;'
243 #
244 # Declare arguments
245 #
246 for i in range(len(database)):
247 a_type, a_mode, a_factor, a_sub = database[i]
248 print '\t' + a_type,
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000249 brac = ket = ''
250 if a_sub and not isnum(a_sub):
251 if a_factor:
252 brac = '('
253 ket = ')'
254 print brac + '*',
255 print 'arg' + `i+1` + ket,
256 if a_sub and isnum(a_sub):
257 print '[', a_sub, ']',
258 if a_factor:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000259 print '[', a_factor, ']',
260 print ';'
261 #
262 # Find input arguments derived from array sizes
263 #
264 for i in range(len(database)):
265 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000266 if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000267 # Sending a variable-length array
268 n = eval(a_sub[3:])
269 if 1 <= n <= len(database):
270 b_type, b_mode, b_factor, b_sub = database[n-1]
Guido van Rossum28178751992-01-12 17:18:12 +0000271 if b_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000272 database[n-1] = b_type, 'i', a_factor, `i`
273 n_in_args = n_in_args - 1
274 #
275 # Assign argument positions in the Python argument list
276 #
277 in_pos = []
278 i_in = 0
279 for i in range(len(database)):
280 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000281 if a_mode == 's':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000282 in_pos.append(i_in)
283 i_in = i_in + 1
284 else:
285 in_pos.append(-1)
286 #
287 # Get input arguments
288 #
289 for i in range(len(database)):
290 a_type, a_mode, a_factor, a_sub = database[i]
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000291 if a_type[:9] == 'unsigned ':
292 xtype = a_type[9:]
293 else:
294 xtype = a_type
Guido van Rossum28178751992-01-12 17:18:12 +0000295 if a_mode == 'i':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000296 #
297 # Implicit argument;
298 # a_factor is divisor if present,
299 # a_sub indicates which arg (`database index`)
300 #
301 j = eval(a_sub)
302 print '\tif',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000303 print '(!geti' + xtype + 'arraysize(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000304 print `n_in_args` + ',',
305 print `in_pos[j]` + ',',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000306 if xtype <> a_type:
307 print '('+xtype+' *)',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000308 print '&arg' + `i+1` + '))'
309 print '\t\treturn NULL;'
310 if a_factor:
311 print '\targ' + `i+1`,
312 print '= arg' + `i+1`,
313 print '/', a_factor + ';'
Guido van Rossum28178751992-01-12 17:18:12 +0000314 elif a_mode == 's':
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000315 if a_sub and not isnum(a_sub):
316 # Allocate memory for varsize array
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000317 print '\tif ((arg' + `i+1`, '=',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000318 if a_factor:
319 print '('+a_type+'(*)['+a_factor+'])',
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000320 print 'PyMem_NEW(' + a_type, ',',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000321 if a_factor:
322 print a_factor, '*',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000323 print a_sub, ')) == NULL)'
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000324 print '\t\treturn PyErr_NoMemory();'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000325 print '\tif',
326 if a_factor or a_sub: # Get a fixed-size array array
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000327 print '(!geti' + xtype + 'array(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000328 print `n_in_args` + ',',
329 print `in_pos[i]` + ',',
330 if a_factor: print a_factor,
331 if a_factor and a_sub: print '*',
332 if a_sub: print a_sub,
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000333 print ',',
334 if (a_sub and a_factor) or xtype <> a_type:
335 print '('+xtype+' *)',
336 print 'arg' + `i+1` + '))'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000337 else: # Get a simple variable
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000338 print '(!geti' + xtype + 'arg(args,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000339 print `n_in_args` + ',',
340 print `in_pos[i]` + ',',
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000341 if xtype <> a_type:
342 print '('+xtype+' *)',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000343 print '&arg' + `i+1` + '))'
344 print '\t\treturn NULL;'
345 #
346 # Begin of function call
347 #
348 if type <> 'void':
349 print '\tretval =', func + '(',
350 else:
351 print '\t' + func + '(',
352 #
353 # Argument list
354 #
355 for i in range(len(database)):
356 if i > 0: print ',',
357 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000358 if a_mode == 'r' and not a_factor:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000359 print '&',
360 print 'arg' + `i+1`,
361 #
362 # End of function call
363 #
364 print ');'
365 #
366 # Free varsize arrays
367 #
368 for i in range(len(database)):
369 a_type, a_mode, a_factor, a_sub = database[i]
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000370 if a_mode == 's' and a_sub and not isnum(a_sub):
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000371 print '\tPyMem_DEL(arg' + `i+1` + ');'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000372 #
373 # Return
374 #
375 if n_out_args:
376 #
377 # Multiple return values -- construct a tuple
378 #
379 if type <> 'void':
380 n_out_args = n_out_args + 1
Guido van Rossum28178751992-01-12 17:18:12 +0000381 if n_out_args == 1:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000382 for i in range(len(database)):
383 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000384 if a_mode == 'r':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000385 break
386 else:
387 raise arg_error, 'expected r arg not found'
388 print '\treturn',
389 print mkobject(a_type, 'arg' + `i+1`) + ';'
390 else:
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000391 print '\t{ PyObject *v = PyTuple_New(',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000392 print n_out_args, ');'
393 print '\t if (v == NULL) return NULL;'
394 i_out = 0
395 if type <> 'void':
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000396 print '\t PyTuple_SetItem(v,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000397 print `i_out` + ',',
398 print mkobject(type, 'retval') + ');'
399 i_out = i_out + 1
400 for i in range(len(database)):
401 a_type, a_mode, a_factor, a_sub = database[i]
Guido van Rossum28178751992-01-12 17:18:12 +0000402 if a_mode == 'r':
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000403 print '\t PyTuple_SetItem(v,',
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000404 print `i_out` + ',',
405 s = mkobject(a_type, 'arg' + `i+1`)
406 print s + ');'
407 i_out = i_out + 1
408 print '\t return v;'
409 print '\t}'
410 else:
411 #
412 # Simple function return
413 # Return None or return value
414 #
Guido van Rossum28178751992-01-12 17:18:12 +0000415 if type == 'void':
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000416 print '\tPy_INCREF(Py_None);'
417 print '\treturn Py_None;'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000418 else:
419 print '\treturn', mkobject(type, 'retval') + ';'
420 #
421 # Stub body closing brace
422 #
423 print '}'
424
425
426# Subroutine to return a function call to mknew<type>object(<arg>)
427#
428def mkobject(type, arg):
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000429 if type[:9] == 'unsigned ':
430 type = type[9:]
431 return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000432 return 'mknew' + type + 'object(' + arg + ')'
433
434
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000435defined_archs = []
436
437# usage: cgen [ -Dmach ... ] [ file ]
438for arg in sys.argv[1:]:
439 if arg[:2] == '-D':
440 defined_archs.append(arg[2:])
441 else:
442 # Open optional file argument
443 sys.stdin = open(arg, 'r')
Guido van Rossum5c850621992-09-11 23:55:51 +0000444
445
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000446# Input line number
447lno = 0
448
449
450# Input is divided in two parts, separated by a line containing '%%'.
451# <part1> -- literally copied to stdout
452# <part2> -- stub definitions
453
454# Variable indicating the current input part.
455#
456part = 1
457
458# Main loop over the input
459#
460while 1:
461 try:
462 line = raw_input()
463 except EOFError:
464 break
465 #
466 lno = lno+1
467 words = string.split(line)
468 #
Guido van Rossum28178751992-01-12 17:18:12 +0000469 if part == 1:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000470 #
471 # In part 1, copy everything literally
472 # except look for a line of just '%%'
473 #
Guido van Rossum28178751992-01-12 17:18:12 +0000474 if words == ['%%']:
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000475 part = part + 1
476 else:
477 #
478 # Look for names of manually written
479 # stubs: a single percent followed by the name
480 # of the function in Python.
481 # The stub name is derived by prefixing 'gl_'.
482 #
Guido van Rossum28178751992-01-12 17:18:12 +0000483 if words and words[0][0] == '%':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000484 func = words[0][1:]
485 if (not func) and words[1:]:
486 func = words[1]
487 if func:
488 functions.append(func)
489 else:
490 print line
Sjoerd Mullenderc4f169c1993-12-21 17:06:12 +0000491 continue
492 if not words:
493 continue # skip empty line
494 elif words[0] == 'if':
495 # if XXX rest
496 # if !XXX rest
497 if words[1][0] == '!':
498 if words[1][1:] in defined_archs:
499 continue
500 elif words[1] not in defined_archs:
501 continue
502 words = words[2:]
503 if words[0] == '#include':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000504 print line
Guido van Rossum28178751992-01-12 17:18:12 +0000505 elif words[0][:1] == '#':
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000506 pass # ignore comment
507 elif words[0] not in return_types:
508 err('Line', lno, ': bad return type :', words[0])
509 elif len(words) < 2:
510 err('Line', lno, ': no funcname :', line)
511 else:
512 if len(words) % 2 <> 0:
513 err('Line', lno, ': odd argument list :', words[2:])
514 else:
515 database = []
516 try:
517 for i in range(2, len(words), 2):
518 x = checkarg(words[i], words[i+1])
519 database.append(x)
520 print
521 print '/*',
522 for w in words: print w,
523 print '*/'
524 generate(words[0], words[1], database)
525 except arg_error, msg:
526 err('Line', lno, ':', msg)
527
528
529print
Guido van Rossum0a3eaf01997-04-29 15:39:28 +0000530print 'static struct PyMethodDef gl_methods[] = {'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000531for func in functions:
532 print '\t{"' + func + '", gl_' + func + '},'
533print '\t{NULL, NULL} /* Sentinel */'
534print '};'
535print
Guido van Rossum7ce52be1996-12-09 18:51:51 +0000536print 'void'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000537print 'initgl()'
538print '{'
Guido van Rossum1ed5e571997-04-29 21:34:16 +0000539print '\t(void) Py_InitModule("gl", gl_methods);'
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000540print '}'