mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 09:57:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			520 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			520 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ########################################################################
 | |
| # Copyright (c) 2000, BeOpen.com.
 | |
| # Copyright (c) 1995-2000, Corporation for National Research Initiatives.
 | |
| # Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
 | |
| # All rights reserved.
 | |
| #
 | |
| # See the file "Misc/COPYRIGHT" for information on usage and
 | |
| # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 | |
| ########################################################################
 | |
| 
 | |
| # Python script to parse cstubs file for gl and generate C stubs.
 | |
| # usage: python cgen.py <cstubs >glmodule.c
 | |
| #
 | |
| # NOTE: You  must first make a python binary without the "GL" option
 | |
| #       before you can run this, when building Python for the first time.
 | |
| #       See comments in the Makefile.
 | |
| #
 | |
| # XXX BUG return arrays generate wrong code
 | |
| # XXX need to change error returns into gotos to free mallocked arrays
 | |
| 
 | |
| 
 | |
| import string
 | |
| import sys
 | |
| 
 | |
| 
 | |
| # Function to print to stderr
 | |
| #
 | |
| def err(*args):
 | |
|     savestdout = sys.stdout
 | |
|     try:
 | |
|         sys.stdout = sys.stderr
 | |
|         for i in args:
 | |
|             print i,
 | |
|         print
 | |
|     finally:
 | |
|         sys.stdout = savestdout
 | |
| 
 | |
| 
 | |
| # The set of digits that form a number
 | |
| #
 | |
| digits = '0123456789'
 | |
| 
 | |
| 
 | |
| # Function to extract a string of digits from the front of the string.
 | |
| # Returns the leading string of digits and the remaining string.
 | |
| # If no number is found, returns '' and the original string.
 | |
| #
 | |
| def getnum(s):
 | |
|     n = ''
 | |
|     while s and s[0] in digits:
 | |
|         n = n + s[0]
 | |
|         s = s[1:]
 | |
|     return n, s
 | |
| 
 | |
| 
 | |
| # Function to check if a string is a number
 | |
| #
 | |
| def isnum(s):
 | |
|     if not s: return False
 | |
|     for c in s:
 | |
|         if not c in digits: return False
 | |
|     return True
 | |
| 
 | |
| 
 | |
| # Allowed function return types
 | |
| #
 | |
| return_types = ['void', 'short', 'long']
 | |
| 
 | |
| 
 | |
| # Allowed function argument types
 | |
| #
 | |
| arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
 | |
| 
 | |
| 
 | |
| # Need to classify arguments as follows
 | |
| #       simple input variable
 | |
| #       simple output variable
 | |
| #       input array
 | |
| #       output array
 | |
| #       input giving size of some array
 | |
| #
 | |
| # Array dimensions can be specified as follows
 | |
| #       constant
 | |
| #       argN
 | |
| #       constant * argN
 | |
| #       retval
 | |
| #       constant * retval
 | |
| #
 | |
| # The dimensions given as constants * something are really
 | |
| # arrays of points where points are 2- 3- or 4-tuples
 | |
| #
 | |
| # We have to consider three lists:
 | |
| #       python input arguments
 | |
| #       C stub arguments (in & out)
 | |
| #       python output arguments (really return values)
 | |
| #
 | |
| # There is a mapping from python input arguments to the input arguments
 | |
| # of the C stub, and a further mapping from C stub arguments to the
 | |
| # python return values
 | |
| 
 | |
| 
 | |
| # Exception raised by checkarg() and generate()
 | |
| #
 | |
| arg_error = 'bad arg'
 | |
| 
 | |
| 
 | |
| # Function to check one argument.
 | |
| # Arguments: the type and the arg "name" (really mode plus subscript).
 | |
| # Raises arg_error if something's wrong.
 | |
| # Return type, mode, factor, rest of subscript; factor and rest may be empty.
 | |
| #
 | |
| def checkarg(type, arg):
 | |
|     #
 | |
|     # Turn "char *x" into "string x".
 | |
|     #
 | |
|     if type == 'char' and arg[0] == '*':
 | |
|         type = 'string'
 | |
|         arg = arg[1:]
 | |
|     #
 | |
|     # Check that the type is supported.
 | |
|     #
 | |
|     if type not in arg_types:
 | |
|         raise arg_error, ('bad type', type)
 | |
|     if type[:2] == 'u_':
 | |
|         type = 'unsigned ' + type[2:]
 | |
|     #
 | |
|     # Split it in the mode (first character) and the rest.
 | |
|     #
 | |
|     mode, rest = arg[:1], arg[1:]
 | |
|     #
 | |
|     # The mode must be 's' for send (= input) or 'r' for return argument.
 | |
|     #
 | |
|     if mode not in ('r', 's'):
 | |
|         raise arg_error, ('bad arg mode', mode)
 | |
|     #
 | |
|     # Is it a simple argument: if so, we are done.
 | |
|     #
 | |
|     if not rest:
 | |
|         return type, mode, '', ''
 | |
|     #
 | |
|     # Not a simple argument; must be an array.
 | |
|     # The 'rest' must be a subscript enclosed in [ and ].
 | |
|     # The subscript must be one of the following forms,
 | |
|     # otherwise we don't handle it (where N is a number):
 | |
|     #       N
 | |
|     #       argN
 | |
|     #       retval
 | |
|     #       N*argN
 | |
|     #       N*retval
 | |
|     #
 | |
|     if rest[:1] <> '[' or rest[-1:] <> ']':
 | |
|         raise arg_error, ('subscript expected', rest)
 | |
|     sub = rest[1:-1]
 | |
|     #
 | |
|     # Is there a leading number?
 | |
|     #
 | |
|     num, sub = getnum(sub)
 | |
|     if num:
 | |
|         # There is a leading number
 | |
|         if not sub:
 | |
|             # The subscript is just a number
 | |
|             return type, mode, num, ''
 | |
|         if sub[:1] == '*':
 | |
|             # There is a factor prefix
 | |
|             sub = sub[1:]
 | |
|         else:
 | |
|             raise arg_error, ('\'*\' expected', sub)
 | |
|     if sub == 'retval':
 | |
|         # size is retval -- must be a reply argument
 | |
|         if mode <> 'r':
 | |
|             raise arg_error, ('non-r mode with [retval]', mode)
 | |
|     elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
 | |
|         raise arg_error, ('bad subscript', sub)
 | |
|     #
 | |
|     return type, mode, num, sub
 | |
| 
 | |
| 
 | |
| # List of functions for which we have generated stubs
 | |
| #
 | |
| functions = []
 | |
| 
 | |
| 
 | |
| # Generate the stub for the given function, using the database of argument
 | |
| # information build by successive calls to checkarg()
 | |
| #
 | |
| def generate(type, func, database):
 | |
|     #
 | |
|     # Check that we can handle this case:
 | |
|     # no variable size reply arrays yet
 | |
|     #
 | |
|     n_in_args = 0
 | |
|     n_out_args = 0
 | |
|     #
 | |
|     for a_type, a_mode, a_factor, a_sub in database:
 | |
|         if a_mode == 's':
 | |
|             n_in_args = n_in_args + 1
 | |
|         elif a_mode == 'r':
 | |
|             n_out_args = n_out_args + 1
 | |
|         else:
 | |
|             # Can't happen
 | |
|             raise arg_error, ('bad a_mode', a_mode)
 | |
|         if (a_mode == 'r' and a_sub) or a_sub == 'retval':
 | |
|             err('Function', func, 'too complicated:',
 | |
|                 a_type, a_mode, a_factor, a_sub)
 | |
|             print '/* XXX Too complicated to generate code for */'
 | |
|             return
 | |
|     #
 | |
|     functions.append(func)
 | |
|     #
 | |
|     # Stub header
 | |
|     #
 | |
|     print
 | |
|     print 'static PyObject *'
 | |
|     print 'gl_' + func + '(self, args)'
 | |
|     print '\tPyObject *self;'
 | |
|     print '\tPyObject *args;'
 | |
|     print '{'
 | |
|     #
 | |
|     # Declare return value if any
 | |
|     #
 | |
|     if type <> 'void':
 | |
|         print '\t' + type, 'retval;'
 | |
|     #
 | |
|     # Declare arguments
 | |
|     #
 | |
|     for i in range(len(database)):
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         print '\t' + a_type,
 | |
|         brac = ket = ''
 | |
|         if a_sub and not isnum(a_sub):
 | |
|             if a_factor:
 | |
|                 brac = '('
 | |
|                 ket = ')'
 | |
|             print brac + '*',
 | |
|         print 'arg' + repr(i+1) + ket,
 | |
|         if a_sub and isnum(a_sub):
 | |
|             print '[', a_sub, ']',
 | |
|         if a_factor:
 | |
|             print '[', a_factor, ']',
 | |
|         print ';'
 | |
|     #
 | |
|     # Find input arguments derived from array sizes
 | |
|     #
 | |
|     for i in range(len(database)):
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
 | |
|             # Sending a variable-length array
 | |
|             n = eval(a_sub[3:])
 | |
|             if 1 <= n <= len(database):
 | |
|                 b_type, b_mode, b_factor, b_sub = database[n-1]
 | |
|                 if b_mode == 's':
 | |
|                     database[n-1] = b_type, 'i', a_factor, repr(i)
 | |
|                     n_in_args = n_in_args - 1
 | |
|     #
 | |
|     # Assign argument positions in the Python argument list
 | |
|     #
 | |
|     in_pos = []
 | |
|     i_in = 0
 | |
|     for i in range(len(database)):
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         if a_mode == 's':
 | |
|             in_pos.append(i_in)
 | |
|             i_in = i_in + 1
 | |
|         else:
 | |
|             in_pos.append(-1)
 | |
|     #
 | |
|     # Get input arguments
 | |
|     #
 | |
|     for i in range(len(database)):
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         if a_type[:9] == 'unsigned ':
 | |
|             xtype = a_type[9:]
 | |
|         else:
 | |
|             xtype = a_type
 | |
|         if a_mode == 'i':
 | |
|             #
 | |
|             # Implicit argument;
 | |
|             # a_factor is divisor if present,
 | |
|             # a_sub indicates which arg (`database index`)
 | |
|             #
 | |
|             j = eval(a_sub)
 | |
|             print '\tif',
 | |
|             print '(!geti' + xtype + 'arraysize(args,',
 | |
|             print repr(n_in_args) + ',',
 | |
|             print repr(in_pos[j]) + ',',
 | |
|             if xtype <> a_type:
 | |
|                 print '('+xtype+' *)',
 | |
|             print '&arg' + repr(i+1) + '))'
 | |
|             print '\t\treturn NULL;'
 | |
|             if a_factor:
 | |
|                 print '\targ' + repr(i+1),
 | |
|                 print '= arg' + repr(i+1),
 | |
|                 print '/', a_factor + ';'
 | |
|         elif a_mode == 's':
 | |
|             if a_sub and not isnum(a_sub):
 | |
|                 # Allocate memory for varsize array
 | |
|                 print '\tif ((arg' + repr(i+1), '=',
 | |
|                 if a_factor:
 | |
|                     print '('+a_type+'(*)['+a_factor+'])',
 | |
|                 print 'PyMem_NEW(' + a_type, ',',
 | |
|                 if a_factor:
 | |
|                     print a_factor, '*',
 | |
|                 print a_sub, ')) == NULL)'
 | |
|                 print '\t\treturn PyErr_NoMemory();'
 | |
|             print '\tif',
 | |
|             if a_factor or a_sub: # Get a fixed-size array array
 | |
|                 print '(!geti' + xtype + 'array(args,',
 | |
|                 print repr(n_in_args) + ',',
 | |
|                 print repr(in_pos[i]) + ',',
 | |
|                 if a_factor: print a_factor,
 | |
|                 if a_factor and a_sub: print '*',
 | |
|                 if a_sub: print a_sub,
 | |
|                 print ',',
 | |
|                 if (a_sub and a_factor) or xtype <> a_type:
 | |
|                     print '('+xtype+' *)',
 | |
|                 print 'arg' + repr(i+1) + '))'
 | |
|             else: # Get a simple variable
 | |
|                 print '(!geti' + xtype + 'arg(args,',
 | |
|                 print repr(n_in_args) + ',',
 | |
|                 print repr(in_pos[i]) + ',',
 | |
|                 if xtype <> a_type:
 | |
|                     print '('+xtype+' *)',
 | |
|                 print '&arg' + repr(i+1) + '))'
 | |
|             print '\t\treturn NULL;'
 | |
|     #
 | |
|     # Begin of function call
 | |
|     #
 | |
|     if type <> 'void':
 | |
|         print '\tretval =', func + '(',
 | |
|     else:
 | |
|         print '\t' + func + '(',
 | |
|     #
 | |
|     # Argument list
 | |
|     #
 | |
|     for i in range(len(database)):
 | |
|         if i > 0: print ',',
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         if a_mode == 'r' and not a_factor:
 | |
|             print '&',
 | |
|         print 'arg' + repr(i+1),
 | |
|     #
 | |
|     # End of function call
 | |
|     #
 | |
|     print ');'
 | |
|     #
 | |
|     # Free varsize arrays
 | |
|     #
 | |
|     for i in range(len(database)):
 | |
|         a_type, a_mode, a_factor, a_sub = database[i]
 | |
|         if a_mode == 's' and a_sub and not isnum(a_sub):
 | |
|             print '\tPyMem_DEL(arg' + repr(i+1) + ');'
 | |
|     #
 | |
|     # Return
 | |
|     #
 | |
|     if n_out_args:
 | |
|         #
 | |
|         # Multiple return values -- construct a tuple
 | |
|         #
 | |
|         if type <> 'void':
 | |
|             n_out_args = n_out_args + 1
 | |
|         if n_out_args == 1:
 | |
|             for i in range(len(database)):
 | |
|                 a_type, a_mode, a_factor, a_sub = database[i]
 | |
|                 if a_mode == 'r':
 | |
|                     break
 | |
|             else:
 | |
|                 raise arg_error, 'expected r arg not found'
 | |
|             print '\treturn',
 | |
|             print mkobject(a_type, 'arg' + repr(i+1)) + ';'
 | |
|         else:
 | |
|             print '\t{ PyObject *v = PyTuple_New(',
 | |
|             print n_out_args, ');'
 | |
|             print '\t  if (v == NULL) return NULL;'
 | |
|             i_out = 0
 | |
|             if type <> 'void':
 | |
|                 print '\t  PyTuple_SetItem(v,',
 | |
|                 print repr(i_out) + ',',
 | |
|                 print mkobject(type, 'retval') + ');'
 | |
|                 i_out = i_out + 1
 | |
|             for i in range(len(database)):
 | |
|                 a_type, a_mode, a_factor, a_sub = database[i]
 | |
|                 if a_mode == 'r':
 | |
|                     print '\t  PyTuple_SetItem(v,',
 | |
|                     print repr(i_out) + ',',
 | |
|                     s = mkobject(a_type, 'arg' + repr(i+1))
 | |
|                     print s + ');'
 | |
|                     i_out = i_out + 1
 | |
|             print '\t  return v;'
 | |
|             print '\t}'
 | |
|     else:
 | |
|         #
 | |
|         # Simple function return
 | |
|         # Return None or return value
 | |
|         #
 | |
|         if type == 'void':
 | |
|             print '\tPy_INCREF(Py_None);'
 | |
|             print '\treturn Py_None;'
 | |
|         else:
 | |
|             print '\treturn', mkobject(type, 'retval') + ';'
 | |
|     #
 | |
|     # Stub body closing brace
 | |
|     #
 | |
|     print '}'
 | |
| 
 | |
| 
 | |
| # Subroutine to return a function call to mknew<type>object(<arg>)
 | |
| #
 | |
| def mkobject(type, arg):
 | |
|     if type[:9] == 'unsigned ':
 | |
|         type = type[9:]
 | |
|         return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
 | |
|     return 'mknew' + type + 'object(' + arg + ')'
 | |
| 
 | |
| 
 | |
| defined_archs = []
 | |
| 
 | |
| # usage: cgen [ -Dmach ... ] [ file ]
 | |
| for arg in sys.argv[1:]:
 | |
|     if arg[:2] == '-D':
 | |
|         defined_archs.append(arg[2:])
 | |
|     else:
 | |
|         # Open optional file argument
 | |
|         sys.stdin = open(arg, 'r')
 | |
| 
 | |
| 
 | |
| # Input line number
 | |
| lno = 0
 | |
| 
 | |
| 
 | |
| # Input is divided in two parts, separated by a line containing '%%'.
 | |
| #       <part1>         -- literally copied to stdout
 | |
| #       <part2>         -- stub definitions
 | |
| 
 | |
| # Variable indicating the current input part.
 | |
| #
 | |
| part = 1
 | |
| 
 | |
| # Main loop over the input
 | |
| #
 | |
| while 1:
 | |
|     try:
 | |
|         line = raw_input()
 | |
|     except EOFError:
 | |
|         break
 | |
|     #
 | |
|     lno = lno+1
 | |
|     words = string.split(line)
 | |
|     #
 | |
|     if part == 1:
 | |
|         #
 | |
|         # In part 1, copy everything literally
 | |
|         # except look for a line of just '%%'
 | |
|         #
 | |
|         if words == ['%%']:
 | |
|             part = part + 1
 | |
|         else:
 | |
|             #
 | |
|             # Look for names of manually written
 | |
|             # stubs: a single percent followed by the name
 | |
|             # of the function in Python.
 | |
|             # The stub name is derived by prefixing 'gl_'.
 | |
|             #
 | |
|             if words and words[0][0] == '%':
 | |
|                 func = words[0][1:]
 | |
|                 if (not func) and words[1:]:
 | |
|                     func = words[1]
 | |
|                 if func:
 | |
|                     functions.append(func)
 | |
|             else:
 | |
|                 print line
 | |
|         continue
 | |
|     if not words:
 | |
|         continue                # skip empty line
 | |
|     elif words[0] == 'if':
 | |
|         # if XXX rest
 | |
|         # if !XXX rest
 | |
|         if words[1][0] == '!':
 | |
|             if words[1][1:] in defined_archs:
 | |
|                 continue
 | |
|         elif words[1] not in defined_archs:
 | |
|             continue
 | |
|         words = words[2:]
 | |
|     if words[0] == '#include':
 | |
|         print line
 | |
|     elif words[0][:1] == '#':
 | |
|         pass                    # ignore comment
 | |
|     elif words[0] not in return_types:
 | |
|         err('Line', lno, ': bad return type :', words[0])
 | |
|     elif len(words) < 2:
 | |
|         err('Line', lno, ': no funcname :', line)
 | |
|     else:
 | |
|         if len(words) % 2 <> 0:
 | |
|             err('Line', lno, ': odd argument list :', words[2:])
 | |
|         else:
 | |
|             database = []
 | |
|             try:
 | |
|                 for i in range(2, len(words), 2):
 | |
|                     x = checkarg(words[i], words[i+1])
 | |
|                     database.append(x)
 | |
|                 print
 | |
|                 print '/*',
 | |
|                 for w in words: print w,
 | |
|                 print '*/'
 | |
|                 generate(words[0], words[1], database)
 | |
|             except arg_error, msg:
 | |
|                 err('Line', lno, ':', msg)
 | |
| 
 | |
| 
 | |
| print
 | |
| print 'static struct PyMethodDef gl_methods[] = {'
 | |
| for func in functions:
 | |
|     print '\t{"' + func + '", gl_' + func + '},'
 | |
| print '\t{NULL, NULL} /* Sentinel */'
 | |
| print '};'
 | |
| print
 | |
| print 'void'
 | |
| print 'initgl()'
 | |
| print '{'
 | |
| print '\t(void) Py_InitModule("gl", gl_methods);'
 | |
| print '}'
 | 
