diff options
Diffstat (limited to 'gnulib-local/build-aux/moopp')
-rwxr-xr-x | gnulib-local/build-aux/moopp | 760 |
1 files changed, 760 insertions, 0 deletions
diff --git a/gnulib-local/build-aux/moopp b/gnulib-local/build-aux/moopp new file mode 100755 index 0000000..6be82fc --- /dev/null +++ b/gnulib-local/build-aux/moopp @@ -0,0 +1,760 @@ +#!/bin/sh +# Minimal Object-Oriented style PreProcessor. + +# Copyright (C) 2006-2008 Free Software Foundation, Inc. +# Written by Bruno Haible <bruno@clisp.org>, 2006. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Usage: moopp source.oo.c source.oo.h superclass.oo.h ... +# Arguments: +# - the source file of the class, +# - the header file declaring the class, +# - the header file declaring its superclass, +# - etc. up to the root class. +# Creates four files in the current directory: +# - source.c, the preprocessing result of source.oo.c, +# - source.h, the preprocessing result of source.oo.h, +# - class.priv.h, a file declaring the private fields of the class, +# - class.vt.h, a file declaring the virtual function table of the class. + +# This implementation of the preprocessor is a quick hack. It makes assumptions +# about the source code: +# - GNU indentation style, +# - the struct declaration must be in a single line, +# - no comments on the struct declaration line, +# - no #ifs in relevant position, +# - ... +# Someday this should be rewritten to use a proper tokenizer and parser. + +# func_usage +# outputs to stdout the --help usage message. +func_usage () +{ + echo "\ +Usage: moopp [OPTION]... SOURCE.oo.c SOURCE.oo.h SUPERCLASS.oo.h ... + +Preprocesses SOURCE.oo.c into CLASS.c and SOURCE.oo.h into CLASS.h, +where CLASS is the name of the class defined in these files. + +See moo.h for the object-oriented features and the syntax of the input files. + +Options: + --help print this help and exit + --version print version information and exit + --dllexport=NAME Arrange so that the specified class name can be accessed + from outside the shared library it is compiled into. + This option can be repeated. + +Report bugs to <bruno@clisp.org>." +} + +# func_version +# outputs to stdout the --version message. +func_version () +{ + echo "$progname (GNU $package) $version" + echo "Copyright (C) 2006-2007 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law." + echo "Written by" "Bruno Haible" +} + +# func_fatal_error message +# outputs to stderr a fatal error message, and terminates the program. +func_fatal_error () +{ + echo "moopp: *** $1" 1>&2 + echo "moopp: *** Stop." 1>&2 + exit 1 +} + +# Command-line option processing. +# Removes the OPTIONS from the arguments. Sets the variables: +# - dllexports list of class names to export from Woe32 DLLs +dllexports= +while test $# -gt 0; do + case "$1" in + --dllexport | --dllexpor | --dllexpo | --dllexp | --dllex | --dlle ) + shift + if test $# = 0; then + func_fatal_error "missing argument for --dllexport" + fi + case "$1" in + -*) func_fatal_error "missing argument for --dllexport" ;; + esac + dllexports="$dllexports $1" + shift ;; + --dllexport=* ) + arg=`echo "X$1" | sed -e 's/^X--dllexport=//'` + dllexports="$dllexports $arg" + shift ;; + --help | --hel | --he | --h ) + func_usage + exit 0 ;; + --version | --versio | --versi | --vers | --ver | --ve | --v ) + func_version + exit 0 ;; + -- ) # Stop option prcessing + shift; break ;; + -* ) + func_fatal_error "unrecognized option: $option" + ;; + * ) + break ;; + esac +done + +if test $# -lt 2; then + func_fatal_error "Usage: $0 [OPTION]... source.oo.c source.oo.h superclass.oo.h ..." +fi + +# Check that all files exist. +for file +do + test -r "$file" || { + func_fatal_error "file $file does not exist" + } +done + +source_impl_file="$1" +source_header_file="$2" +shift +shift + +case "$source_impl_file" in + *.oo.c) ;; + *) func_fatal_error "invalid class source file name: $source_impl_file" ;; +esac +case "$source_header_file" in + *.oo.h) ;; + *) func_fatal_error "invalid class header file name: $source_header_file" ;; +esac + +# A sed expression that removes empty lines. +sed_remove_empty_lines='/^$/d' + +# A sed expression that removes ANSI C and ISO C99 comments. +sed_remove_comments=" +/[/][/*]/{ + ta + :a + s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)//.*,\\1, + te + s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*]\\([^*]\\|[*][^/*]\\)*[*][*]*/,\\1 , + ta + /^\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*[/][*]/{ + s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*].*,\\1 , + tu + :u + n + s,^\\([^*]\\|[*][^/*]\\)*[*][*]*/,, + tv + s,^.*\$,, + bu + :v + } + :e +}" +# The same thing as an extended regular expression, for use with +# sed --regexp-extended. +sed_remove_comments_ERE=" +/[/][/*]/{ + ta + :a + s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)//.*,\\1, + te + s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*]([^*]|[*][^/*])*[*][*]*/,\\1 , + ta + /^([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*[/][*]/{ + s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*].*,\\1 , + tu + :u + n + s,^([^*]|[*][^/*])*[*][*]*/,, + tv + s,^.*\$,, + bu + :v + } + :e +}" + +# Check that 'sed' supports the kind of regular expressions used in +# sed_remove_comments. The use of \| meaning alternation of basic regular +# expressions is a GNU extension. +sed_test='s,^\(\(a\|X\)*\)//.*,\1,' +sed_result=`echo 'aaa//bcd' | sed -e "$sed_test"` +test "$sed_result" = 'aaa' \ + || func_fatal_error "The 'sed' program is not GNU sed. Try installing GNU sed." + +# func_check_impl_syntax file +# Check the syntax of the source implementation file. +# Output: +# - classname name of the class being defined (without 'struct') +# - superclassname name of the superclass, or empty for a root class +# - impl_decl_lineno line number of the class name declaration ('struct') +# - impl_beg_lineno line number of the start of the class declaration ('{') +# - impl_end_lineno line number of the end of the class declaration ('}') +# - fields field declarations, including preprocessor directives +func_check_impl_syntax () +{ + file="$1" + sed -e "$sed_remove_comments" < "$file" | grep '^fields:' > /dev/null || { + func_fatal_error "$file does not contain 'fields:'" + } + test `sed -e "$sed_remove_comments" < "$file" | grep -c '^fields:'` = 1 || { + func_fatal_error "$file contains more than one 'fields:'" + } + fields_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^fields:' | sed -e 's,:.*,,'` + sed_before_fields="$fields_lineno"',$d' + impl_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'` + test -n "$impl_decl_lineno" || { + func_fatal_error "$file: class declaration not found" + } + class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$impl_decl_lineno"'p'` + sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' + classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"` + test -n "$classname" || { + func_fatal_error "$0: $file: class name not recognized at line $impl_decl_lineno" + } + superclassname= + if echo "$class_line" | grep ':' > /dev/null; then + sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' + superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"` + test -n "$superclassname" || { + func_fatal_error "$file: superclass name not recognized at line $impl_decl_lineno" + } + fi + impl_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'` + { test -n "$impl_beg_lineno" && test "$impl_decl_lineno" -lt "$impl_beg_lineno"; } || { + func_fatal_error "$file: opening brace of class declaration not found after line $impl_decl_lineno" + } + sed_after_fields='1,'"$fields_lineno"'d' + impl_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_fields" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'` + test -n "$impl_end_lineno" || { + func_fatal_error "$file: closing brace of class declaration not found after line $fields_lineno" + } + impl_end_lineno=`expr $fields_lineno + $impl_end_lineno` + sed_extract_fields="$impl_end_lineno"',$d;1,'"$fields_lineno"'d' + fields=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_fields"` +} + +# func_check_header_syntax file +# Check the syntax of a header file. +# Output: +# - classname name of the class being defined (without 'struct') +# - superclassname name of the superclass, or empty for a root class +# - class_decl_lineno line number of the class name declaration ('struct') +# - class_beg_lineno line number of the start of the class declaration ('{') +# - class_end_lineno line number of the end of the class declaration ('}') +# - methods newline-separated list of method declarations +func_check_header_syntax () +{ + file="$1" + sed -e "$sed_remove_comments" < "$file" | grep '^methods:' > /dev/null || { + func_fatal_error "$file does not contain 'methods:'" + } + test `sed -e "$sed_remove_comments" < "$file" | grep -c '^methods:'` = 1 || { + func_fatal_error "$file contains more than one 'methods:'" + } + methods_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^methods:' | sed -e 's,:.*,,'` + sed_before_methods="$methods_lineno"',$d' + class_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'` + test -n "$class_decl_lineno" || { + func_fatal_error "$file: class declaration not found" + } + class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$class_decl_lineno"'p'` + sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' + classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"` + test -n "$classname" || { + func_fatal_error "$0: $file: class name not recognized at line $class_decl_lineno" + } + superclassname= + if echo "$class_line" | grep ':' > /dev/null; then + sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' + superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"` + test -n "$superclassname" || { + func_fatal_error "$file: superclass name not recognized at line $class_decl_lineno" + } + fi + class_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'` + { test -n "$class_beg_lineno" && test "$class_decl_lineno" -lt "$class_beg_lineno"; } || { + func_fatal_error "$file: opening brace of class declaration not found after line $class_decl_lineno" + } + sed_after_methods='1,'"$methods_lineno"'d' + class_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_methods" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'` + test -n "$class_end_lineno" || { + func_fatal_error "$file: closing brace of class declaration not found after line $methods_lineno" + } + class_end_lineno=`expr $methods_lineno + $class_end_lineno` + sed_extract_methods="$class_end_lineno"',$d;1,'"$methods_lineno"'d' + methods=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_methods" | tr '\n' ' ' | tr ';' '\n' | sed -e 's,[ ]*$,,'` + sed_remove_valid_arg1_lines='/([ ]*'"$classname"'_t[ ]*[A-Za-z_0-9]*[ ]*[,)]/d' + sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,' + methods_with_bad_arg1=`echo "$methods" | sed -e "$sed_remove_empty_lines" -e "$sed_remove_valid_arg1_lines" -e "$sed_extract_method_name"` + if test -n "$methods_with_bad_arg1"; then + methods_with_bad_arg1=`{ echo "$methods_with_bad_arg1" | sed -e 's/$/, /' | tr -d '\n'; echo; } | sed -e 's/\(, \)*$//'` + func_fatal_error "$file: some methods don't have a first argument of type ${classname}_t: $methods_with_bad_arg1" + fi +} + +func_check_impl_syntax "$source_impl_file" +impl_classname="$classname" +impl_superclassname="$superclassname" + +func_check_header_syntax "$source_header_file" +main_classname="$classname" +main_superclassname="$superclassname" +main_class_decl_lineno="$class_decl_lineno" +main_class_beg_lineno="$class_beg_lineno" +main_class_end_lineno="$class_end_lineno" +main_methods="$methods" +all_superclasses= +all_methods="$methods" +inherited_methods= +last_header_file="$source_header_file" +expected_superclassname="$superclassname" + +for file +do + if test -z "$expected_superclassname"; then + func_fatal_error "file $last_header_file does not specify a superclass; superfluous command line argument $file" + fi + func_check_header_syntax "$file" + all_superclasses="$classname $all_superclasses" + all_methods="$methods +$all_methods" + inherited_methods="$methods +$inherited_methods" + if test "$classname" != "$expected_superclassname"; then + func_fatal_error "file $last_header_file specifies superclass '$expected_superclassname', but file $file defines class '$classname'" + fi + last_header_file="$file" + expected_superclassname="$superclassname" +done + +if test -n "$expected_superclassname"; then + func_fatal_error "$0: file $last_header_file specifies superclass '$expected_superclassname', please specify the header file that defines it as additional command line argument" +fi + +if test "$impl_classname" != "$main_classname"; then + func_fatal_error "file $source_header_file specifies class '$main_classname', but file $source_impl_file specifies class '$impl_classname'" +fi +if test "$impl_superclassname" != "$main_superclassname"; then + if test -z "$main_superclassname"; then + func_fatal_error "file $source_header_file specifies no superclass, but file $source_impl_file specifies a superclass '$impl_superclassname'" + fi + if test -z "$impl_superclassname"; then + func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies no superclass" + fi + func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies a superclass '$impl_superclassname'" +fi + +# func_start_creation file +# starts the creation of the named file. +func_start_creation () +{ + file="$1" + if test -f "$file"; then + echo "Updating $file (backup in ${file}~)" + mv -f "$file" "${file}~" || func_fatal_error "failed" + else + echo "Creating $file" + fi +} + +# func_emit_priv_h newfile +# outputs to $newfile the contents of class.priv.h. +func_emit_priv_h () +{ + newfile="$1" + { + echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' + echo + if test -n "${main_superclassname}"; then + echo "/* Field layout of superclass. */" + echo "#include \"${main_superclassname}.priv.h\"" + echo + fi + echo "/* Field layout of ${main_classname} class. */" + echo "struct ${main_classname}_representation" + echo "{" + if test -n "${main_superclassname}"; then + echo " struct ${main_superclassname}_representation base;" + else + echo " const void *vtable;" + fi + echo "$fields" | sed -e "$sed_remove_empty_lines" + echo "};" + } > "$newfile" +} + +# func_emit_vt_h newfile +# outputs to $newfile the contents of class.vt.h. +func_emit_vt_h () +{ + newfile="$1" + { + echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' + echo + if test -n "${main_superclassname}"; then + echo "/* Virtual function table layout of superclass. */" + echo "#include \"${main_superclassname}.vt.h\"" + echo + fi + echo "/* Virtual function table layout of ${main_classname} class. */" + echo "$main_methods" | sed -e "$sed_remove_empty_lines" -e 's/\([^A-Za-z_0-9]\)\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*([^,)]*/\1(*\2) (THIS_ARG/' -e 's,$,;,' + } > "$newfile" +} + +# In C++ mode, we have a precise type checking. But in C mode, we have only +# loose type checking: So that rootclass_t and subclass_t are assignment +# compatible, we have to define subclass_t as identical to rootclass_t. +# Therefore we need an alias name for the representation of any type in the +# hierarchy. +if test -z "$main_superclassname"; then + main_repclassalias="any_${main_classname}_representation" +else + main_repclassalias="${main_classname}_representation" +fi + +sed_extract_method_rettype='s,^\(.*[^A-Za-z_0-9]\)[A-Za-z_0-9][A-Za-z_0-9]*[ ]*(.*$,\1, +s,^[ ]*,, +s,[ ]*$,,' +sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,' +sed_extract_method_arglist='s,^.*[^A-Za-z_0-9][A-Za-z_0-9][A-Za-z_0-9]*[ ]*([^,)]*\(.*\)).*$,'"${main_classname}_t"' first_arg\1,' +sed_extract_method_args='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)$,\1,' + +# func_emit_source_h newfile newfile_base +# outputs to $newfile the contents of source.h. +source_header_file_base=`echo "$source_header_file" | sed -e 's,^.*/,,'` +func_emit_source_h () +{ + newfile="$1" + newfile_base="$2" + # Use DLL_VARIABLE if and only if the main classname is among the names + # specified with --dllexport options. + dllexport_for_variables= + for name in $dllexports; do + if test "${main_classname}" = "${name}"; then + dllexport_for_variables=" DLL_VARIABLE" + break + fi + done + { + echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' + echo + echo "#line 1 \"${source_header_file_base}\"" + cat "$source_header_file" | sed -e "${main_class_decl_lineno}"',$d' + echo "#line "`expr 3 + ${main_class_decl_lineno} + 1`" \"$newfile_base\"" + echo "struct ${main_repclassalias};" + echo "/* ${main_classname}_t is defined as a pointer to struct ${main_repclassalias}." + echo " In C++ mode, we use a smart pointer class." + echo " In C mode, we have no other choice than a typedef to the root class type. */" + echo "#if IS_CPLUSPLUS" + echo "struct ${main_classname}_t" + echo "{" + echo "private:" + echo " struct ${main_repclassalias} *_pointer;" + echo "public:" + echo " ${main_classname}_t () : _pointer (NULL) {}" + echo " ${main_classname}_t (struct ${main_repclassalias} *pointer) : _pointer (pointer) {}" + echo " struct ${main_repclassalias} * operator -> () { return _pointer; }" + echo " operator struct ${main_repclassalias} * () { return _pointer; }" + atroot=yes + for classname in $all_superclasses; do + if test -n "$atroot"; then + repclassalias="any_${classname}_representation" + else + repclassalias="${classname}_representation" + fi + echo " operator struct ${repclassalias} * () { return (struct ${repclassalias} *) _pointer; }" + atroot= + done + # The 'operator void *' is needed to avoid ambiguous conversion chains. + echo " operator void * () { return _pointer; }" + # The 'operator ==' and 'operator !=' are needed to avoid ambiguous comparisons with NULL. + echo " bool operator == (const void *p) { return _pointer == p; }" + echo " bool operator != (const void *p) { return _pointer != p; }" + atroot=yes + for classname in $all_superclasses; do + if test -n "$atroot"; then + repclassalias="any_${classname}_representation" + else + repclassalias="${classname}_representation" + fi + echo " operator ${classname}_t () { return (${classname}_t) (struct ${repclassalias} *) _pointer; }" + # The 'explicit' constructors allow to downcast. + echo " explicit ${main_classname}_t (${classname}_t x) : _pointer ((struct ${main_repclassalias} *) (void *) x) {}" + atroot= + done + echo "};" + echo "#else" + if test -n "${main_superclassname}"; then + echo "typedef ${main_superclassname}_t ${main_classname}_t;" + else + echo "typedef struct ${main_repclassalias} * ${main_classname}_t;" + fi + echo "#endif" + echo + echo "/* Functions that invoke the methods. */" + echo "$all_methods" | sed -e "$sed_remove_empty_lines" -e 's/\([^A-Za-z_0-9]\)\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*([^,)]*/\1'"${main_classname}_"'\2 ('"${main_classname}_t first_arg"'/' -e 's,^,extern ,' -e 's,$,;,' + echo + # Now come the implementation details. + echo "/* Type representing an implementation of ${main_classname}_t. */" + echo "struct ${main_classname}_implementation" + echo "{" + echo " const typeinfo_t * const *superclasses;" + echo " size_t superclasses_length;" + echo " size_t instance_size;" + echo "#define THIS_ARG ${main_classname}_t first_arg" + echo "#include \"${main_classname}.vt.h\"" + echo "#undef THIS_ARG" + echo "};" + echo + echo "/* Public portion of the object pointed to by a ${main_classname}_t. */" + echo "struct ${main_classname}_representation_header" + echo "{" + echo " const struct ${main_classname}_implementation *vtable;" + echo "};" + echo + echo "#if HAVE_INLINE" + echo + echo "/* Define the functions that invoke the methods as inline accesses to" + echo " the ${main_classname}_implementation." + echo " Use #define to avoid a warning because of extern vs. static. */" + echo + echo "$all_methods" | sed -e "$sed_remove_empty_lines" | + while read method; do + rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` + name=`echo "$method" | sed -e "$sed_extract_method_name"` + arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` + if test "$arglist" = "void"; then + args= + else + args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` + fi + if test "$rettype" = "void"; then + return= + else + return="return " + fi + echo "# define ${main_classname}_${name} ${main_classname}_${name}_inline" + echo "static inline $rettype" + echo "${main_classname}_${name} ($arglist)" + echo "{" + echo " const struct ${main_classname}_implementation *vtable =" + echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;" + echo " ${return}vtable->${name} ($args);" + echo "}" + echo + done + echo "#endif" + echo + echo "extern${dllexport_for_variables} const typeinfo_t ${main_classname}_typeinfo;" + if test -n "${main_superclassname}"; then + superclasses_array_initializer="${main_superclassname}_SUPERCLASSES" + else + superclasses_array_initializer="NULL" + fi + echo "#define ${main_classname}_SUPERCLASSES &${main_classname}_typeinfo, ${superclasses_array_initializer}" + if test -n "${main_superclassname}"; then + echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + ${main_superclassname}_SUPERCLASSES_LENGTH)" + else + echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + 1)" + fi + echo + echo "extern${dllexport_for_variables} const struct ${main_classname}_implementation ${main_classname}_vtable;" + echo + echo "#line "`expr $main_class_end_lineno + 1`" \"${source_header_file_base}\"" + cat "$source_header_file" | sed -e "1,${main_class_end_lineno}d" + } > "$newfile" +} + +# func_emit_source_c newfile newfile_base +# outputs to $newfile the contents of source.c. +source_impl_file_base=`echo "$source_impl_file" | sed -e 's,^.*/,,'` +func_emit_source_c () +{ + newfile="$1" + newfile_base="$2" + { + echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' + echo + echo "#line 1 \"${source_impl_file_base}\"" + cat "$source_impl_file" | sed -e "${impl_decl_lineno}"',$d' + echo "#line "`expr 3 + ${impl_decl_lineno} + 1`" \"$newfile_base\"" + # In C mode, where subclass_t is identical to rootclass_t, we define the + # any_rootclass_representation type to the right one for subclass. + if test -n "$all_superclasses"; then + for classname in $all_superclasses; do + rootclassname="$classname" + break + done + else + rootclassname="$main_classname" + fi + echo "#if !IS_CPLUSPLUS" + echo "#define ${main_classname}_representation any_${rootclassname}_representation" + echo "#endif" + echo "#include \"${main_classname}.priv.h\"" + echo + echo "const typeinfo_t ${main_classname}_typeinfo = { \"${main_classname}\" };" + echo + echo "static const typeinfo_t * const ${main_classname}_superclasses[] =" + echo " { ${main_classname}_SUPERCLASSES };" + echo + if test -n "${main_superclassname}"; then + echo "#define super ${main_superclassname}_vtable" + echo + fi + echo "#line "`expr $impl_end_lineno + 1`" \"${source_impl_file_base}\"" + cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "s,${main_classname}::,${main_classname}__,g" + echo + lineno=`wc -l < "$newfile"` + echo "#line "`expr $lineno + 2`" \"$newfile_base\"" + # Define trivial stubs for methods that are not defined or overridden. + inherited_method_names=`echo "$inherited_methods" | sed -e "$sed_remove_empty_lines" | sed -e "$sed_extract_method_name"` + echo "$all_methods" | sed -e "$sed_remove_empty_lines" | + while read method; do + rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` + name=`echo "$method" | sed -e "$sed_extract_method_name"` + arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` + if test "$arglist" = "void"; then + args= + else + args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` + fi + if test "$rettype" = "void"; then + return= + else + return="return " + fi + if cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "$sed_remove_comments" | grep "${main_classname}::${name} *(" > /dev/null; then + # The class defines or overrides the method. + : + else + # Add a stub for the method. + inherited= + for i in $inherited_method_names; do + if test "$i" = "$name"; then + inherited=yes + fi + done + # First a prototype, to avoid gcc -Wmissing-prototypes warnings. + echo "$rettype ${main_classname}__${name} ($arglist);" + echo "$rettype" + echo "${main_classname}__${name} ($arglist)" + echo "{" + if test -n "$inherited"; then + echo " ${return}super.${name} ($args);" + else + echo " /* Abstract (unimplemented) method called. */" + echo " abort ();" + # Avoid C++ compiler warning about missing return value. + echo " #ifndef __GNUC__" + echo " ${return}${main_classname}__${name} ($args);" + echo " #endif" + fi + echo "}" + echo + fi + done + echo + echo "const struct ${main_classname}_implementation ${main_classname}_vtable =" + echo "{" + echo " ${main_classname}_superclasses," + echo " sizeof (${main_classname}_superclasses) / sizeof (${main_classname}_superclasses[0])," + echo " sizeof (struct ${main_classname}_representation)," + echo "$all_methods" | sed -e "$sed_remove_empty_lines" | + while read method; do + name=`echo "$method" | sed -e "$sed_extract_method_name"` + echo " ${main_classname}__${name}," + done + echo "};" + echo + echo "#if !HAVE_INLINE" + echo + echo "/* Define the functions that invoke the methods. */" + echo + echo "$all_methods" | sed -e "$sed_remove_empty_lines" | + while read method; do + rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` + name=`echo "$method" | sed -e "$sed_extract_method_name"` + arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` + if test "$arglist" = "void"; then + args= + else + args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` + fi + if test "$rettype" = "void"; then + return= + else + return="return " + fi + echo "$rettype" + echo "${main_classname}_${name} ($arglist)" + echo "{" + echo " const struct ${main_classname}_implementation *vtable =" + echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;" + echo " ${return}vtable->${name} ($args);" + echo "}" + echo + done + echo "#endif" + } > "$newfile" +} + +# Generate the files in the source directory, not in the current directory. +# This is needed because they need to be distributed, since not all platforms +# have GNU 'sed' preinstalled. + +sed_butbase='s,[^/]*$,,' +destdir=`echo "$source_impl_file" | sed -e "$sed_butbase"` + +# Generate the source.h file first. The Makefile.am snippets rely on the +# fact that the other generated files have the same or a newer timestamp. +# +# Also, generate the source.c file last. The Makefile.am snippets don't know +# about the other generated files; they assume that when the source.c file +# is finished, this command is complete. + +new_source_header_file_base=`echo "$source_header_file_base" | sed -e 's,\.oo\.h$,.h,'` +new_source_header_file="${destdir}$new_source_header_file_base" +func_start_creation "$new_source_header_file" +func_emit_source_h "$new_source_header_file" "$new_source_header_file_base" \ + || func_fatal_error "failed" + +new_priv_header_file="${destdir}${main_classname}.priv.h" +func_start_creation "$new_priv_header_file" +func_emit_priv_h "$new_priv_header_file" \ + || func_fatal_error "failed" + +new_vt_header_file="${destdir}${main_classname}.vt.h" +func_start_creation "$new_vt_header_file" +func_emit_vt_h "$new_vt_header_file" \ + || func_fatal_error "failed" + +new_source_impl_file_base=`echo "$source_impl_file_base" | sed -e 's,\.oo\.c$,.c,'` +new_source_impl_file="${destdir}$new_source_impl_file_base" +func_start_creation "$new_source_impl_file" +func_emit_source_c "$new_source_impl_file" "$new_source_impl_file_base" \ + || func_fatal_error "failed" |