brender-v1.3.2/make/classgen.pl

233 lines
4.2 KiB
Perl
Raw Normal View History

# Convert a C++ class file into a C header file
#
# makes alot of assumptions about the layout of the C++ file
#
while(<STDIN>) {
# 'class' <class_name> [: ['public'] <super_class_name> ] '{'
#
if(/^\s*class\s+(\w+)\s*(:\s*(public)?\s*(\w*))?\s*{/) {
$class = $1;
$super = $4;
# print "Class '$1' super='$4'\n";
push(@classes,$class);
# Construct class macro name
#
# Build macro name
#
@class_words = split("_",$class);
# See if first word of class name is some generic prefix
# and drop it if so
#
if($class_words[0] eq "br" || $class_words[0] eq "brp") {
shift(@class_words);
}
$macro_name = "";
foreach $w (@class_words) {
$macro_name .= "\u$w";
}
$class_macro_names{$class} = $macro_name;
# Initialise methods list from superclass
#
@this_methods = split(" ",$class_methods{$super});
# Read class definition
#
while(<STDIN>) {
last if(/^\s*}/);
# 'virtual' <return type> 'BR_METHOD' <name> '(' <args> [= 0] [';']
#
if(/^\s*virtual\s+(.*)\s+BR_METHOD\s+(\w+)\s*\(([^;=]*)\s*(=\s*0)?\s*(;)?\s*$/) {
$method = "$class\:\:$2";
$args = $3;
push(@this_methods,$method);
$method_return{$method} = $1;
# Read any remaining argument lines until a terminating semicolon is found
#
if(!$5) {
while(<STDIN>) {
if(/\s*([^;=]*)\s*(=\s*0)?\s*(;?)/) {
$args .= $1;
last if($3);
}
}
}
# Tidy up argument list:
# squeeze out white space
# remove trailing ')'
# change '&' to '*' (references to pointers)
# change 'class' to 'struct'
# remove any leading and trailing space
#
$args =~ tr/\n\t \r/ /s;
$args =~ s/\)\s*$//;
$args =~ s/\&/\*/;
$args =~ s/^\s*(.*)\s*/\1/;
$method_args{$method} = $args if($args ne "void");
# print " method[$method] args[$method_args{$method}] ret[$method_return{$method}]\n";
}
# Any line with CG_PUBLIC in it gets added to front of class
#
if(/CG_PUBLIC/) {
s/CG_PUBLIC//g;
$class_public{$class} .= $_;
}
}
# Remember class list
#
$class_methods{$class} = join(" ",@this_methods);
}
}
# Start building output file
#
print <<END;
/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* Automatically generated by classgen.pl
*/
#ifndef _\U$ARGV[0]\E_H_
#define _\U$ARGV[0]\E_H_
#ifdef __cplusplus
extern "C" {
#endif
#define class struct
END
# Class declarations
#
foreach $class (@classes) {
print "struct $class;\n";
}
print "\n\n";
# Classes
#
foreach $class (@classes) {
@this_methods = split(" ",$class_methods{$class});
print <<END;
struct ${class}_dispatch;
#ifndef \U${class}\E_PRIVATE
typedef struct $class {
struct ${class}_dispatch *dispatch;
$class_public{$class}
} $class;
#endif
struct ${class}_dispatch {
END
foreach $method (@this_methods) {
$ret = $method_return{$method};
$args = $method_args{$method};
($m_class, $m_name) = split("::",$method);
# Generate vtbl entry
#
print "\t$ret BR_CMETHOD_PTR_DECL($m_class, $m_name)(\n";
print "\t\tstruct $m_class *self";
foreach $arg (split(",",$args)) {
$arg =~ s/^\s*(.*)\s*/\1/;
print ",\n\t\t$arg";
}
print ");\n";
}
print "};\n";
};
# Generate C macros for calling methods
#
foreach $method (sort(keys(%method_return))) {
@args = split(",",$method_args{$method});
($m_class, $m_name) = split("::",$method);
# Construct comma seperated list of arguments for macro
#
$alist = "";
foreach $a ((1 .. @args)) {
$alist .= ", a$a";
}
$define_name = "$class_macro_names{$m_class}\u$m_name";
print "#define $define_name(self$alist) BR_CMETHOD_CALL($m_class,$m_name,self)(($m_class *)self$alist)\n";
}
# Generate templates for dispatch tables
#
print <<END;
/*
* Example templates for class dispatch tables
*/
#if 0
END
foreach $class (@classes) {
@this_methods = split(" ",$class_methods{$class});
print <<END;
/*
* Example dispatch table for $class
*/
static struct ${class}_dispatch \l$class_macro_names{$class}Dispatch = {
END
foreach $method (split(" ",$class_methods{$class})) {
($m_class, $m_name) = split("::",$method);
printf("\tBR_CMETHOD_REF(%-32s %s),\n", $m_class . "," , $m_name);
}
print "};\n\n";
}
print <<END;
#endif
#undef class
#ifdef __cplusplus
};
#endif
#endif
END