home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Modules / cgen.py < prev    next >
Encoding:
Python Source  |  2000-10-25  |  12.2 KB  |  521 lines

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