#!/bin/sh # Minimal Object-Oriented style PreProcessor. # Copyright (C) 2006-2008, 2015-2016 Free Software Foundation, Inc. # Written by Bruno Haible , 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 . # 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 ." } # 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 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 '\015\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 '\015\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"