glew/auto/bin/parse_spec.pl
Matthias Bentrup 0c1a32c5e4 Add deleters to functions that exist both in core and extensions.
Parts of later GL versions are often published as extension too, so
these functions may be queried twice.
2015-12-16 21:16:06 +10:00

406 lines
13 KiB
Perl
Executable File

#!/usr/bin/perl
##
## Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>
## Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>
##
## This program is distributed under the terms and conditions of the GNU
## General Public License Version 2 as published by the Free Software
## Foundation or, at your option, any later version.
use strict;
use warnings;
sub compile_regex
{
my $regex = join('', @_);
return qr/$regex/
}
my @sections = (
"Name",
"Name Strings?",
"New Procedures and Functions",
"New Tokens.*", # Optional (GL/WGL/GLX/...) suffix
"Additions to Chapter.*",
);
my %typemap = (
bitfield => "GLbitfield",
boolean => "GLboolean",
# fsck up in EXT_vertex_array
Boolean => "GLboolean",
byte => "GLbyte",
clampd => "GLclampd",
clampf => "GLclampf",
double => "GLdouble",
enum => "GLenum",
# Intel fsck up
Glenum => "GLenum",
float => "GLfloat",
half => "GLhalf",
int => "GLint",
short => "GLshort",
sizei => "GLsizei",
ubyte => "GLubyte",
uint => "GLuint",
ushort => "GLushort",
DMbuffer => "void *",
# Nvidia video output fsck up
int64EXT => "GLint64EXT",
uint64EXT=> "GLuint64EXT",
# ARB VBO introduces these.
sizeiptr => "GLsizeiptr",
intptr => "GLintptr",
sizeiptrARB => "GLsizeiptrARB",
intptrARB => "GLintptrARB",
# ARB shader objects introduces these, charARB is at least 8 bits,
# handleARB is at least 32 bits
charARB => "GLcharARB",
handleARB => "GLhandleARB",
char => "GLchar",
# OpenGL 3.2 and GL_ARB_sync
int64 => "GLint64",
uint64 => "GLuint64",
sync => "GLsync",
# AMD_debug_output
DEBUGPROCAMD => "GLDEBUGPROCAMD",
# ARB_debug_output
DEBUGPROCARB => "GLDEBUGPROCARB",
# KHR_debug
DEBUGPROC => "GLDEBUGPROC",
vdpauSurfaceNV => "GLvdpauSurfaceNV",
# GLX 1.3 defines new types which might not be available at compile time
#GLXFBConfig => "void*",
#GLXFBConfigID => "XID",
#GLXContextID => "XID",
#GLXWindow => "XID",
#GLXPbuffer => "XID",
# Weird stuff to some SGIX extension
#GLXFBConfigSGIX => "void*",
#GLXFBConfigIDSGIX => "XID",
);
my %voidtypemap = (
void => "GLvoid",
);
my %taboo_tokens = (
GL_ZERO => 1,
);
# list of function definitions to be ignored, unless they are being defined in
# the given spec. This is an ugly hack arround the fact that people writing
# spec files seem to shut down all brain activity while they are at this task.
#
# This will be moved to its own file eventually.
#
# (mem, 2003-03-19)
my %fnc_ignore_list = (
"BindProgramARB" => "ARB_vertex_program",
"ColorSubTableEXT" => "EXT_color_subtable",
"DeleteProgramsARB" => "ARB_vertex_program",
"GenProgramsARB" => "ARB_vertex_program",
"GetProgramEnvParameterdvARB" => "ARB_vertex_program",
"GetProgramEnvParameterfvARB" => "ARB_vertex_program",
"GetProgramLocalParameterdvARB" => "ARB_vertex_program",
"GetProgramLocalParameterfvARB" => "ARB_vertex_program",
"GetProgramStringARB" => "ARB_vertex_program",
"GetProgramivARB" => "ARB_vertex_program",
"IsProgramARB" => "ARB_vertex_program",
"ProgramEnvParameter4dARB" => "ARB_vertex_program",
"ProgramEnvParameter4dvARB" => "ARB_vertex_program",
"ProgramEnvParameter4fARB" => "ARB_vertex_program",
"ProgramEnvParameter4fvARB" => "ARB_vertex_program",
"ProgramLocalParameter4dARB" => "ARB_vertex_program",
"ProgramLocalParameter4dvARB" => "ARB_vertex_program",
"ProgramLocalParameter4fARB" => "ARB_vertex_program",
"ProgramLocalParameter4fvARB" => "ARB_vertex_program",
"ProgramStringARB" => "ARB_vertex_program",
"glXCreateContextAttribsARB" => "ARB_create_context_profile",
"wglCreateContextAttribsARB" => "WGL_ARB_create_context_profile",
);
my %regex = (
eofnc => qr/(?:\);?$|^$)/, # )$ | );$ | ^$
extname => qr/^[A-Z][A-Za-z0-9_]+$/,
none => qr/^\(none\)$/,
function => qr/^(.+) ([a-z][a-z0-9_]*) \((.+)\)$/i,
prefix => qr/^(?:[aw]?gl|glX)/, # gl | agl | wgl | glX
tprefix => qr/^(?:[AW]?GL|GLX)_/, # GL_ | AGL_ | WGL_ | GLX_
section => compile_regex('^(', join('|', @sections), ')$'), # sections in spec
token => qr/^([A-Z0-9][A-Z0-9_x]*):?\s+((?:0x)?[0-9A-F]+)([^\?]*)$/, # define tokens
types => compile_regex('\b(', join('|', keys %typemap), ')\b'), # var types
voidtype => compile_regex('\b(', keys %voidtypemap, ')\b '), # void type
);
# reshapes the the function declaration from multiline to single line form
sub normalize_prototype
{
local $_ = join(" ", @_);
s/\s+/ /g; # multiple whitespace -> single space
s/\<.*\>//g; # remove <comments> from direct state access extension
s/\<.*$//g; # remove incomplete <comments> from direct state access extension
s#/\*.*\*/##g; # remove /* ... */ comments
s/\s*\(\s*/ \(/; # exactly one space before ( and none after
s/\s*\)\s*/\)/; # no space before or after )
s/\s*\*([a-zA-Z])/\* $1/; # "* identifier"
s/\*wgl/\* wgl/; # "* wgl"
s/\*glX/\* glX/; # "* glX"
s/\.\.\./void/; # ... -> void
s/;$//; # remove ; at the end of the line
return $_;
}
# Ugly hack to work arround the fact that functions are declared in more
# than one spec file.
sub ignore_function($$)
{
return exists($fnc_ignore_list{$_[0]}) && $fnc_ignore_list{$_[0]} ne $_[1]
}
sub parse_spec($)
{
my $filename = shift;
my $extname = "";
my $vendortag = "";
my @extnames = ();
my %functions = ();
my %tokens = ();
my $section = "";
my @fnc = ();
my %proc = (
"Name" => sub {
if (/^([a-z0-9]+)_([a-z0-9_]+)/i)
{
$extname = "$1_$2";
$vendortag = $1;
}
},
"Name Strings" => sub {
# Add extension name to extension list
# Initially use $extname if (none) specified
if (/$regex{none}/)
{
$_ = $extname;
}
if (/$regex{extname}/)
{
# prefix with "GL_" if prefix not present
s/^/GL_/ unless /$regex{tprefix}/o;
# Add extension name to extension list
push @extnames, $_;
}
},
"New Procedures and Functions" => sub {
# if line matches end of function
if (/$regex{eofnc}/)
{
# add line to function declaration
push @fnc, $_;
# if normalized version of function looks like a function
if (normalize_prototype(@fnc) =~ /$regex{function}/)
{
# get return type, name, and arguments from regex
my ($return, $name, $parms) = ($1, $2, $3);
if (!ignore_function($name, $extname))
{
# prefix with "gl" if prefix not present
$name =~ s/^/gl/ unless $name =~ /$regex{prefix}/;
# is this a pure GL function?
if ($name =~ /^gl/ && $name !~ /^glX/)
{
# apply typemaps
$return =~ s/$regex{types}/$typemap{$1}/og;
$return =~ s/GLvoid/void/og;
$return =~ s/void\*/void */og;
$parms =~ s/$regex{types}/$typemap{$1}/og;
$parms =~ s/$regex{voidtype}/$voidtypemap{$1}/og;
$parms =~ s/GLvoid/void/og;
$parms =~ s/ void\* / void */og;
}
# add to functions hash
$functions{$name} = {
rtype => $return,
parms => $parms,
};
}
}
# reset function declaration
@fnc = ();
} elsif ($_ ne "" and $_ ne "None") {
# if not eof, add line to function declaration
push @fnc, $_
}
},
"New Tokens" => sub {
if (/$regex{token}/)
{
my ($name, $value) = ($1, $2);
# prefix with "GL_" if prefix not present
$name =~ s/^/GL_/ unless $name =~ /$regex{tprefix}/;
# Add (name, value) pair to tokens hash, unless it's taboo
$tokens{$name} = $value unless exists $taboo_tokens{$name};
}
},
);
# Some people can't read, the template clearly says "Name String_s_"
$proc{"Name String"} = $proc{"Name Strings"};
# Open spec file
open SPEC, "<$filename" or return;
# For each line of SPEC
while(<SPEC>)
{
# Delete trailing newline character
chomp;
# Remove trailing white spaces
s/\s+$//;
# If starts with a capital letter, it must be a new section
if (/^[A-Z]/)
{
# Match section name with one of the predefined names
$section = /$regex{section}/o ? $1 : "default";
} else {
# Line is internal to a section
# Remove leading whitespace
s/^\s+//;
# Call appropriate section processing function if it exists
&{$proc{$section}} if exists $proc{$section};
}
}
close SPEC;
return ($extname, \@extnames, \%tokens, \%functions);
}
#----------------------------------------------------------------------------------------
my @speclist = ();
my %extensions = ();
my %fcn_in_core = ();
my $ext_dir = shift;
my $core_dir = shift;
my $reg_http = "http://www.opengl.org/registry/specs/";
# Take command line arguments or read list from file
if (@ARGV)
{
@speclist = @ARGV;
} else {
local $/; #???
@speclist = split "\n", (<>);
}
# Get functions moved to the GL core
my %core_fnc = ();
foreach my $spec (<$core_dir/GL_VERSION_*>)
{
my $vsn = $spec;
$vsn =~ s/.*\/GL_VERSION_(\d+)_(\d+)/$1.$2/;
open SPEC, "<$spec";
while (<SPEC>)
{
if ($_ =~ qr/^(.+) ([a-z][a-z0-9_]*) \((.+)\)\s*(~.*)?$/i )
{
$core_fnc{$2} = $vsn;
}
}
close SPEC;
}
foreach my $spec (sort @speclist)
{
my ($extname, $extnames, $tokens, $functions) = parse_spec($spec);
foreach my $ext (@{$extnames})
{
my $info = "$ext_dir/" . $ext;
open EXT, ">$info";
print EXT $ext . "\n"; # Extension name
my $specname = $spec;
$specname =~ s/registry\/gl\/specs\///;
print EXT $reg_http . $specname . "\n"; # Extension info URL
print EXT $ext . "\n"; # Extension string
print EXT "\n"; # Resuses nothing by default
my $prefix = $ext;
$prefix =~ s/^(.+?)(_.+)$/$1/;
foreach my $token (sort {
if (${$tokens}{$a} eq ${$tokens}{$b}) {
$a cmp $b
} else {
if (${$tokens}{$a} =~ /_/) {
if (${$tokens}{$b} =~ /_/) {
$a cmp $b
} else {
-1
}
} else {
if (${$tokens}{$b} =~ /_/) {
1
} else {
if (hex ${$tokens}{$a} eq hex ${$tokens}{$b})
{
$a cmp $b
} else {
hex ${$tokens}{$a} <=> hex ${$tokens}{$b}
}
}
}
}
} keys %{$tokens})
{
if ($token =~ /^$prefix\_.*/i)
{
print EXT "\t" . $token . " " . ${\%{$tokens}}{$token} . "\n";
}
}
foreach my $function (sort keys %{$functions})
{
if ($function =~ /^$prefix.*/i)
{
my $deleter = "";
if ($core_fnc{$function})
{
$deleter = " ~ " . $core_fnc{$function};
}
print EXT "\t" . ${$functions}{$function}{rtype} . " " . $function . " (" . ${$functions}{$function}{parms} . ")" . $deleter . "\n";
}
}
close EXT;
}
}