1#!/bin/sh 2# Minimal Object-Oriented style PreProcessor. 3 4# Copyright (C) 2006-2008, 2016, 2018-2019 Free Software Foundation, Inc. 5# Written by Bruno Haible <bruno@clisp.org>, 2006. 6# 7# This program is free software: you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 3 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <https://www.gnu.org/licenses/>. 19 20# As a special exception to the GNU General Public License, if you 21# distribute this file as part of a program that contains a 22# configuration script generated by Autoconf, you may include it under 23# the same distribution terms that you use for the rest of that program. 24 25# Usage: moopp source.oo.c source.oo.h superclass.oo.h ... 26# Arguments: 27# - the source file of the class, 28# - the header file declaring the class, 29# - the header file declaring its superclass, 30# - etc. up to the root class. 31# Creates four files in the current directory: 32# - source.c, the preprocessing result of source.oo.c, 33# - source.h, the preprocessing result of source.oo.h, 34# - class.priv.h, a file declaring the private fields of the class, 35# - class.vt.h, a file declaring the virtual function table of the class. 36 37# This implementation of the preprocessor is a quick hack. It makes assumptions 38# about the source code: 39# - GNU indentation style, 40# - the struct declaration must be in a single line, 41# - no comments on the struct declaration line, 42# - no #ifs in relevant position, 43# - ... 44# Someday this should be rewritten to use a proper tokenizer and parser. 45 46# func_usage 47# outputs to stdout the --help usage message. 48func_usage () 49{ 50 echo "\ 51Usage: moopp [OPTION]... SOURCE.oo.c SOURCE.oo.h SUPERCLASS.oo.h ... 52 53Preprocesses SOURCE.oo.c into CLASS.c and SOURCE.oo.h into CLASS.h, 54where CLASS is the name of the class defined in these files. 55 56See moo.h for the object-oriented features and the syntax of the input files. 57 58Options: 59 --help print this help and exit 60 --version print version information and exit 61 --dllexport=NAME Arrange so that the specified class name can be accessed 62 from outside the shared library it is compiled into. 63 This option can be repeated. 64 65Report bugs to <bruno@clisp.org>." 66} 67 68# func_version 69# outputs to stdout the --version message. 70func_version () 71{ 72 echo "$progname (GNU $package) $version" 73 echo "Copyright (C) 2006-2019 Free Software Foundation, Inc. 74License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html> 75This is free software: you are free to change and redistribute it. 76There is NO WARRANTY, to the extent permitted by law." 77 echo "Written by" "Bruno Haible" 78} 79 80# func_fatal_error message 81# outputs to stderr a fatal error message, and terminates the program. 82func_fatal_error () 83{ 84 echo "moopp: *** $1" 1>&2 85 echo "moopp: *** Stop." 1>&2 86 exit 1 87} 88 89# Command-line option processing. 90# Removes the OPTIONS from the arguments. Sets the variables: 91# - dllexports list of class names to export from Woe32 DLLs 92dllexports= 93while test $# -gt 0; do 94 case "$1" in 95 --dllexport | --dllexpor | --dllexpo | --dllexp | --dllex | --dlle ) 96 shift 97 if test $# = 0; then 98 func_fatal_error "missing argument for --dllexport" 99 fi 100 case "$1" in 101 -*) func_fatal_error "missing argument for --dllexport" ;; 102 esac 103 dllexports="$dllexports $1" 104 shift ;; 105 --dllexport=* ) 106 arg=`echo "X$1" | sed -e 's/^X--dllexport=//'` 107 dllexports="$dllexports $arg" 108 shift ;; 109 --help | --hel | --he | --h ) 110 func_usage 111 exit 0 ;; 112 --version | --versio | --versi | --vers | --ver | --ve | --v ) 113 func_version 114 exit 0 ;; 115 -- ) # Stop option prcessing 116 shift; break ;; 117 -* ) 118 func_fatal_error "unrecognized option: $option" 119 ;; 120 * ) 121 break ;; 122 esac 123done 124 125if test $# -lt 2; then 126 func_fatal_error "Usage: $0 [OPTION]... source.oo.c source.oo.h superclass.oo.h ..." 127fi 128 129# Check that all files exist. 130for file 131do 132 test -r "$file" || { 133 func_fatal_error "file $file does not exist" 134 } 135done 136 137source_impl_file="$1" 138source_header_file="$2" 139shift 140shift 141 142case "$source_impl_file" in 143 *.oo.c) ;; 144 *) func_fatal_error "invalid class source file name: $source_impl_file" ;; 145esac 146case "$source_header_file" in 147 *.oo.h) ;; 148 *) func_fatal_error "invalid class header file name: $source_header_file" ;; 149esac 150 151# A sed expression that removes empty lines. 152sed_remove_empty_lines='/^$/d' 153 154# A sed expression that removes ANSI C and ISO C99 comments. 155sed_remove_comments=" 156/[/][/*]/{ 157 ta 158 :a 159 s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)//.*,\\1, 160 te 161 s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*]\\([^*]\\|[*][^/*]\\)*[*][*]*/,\\1 , 162 ta 163 /^\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*[/][*]/{ 164 s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*].*,\\1 , 165 tu 166 :u 167 n 168 s,^\\([^*]\\|[*][^/*]\\)*[*][*]*/,, 169 tv 170 s,^.*\$,, 171 bu 172 :v 173 } 174 :e 175}" 176# The same thing as an extended regular expression, for use with 177# sed --regexp-extended. 178sed_remove_comments_ERE=" 179/[/][/*]/{ 180 ta 181 :a 182 s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)//.*,\\1, 183 te 184 s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*]([^*]|[*][^/*])*[*][*]*/,\\1 , 185 ta 186 /^([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*[/][*]/{ 187 s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*].*,\\1 , 188 tu 189 :u 190 n 191 s,^([^*]|[*][^/*])*[*][*]*/,, 192 tv 193 s,^.*\$,, 194 bu 195 :v 196 } 197 :e 198}" 199 200# Check that 'sed' supports the kind of regular expressions used in 201# sed_remove_comments. The use of \| meaning alternation of basic regular 202# expressions is a GNU extension. 203sed_test='s,^\(\(a\|X\)*\)//.*,\1,' 204sed_result=`echo 'aaa//bcd' | sed -e "$sed_test"` 205test "$sed_result" = 'aaa' \ 206 || func_fatal_error "The 'sed' program is not GNU sed. Try installing GNU sed." 207 208# func_check_impl_syntax file 209# Check the syntax of the source implementation file. 210# Output: 211# - classname name of the class being defined (without 'struct') 212# - superclassname name of the superclass, or empty for a root class 213# - impl_decl_lineno line number of the class name declaration ('struct') 214# - impl_beg_lineno line number of the start of the class declaration ('{') 215# - impl_end_lineno line number of the end of the class declaration ('}') 216# - fields field declarations, including preprocessor directives 217func_check_impl_syntax () 218{ 219 file="$1" 220 sed -e "$sed_remove_comments" < "$file" | grep '^fields:' > /dev/null || { 221 func_fatal_error "$file does not contain 'fields:'" 222 } 223 test `sed -e "$sed_remove_comments" < "$file" | grep -c '^fields:'` = 1 || { 224 func_fatal_error "$file contains more than one 'fields:'" 225 } 226 fields_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^fields:' | sed -e 's,:.*,,'` 227 sed_before_fields="$fields_lineno"',$d' 228 impl_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'` 229 test -n "$impl_decl_lineno" || { 230 func_fatal_error "$file: class declaration not found" 231 } 232 class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$impl_decl_lineno"'p'` 233 sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' 234 classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"` 235 test -n "$classname" || { 236 func_fatal_error "$0: $file: class name not recognized at line $impl_decl_lineno" 237 } 238 superclassname= 239 if echo "$class_line" | grep ':' > /dev/null; then 240 sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' 241 superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"` 242 test -n "$superclassname" || { 243 func_fatal_error "$file: superclass name not recognized at line $impl_decl_lineno" 244 } 245 fi 246 impl_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'` 247 { test -n "$impl_beg_lineno" && test "$impl_decl_lineno" -lt "$impl_beg_lineno"; } || { 248 func_fatal_error "$file: opening brace of class declaration not found after line $impl_decl_lineno" 249 } 250 sed_after_fields='1,'"$fields_lineno"'d' 251 impl_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_fields" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'` 252 test -n "$impl_end_lineno" || { 253 func_fatal_error "$file: closing brace of class declaration not found after line $fields_lineno" 254 } 255 impl_end_lineno=`expr $fields_lineno + $impl_end_lineno` 256 sed_extract_fields="$impl_end_lineno"',$d;1,'"$fields_lineno"'d' 257 fields=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_fields"` 258} 259 260# func_check_header_syntax file 261# Check the syntax of a header file. 262# Output: 263# - classname name of the class being defined (without 'struct') 264# - superclassname name of the superclass, or empty for a root class 265# - class_decl_lineno line number of the class name declaration ('struct') 266# - class_beg_lineno line number of the start of the class declaration ('{') 267# - class_end_lineno line number of the end of the class declaration ('}') 268# - methods newline-separated list of method declarations 269func_check_header_syntax () 270{ 271 file="$1" 272 sed -e "$sed_remove_comments" < "$file" | grep '^methods:' > /dev/null || { 273 func_fatal_error "$file does not contain 'methods:'" 274 } 275 test `sed -e "$sed_remove_comments" < "$file" | grep -c '^methods:'` = 1 || { 276 func_fatal_error "$file contains more than one 'methods:'" 277 } 278 methods_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^methods:' | sed -e 's,:.*,,'` 279 sed_before_methods="$methods_lineno"',$d' 280 class_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'` 281 test -n "$class_decl_lineno" || { 282 func_fatal_error "$file: class declaration not found" 283 } 284 class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$class_decl_lineno"'p'` 285 sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' 286 classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"` 287 test -n "$classname" || { 288 func_fatal_error "$0: $file: class name not recognized at line $class_decl_lineno" 289 } 290 superclassname= 291 if echo "$class_line" | grep ':' > /dev/null; then 292 sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p' 293 superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"` 294 test -n "$superclassname" || { 295 func_fatal_error "$file: superclass name not recognized at line $class_decl_lineno" 296 } 297 fi 298 class_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'` 299 { test -n "$class_beg_lineno" && test "$class_decl_lineno" -lt "$class_beg_lineno"; } || { 300 func_fatal_error "$file: opening brace of class declaration not found after line $class_decl_lineno" 301 } 302 sed_after_methods='1,'"$methods_lineno"'d' 303 class_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_methods" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'` 304 test -n "$class_end_lineno" || { 305 func_fatal_error "$file: closing brace of class declaration not found after line $methods_lineno" 306 } 307 class_end_lineno=`expr $methods_lineno + $class_end_lineno` 308 sed_extract_methods="$class_end_lineno"',$d;1,'"$methods_lineno"'d' 309 methods=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_methods" | tr '\015\n' ' ' | tr ';' '\n' | sed -e 's,[ ]*$,,'` 310 sed_remove_valid_arg1_lines='/([ ]*'"$classname"'_t[ ]*[A-Za-z_0-9]*[ ]*[,)]/d' 311 sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,' 312 methods_with_bad_arg1=`echo "$methods" | sed -e "$sed_remove_empty_lines" -e "$sed_remove_valid_arg1_lines" -e "$sed_extract_method_name"` 313 if test -n "$methods_with_bad_arg1"; then 314 methods_with_bad_arg1=`{ echo "$methods_with_bad_arg1" | sed -e 's/$/, /' | tr -d '\015\n'; echo; } | sed -e 's/\(, \)*$//'` 315 func_fatal_error "$file: some methods don't have a first argument of type ${classname}_t: $methods_with_bad_arg1" 316 fi 317} 318 319func_check_impl_syntax "$source_impl_file" 320impl_classname="$classname" 321impl_superclassname="$superclassname" 322 323func_check_header_syntax "$source_header_file" 324main_classname="$classname" 325main_superclassname="$superclassname" 326main_class_decl_lineno="$class_decl_lineno" 327main_class_beg_lineno="$class_beg_lineno" 328main_class_end_lineno="$class_end_lineno" 329main_methods="$methods" 330all_superclasses= 331all_methods="$methods" 332inherited_methods= 333last_header_file="$source_header_file" 334expected_superclassname="$superclassname" 335 336for file 337do 338 if test -z "$expected_superclassname"; then 339 func_fatal_error "file $last_header_file does not specify a superclass; superfluous command line argument $file" 340 fi 341 func_check_header_syntax "$file" 342 all_superclasses="$classname $all_superclasses" 343 all_methods="$methods 344$all_methods" 345 inherited_methods="$methods 346$inherited_methods" 347 if test "$classname" != "$expected_superclassname"; then 348 func_fatal_error "file $last_header_file specifies superclass '$expected_superclassname', but file $file defines class '$classname'" 349 fi 350 last_header_file="$file" 351 expected_superclassname="$superclassname" 352done 353 354if test -n "$expected_superclassname"; then 355 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" 356fi 357 358if test "$impl_classname" != "$main_classname"; then 359 func_fatal_error "file $source_header_file specifies class '$main_classname', but file $source_impl_file specifies class '$impl_classname'" 360fi 361if test "$impl_superclassname" != "$main_superclassname"; then 362 if test -z "$main_superclassname"; then 363 func_fatal_error "file $source_header_file specifies no superclass, but file $source_impl_file specifies a superclass '$impl_superclassname'" 364 fi 365 if test -z "$impl_superclassname"; then 366 func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies no superclass" 367 fi 368 func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies a superclass '$impl_superclassname'" 369fi 370 371# func_start_creation file 372# starts the creation of the named file. 373func_start_creation () 374{ 375 file="$1" 376 if test -f "$file"; then 377 echo "Updating $file (backup in ${file}~)" 378 mv -f "$file" "${file}~" || func_fatal_error "failed" 379 else 380 echo "Creating $file" 381 fi 382} 383 384# func_emit_priv_h newfile 385# outputs to $newfile the contents of class.priv.h. 386func_emit_priv_h () 387{ 388 newfile="$1" 389 { 390 echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' 391 echo 392 if test -n "${main_superclassname}"; then 393 echo "/* Field layout of superclass. */" 394 echo "#include \"${main_superclassname}.priv.h\"" 395 echo 396 fi 397 echo "/* Field layout of ${main_classname} class. */" 398 echo "struct ${main_classname}_representation" 399 echo "{" 400 if test -n "${main_superclassname}"; then 401 echo " struct ${main_superclassname}_representation base;" 402 else 403 echo " const void *vtable;" 404 fi 405 echo "$fields" | sed -e "$sed_remove_empty_lines" 406 echo "};" 407 } > "$newfile" 408} 409 410# func_emit_vt_h newfile 411# outputs to $newfile the contents of class.vt.h. 412func_emit_vt_h () 413{ 414 newfile="$1" 415 { 416 echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' 417 echo 418 if test -n "${main_superclassname}"; then 419 echo "/* Virtual function table layout of superclass. */" 420 echo "#include \"${main_superclassname}.vt.h\"" 421 echo 422 fi 423 echo "/* Virtual function table layout of ${main_classname} class. */" 424 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,$,;,' 425 } > "$newfile" 426} 427 428# In C++ mode, we have a precise type checking. But in C mode, we have only 429# loose type checking: So that rootclass_t and subclass_t are assignment 430# compatible, we have to define subclass_t as identical to rootclass_t. 431# Therefore we need an alias name for the representation of any type in the 432# hierarchy. 433if test -z "$main_superclassname"; then 434 main_repclassalias="any_${main_classname}_representation" 435else 436 main_repclassalias="${main_classname}_representation" 437fi 438 439sed_extract_method_rettype='s,^\(.*[^A-Za-z_0-9]\)[A-Za-z_0-9][A-Za-z_0-9]*[ ]*(.*$,\1, 440s,^[ ]*,, 441s,[ ]*$,,' 442sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,' 443sed_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,' 444sed_extract_method_args='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)$,\1,' 445 446# func_emit_source_h newfile newfile_base 447# outputs to $newfile the contents of source.h. 448source_header_file_base=`echo "$source_header_file" | sed -e 's,^.*/,,'` 449func_emit_source_h () 450{ 451 newfile="$1" 452 newfile_base="$2" 453 # Use DLL_VARIABLE if and only if the main classname is among the names 454 # specified with --dllexport options. 455 dllexport_for_variables= 456 for name in $dllexports; do 457 if test "${main_classname}" = "${name}"; then 458 dllexport_for_variables=" DLL_VARIABLE" 459 break 460 fi 461 done 462 { 463 echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' 464 echo 465 echo "#line 1 \"${source_header_file_base}\"" 466 cat "$source_header_file" | sed -e "${main_class_decl_lineno}"',$d' 467 echo "#line "`expr 3 + ${main_class_decl_lineno} + 1`" \"$newfile_base\"" 468 echo "struct ${main_repclassalias};" 469 echo "/* ${main_classname}_t is defined as a pointer to struct ${main_repclassalias}." 470 echo " In C++ mode, we use a smart pointer class." 471 echo " In C mode, we have no other choice than a typedef to the root class type. */" 472 echo "#if IS_CPLUSPLUS" 473 echo "struct ${main_classname}_t" 474 echo "{" 475 echo "private:" 476 echo " struct ${main_repclassalias} *_pointer;" 477 echo "public:" 478 echo " ${main_classname}_t () : _pointer (NULL) {}" 479 echo " ${main_classname}_t (struct ${main_repclassalias} *pointer) : _pointer (pointer) {}" 480 echo " struct ${main_repclassalias} * operator -> () { return _pointer; }" 481 echo " operator struct ${main_repclassalias} * () { return _pointer; }" 482 atroot=yes 483 for classname in $all_superclasses; do 484 if test -n "$atroot"; then 485 repclassalias="any_${classname}_representation" 486 else 487 repclassalias="${classname}_representation" 488 fi 489 echo " operator struct ${repclassalias} * () { return (struct ${repclassalias} *) _pointer; }" 490 atroot= 491 done 492 # The 'operator void *' is needed to avoid ambiguous conversion chains. 493 echo " operator void * () { return _pointer; }" 494 # The 'operator ==' and 'operator !=' are needed to avoid ambiguous comparisons with NULL. 495 echo " bool operator == (const void *p) { return _pointer == p; }" 496 echo " bool operator != (const void *p) { return _pointer != p; }" 497 atroot=yes 498 for classname in $all_superclasses; do 499 if test -n "$atroot"; then 500 repclassalias="any_${classname}_representation" 501 else 502 repclassalias="${classname}_representation" 503 fi 504 echo " operator ${classname}_t () { return (${classname}_t) (struct ${repclassalias} *) _pointer; }" 505 # The 'explicit' constructors allow to downcast. 506 echo " explicit ${main_classname}_t (${classname}_t x) : _pointer ((struct ${main_repclassalias} *) (void *) x) {}" 507 atroot= 508 done 509 echo "};" 510 echo "#else" 511 if test -n "${main_superclassname}"; then 512 echo "typedef ${main_superclassname}_t ${main_classname}_t;" 513 else 514 echo "typedef struct ${main_repclassalias} * ${main_classname}_t;" 515 fi 516 echo "#endif" 517 echo 518 echo "/* Functions that invoke the methods. */" 519 echo "#ifdef __cplusplus" 520 echo "extern \"C\" {" 521 echo "#endif" 522 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,$,;,' 523 echo "#ifdef __cplusplus" 524 echo "}" 525 echo "#endif" 526 echo 527 # Now come the implementation details. 528 echo "/* Type representing an implementation of ${main_classname}_t. */" 529 echo "struct ${main_classname}_implementation" 530 echo "{" 531 echo " const typeinfo_t * const *superclasses;" 532 echo " size_t superclasses_length;" 533 echo " size_t instance_size;" 534 echo "#define THIS_ARG ${main_classname}_t first_arg" 535 echo "#include \"${main_classname}.vt.h\"" 536 echo "#undef THIS_ARG" 537 echo "};" 538 echo 539 echo "/* Public portion of the object pointed to by a ${main_classname}_t. */" 540 echo "struct ${main_classname}_representation_header" 541 echo "{" 542 echo " const struct ${main_classname}_implementation *vtable;" 543 echo "};" 544 echo 545 echo "#if HAVE_INLINE" 546 echo 547 echo "/* Define the functions that invoke the methods as inline accesses to" 548 echo " the ${main_classname}_implementation." 549 echo " Use #define to avoid a warning because of extern vs. static. */" 550 echo 551 echo "$all_methods" | sed -e "$sed_remove_empty_lines" | 552 while read method; do 553 rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` 554 name=`echo "$method" | sed -e "$sed_extract_method_name"` 555 arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` 556 if test "$arglist" = "void"; then 557 args= 558 else 559 args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` 560 fi 561 if test "$rettype" = "void"; then 562 return= 563 else 564 return="return " 565 fi 566 echo "# define ${main_classname}_${name} ${main_classname}_${name}_inline" 567 echo "static inline $rettype" 568 echo "${main_classname}_${name} ($arglist)" 569 echo "{" 570 echo " const struct ${main_classname}_implementation *vtable =" 571 echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;" 572 echo " ${return}vtable->${name} ($args);" 573 echo "}" 574 echo 575 done 576 echo "#endif" 577 echo 578 echo "extern${dllexport_for_variables} const typeinfo_t ${main_classname}_typeinfo;" 579 if test -n "${main_superclassname}"; then 580 superclasses_array_initializer="${main_superclassname}_SUPERCLASSES" 581 else 582 superclasses_array_initializer="NULL" 583 fi 584 echo "#define ${main_classname}_SUPERCLASSES &${main_classname}_typeinfo, ${superclasses_array_initializer}" 585 if test -n "${main_superclassname}"; then 586 echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + ${main_superclassname}_SUPERCLASSES_LENGTH)" 587 else 588 echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + 1)" 589 fi 590 echo 591 echo "extern${dllexport_for_variables} const struct ${main_classname}_implementation ${main_classname}_vtable;" 592 echo 593 echo "#line "`expr $main_class_end_lineno + 1`" \"${source_header_file_base}\"" 594 cat "$source_header_file" | sed -e "1,${main_class_end_lineno}d" 595 } > "$newfile" 596} 597 598# func_emit_source_c newfile newfile_base 599# outputs to $newfile the contents of source.c. 600source_impl_file_base=`echo "$source_impl_file" | sed -e 's,^.*/,,'` 601func_emit_source_c () 602{ 603 newfile="$1" 604 newfile_base="$2" 605 { 606 echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' 607 echo 608 # In C mode, where subclass_t is identical to rootclass_t, we define the 609 # any_rootclass_representation type to the right one for subclass. 610 if test -n "$all_superclasses"; then 611 for classname in $all_superclasses; do 612 rootclassname="$classname" 613 break 614 done 615 else 616 rootclassname="$main_classname" 617 fi 618 echo "#if !IS_CPLUSPLUS" 619 echo "#define ${main_classname}_representation any_${rootclassname}_representation" 620 echo "#endif" 621 echo "#line 1 \"${source_impl_file_base}\"" 622 cat "$source_impl_file" | sed -e "${impl_decl_lineno}"',$d' 623 echo "#line "`expr 6 + ${impl_decl_lineno} + 1`" \"$newfile_base\"" 624 echo "#include \"${main_classname}.priv.h\"" 625 echo 626 echo "const typeinfo_t ${main_classname}_typeinfo = { \"${main_classname}\" };" 627 echo 628 echo "static const typeinfo_t * const ${main_classname}_superclasses[] =" 629 echo " { ${main_classname}_SUPERCLASSES };" 630 echo 631 if test -n "${main_superclassname}"; then 632 echo "#define super ${main_superclassname}_vtable" 633 echo 634 fi 635 echo "#line "`expr $impl_end_lineno + 1`" \"${source_impl_file_base}\"" 636 cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "s,${main_classname}::,${main_classname}__,g" 637 echo 638 lineno=`wc -l < "$newfile"` 639 echo "#line "`expr $lineno + 2`" \"$newfile_base\"" 640 # Define trivial stubs for methods that are not defined or overridden. 641 inherited_method_names=`echo "$inherited_methods" | sed -e "$sed_remove_empty_lines" | sed -e "$sed_extract_method_name"` 642 echo "$all_methods" | sed -e "$sed_remove_empty_lines" | 643 while read method; do 644 rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` 645 name=`echo "$method" | sed -e "$sed_extract_method_name"` 646 arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` 647 if test "$arglist" = "void"; then 648 args= 649 else 650 args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` 651 fi 652 if test "$rettype" = "void"; then 653 return= 654 else 655 return="return " 656 fi 657 if cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "$sed_remove_comments" | grep "${main_classname}::${name} *(" > /dev/null; then 658 # The class defines or overrides the method. 659 : 660 else 661 # Add a stub for the method. 662 inherited= 663 for i in $inherited_method_names; do 664 if test "$i" = "$name"; then 665 inherited=yes 666 fi 667 done 668 # First a prototype, to avoid gcc -Wmissing-prototypes warnings. 669 echo "$rettype ${main_classname}__${name} ($arglist);" 670 echo "$rettype" 671 echo "${main_classname}__${name} ($arglist)" 672 echo "{" 673 if test -n "$inherited"; then 674 echo " ${return}super.${name} ($args);" 675 else 676 echo " /* Abstract (unimplemented) method called. */" 677 echo " abort ();" 678 # Avoid C++ compiler warning about missing return value. 679 echo " #ifndef __GNUC__" 680 echo " ${return}${main_classname}__${name} ($args);" 681 echo " #endif" 682 fi 683 echo "}" 684 echo 685 fi 686 done 687 echo 688 echo "const struct ${main_classname}_implementation ${main_classname}_vtable =" 689 echo "{" 690 echo " ${main_classname}_superclasses," 691 echo " sizeof (${main_classname}_superclasses) / sizeof (${main_classname}_superclasses[0])," 692 echo " sizeof (struct ${main_classname}_representation)," 693 echo "$all_methods" | sed -e "$sed_remove_empty_lines" | 694 while read method; do 695 name=`echo "$method" | sed -e "$sed_extract_method_name"` 696 echo " ${main_classname}__${name}," 697 done 698 echo "};" 699 echo 700 echo "#if !HAVE_INLINE" 701 echo 702 echo "/* Define the functions that invoke the methods. */" 703 echo 704 echo "$all_methods" | sed -e "$sed_remove_empty_lines" | 705 while read method; do 706 rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"` 707 name=`echo "$method" | sed -e "$sed_extract_method_name"` 708 arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"` 709 if test "$arglist" = "void"; then 710 args= 711 else 712 args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'` 713 fi 714 if test "$rettype" = "void"; then 715 return= 716 else 717 return="return " 718 fi 719 echo "$rettype" 720 echo "${main_classname}_${name} ($arglist)" 721 echo "{" 722 echo " const struct ${main_classname}_implementation *vtable =" 723 echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;" 724 echo " ${return}vtable->${name} ($args);" 725 echo "}" 726 echo 727 done 728 echo "#endif" 729 } > "$newfile" 730} 731 732# Generate the files in the source directory, not in the current directory. 733# This is needed because they need to be distributed, since not all platforms 734# have GNU 'sed' preinstalled. 735 736sed_butbase='s,[^/]*$,,' 737destdir=`echo "$source_impl_file" | sed -e "$sed_butbase"` 738 739# Generate the source.h file first. The Makefile.am snippets rely on the 740# fact that the other generated files have the same or a newer timestamp. 741# 742# Also, generate the source.c file last. The Makefile.am snippets don't know 743# about the other generated files; they assume that when the source.c file 744# is finished, this command is complete. 745 746new_source_header_file_base=`echo "$source_header_file_base" | sed -e 's,\.oo\.h$,.h,'` 747new_source_header_file="${destdir}$new_source_header_file_base" 748func_start_creation "$new_source_header_file" 749func_emit_source_h "$new_source_header_file" "$new_source_header_file_base" \ 750 || func_fatal_error "failed" 751 752new_priv_header_file="${destdir}${main_classname}.priv.h" 753func_start_creation "$new_priv_header_file" 754func_emit_priv_h "$new_priv_header_file" \ 755 || func_fatal_error "failed" 756 757new_vt_header_file="${destdir}${main_classname}.vt.h" 758func_start_creation "$new_vt_header_file" 759func_emit_vt_h "$new_vt_header_file" \ 760 || func_fatal_error "failed" 761 762new_source_impl_file_base=`echo "$source_impl_file_base" | sed -e 's,\.oo\.c$,.c,'` 763new_source_impl_file="${destdir}$new_source_impl_file_base" 764func_start_creation "$new_source_impl_file" 765func_emit_source_c "$new_source_impl_file" "$new_source_impl_file_base" \ 766 || func_fatal_error "failed" 767