From 27ced2422a87714c5c2afea10b946cea977a512c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Thu, 1 Dec 2011 09:00:50 +0000 Subject: [PATCH] Minor cleanups and better documentation for the spec generation scripts. --- common/os_win32.cpp | 1 + specs/scripts/README | 12 --------- specs/scripts/README.markdown | 54 +++++++++++++++++++++++++++++++++++++ specs/scripts/cdecl.py | 17 ++++++------ specs/scripts/gltxt.py | 63 ++++++++++++++++++++++++++++++++++++------- 5 files changed, 118 insertions(+), 29 deletions(-) delete mode 100644 specs/scripts/README create mode 100644 specs/scripts/README.markdown diff --git a/common/os_win32.cpp b/common/os_win32.cpp index 13dd4f8..0b72433 100644 --- a/common/os_win32.cpp +++ b/common/os_win32.cpp @@ -196,6 +196,7 @@ int execute(char * const * args) &processInformation )) { log("error: failed to execute %s\n", arg0); + return -1; } WaitForSingleObject(processInformation.hProcess, INFINITE); diff --git a/specs/scripts/README b/specs/scripts/README deleted file mode 100644 index 6df2a3d..0000000 --- a/specs/scripts/README +++ /dev/null @@ -1,12 +0,0 @@ -This directory contains several helper scripts that facilitate the generation -of the API descriptions from specs and/or header files. - -The specs/headers are not expressive enough, which is why we can't just code -generate everything from them. - -For GL the typical procedure is to run - - make -B - -and then manually crossport new functions / enums to the files in the top dir -via a side-by-side diff tool, such as gvimdiff. diff --git a/specs/scripts/README.markdown b/specs/scripts/README.markdown new file mode 100644 index 0000000..66f9faa --- /dev/null +++ b/specs/scripts/README.markdown @@ -0,0 +1,54 @@ +This directory contains several helper scripts that facilitate the generation +of the API descriptions from specs and/or header files. + +The specs/headers are not expressive enough, which is why we can't just code +generate everything from them directly. However the scripts in this directory +usually get 90% of the work done automatically. + + +OpenGL +====== + +For OpenGL the typical procedure is to run + + make -B + +which will generate several python scripts with prototypes and defines from the +Khronos `.spec` files: + +* glapi.py + +* glparams.py + +* glxapi.py + +* wglapi.py + +* wglenum.py + +and then manually crossport new functions / enums to the identically named +files in the parent dir via a side-by-side diff tool, such as gvimdiff. + + +OpenGL ES +========= + +Khronos doesn't provide `.spec` files for OpenGL ES. But the `gltxt.py` script +can extract and convert prototypes for the `.txt` extension specifications: + + $ ./gltxt.py http://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt + # GL_OES_mapbuffer + GlFunction(Void, "glGetBufferPointervOES", [(GLenum, "target"), (GLenum, "pname"), (OpaquePointer(OpaquePointer(Void)), "params")], sideeffects=False), + GlFunction(OpaquePointer(Void), "glMapBufferOES", [(GLenum, "target"), (GLenum, "access")]), + GlFunction(GLboolean, "glUnmapBufferOES", [(GLenum, "target")]), + + +Generic +======= + +When the domain specific scripts don't work the fallback solution is `cdecl.py`, which can parse most C declarations: + + $ echo 'void *memcpy(void *dest, const void *src, size_t n);' | ./cdecl.py + Function(OpaquePointer(Void), "memcpy", [(OpaquePointer(Void), "dest"), (OpaquePointer(Const(Void)), "src"), (size_t, "n")]), + + diff --git a/specs/scripts/cdecl.py b/specs/scripts/cdecl.py index 613561c..d6ee058 100755 --- a/specs/scripts/cdecl.py +++ b/specs/scripts/cdecl.py @@ -34,7 +34,7 @@ import re import optparse -class Parser: +class DeclParser: token_re = re.compile(r'(\d[x0-9a-fA-F.UL]*|\w+|\s+|.)') @@ -354,14 +354,15 @@ class Parser: return type - - - - def main(): - parser = Parser() - for arg in sys.argv[1:]: - parser.parse(open(arg, 'rt').read()) + args = sys.argv[1:] + + parser = DeclParser() + if args: + for arg in args: + parser.parse(open(arg, 'rt').read()) + else: + parser.parse(sys.stdin.read()) if __name__ == '__main__': diff --git a/specs/scripts/gltxt.py b/specs/scripts/gltxt.py index 7fc62f5..4ce9232 100755 --- a/specs/scripts/gltxt.py +++ b/specs/scripts/gltxt.py @@ -31,6 +31,7 @@ import sys import re import optparse +from urllib2 import urlopen def stderr(x): @@ -91,6 +92,8 @@ class LineParser: class TxtParser(LineParser): + section_re = re.compile(r'^([A-Z]\w+)( \w+)*$') + property_re = re.compile(r'^\w+:') prototype_re = re.compile(r'^(\w+)\((.*)\)$') @@ -99,22 +102,51 @@ class TxtParser(LineParser): self.prefix = prefix def parse(self): - line = self.consume() - while not line.startswith("New Procedures and Functions"): + while not self.eof(): + while not self.eof(): + line = self.lookahead() + if self.eof(): + return + mo = self.section_re.match(line) + if mo: + break + self.consume() line = self.consume() - self.parse_procs() + self.parse_section(line) + print + + def parse_section(self, name): + if name == 'Name Strings': + self.parse_strings() + if name == 'New Procedures and Functions': + self.parse_procs() + + def parse_strings(self): + while not self.eof(): + line = self.lookahead() + if not line.strip(): + self.consume() + continue + if not line.startswith(' '): + break + self.consume() + name = line.strip() + print ' # %s' % name def parse_procs(self): lines = [] - while True: - line = self.consume() + while not self.eof(): + line = self.lookahead() if not line.strip(): + self.consume() continue if not line.startswith(' '): break + self.consume() lines.append(line.strip()) - if line.endswith(';'): - self.parse_proc(' '.join(lines)) + if line[-1] in (';', ')'): + prototype = ' '.join(lines) + self.parse_proc(prototype) lines = [] token_re = re.compile(r'(\w+|\s+|.)') @@ -163,8 +195,21 @@ class TxtParser(LineParser): def main(): - for arg in sys.argv[1:]: - parser = TxtParser(open(arg, 'rt'), prefix='gl') + optparser = optparse.OptionParser( + usage="\n\t%prog [options] [SPEC] ") + optparser.add_option( + '-p', '--prefix', metavar='STRING', + type="string", dest="prefix", default='gl', + help="function prefix [default: %default]") + + (options, args) = optparser.parse_args(sys.argv[1:]) + + for arg in args: + if arg.startswith('http://'): + stream = urlopen(arg, 'rt') + else: + stream = open(arg, 'rt') + parser = TxtParser(stream, prefix = options.prefix) parser.parse() -- 2.7.4