Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1900 → Rev 1901

/programs/develop/libraries/Mesa/src/mapi/glapi/gen-es/gl_parse_header.py
0,0 → 1,450
#!/usr/bin/python
#
# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
 
import sys
import os.path
import getopt
import re
 
GLAPI = "../../glapi/gen"
sys.path.append(GLAPI)
 
class HeaderParser(object):
"""Parser for GL header files."""
 
def __init__(self, verbose=0):
# match #if and #ifdef
self.IFDEF = re.compile('#\s*if(n?def\s+(?P<ifdef>\w+)|\s+(?P<if>.+))')
# match #endif
self.ENDIF = re.compile('#\s*endif')
# match typedef abc def;
self.TYPEDEF = re.compile('typedef\s+(?P<from>[\w ]+)\s+(?P<to>\w+);')
# match #define XYZ VAL
self.DEFINE = re.compile('#\s*define\s+(?P<key>\w+)(?P<value>\s+[\w"]*)?')
# match GLAPI
self.GLAPI = re.compile('^GL_?API(CALL)?\s+(?P<return>[\w\s*]+[\w*])\s+(GL)?_?APIENTRY\s+(?P<name>\w+)\s*\((?P<params>[\w\s(,*\[\])]+)\)\s*;')
 
self.split_params = re.compile('\s*,\s*')
self.split_ctype = re.compile('(\W)')
# ignore GL_VERSION_X_Y
self.ignore_enum = re.compile('GL(_ES)?_VERSION(_ES_C[ML])?_\d_\d')
 
self.verbose = verbose
self._reset()
 
def _reset(self):
"""Reset to initial state."""
self.ifdef_levels = []
self.need_char = False
 
# use typeexpr?
def _format_ctype(self, ctype, fix=True):
"""Format a ctype string, optionally fix it."""
# split the type string
tmp = self.split_ctype.split(ctype)
tmp = [s for s in tmp if s and s != " "]
 
pretty = ""
for i in xrange(len(tmp)):
# add missing GL prefix
if (fix and tmp[i] != "const" and tmp[i] != "*" and
not tmp[i].startswith("GL")):
tmp[i] = "GL" + tmp[i]
 
if i == 0:
pretty = tmp[i]
else:
sep = " "
if tmp[i - 1] == "*":
sep = ""
pretty += sep + tmp[i]
return pretty
 
# use typeexpr?
def _get_ctype_attrs(self, ctype):
"""Get the attributes of a ctype."""
is_float = (ctype.find("float") != -1 or ctype.find("double") != -1)
is_signed = not (ctype.find("unsigned") != -1)
 
size = 0
if ctype.find("char") != -1:
size = 1
elif ctype.find("short") != -1:
size = 2
elif ctype.find("int") != -1:
size = 4
elif is_float:
if ctype.find("float") != -1:
size = 4
else:
size = 8
 
return (size, is_float, is_signed)
 
def _parse_define(self, line):
"""Parse a #define line for an <enum>."""
m = self.DEFINE.search(line)
if not m:
if self.verbose and line.find("#define") >= 0:
print "ignore %s" % (line)
return None
 
key = m.group("key").strip()
val = m.group("value").strip()
 
# enum must begin with GL_ and be all uppercase
if ((not (key.startswith("GL_") and key.isupper())) or
(self.ignore_enum.match(key) and val == "1")):
if self.verbose:
print "ignore enum %s" % (key)
return None
 
return (key, val)
 
def _parse_typedef(self, line):
"""Parse a typedef line for a <type>."""
m = self.TYPEDEF.search(line)
if not m:
if self.verbose and line.find("typedef") >= 0:
print "ignore %s" % (line)
return None
 
f = m.group("from").strip()
t = m.group("to").strip()
if not t.startswith("GL"):
if self.verbose:
print "ignore type %s" % (t)
return None
attrs = self._get_ctype_attrs(f)
 
return (f, t, attrs)
 
def _parse_gl_api(self, line):
"""Parse a GLAPI line for a <function>."""
m = self.GLAPI.search(line)
if not m:
if self.verbose and line.find("APIENTRY") >= 0:
print "ignore %s" % (line)
return None
 
rettype = m.group("return")
rettype = self._format_ctype(rettype)
if rettype == "GLvoid":
rettype = ""
 
name = m.group("name")
 
param_str = m.group("params")
chunks = self.split_params.split(param_str)
chunks = [s.strip() for s in chunks]
if len(chunks) == 1 and (chunks[0] == "void" or chunks[0] == "GLvoid"):
chunks = []
 
params = []
for c in chunks:
# split type and variable name
idx = c.rfind("*")
if idx < 0:
idx = c.rfind(" ")
if idx >= 0:
idx += 1
ctype = c[:idx]
var = c[idx:]
else:
ctype = c
var = "unnamed"
 
# convert array to pointer
idx = var.find("[")
if idx >= 0:
var = var[:idx]
ctype += "*"
 
ctype = self._format_ctype(ctype)
var = var.strip()
 
if not self.need_char and ctype.find("GLchar") >= 0:
self.need_char = True
 
params.append((ctype, var))
 
return (rettype, name, params)
 
def _change_level(self, line):
"""Parse a #ifdef line and change level."""
m = self.IFDEF.search(line)
if m:
ifdef = m.group("ifdef")
if not ifdef:
ifdef = m.group("if")
self.ifdef_levels.append(ifdef)
return True
m = self.ENDIF.search(line)
if m:
self.ifdef_levels.pop()
return True
return False
 
def _read_header(self, header):
"""Open a header file and read its contents."""
lines = []
try:
fp = open(header, "rb")
lines = fp.readlines()
fp.close()
except IOError, e:
print "failed to read %s: %s" % (header, e)
return lines
 
def _cmp_enum(self, enum1, enum2):
"""Compare two enums."""
# sort by length of the values as strings
val1 = enum1[1]
val2 = enum2[1]
ret = len(val1) - len(val2)
# sort by the values
if not ret:
val1 = int(val1, 16)
val2 = int(val2, 16)
ret = val1 - val2
# in case int cannot hold the result
if ret > 0:
ret = 1
elif ret < 0:
ret = -1
# sort by the names
if not ret:
if enum1[0] < enum2[0]:
ret = -1
elif enum1[0] > enum2[0]:
ret = 1
return ret
 
def _cmp_type(self, type1, type2):
"""Compare two types."""
attrs1 = type1[2]
attrs2 = type2[2]
# sort by type size
ret = attrs1[0] - attrs2[0]
# float is larger
if not ret:
ret = attrs1[1] - attrs2[1]
# signed is larger
if not ret:
ret = attrs1[2] - attrs2[2]
# reverse
ret = -ret
return ret
 
def _cmp_function(self, func1, func2):
"""Compare two functions."""
name1 = func1[1]
name2 = func2[1]
ret = 0
# sort by the names
if name1 < name2:
ret = -1
elif name1 > name2:
ret = 1
return ret
 
def _postprocess_dict(self, hdict):
"""Post-process a header dict and return an ordered list."""
hlist = []
largest = 0
for key, cat in hdict.iteritems():
size = len(cat["enums"]) + len(cat["types"]) + len(cat["functions"])
# ignore empty category
if not size:
continue
 
cat["enums"].sort(self._cmp_enum)
# remove duplicates
dup = []
for i in xrange(1, len(cat["enums"])):
if cat["enums"][i] == cat["enums"][i - 1]:
dup.insert(0, i)
for i in dup:
e = cat["enums"].pop(i)
if self.verbose:
print "remove duplicate enum %s" % e[0]
 
cat["types"].sort(self._cmp_type)
cat["functions"].sort(self._cmp_function)
 
# largest category comes first
if size > largest:
hlist.insert(0, (key, cat))
largest = size
else:
hlist.append((key, cat))
return hlist
 
def parse(self, header):
"""Parse a header file."""
self._reset()
 
if self.verbose:
print "Parsing %s" % (header)
 
hdict = {}
lines = self._read_header(header)
for line in lines:
if self._change_level(line):
continue
 
# skip until the first ifdef (i.e. __gl_h_)
if not self.ifdef_levels:
continue
 
cat_name = os.path.basename(header)
# check if we are in an extension
if (len(self.ifdef_levels) > 1 and
self.ifdef_levels[-1].startswith("GL_")):
cat_name = self.ifdef_levels[-1]
 
try:
cat = hdict[cat_name]
except KeyError:
cat = {
"enums": [],
"types": [],
"functions": []
}
hdict[cat_name] = cat
 
key = "enums"
elem = self._parse_define(line)
if not elem:
key = "types"
elem = self._parse_typedef(line)
if not elem:
key = "functions"
elem = self._parse_gl_api(line)
 
if elem:
cat[key].append(elem)
 
if self.need_char:
if self.verbose:
print "define GLchar"
elem = self._parse_typedef("typedef char GLchar;")
cat["types"].append(elem)
return self._postprocess_dict(hdict)
 
def spaces(n, str=""):
spaces = n - len(str)
if spaces < 1:
spaces = 1
return " " * spaces
 
def output_xml(name, hlist):
"""Output a parsed header in OpenGLAPI XML."""
 
for i in xrange(len(hlist)):
cat_name, cat = hlist[i]
 
print '<category name="%s">' % (cat_name)
indent = 4
 
for enum in cat["enums"]:
name = enum[0][3:]
value = enum[1]
tab = spaces(41, name)
attrs = 'name="%s"%svalue="%s"' % (name, tab, value)
print '%s<enum %s/>' % (spaces(indent), attrs)
 
if cat["enums"] and cat["types"]:
print
 
for type in cat["types"]:
ctype = type[0]
size, is_float, is_signed = type[2]
 
attrs = 'name="%s"' % (type[1][2:])
attrs += spaces(16, attrs) + 'size="%d"' % (size)
if is_float:
attrs += ' float="true"'
elif not is_signed:
attrs += ' unsigned="true"'
 
print '%s<type %s/>' % (spaces(indent), attrs)
 
for func in cat["functions"]:
print
ret = func[0]
name = func[1][2:]
params = func[2]
 
attrs = 'name="%s" offset="assign"' % name
print '%s<function %s>' % (spaces(indent), attrs)
 
for param in params:
attrs = 'name="%s" type="%s"' % (param[1], param[0])
print '%s<param %s/>' % (spaces(indent * 2), attrs)
if ret:
attrs = 'type="%s"' % ret
print '%s<return %s/>' % (spaces(indent * 2), attrs)
 
print '%s</function>' % spaces(indent)
 
print '</category>'
print
 
def show_usage():
print "Usage: %s [-v] <header> ..." % sys.argv[0]
sys.exit(1)
 
def main():
try:
args, headers = getopt.getopt(sys.argv[1:], "v")
except Exception, e:
show_usage()
if not headers:
show_usage()
 
verbose = 0
for arg in args:
if arg[0] == "-v":
verbose += 1
 
need_xml_header = True
parser = HeaderParser(verbose)
for h in headers:
h = os.path.abspath(h)
hlist = parser.parse(h)
 
if need_xml_header:
print '<?xml version="1.0"?>'
print '<!DOCTYPE OpenGLAPI SYSTEM "%s/gl_API.dtd">' % GLAPI
need_xml_header = False
 
print
print '<!-- %s -->' % (h)
print '<OpenGLAPI>'
print
output_xml(h, hlist)
print '</OpenGLAPI>'
 
if __name__ == '__main__':
main()