symbian-qemu-0.9.1-12/python-2.6.1/Modules/cgen.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 ########################################################################
       
     2 # Copyright (c) 2000, BeOpen.com.
       
     3 # Copyright (c) 1995-2000, Corporation for National Research Initiatives.
       
     4 # Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
       
     5 # All rights reserved.
       
     6 #
       
     7 # See the file "Misc/COPYRIGHT" for information on usage and
       
     8 # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
       
     9 ########################################################################
       
    10 
       
    11 # Python script to parse cstubs file for gl and generate C stubs.
       
    12 # usage: python cgen.py <cstubs >glmodule.c
       
    13 #
       
    14 # NOTE: You  must first make a python binary without the "GL" option
       
    15 #       before you can run this, when building Python for the first time.
       
    16 #       See comments in the Makefile.
       
    17 #
       
    18 # XXX BUG return arrays generate wrong code
       
    19 # XXX need to change error returns into gotos to free mallocked arrays
       
    20 from warnings import warnpy3k
       
    21 warnpy3k("the cgen module has been removed in Python 3.0", stacklevel=2)
       
    22 del warnpy3k
       
    23 
       
    24 
       
    25 import string
       
    26 import sys
       
    27 
       
    28 
       
    29 # Function to print to stderr
       
    30 #
       
    31 def err(*args):
       
    32     savestdout = sys.stdout
       
    33     try:
       
    34         sys.stdout = sys.stderr
       
    35         for i in args:
       
    36             print i,
       
    37         print
       
    38     finally:
       
    39         sys.stdout = savestdout
       
    40 
       
    41 
       
    42 # The set of digits that form a number
       
    43 #
       
    44 digits = '0123456789'
       
    45 
       
    46 
       
    47 # Function to extract a string of digits from the front of the string.
       
    48 # Returns the leading string of digits and the remaining string.
       
    49 # If no number is found, returns '' and the original string.
       
    50 #
       
    51 def getnum(s):
       
    52     n = ''
       
    53     while s and s[0] in digits:
       
    54         n = n + s[0]
       
    55         s = s[1:]
       
    56     return n, s
       
    57 
       
    58 
       
    59 # Function to check if a string is a number
       
    60 #
       
    61 def isnum(s):
       
    62     if not s: return False
       
    63     for c in s:
       
    64         if not c in digits: return False
       
    65     return True
       
    66 
       
    67 
       
    68 # Allowed function return types
       
    69 #
       
    70 return_types = ['void', 'short', 'long']
       
    71 
       
    72 
       
    73 # Allowed function argument types
       
    74 #
       
    75 arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
       
    76 
       
    77 
       
    78 # Need to classify arguments as follows
       
    79 #       simple input variable
       
    80 #       simple output variable
       
    81 #       input array
       
    82 #       output array
       
    83 #       input giving size of some array
       
    84 #
       
    85 # Array dimensions can be specified as follows
       
    86 #       constant
       
    87 #       argN
       
    88 #       constant * argN
       
    89 #       retval
       
    90 #       constant * retval
       
    91 #
       
    92 # The dimensions given as constants * something are really
       
    93 # arrays of points where points are 2- 3- or 4-tuples
       
    94 #
       
    95 # We have to consider three lists:
       
    96 #       python input arguments
       
    97 #       C stub arguments (in & out)
       
    98 #       python output arguments (really return values)
       
    99 #
       
   100 # There is a mapping from python input arguments to the input arguments
       
   101 # of the C stub, and a further mapping from C stub arguments to the
       
   102 # python return values
       
   103 
       
   104 
       
   105 # Exception raised by checkarg() and generate()
       
   106 #
       
   107 arg_error = 'bad arg'
       
   108 
       
   109 
       
   110 # Function to check one argument.
       
   111 # Arguments: the type and the arg "name" (really mode plus subscript).
       
   112 # Raises arg_error if something's wrong.
       
   113 # Return type, mode, factor, rest of subscript; factor and rest may be empty.
       
   114 #
       
   115 def checkarg(type, arg):
       
   116     #
       
   117     # Turn "char *x" into "string x".
       
   118     #
       
   119     if type == 'char' and arg[0] == '*':
       
   120         type = 'string'
       
   121         arg = arg[1:]
       
   122     #
       
   123     # Check that the type is supported.
       
   124     #
       
   125     if type not in arg_types:
       
   126         raise arg_error, ('bad type', type)
       
   127     if type[:2] == 'u_':
       
   128         type = 'unsigned ' + type[2:]
       
   129     #
       
   130     # Split it in the mode (first character) and the rest.
       
   131     #
       
   132     mode, rest = arg[:1], arg[1:]
       
   133     #
       
   134     # The mode must be 's' for send (= input) or 'r' for return argument.
       
   135     #
       
   136     if mode not in ('r', 's'):
       
   137         raise arg_error, ('bad arg mode', mode)
       
   138     #
       
   139     # Is it a simple argument: if so, we are done.
       
   140     #
       
   141     if not rest:
       
   142         return type, mode, '', ''
       
   143     #
       
   144     # Not a simple argument; must be an array.
       
   145     # The 'rest' must be a subscript enclosed in [ and ].
       
   146     # The subscript must be one of the following forms,
       
   147     # otherwise we don't handle it (where N is a number):
       
   148     #       N
       
   149     #       argN
       
   150     #       retval
       
   151     #       N*argN
       
   152     #       N*retval
       
   153     #
       
   154     if rest[:1] <> '[' or rest[-1:] <> ']':
       
   155         raise arg_error, ('subscript expected', rest)
       
   156     sub = rest[1:-1]
       
   157     #
       
   158     # Is there a leading number?
       
   159     #
       
   160     num, sub = getnum(sub)
       
   161     if num:
       
   162         # There is a leading number
       
   163         if not sub:
       
   164             # The subscript is just a number
       
   165             return type, mode, num, ''
       
   166         if sub[:1] == '*':
       
   167             # There is a factor prefix
       
   168             sub = sub[1:]
       
   169         else:
       
   170             raise arg_error, ('\'*\' expected', sub)
       
   171     if sub == 'retval':
       
   172         # size is retval -- must be a reply argument
       
   173         if mode <> 'r':
       
   174             raise arg_error, ('non-r mode with [retval]', mode)
       
   175     elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
       
   176         raise arg_error, ('bad subscript', sub)
       
   177     #
       
   178     return type, mode, num, sub
       
   179 
       
   180 
       
   181 # List of functions for which we have generated stubs
       
   182 #
       
   183 functions = []
       
   184 
       
   185 
       
   186 # Generate the stub for the given function, using the database of argument
       
   187 # information build by successive calls to checkarg()
       
   188 #
       
   189 def generate(type, func, database):
       
   190     #
       
   191     # Check that we can handle this case:
       
   192     # no variable size reply arrays yet
       
   193     #
       
   194     n_in_args = 0
       
   195     n_out_args = 0
       
   196     #
       
   197     for a_type, a_mode, a_factor, a_sub in database:
       
   198         if a_mode == 's':
       
   199             n_in_args = n_in_args + 1
       
   200         elif a_mode == 'r':
       
   201             n_out_args = n_out_args + 1
       
   202         else:
       
   203             # Can't happen
       
   204             raise arg_error, ('bad a_mode', a_mode)
       
   205         if (a_mode == 'r' and a_sub) or a_sub == 'retval':
       
   206             err('Function', func, 'too complicated:',
       
   207                 a_type, a_mode, a_factor, a_sub)
       
   208             print '/* XXX Too complicated to generate code for */'
       
   209             return
       
   210     #
       
   211     functions.append(func)
       
   212     #
       
   213     # Stub header
       
   214     #
       
   215     print
       
   216     print 'static PyObject *'
       
   217     print 'gl_' + func + '(self, args)'
       
   218     print '\tPyObject *self;'
       
   219     print '\tPyObject *args;'
       
   220     print '{'
       
   221     #
       
   222     # Declare return value if any
       
   223     #
       
   224     if type <> 'void':
       
   225         print '\t' + type, 'retval;'
       
   226     #
       
   227     # Declare arguments
       
   228     #
       
   229     for i in range(len(database)):
       
   230         a_type, a_mode, a_factor, a_sub = database[i]
       
   231         print '\t' + a_type,
       
   232         brac = ket = ''
       
   233         if a_sub and not isnum(a_sub):
       
   234             if a_factor:
       
   235                 brac = '('
       
   236                 ket = ')'
       
   237             print brac + '*',
       
   238         print 'arg' + repr(i+1) + ket,
       
   239         if a_sub and isnum(a_sub):
       
   240             print '[', a_sub, ']',
       
   241         if a_factor:
       
   242             print '[', a_factor, ']',
       
   243         print ';'
       
   244     #
       
   245     # Find input arguments derived from array sizes
       
   246     #
       
   247     for i in range(len(database)):
       
   248         a_type, a_mode, a_factor, a_sub = database[i]
       
   249         if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
       
   250             # Sending a variable-length array
       
   251             n = eval(a_sub[3:])
       
   252             if 1 <= n <= len(database):
       
   253                 b_type, b_mode, b_factor, b_sub = database[n-1]
       
   254                 if b_mode == 's':
       
   255                     database[n-1] = b_type, 'i', a_factor, repr(i)
       
   256                     n_in_args = n_in_args - 1
       
   257     #
       
   258     # Assign argument positions in the Python argument list
       
   259     #
       
   260     in_pos = []
       
   261     i_in = 0
       
   262     for i in range(len(database)):
       
   263         a_type, a_mode, a_factor, a_sub = database[i]
       
   264         if a_mode == 's':
       
   265             in_pos.append(i_in)
       
   266             i_in = i_in + 1
       
   267         else:
       
   268             in_pos.append(-1)
       
   269     #
       
   270     # Get input arguments
       
   271     #
       
   272     for i in range(len(database)):
       
   273         a_type, a_mode, a_factor, a_sub = database[i]
       
   274         if a_type[:9] == 'unsigned ':
       
   275             xtype = a_type[9:]
       
   276         else:
       
   277             xtype = a_type
       
   278         if a_mode == 'i':
       
   279             #
       
   280             # Implicit argument;
       
   281             # a_factor is divisor if present,
       
   282             # a_sub indicates which arg (`database index`)
       
   283             #
       
   284             j = eval(a_sub)
       
   285             print '\tif',
       
   286             print '(!geti' + xtype + 'arraysize(args,',
       
   287             print repr(n_in_args) + ',',
       
   288             print repr(in_pos[j]) + ',',
       
   289             if xtype <> a_type:
       
   290                 print '('+xtype+' *)',
       
   291             print '&arg' + repr(i+1) + '))'
       
   292             print '\t\treturn NULL;'
       
   293             if a_factor:
       
   294                 print '\targ' + repr(i+1),
       
   295                 print '= arg' + repr(i+1),
       
   296                 print '/', a_factor + ';'
       
   297         elif a_mode == 's':
       
   298             if a_sub and not isnum(a_sub):
       
   299                 # Allocate memory for varsize array
       
   300                 print '\tif ((arg' + repr(i+1), '=',
       
   301                 if a_factor:
       
   302                     print '('+a_type+'(*)['+a_factor+'])',
       
   303                 print 'PyMem_NEW(' + a_type, ',',
       
   304                 if a_factor:
       
   305                     print a_factor, '*',
       
   306                 print a_sub, ')) == NULL)'
       
   307                 print '\t\treturn PyErr_NoMemory();'
       
   308             print '\tif',
       
   309             if a_factor or a_sub: # Get a fixed-size array array
       
   310                 print '(!geti' + xtype + 'array(args,',
       
   311                 print repr(n_in_args) + ',',
       
   312                 print repr(in_pos[i]) + ',',
       
   313                 if a_factor: print a_factor,
       
   314                 if a_factor and a_sub: print '*',
       
   315                 if a_sub: print a_sub,
       
   316                 print ',',
       
   317                 if (a_sub and a_factor) or xtype <> a_type:
       
   318                     print '('+xtype+' *)',
       
   319                 print 'arg' + repr(i+1) + '))'
       
   320             else: # Get a simple variable
       
   321                 print '(!geti' + xtype + 'arg(args,',
       
   322                 print repr(n_in_args) + ',',
       
   323                 print repr(in_pos[i]) + ',',
       
   324                 if xtype <> a_type:
       
   325                     print '('+xtype+' *)',
       
   326                 print '&arg' + repr(i+1) + '))'
       
   327             print '\t\treturn NULL;'
       
   328     #
       
   329     # Begin of function call
       
   330     #
       
   331     if type <> 'void':
       
   332         print '\tretval =', func + '(',
       
   333     else:
       
   334         print '\t' + func + '(',
       
   335     #
       
   336     # Argument list
       
   337     #
       
   338     for i in range(len(database)):
       
   339         if i > 0: print ',',
       
   340         a_type, a_mode, a_factor, a_sub = database[i]
       
   341         if a_mode == 'r' and not a_factor:
       
   342             print '&',
       
   343         print 'arg' + repr(i+1),
       
   344     #
       
   345     # End of function call
       
   346     #
       
   347     print ');'
       
   348     #
       
   349     # Free varsize arrays
       
   350     #
       
   351     for i in range(len(database)):
       
   352         a_type, a_mode, a_factor, a_sub = database[i]
       
   353         if a_mode == 's' and a_sub and not isnum(a_sub):
       
   354             print '\tPyMem_DEL(arg' + repr(i+1) + ');'
       
   355     #
       
   356     # Return
       
   357     #
       
   358     if n_out_args:
       
   359         #
       
   360         # Multiple return values -- construct a tuple
       
   361         #
       
   362         if type <> 'void':
       
   363             n_out_args = n_out_args + 1
       
   364         if n_out_args == 1:
       
   365             for i in range(len(database)):
       
   366                 a_type, a_mode, a_factor, a_sub = database[i]
       
   367                 if a_mode == 'r':
       
   368                     break
       
   369             else:
       
   370                 raise arg_error, 'expected r arg not found'
       
   371             print '\treturn',
       
   372             print mkobject(a_type, 'arg' + repr(i+1)) + ';'
       
   373         else:
       
   374             print '\t{ PyObject *v = PyTuple_New(',
       
   375             print n_out_args, ');'
       
   376             print '\t  if (v == NULL) return NULL;'
       
   377             i_out = 0
       
   378             if type <> 'void':
       
   379                 print '\t  PyTuple_SetItem(v,',
       
   380                 print repr(i_out) + ',',
       
   381                 print mkobject(type, 'retval') + ');'
       
   382                 i_out = i_out + 1
       
   383             for i in range(len(database)):
       
   384                 a_type, a_mode, a_factor, a_sub = database[i]
       
   385                 if a_mode == 'r':
       
   386                     print '\t  PyTuple_SetItem(v,',
       
   387                     print repr(i_out) + ',',
       
   388                     s = mkobject(a_type, 'arg' + repr(i+1))
       
   389                     print s + ');'
       
   390                     i_out = i_out + 1
       
   391             print '\t  return v;'
       
   392             print '\t}'
       
   393     else:
       
   394         #
       
   395         # Simple function return
       
   396         # Return None or return value
       
   397         #
       
   398         if type == 'void':
       
   399             print '\tPy_INCREF(Py_None);'
       
   400             print '\treturn Py_None;'
       
   401         else:
       
   402             print '\treturn', mkobject(type, 'retval') + ';'
       
   403     #
       
   404     # Stub body closing brace
       
   405     #
       
   406     print '}'
       
   407 
       
   408 
       
   409 # Subroutine to return a function call to mknew<type>object(<arg>)
       
   410 #
       
   411 def mkobject(type, arg):
       
   412     if type[:9] == 'unsigned ':
       
   413         type = type[9:]
       
   414         return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
       
   415     return 'mknew' + type + 'object(' + arg + ')'
       
   416 
       
   417 
       
   418 defined_archs = []
       
   419 
       
   420 # usage: cgen [ -Dmach ... ] [ file ]
       
   421 for arg in sys.argv[1:]:
       
   422     if arg[:2] == '-D':
       
   423         defined_archs.append(arg[2:])
       
   424     else:
       
   425         # Open optional file argument
       
   426         sys.stdin = open(arg, 'r')
       
   427 
       
   428 
       
   429 # Input line number
       
   430 lno = 0
       
   431 
       
   432 
       
   433 # Input is divided in two parts, separated by a line containing '%%'.
       
   434 #       <part1>         -- literally copied to stdout
       
   435 #       <part2>         -- stub definitions
       
   436 
       
   437 # Variable indicating the current input part.
       
   438 #
       
   439 part = 1
       
   440 
       
   441 # Main loop over the input
       
   442 #
       
   443 while 1:
       
   444     try:
       
   445         line = raw_input()
       
   446     except EOFError:
       
   447         break
       
   448     #
       
   449     lno = lno+1
       
   450     words = string.split(line)
       
   451     #
       
   452     if part == 1:
       
   453         #
       
   454         # In part 1, copy everything literally
       
   455         # except look for a line of just '%%'
       
   456         #
       
   457         if words == ['%%']:
       
   458             part = part + 1
       
   459         else:
       
   460             #
       
   461             # Look for names of manually written
       
   462             # stubs: a single percent followed by the name
       
   463             # of the function in Python.
       
   464             # The stub name is derived by prefixing 'gl_'.
       
   465             #
       
   466             if words and words[0][0] == '%':
       
   467                 func = words[0][1:]
       
   468                 if (not func) and words[1:]:
       
   469                     func = words[1]
       
   470                 if func:
       
   471                     functions.append(func)
       
   472             else:
       
   473                 print line
       
   474         continue
       
   475     if not words:
       
   476         continue                # skip empty line
       
   477     elif words[0] == 'if':
       
   478         # if XXX rest
       
   479         # if !XXX rest
       
   480         if words[1][0] == '!':
       
   481             if words[1][1:] in defined_archs:
       
   482                 continue
       
   483         elif words[1] not in defined_archs:
       
   484             continue
       
   485         words = words[2:]
       
   486     if words[0] == '#include':
       
   487         print line
       
   488     elif words[0][:1] == '#':
       
   489         pass                    # ignore comment
       
   490     elif words[0] not in return_types:
       
   491         err('Line', lno, ': bad return type :', words[0])
       
   492     elif len(words) < 2:
       
   493         err('Line', lno, ': no funcname :', line)
       
   494     else:
       
   495         if len(words) % 2 <> 0:
       
   496             err('Line', lno, ': odd argument list :', words[2:])
       
   497         else:
       
   498             database = []
       
   499             try:
       
   500                 for i in range(2, len(words), 2):
       
   501                     x = checkarg(words[i], words[i+1])
       
   502                     database.append(x)
       
   503                 print
       
   504                 print '/*',
       
   505                 for w in words: print w,
       
   506                 print '*/'
       
   507                 generate(words[0], words[1], database)
       
   508             except arg_error, msg:
       
   509                 err('Line', lno, ':', msg)
       
   510 
       
   511 
       
   512 print
       
   513 print 'static struct PyMethodDef gl_methods[] = {'
       
   514 for func in functions:
       
   515     print '\t{"' + func + '", gl_' + func + '},'
       
   516 print '\t{NULL, NULL} /* Sentinel */'
       
   517 print '};'
       
   518 print
       
   519 print 'void'
       
   520 print 'initgl()'
       
   521 print '{'
       
   522 print '\t(void) Py_InitModule("gl", gl_methods);'
       
   523 print '}'