1 ########################################################################
2 # Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 # Permission to use, copy, modify, and distribute this software and its
8 # documentation for any purpose and without fee is hereby granted,
9 # provided that the above copyright notice appear in all copies and that
10 # both that copyright notice and this permission notice appear in
11 # 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.
15 # 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 ########################################################################
24 # Python script to parse cstubs file for gl and generate C stubs.
25 # usage: python cgen.py <cstubs >glmodule.c
27 # 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.
31 # XXX BUG return arrays generate wrong code
32 # XXX need to change error returns into gotos to free mallocked arrays
39 # Function to print to stderr
42 savestdout
= sys
.stdout
44 sys
.stdout
= sys
.stderr
49 sys
.stdout
= savestdout
52 # The set of digits that form a number
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.
63 while s
and s
[0] in digits
:
69 # Function to check if a string is a number
74 if not c
in digits
: return 0
78 # Allowed function return types
80 return_types
= ['void', 'short', 'long']
83 # Allowed function argument types
85 arg_types
= ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
88 # Need to classify arguments as follows
89 # simple input variable
90 # simple output variable
93 # input giving size of some array
95 # Array dimensions can be specified as follows
102 # The dimensions given as constants * something are really
103 # arrays of points where points are 2- 3- or 4-tuples
105 # We have to consider three lists:
106 # python input arguments
107 # C stub arguments (in & out)
108 # python output arguments (really return values)
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
115 # Exception raised by checkarg() and generate()
117 arg_error
= 'bad arg'
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.
125 def checkarg(type, arg
):
127 # Turn "char *x" into "string x".
129 if type == 'char' and arg
[0] == '*':
133 # Check that the type is supported.
135 if type not in arg_types
:
136 raise arg_error
, ('bad type', type)
138 type = 'unsigned ' + type[2:]
140 # Split it in the mode (first character) and the rest.
142 mode
, rest
= arg
[:1], arg
[1:]
144 # The mode must be 's' for send (= input) or 'r' for return argument.
146 if mode
not in ('r', 's'):
147 raise arg_error
, ('bad arg mode', mode
)
149 # Is it a simple argument: if so, we are done.
152 return type, mode
, '', ''
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):
164 if rest
[:1] <> '[' or rest
[-1:] <> ']':
165 raise arg_error
, ('subscript expected', rest
)
168 # Is there a leading number?
170 num
, sub
= getnum(sub
)
172 # There is a leading number
174 # The subscript is just a number
175 return type, mode
, num
, ''
177 # There is a factor prefix
180 raise arg_error
, ('\'*\' expected', sub
)
182 # size is retval -- must be a reply argument
184 raise arg_error
, ('non-r mode with [retval]', mode
)
185 elif not isnum(sub
) and (sub
[:3] <> 'arg' or not isnum(sub
[3:])):
186 raise arg_error
, ('bad subscript', sub
)
188 return type, mode
, num
, sub
191 # List of functions for which we have generated stubs
196 # Generate the stub for the given function, using the database of argument
197 # information build by successive calls to checkarg()
199 def generate(type, func
, database
):
201 # Check that we can handle this case:
202 # no variable size reply arrays yet
207 for a_type
, a_mode
, a_factor
, a_sub
in database
:
209 n_in_args
= n_in_args
+ 1
211 n_out_args
= n_out_args
+ 1
214 raise arg_error
, ('bad a_mode', a_mode
)
215 if (a_mode
== 'r' and a_sub
) or a_sub
== 'retval':
216 e
= 'Function', func
, 'too complicated:'
217 err(e
+ (a_type
, a_mode
, a_factor
, a_sub
))
218 print '/* XXX Too complicated to generate code for */'
221 functions
.append(func
)
226 print 'static object *'
227 print 'gl_' + func
+ '(self, args)'
228 print '\tobject *self;'
229 print '\tobject *args;'
232 # Declare return value if any
235 print '\t' + type, 'retval;'
239 for i
in range(len(database
)):
240 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
243 if a_sub
and not isnum(a_sub
):
248 print 'arg' + `i
+1`
+ ket
,
249 if a_sub
and isnum(a_sub
):
250 print '[', a_sub
, ']',
252 print '[', a_factor
, ']',
255 # Find input arguments derived from array sizes
257 for i
in range(len(database
)):
258 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
259 if a_mode
== 's' and a_sub
[:3] == 'arg' and isnum(a_sub
[3:]):
260 # Sending a variable-length array
262 if 1 <= n
<= len(database
):
263 b_type
, b_mode
, b_factor
, b_sub
= database
[n
-1]
265 database
[n
-1] = b_type
, 'i', a_factor
, `i`
266 n_in_args
= n_in_args
- 1
268 # Assign argument positions in the Python argument list
272 for i
in range(len(database
)):
273 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
280 # Get input arguments
282 for i
in range(len(database
)):
283 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
284 if a_type
[:9] == 'unsigned ':
291 # a_factor is divisor if present,
292 # a_sub indicates which arg (`database index`)
296 print '(!geti' + xtype
+ 'arraysize(args,',
297 print `n_in_args`
+ ',',
298 print `in_pos
[j
]`
+ ',',
300 print '('+xtype
+' *)',
301 print '&arg' + `i
+1`
+ '))'
302 print '\t\treturn NULL;'
304 print '\targ' + `i
+1`
,
305 print '= arg' + `i
+1`
,
306 print '/', a_factor
+ ';'
308 if a_sub
and not isnum(a_sub
):
309 # Allocate memory for varsize array
310 print '\tif ((arg' + `i
+1`
, '=',
312 print '('+a_type
+'(*)['+a_factor
+'])',
313 print 'NEW(' + a_type
, ',',
316 print a_sub
, ')) == NULL)'
317 print '\t\treturn err_nomem();'
319 if a_factor
or a_sub
: # Get a fixed-size array array
320 print '(!geti' + xtype
+ 'array(args,',
321 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
,
327 if (a_sub
and a_factor
) or xtype
<> a_type
:
328 print '('+xtype
+' *)',
329 print 'arg' + `i
+1`
+ '))'
330 else: # Get a simple variable
331 print '(!geti' + xtype
+ 'arg(args,',
332 print `n_in_args`
+ ',',
333 print `in_pos
[i
]`
+ ',',
335 print '('+xtype
+' *)',
336 print '&arg' + `i
+1`
+ '))'
337 print '\t\treturn NULL;'
339 # Begin of function call
342 print '\tretval =', func
+ '(',
344 print '\t' + func
+ '(',
348 for i
in range(len(database
)):
350 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
351 if a_mode
== 'r' and not a_factor
:
355 # End of function call
359 # Free varsize arrays
361 for i
in range(len(database
)):
362 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
363 if a_mode
== 's' and a_sub
and not isnum(a_sub
):
364 print '\tDEL(arg' + `i
+1`
+ ');'
370 # Multiple return values -- construct a tuple
373 n_out_args
= n_out_args
+ 1
375 for i
in range(len(database
)):
376 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
380 raise arg_error
, 'expected r arg not found'
382 print mkobject(a_type
, 'arg' + `i
+1`
) + ';'
384 print '\t{ object *v = newtupleobject(',
385 print n_out_args
, ');'
386 print '\t if (v == NULL) return NULL;'
389 print '\t settupleitem(v,',
391 print mkobject(type, 'retval') + ');'
393 for i
in range(len(database
)):
394 a_type
, a_mode
, a_factor
, a_sub
= database
[i
]
396 print '\t settupleitem(v,',
398 s
= mkobject(a_type
, 'arg' + `i
+1`
)
405 # Simple function return
406 # Return None or return value
409 print '\tINCREF(None);'
410 print '\treturn None;'
412 print '\treturn', mkobject(type, 'retval') + ';'
414 # Stub body closing brace
419 # Subroutine to return a function call to mknew<type>object(<arg>)
421 def mkobject(type, arg
):
422 if type[:9] == 'unsigned ':
424 return 'mknew' + type + 'object((' + type + ') ' + arg
+ ')'
425 return 'mknew' + type + 'object(' + arg
+ ')'
430 # usage: cgen [ -Dmach ... ] [ file ]
431 for arg
in sys
.argv
[1:]:
433 defined_archs
.append(arg
[2:])
435 # Open optional file argument
436 sys
.stdin
= open(arg
, 'r')
443 # Input is divided in two parts, separated by a line containing '%%'.
444 # <part1> -- literally copied to stdout
445 # <part2> -- stub definitions
447 # Variable indicating the current input part.
451 # Main loop over the input
460 words
= string
.split(line
)
464 # In part 1, copy everything literally
465 # except look for a line of just '%%'
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_'.
476 if words
and words
[0][0] == '%':
478 if (not func
) and words
[1:]:
481 functions
.append(func
)
486 continue # skip empty line
487 elif words
[0] == 'if':
490 if words
[1][0] == '!':
491 if words
[1][1:] in defined_archs
:
493 elif words
[1] not in defined_archs
:
496 if words
[0] == '#include':
498 elif words
[0][:1] == '#':
499 pass # ignore comment
500 elif words
[0] not in return_types
:
501 err('Line', lno
, ': bad return type :', words
[0])
503 err('Line', lno
, ': no funcname :', line
)
505 if len(words
) % 2 <> 0:
506 err('Line', lno
, ': odd argument list :', words
[2:])
510 for i
in range(2, len(words
), 2):
511 x
= checkarg(words
[i
], words
[i
+1])
515 for w
in words
: print w
,
517 generate(words
[0], words
[1], database
)
518 except arg_error
, msg
:
519 err('Line', lno
, ':', msg
)
523 print 'static struct methodlist gl_methods[] = {'
524 for func
in functions
:
525 print '\t{"' + func
+ '", gl_' + func
+ '},'
526 print '\t{NULL, NULL} /* Sentinel */'
531 print '\tinitmodule("gl", gl_methods);'