├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Doxyfile ├── INSTALL ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── README.md ├── ar-lib ├── config.h.in ├── configure ├── configure.ac ├── depcomp ├── install-sh ├── missing └── src ├── Makefile.am ├── Makefile.in └── infact ├── Makefile.am ├── Makefile.in ├── environment-impl.cc ├── environment-impl.h ├── environment-test.cc ├── environment.cc ├── environment.h ├── error.cc ├── error.h ├── example.cc ├── example.h ├── factory.cc ├── factory.h ├── interpreter-test.cc ├── interpreter.cc ├── interpreter.h ├── stream-init.h ├── stream-tokenizer-test.cc ├── stream-tokenizer.cc └── stream-tokenizer.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.a 4 | *.d 5 | *.pb.* 6 | .DS_store 7 | .*sw? 8 | *.gz 9 | *.html 10 | *.tex 11 | *.png 12 | *.js 13 | *.css 14 | *.log 15 | stamp-h1 16 | Makefile 17 | src/infact/html 18 | src/infact/bin 19 | src/infact/lib 20 | aclocal.m4 21 | config.h 22 | config.status 23 | autom4te.cache 24 | .deps 25 | infact.tag 26 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Daniel M. Bikel (dbikel@google.com) 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2014, Google Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/infact/449cff906c46de086111d65fd7b15897d3e1f05f/ChangeLog -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | InFact Framework (InFact) 2 | =========================================================================== 3 | 4 | Quick Start 5 | --------------------------------------------------------------------------- 6 | To build and install, run 7 | ./configure ; make ; make install 8 | 9 | 10 | Building and Installing 11 | --------------------------------------------------------------------------- 12 | Requirements: 13 | autoconf 2.68 or higher 14 | automake 1.11 or higher 15 | 16 | To build the InFact library, you must first run the 17 | supplied configure script. Please run 18 | ./configure --help 19 | to see common options. In particular, you can use the --prefix option 20 | to specify the installation directory, which defaults to /usr/local. 21 | 22 | After running ./configure with any desired options, you can build the entire 23 | package by simply issuing the make command: 24 | make 25 | 26 | Installation of the package is completed by running 27 | make install 28 | 29 | Finally, there are a number of additional make targets supplied "for free" 30 | with the GNU autoconf build system, the most useful of which is 31 | make clean 32 | which cleans the build directory and 33 | make distclean 34 | which cleans everything, including files auto-generated by the 35 | configure script. 36 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | The InFact Framework (InFact) Release 1.0. 2 | 3 | * Initial public release 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Copyright 2014, Google Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | ------------------------- 31 | InFact Framework (InFact) 32 | ------------------------- 33 | 34 | Directory structure: 35 | 36 | src/infact - all code is in here 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InFact: An easy way to construct C++ objects dynamically 2 | 3 | InFact provides an interpreter and factory for the construction of 4 | instances of C++ classes. The syntax is very much like that of C++ 5 | itself, and objects may be created that wrap other objects, just like 6 | in C++. It supports all the common primitive types (`bool`, `int`, `double`, 7 | `string`), as well as vectors of primitives or of Factory-constructible 8 | objects. Here's what it looks like: 9 | 10 | ``` 11 | // Construct a cow with a required argument, its name. 12 | Cow c1 = Cow(name("Bessie")); 13 | 14 | // Construct a second cow with a different name, and an optional age. 15 | // Also, specifying a type is optional, since InFact does type inference. 16 | c2 = Cow(name("Lani Moo"), age(2)); 17 | 18 | // Construct a human pet owner with the two cows as pets. 19 | PetOwner p = HumanPetOwner(pets({c1, c2})); 20 | ``` 21 | 22 | Feeding the above to InFact’s 23 | [Interpreter](http://google.github.io/infact/classinfact_1_1_interpreter.html) 24 | class will construct three new objects at run-time (the referents of 25 | `c1`, `c2` and `p`) _without any new C++ code_. 26 | 27 | While being very powerful, the library is also quite lightweight: it 28 | is a simple recursive-descent parser with a single token of 29 | look-ahead, with the entire library implemented with fewer than 1000 30 | C++ statements. The inspiration was the 31 | [BeanShell library](http://www.beanshell.org/) for Java, which 32 | provides a very convenient mechanism for configuration of any Java 33 | project. Similarly, InFact can be used as an effective configuration 34 | mechansim for C++ projects. See 35 | [the ReFr project](https://github.com/google/refr) for an example, 36 | especially 37 | [the default configuration file](https://github.com/google/refr/blob/master/src/reranker/config/default.infact). 38 | 39 | The interpreted InFact language supports _type inference_ and _named 40 | parameters_. Compile-time equivalents of these two properties are 41 | available with the Boost Parameter library. 42 | 43 | For documentation, please visit 44 | [our documentation site](http://google.github.io/infact/index.html). 45 | -------------------------------------------------------------------------------- /ar-lib: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for Microsoft lib.exe 3 | 4 | me=ar-lib 5 | scriptversion=2012-01-30.22; # UTC 6 | 7 | # Copyright (C) 2010, 2012 Free Software Foundation, Inc. 8 | # Written by Peter Rosin . 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | 33 | # func_error message 34 | func_error () 35 | { 36 | echo "$me: $1" 1>&2 37 | exit 1 38 | } 39 | 40 | file_conv= 41 | 42 | # func_file_conv build_file 43 | # Convert a $build file to $host form and store it in $file 44 | # Currently only supports Windows hosts. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv in 65 | mingw) 66 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 67 | ;; 68 | cygwin) 69 | file=`cygpath -m "$file" || echo "$file"` 70 | ;; 71 | wine) 72 | file=`winepath -w "$file" || echo "$file"` 73 | ;; 74 | esac 75 | ;; 76 | esac 77 | } 78 | 79 | # func_at_file at_file operation archive 80 | # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE 81 | # for each of them. 82 | # When interpreting the content of the @FILE, do NOT use func_file_conv, 83 | # since the user would need to supply preconverted file names to 84 | # binutils ar, at least for MinGW. 85 | func_at_file () 86 | { 87 | operation=$2 88 | archive=$3 89 | at_file_contents=`cat "$1"` 90 | eval set x "$at_file_contents" 91 | shift 92 | 93 | for member 94 | do 95 | $AR -NOLOGO $operation:"$member" "$archive" || exit $? 96 | done 97 | } 98 | 99 | case $1 in 100 | '') 101 | func_error "no command. Try '$0 --help' for more information." 102 | ;; 103 | -h | --h*) 104 | cat < header file. */ 4 | #undef HAVE_FCNTL_H 5 | 6 | /* Define to 1 if you have the `floor' function. */ 7 | #undef HAVE_FLOOR 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_MEMORY_H 14 | 15 | /* Define to 1 if you have the `memset' function. */ 16 | #undef HAVE_MEMSET 17 | 18 | /* Define to 1 if stdbool.h conforms to C99. */ 19 | #undef HAVE_STDBOOL_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STDINT_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STDLIB_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_STRINGS_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_STRING_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_SYS_STAT_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_SYS_TYPES_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_UNISTD_H 41 | 42 | /* Define to 1 if the system has the type `_Bool'. */ 43 | #undef HAVE__BOOL 44 | 45 | /* Name of package */ 46 | #undef PACKAGE 47 | 48 | /* Define to the address where bug reports for this package should be sent. */ 49 | #undef PACKAGE_BUGREPORT 50 | 51 | /* Define to the full name of this package. */ 52 | #undef PACKAGE_NAME 53 | 54 | /* Define to the full name and version of this package. */ 55 | #undef PACKAGE_STRING 56 | 57 | /* Define to the one symbol short name of this package. */ 58 | #undef PACKAGE_TARNAME 59 | 60 | /* Define to the home page for this package. */ 61 | #undef PACKAGE_URL 62 | 63 | /* Define to the version of this package. */ 64 | #undef PACKAGE_VERSION 65 | 66 | /* Define to 1 if you have the ANSI C header files. */ 67 | #undef STDC_HEADERS 68 | 69 | /* Version number of package */ 70 | #undef VERSION 71 | 72 | /* Define to `__inline__' or `__inline' if that's what the C compiler 73 | calls it, or to nothing if 'inline' is not supported under any name. */ 74 | #ifndef __cplusplus 75 | #undef inline 76 | #endif 77 | 78 | /* Define to `unsigned int' if does not define. */ 79 | #undef size_t 80 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.65]) 5 | AC_INIT([InFact Framework], [1.0], [dbikel@google.com]) 6 | AM_INIT_AUTOMAKE([foreign nostdinc -Wall -Werror]) 7 | 8 | # Checks for programs. 9 | AC_PROG_CXX 10 | AC_PROG_CC 11 | AC_PROG_CPP 12 | AC_PROG_MAKE_SET 13 | AC_PROG_RANLIB 14 | AC_PROG_SED 15 | AM_PROG_AR 16 | 17 | AC_CONFIG_HEADERS([config.h]) 18 | AC_CONFIG_FILES([Makefile 19 | src/Makefile 20 | src/infact/Makefile]) 21 | 22 | AC_SUBST(CPPFLAGS, "$CPPFLAGS -std=c++0x") 23 | 24 | # Checks for header files. 25 | AC_CHECK_HEADERS([fcntl.h stdlib.h string.h]) 26 | 27 | # Checks for typedefs, structures, and compiler characteristics. 28 | AC_HEADER_STDBOOL 29 | AC_C_INLINE 30 | AC_TYPE_SIZE_T 31 | 32 | # Checks for library functions. 33 | AC_CHECK_FUNCS([floor memset]) 34 | 35 | AC_OUTPUT 36 | -------------------------------------------------------------------------------- /depcomp: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # depcomp - compile a program generating dependencies as side-effects 3 | 4 | scriptversion=2011-12-04.11; # UTC 5 | 6 | # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 7 | # 2011 Free Software Foundation, Inc. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # Originally written by Alexandre Oliva . 28 | 29 | case $1 in 30 | '') 31 | echo "$0: No command. Try \`$0 --help' for more information." 1>&2 32 | exit 1; 33 | ;; 34 | -h | --h*) 35 | cat <<\EOF 36 | Usage: depcomp [--help] [--version] PROGRAM [ARGS] 37 | 38 | Run PROGRAMS ARGS to compile a file, generating dependencies 39 | as side-effects. 40 | 41 | Environment variables: 42 | depmode Dependency tracking mode. 43 | source Source file read by `PROGRAMS ARGS'. 44 | object Object file output by `PROGRAMS ARGS'. 45 | DEPDIR directory where to store dependencies. 46 | depfile Dependency file to output. 47 | tmpdepfile Temporary file to use when outputting dependencies. 48 | libtool Whether libtool is used (yes/no). 49 | 50 | Report bugs to . 51 | EOF 52 | exit $? 53 | ;; 54 | -v | --v*) 55 | echo "depcomp $scriptversion" 56 | exit $? 57 | ;; 58 | esac 59 | 60 | if test -z "$depmode" || test -z "$source" || test -z "$object"; then 61 | echo "depcomp: Variables source, object and depmode must be set" 1>&2 62 | exit 1 63 | fi 64 | 65 | # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. 66 | depfile=${depfile-`echo "$object" | 67 | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} 68 | tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} 69 | 70 | rm -f "$tmpdepfile" 71 | 72 | # Some modes work just like other modes, but use different flags. We 73 | # parameterize here, but still list the modes in the big case below, 74 | # to make depend.m4 easier to write. Note that we *cannot* use a case 75 | # here, because this file can only contain one case statement. 76 | if test "$depmode" = hp; then 77 | # HP compiler uses -M and no extra arg. 78 | gccflag=-M 79 | depmode=gcc 80 | fi 81 | 82 | if test "$depmode" = dashXmstdout; then 83 | # This is just like dashmstdout with a different argument. 84 | dashmflag=-xM 85 | depmode=dashmstdout 86 | fi 87 | 88 | cygpath_u="cygpath -u -f -" 89 | if test "$depmode" = msvcmsys; then 90 | # This is just like msvisualcpp but w/o cygpath translation. 91 | # Just convert the backslash-escaped backslashes to single forward 92 | # slashes to satisfy depend.m4 93 | cygpath_u='sed s,\\\\,/,g' 94 | depmode=msvisualcpp 95 | fi 96 | 97 | if test "$depmode" = msvc7msys; then 98 | # This is just like msvc7 but w/o cygpath translation. 99 | # Just convert the backslash-escaped backslashes to single forward 100 | # slashes to satisfy depend.m4 101 | cygpath_u='sed s,\\\\,/,g' 102 | depmode=msvc7 103 | fi 104 | 105 | case "$depmode" in 106 | gcc3) 107 | ## gcc 3 implements dependency tracking that does exactly what 108 | ## we want. Yay! Note: for some reason libtool 1.4 doesn't like 109 | ## it if -MD -MP comes after the -MF stuff. Hmm. 110 | ## Unfortunately, FreeBSD c89 acceptance of flags depends upon 111 | ## the command line argument order; so add the flags where they 112 | ## appear in depend2.am. Note that the slowdown incurred here 113 | ## affects only configure: in makefiles, %FASTDEP% shortcuts this. 114 | for arg 115 | do 116 | case $arg in 117 | -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; 118 | *) set fnord "$@" "$arg" ;; 119 | esac 120 | shift # fnord 121 | shift # $arg 122 | done 123 | "$@" 124 | stat=$? 125 | if test $stat -eq 0; then : 126 | else 127 | rm -f "$tmpdepfile" 128 | exit $stat 129 | fi 130 | mv "$tmpdepfile" "$depfile" 131 | ;; 132 | 133 | gcc) 134 | ## There are various ways to get dependency output from gcc. Here's 135 | ## why we pick this rather obscure method: 136 | ## - Don't want to use -MD because we'd like the dependencies to end 137 | ## up in a subdir. Having to rename by hand is ugly. 138 | ## (We might end up doing this anyway to support other compilers.) 139 | ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like 140 | ## -MM, not -M (despite what the docs say). 141 | ## - Using -M directly means running the compiler twice (even worse 142 | ## than renaming). 143 | if test -z "$gccflag"; then 144 | gccflag=-MD, 145 | fi 146 | "$@" -Wp,"$gccflag$tmpdepfile" 147 | stat=$? 148 | if test $stat -eq 0; then : 149 | else 150 | rm -f "$tmpdepfile" 151 | exit $stat 152 | fi 153 | rm -f "$depfile" 154 | echo "$object : \\" > "$depfile" 155 | alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 156 | ## The second -e expression handles DOS-style file names with drive letters. 157 | sed -e 's/^[^:]*: / /' \ 158 | -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" 159 | ## This next piece of magic avoids the `deleted header file' problem. 160 | ## The problem is that when a header file which appears in a .P file 161 | ## is deleted, the dependency causes make to die (because there is 162 | ## typically no way to rebuild the header). We avoid this by adding 163 | ## dummy dependencies for each header file. Too bad gcc doesn't do 164 | ## this for us directly. 165 | tr ' ' ' 166 | ' < "$tmpdepfile" | 167 | ## Some versions of gcc put a space before the `:'. On the theory 168 | ## that the space means something, we add a space to the output as 169 | ## well. hp depmode also adds that space, but also prefixes the VPATH 170 | ## to the object. Take care to not repeat it in the output. 171 | ## Some versions of the HPUX 10.20 sed can't process this invocation 172 | ## correctly. Breaking it into two sed invocations is a workaround. 173 | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ 174 | | sed -e 's/$/ :/' >> "$depfile" 175 | rm -f "$tmpdepfile" 176 | ;; 177 | 178 | hp) 179 | # This case exists only to let depend.m4 do its work. It works by 180 | # looking at the text of this script. This case will never be run, 181 | # since it is checked for above. 182 | exit 1 183 | ;; 184 | 185 | sgi) 186 | if test "$libtool" = yes; then 187 | "$@" "-Wp,-MDupdate,$tmpdepfile" 188 | else 189 | "$@" -MDupdate "$tmpdepfile" 190 | fi 191 | stat=$? 192 | if test $stat -eq 0; then : 193 | else 194 | rm -f "$tmpdepfile" 195 | exit $stat 196 | fi 197 | rm -f "$depfile" 198 | 199 | if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files 200 | echo "$object : \\" > "$depfile" 201 | 202 | # Clip off the initial element (the dependent). Don't try to be 203 | # clever and replace this with sed code, as IRIX sed won't handle 204 | # lines with more than a fixed number of characters (4096 in 205 | # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; 206 | # the IRIX cc adds comments like `#:fec' to the end of the 207 | # dependency line. 208 | tr ' ' ' 209 | ' < "$tmpdepfile" \ 210 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ 211 | tr ' 212 | ' ' ' >> "$depfile" 213 | echo >> "$depfile" 214 | 215 | # The second pass generates a dummy entry for each header file. 216 | tr ' ' ' 217 | ' < "$tmpdepfile" \ 218 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ 219 | >> "$depfile" 220 | else 221 | # The sourcefile does not contain any dependencies, so just 222 | # store a dummy comment line, to avoid errors with the Makefile 223 | # "include basename.Plo" scheme. 224 | echo "#dummy" > "$depfile" 225 | fi 226 | rm -f "$tmpdepfile" 227 | ;; 228 | 229 | aix) 230 | # The C for AIX Compiler uses -M and outputs the dependencies 231 | # in a .u file. In older versions, this file always lives in the 232 | # current directory. Also, the AIX compiler puts `$object:' at the 233 | # start of each line; $object doesn't have directory information. 234 | # Version 6 uses the directory in both cases. 235 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 236 | test "x$dir" = "x$object" && dir= 237 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 238 | if test "$libtool" = yes; then 239 | tmpdepfile1=$dir$base.u 240 | tmpdepfile2=$base.u 241 | tmpdepfile3=$dir.libs/$base.u 242 | "$@" -Wc,-M 243 | else 244 | tmpdepfile1=$dir$base.u 245 | tmpdepfile2=$dir$base.u 246 | tmpdepfile3=$dir$base.u 247 | "$@" -M 248 | fi 249 | stat=$? 250 | 251 | if test $stat -eq 0; then : 252 | else 253 | rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" 254 | exit $stat 255 | fi 256 | 257 | for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" 258 | do 259 | test -f "$tmpdepfile" && break 260 | done 261 | if test -f "$tmpdepfile"; then 262 | # Each line is of the form `foo.o: dependent.h'. 263 | # Do two passes, one to just change these to 264 | # `$object: dependent.h' and one to simply `dependent.h:'. 265 | sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" 266 | # That's a tab and a space in the []. 267 | sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" 268 | else 269 | # The sourcefile does not contain any dependencies, so just 270 | # store a dummy comment line, to avoid errors with the Makefile 271 | # "include basename.Plo" scheme. 272 | echo "#dummy" > "$depfile" 273 | fi 274 | rm -f "$tmpdepfile" 275 | ;; 276 | 277 | icc) 278 | # Intel's C compiler understands `-MD -MF file'. However on 279 | # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c 280 | # ICC 7.0 will fill foo.d with something like 281 | # foo.o: sub/foo.c 282 | # foo.o: sub/foo.h 283 | # which is wrong. We want: 284 | # sub/foo.o: sub/foo.c 285 | # sub/foo.o: sub/foo.h 286 | # sub/foo.c: 287 | # sub/foo.h: 288 | # ICC 7.1 will output 289 | # foo.o: sub/foo.c sub/foo.h 290 | # and will wrap long lines using \ : 291 | # foo.o: sub/foo.c ... \ 292 | # sub/foo.h ... \ 293 | # ... 294 | 295 | "$@" -MD -MF "$tmpdepfile" 296 | stat=$? 297 | if test $stat -eq 0; then : 298 | else 299 | rm -f "$tmpdepfile" 300 | exit $stat 301 | fi 302 | rm -f "$depfile" 303 | # Each line is of the form `foo.o: dependent.h', 304 | # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. 305 | # Do two passes, one to just change these to 306 | # `$object: dependent.h' and one to simply `dependent.h:'. 307 | sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" 308 | # Some versions of the HPUX 10.20 sed can't process this invocation 309 | # correctly. Breaking it into two sed invocations is a workaround. 310 | sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | 311 | sed -e 's/$/ :/' >> "$depfile" 312 | rm -f "$tmpdepfile" 313 | ;; 314 | 315 | hp2) 316 | # The "hp" stanza above does not work with aCC (C++) and HP's ia64 317 | # compilers, which have integrated preprocessors. The correct option 318 | # to use with these is +Maked; it writes dependencies to a file named 319 | # 'foo.d', which lands next to the object file, wherever that 320 | # happens to be. 321 | # Much of this is similar to the tru64 case; see comments there. 322 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 323 | test "x$dir" = "x$object" && dir= 324 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 325 | if test "$libtool" = yes; then 326 | tmpdepfile1=$dir$base.d 327 | tmpdepfile2=$dir.libs/$base.d 328 | "$@" -Wc,+Maked 329 | else 330 | tmpdepfile1=$dir$base.d 331 | tmpdepfile2=$dir$base.d 332 | "$@" +Maked 333 | fi 334 | stat=$? 335 | if test $stat -eq 0; then : 336 | else 337 | rm -f "$tmpdepfile1" "$tmpdepfile2" 338 | exit $stat 339 | fi 340 | 341 | for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" 342 | do 343 | test -f "$tmpdepfile" && break 344 | done 345 | if test -f "$tmpdepfile"; then 346 | sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" 347 | # Add `dependent.h:' lines. 348 | sed -ne '2,${ 349 | s/^ *// 350 | s/ \\*$// 351 | s/$/:/ 352 | p 353 | }' "$tmpdepfile" >> "$depfile" 354 | else 355 | echo "#dummy" > "$depfile" 356 | fi 357 | rm -f "$tmpdepfile" "$tmpdepfile2" 358 | ;; 359 | 360 | tru64) 361 | # The Tru64 compiler uses -MD to generate dependencies as a side 362 | # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. 363 | # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put 364 | # dependencies in `foo.d' instead, so we check for that too. 365 | # Subdirectories are respected. 366 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 367 | test "x$dir" = "x$object" && dir= 368 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 369 | 370 | if test "$libtool" = yes; then 371 | # With Tru64 cc, shared objects can also be used to make a 372 | # static library. This mechanism is used in libtool 1.4 series to 373 | # handle both shared and static libraries in a single compilation. 374 | # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. 375 | # 376 | # With libtool 1.5 this exception was removed, and libtool now 377 | # generates 2 separate objects for the 2 libraries. These two 378 | # compilations output dependencies in $dir.libs/$base.o.d and 379 | # in $dir$base.o.d. We have to check for both files, because 380 | # one of the two compilations can be disabled. We should prefer 381 | # $dir$base.o.d over $dir.libs/$base.o.d because the latter is 382 | # automatically cleaned when .libs/ is deleted, while ignoring 383 | # the former would cause a distcleancheck panic. 384 | tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 385 | tmpdepfile2=$dir$base.o.d # libtool 1.5 386 | tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 387 | tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 388 | "$@" -Wc,-MD 389 | else 390 | tmpdepfile1=$dir$base.o.d 391 | tmpdepfile2=$dir$base.d 392 | tmpdepfile3=$dir$base.d 393 | tmpdepfile4=$dir$base.d 394 | "$@" -MD 395 | fi 396 | 397 | stat=$? 398 | if test $stat -eq 0; then : 399 | else 400 | rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" 401 | exit $stat 402 | fi 403 | 404 | for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" 405 | do 406 | test -f "$tmpdepfile" && break 407 | done 408 | if test -f "$tmpdepfile"; then 409 | sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" 410 | # That's a tab and a space in the []. 411 | sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" 412 | else 413 | echo "#dummy" > "$depfile" 414 | fi 415 | rm -f "$tmpdepfile" 416 | ;; 417 | 418 | msvc7) 419 | if test "$libtool" = yes; then 420 | showIncludes=-Wc,-showIncludes 421 | else 422 | showIncludes=-showIncludes 423 | fi 424 | "$@" $showIncludes > "$tmpdepfile" 425 | stat=$? 426 | grep -v '^Note: including file: ' "$tmpdepfile" 427 | if test "$stat" = 0; then : 428 | else 429 | rm -f "$tmpdepfile" 430 | exit $stat 431 | fi 432 | rm -f "$depfile" 433 | echo "$object : \\" > "$depfile" 434 | # The first sed program below extracts the file names and escapes 435 | # backslashes for cygpath. The second sed program outputs the file 436 | # name when reading, but also accumulates all include files in the 437 | # hold buffer in order to output them again at the end. This only 438 | # works with sed implementations that can handle large buffers. 439 | sed < "$tmpdepfile" -n ' 440 | /^Note: including file: *\(.*\)/ { 441 | s//\1/ 442 | s/\\/\\\\/g 443 | p 444 | }' | $cygpath_u | sort -u | sed -n ' 445 | s/ /\\ /g 446 | s/\(.*\)/ \1 \\/p 447 | s/.\(.*\) \\/\1:/ 448 | H 449 | $ { 450 | s/.*/ / 451 | G 452 | p 453 | }' >> "$depfile" 454 | rm -f "$tmpdepfile" 455 | ;; 456 | 457 | msvc7msys) 458 | # This case exists only to let depend.m4 do its work. It works by 459 | # looking at the text of this script. This case will never be run, 460 | # since it is checked for above. 461 | exit 1 462 | ;; 463 | 464 | #nosideeffect) 465 | # This comment above is used by automake to tell side-effect 466 | # dependency tracking mechanisms from slower ones. 467 | 468 | dashmstdout) 469 | # Important note: in order to support this mode, a compiler *must* 470 | # always write the preprocessed file to stdout, regardless of -o. 471 | "$@" || exit $? 472 | 473 | # Remove the call to Libtool. 474 | if test "$libtool" = yes; then 475 | while test "X$1" != 'X--mode=compile'; do 476 | shift 477 | done 478 | shift 479 | fi 480 | 481 | # Remove `-o $object'. 482 | IFS=" " 483 | for arg 484 | do 485 | case $arg in 486 | -o) 487 | shift 488 | ;; 489 | $object) 490 | shift 491 | ;; 492 | *) 493 | set fnord "$@" "$arg" 494 | shift # fnord 495 | shift # $arg 496 | ;; 497 | esac 498 | done 499 | 500 | test -z "$dashmflag" && dashmflag=-M 501 | # Require at least two characters before searching for `:' 502 | # in the target name. This is to cope with DOS-style filenames: 503 | # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. 504 | "$@" $dashmflag | 505 | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" 506 | rm -f "$depfile" 507 | cat < "$tmpdepfile" > "$depfile" 508 | tr ' ' ' 509 | ' < "$tmpdepfile" | \ 510 | ## Some versions of the HPUX 10.20 sed can't process this invocation 511 | ## correctly. Breaking it into two sed invocations is a workaround. 512 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 513 | rm -f "$tmpdepfile" 514 | ;; 515 | 516 | dashXmstdout) 517 | # This case only exists to satisfy depend.m4. It is never actually 518 | # run, as this mode is specially recognized in the preamble. 519 | exit 1 520 | ;; 521 | 522 | makedepend) 523 | "$@" || exit $? 524 | # Remove any Libtool call 525 | if test "$libtool" = yes; then 526 | while test "X$1" != 'X--mode=compile'; do 527 | shift 528 | done 529 | shift 530 | fi 531 | # X makedepend 532 | shift 533 | cleared=no eat=no 534 | for arg 535 | do 536 | case $cleared in 537 | no) 538 | set ""; shift 539 | cleared=yes ;; 540 | esac 541 | if test $eat = yes; then 542 | eat=no 543 | continue 544 | fi 545 | case "$arg" in 546 | -D*|-I*) 547 | set fnord "$@" "$arg"; shift ;; 548 | # Strip any option that makedepend may not understand. Remove 549 | # the object too, otherwise makedepend will parse it as a source file. 550 | -arch) 551 | eat=yes ;; 552 | -*|$object) 553 | ;; 554 | *) 555 | set fnord "$@" "$arg"; shift ;; 556 | esac 557 | done 558 | obj_suffix=`echo "$object" | sed 's/^.*\././'` 559 | touch "$tmpdepfile" 560 | ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" 561 | rm -f "$depfile" 562 | # makedepend may prepend the VPATH from the source file name to the object. 563 | # No need to regex-escape $object, excess matching of '.' is harmless. 564 | sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" 565 | sed '1,2d' "$tmpdepfile" | tr ' ' ' 566 | ' | \ 567 | ## Some versions of the HPUX 10.20 sed can't process this invocation 568 | ## correctly. Breaking it into two sed invocations is a workaround. 569 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 570 | rm -f "$tmpdepfile" "$tmpdepfile".bak 571 | ;; 572 | 573 | cpp) 574 | # Important note: in order to support this mode, a compiler *must* 575 | # always write the preprocessed file to stdout. 576 | "$@" || exit $? 577 | 578 | # Remove the call to Libtool. 579 | if test "$libtool" = yes; then 580 | while test "X$1" != 'X--mode=compile'; do 581 | shift 582 | done 583 | shift 584 | fi 585 | 586 | # Remove `-o $object'. 587 | IFS=" " 588 | for arg 589 | do 590 | case $arg in 591 | -o) 592 | shift 593 | ;; 594 | $object) 595 | shift 596 | ;; 597 | *) 598 | set fnord "$@" "$arg" 599 | shift # fnord 600 | shift # $arg 601 | ;; 602 | esac 603 | done 604 | 605 | "$@" -E | 606 | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ 607 | -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | 608 | sed '$ s: \\$::' > "$tmpdepfile" 609 | rm -f "$depfile" 610 | echo "$object : \\" > "$depfile" 611 | cat < "$tmpdepfile" >> "$depfile" 612 | sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" 613 | rm -f "$tmpdepfile" 614 | ;; 615 | 616 | msvisualcpp) 617 | # Important note: in order to support this mode, a compiler *must* 618 | # always write the preprocessed file to stdout. 619 | "$@" || exit $? 620 | 621 | # Remove the call to Libtool. 622 | if test "$libtool" = yes; then 623 | while test "X$1" != 'X--mode=compile'; do 624 | shift 625 | done 626 | shift 627 | fi 628 | 629 | IFS=" " 630 | for arg 631 | do 632 | case "$arg" in 633 | -o) 634 | shift 635 | ;; 636 | $object) 637 | shift 638 | ;; 639 | "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") 640 | set fnord "$@" 641 | shift 642 | shift 643 | ;; 644 | *) 645 | set fnord "$@" "$arg" 646 | shift 647 | shift 648 | ;; 649 | esac 650 | done 651 | "$@" -E 2>/dev/null | 652 | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" 653 | rm -f "$depfile" 654 | echo "$object : \\" > "$depfile" 655 | sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" 656 | echo " " >> "$depfile" 657 | sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" 658 | rm -f "$tmpdepfile" 659 | ;; 660 | 661 | msvcmsys) 662 | # This case exists only to let depend.m4 do its work. It works by 663 | # looking at the text of this script. This case will never be run, 664 | # since it is checked for above. 665 | exit 1 666 | ;; 667 | 668 | none) 669 | exec "$@" 670 | ;; 671 | 672 | *) 673 | echo "Unknown depmode $depmode" 1>&2 674 | exit 1 675 | ;; 676 | esac 677 | 678 | exit 0 679 | 680 | # Local Variables: 681 | # mode: shell-script 682 | # sh-indentation: 2 683 | # eval: (add-hook 'write-file-hooks 'time-stamp) 684 | # time-stamp-start: "scriptversion=" 685 | # time-stamp-format: "%:y-%02m-%02d.%02H" 686 | # time-stamp-time-zone: "UTC" 687 | # time-stamp-end: "; # UTC" 688 | # End: 689 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2011-01-19.21; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | # Protect names problematic for `test' and other utilities. 160 | case $dst_arg in 161 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 162 | esac 163 | shift;; 164 | 165 | -T) no_target_directory=true;; 166 | 167 | --version) echo "$0 $scriptversion"; exit $?;; 168 | 169 | --) shift 170 | break;; 171 | 172 | -*) echo "$0: invalid option: $1" >&2 173 | exit 1;; 174 | 175 | *) break;; 176 | esac 177 | shift 178 | done 179 | 180 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 181 | # When -d is used, all remaining arguments are directories to create. 182 | # When -t is used, the destination is already specified. 183 | # Otherwise, the last argument is the destination. Remove it from $@. 184 | for arg 185 | do 186 | if test -n "$dst_arg"; then 187 | # $@ is not empty: it contains at least $arg. 188 | set fnord "$@" "$dst_arg" 189 | shift # fnord 190 | fi 191 | shift # arg 192 | dst_arg=$arg 193 | # Protect names problematic for `test' and other utilities. 194 | case $dst_arg in 195 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 196 | esac 197 | done 198 | fi 199 | 200 | if test $# -eq 0; then 201 | if test -z "$dir_arg"; then 202 | echo "$0: no input file specified." >&2 203 | exit 1 204 | fi 205 | # It's OK to call `install-sh -d' without argument. 206 | # This can happen when creating conditional directories. 207 | exit 0 208 | fi 209 | 210 | if test -z "$dir_arg"; then 211 | do_exit='(exit $ret); exit $ret' 212 | trap "ret=129; $do_exit" 1 213 | trap "ret=130; $do_exit" 2 214 | trap "ret=141; $do_exit" 13 215 | trap "ret=143; $do_exit" 15 216 | 217 | # Set umask so as not to create temps with too-generous modes. 218 | # However, 'strip' requires both read and write access to temps. 219 | case $mode in 220 | # Optimize common cases. 221 | *644) cp_umask=133;; 222 | *755) cp_umask=22;; 223 | 224 | *[0-7]) 225 | if test -z "$stripcmd"; then 226 | u_plus_rw= 227 | else 228 | u_plus_rw='% 200' 229 | fi 230 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 231 | *) 232 | if test -z "$stripcmd"; then 233 | u_plus_rw= 234 | else 235 | u_plus_rw=,u+rw 236 | fi 237 | cp_umask=$mode$u_plus_rw;; 238 | esac 239 | fi 240 | 241 | for src 242 | do 243 | # Protect names problematic for `test' and other utilities. 244 | case $src in 245 | -* | [=\(\)!]) src=./$src;; 246 | esac 247 | 248 | if test -n "$dir_arg"; then 249 | dst=$src 250 | dstdir=$dst 251 | test -d "$dstdir" 252 | dstdir_status=$? 253 | else 254 | 255 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 256 | # might cause directories to be created, which would be especially bad 257 | # if $src (and thus $dsttmp) contains '*'. 258 | if test ! -f "$src" && test ! -d "$src"; then 259 | echo "$0: $src does not exist." >&2 260 | exit 1 261 | fi 262 | 263 | if test -z "$dst_arg"; then 264 | echo "$0: no destination specified." >&2 265 | exit 1 266 | fi 267 | dst=$dst_arg 268 | 269 | # If destination is a directory, append the input filename; won't work 270 | # if double slashes aren't ignored. 271 | if test -d "$dst"; then 272 | if test -n "$no_target_directory"; then 273 | echo "$0: $dst_arg: Is a directory" >&2 274 | exit 1 275 | fi 276 | dstdir=$dst 277 | dst=$dstdir/`basename "$src"` 278 | dstdir_status=0 279 | else 280 | # Prefer dirname, but fall back on a substitute if dirname fails. 281 | dstdir=` 282 | (dirname "$dst") 2>/dev/null || 283 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 284 | X"$dst" : 'X\(//\)[^/]' \| \ 285 | X"$dst" : 'X\(//\)$' \| \ 286 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 287 | echo X"$dst" | 288 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 289 | s//\1/ 290 | q 291 | } 292 | /^X\(\/\/\)[^/].*/{ 293 | s//\1/ 294 | q 295 | } 296 | /^X\(\/\/\)$/{ 297 | s//\1/ 298 | q 299 | } 300 | /^X\(\/\).*/{ 301 | s//\1/ 302 | q 303 | } 304 | s/.*/./; q' 305 | ` 306 | 307 | test -d "$dstdir" 308 | dstdir_status=$? 309 | fi 310 | fi 311 | 312 | obsolete_mkdir_used=false 313 | 314 | if test $dstdir_status != 0; then 315 | case $posix_mkdir in 316 | '') 317 | # Create intermediate dirs using mode 755 as modified by the umask. 318 | # This is like FreeBSD 'install' as of 1997-10-28. 319 | umask=`umask` 320 | case $stripcmd.$umask in 321 | # Optimize common cases. 322 | *[2367][2367]) mkdir_umask=$umask;; 323 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 324 | 325 | *[0-7]) 326 | mkdir_umask=`expr $umask + 22 \ 327 | - $umask % 100 % 40 + $umask % 20 \ 328 | - $umask % 10 % 4 + $umask % 2 329 | `;; 330 | *) mkdir_umask=$umask,go-w;; 331 | esac 332 | 333 | # With -d, create the new directory with the user-specified mode. 334 | # Otherwise, rely on $mkdir_umask. 335 | if test -n "$dir_arg"; then 336 | mkdir_mode=-m$mode 337 | else 338 | mkdir_mode= 339 | fi 340 | 341 | posix_mkdir=false 342 | case $umask in 343 | *[123567][0-7][0-7]) 344 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 345 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 346 | ;; 347 | *) 348 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 349 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 350 | 351 | if (umask $mkdir_umask && 352 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 353 | then 354 | if test -z "$dir_arg" || { 355 | # Check for POSIX incompatibilities with -m. 356 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 357 | # other-writeable bit of parent directory when it shouldn't. 358 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 359 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 360 | case $ls_ld_tmpdir in 361 | d????-?r-*) different_mode=700;; 362 | d????-?--*) different_mode=755;; 363 | *) false;; 364 | esac && 365 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 366 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 367 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 368 | } 369 | } 370 | then posix_mkdir=: 371 | fi 372 | rmdir "$tmpdir/d" "$tmpdir" 373 | else 374 | # Remove any dirs left behind by ancient mkdir implementations. 375 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 376 | fi 377 | trap '' 0;; 378 | esac;; 379 | esac 380 | 381 | if 382 | $posix_mkdir && ( 383 | umask $mkdir_umask && 384 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 385 | ) 386 | then : 387 | else 388 | 389 | # The umask is ridiculous, or mkdir does not conform to POSIX, 390 | # or it failed possibly due to a race condition. Create the 391 | # directory the slow way, step by step, checking for races as we go. 392 | 393 | case $dstdir in 394 | /*) prefix='/';; 395 | [-=\(\)!]*) prefix='./';; 396 | *) prefix='';; 397 | esac 398 | 399 | eval "$initialize_posix_glob" 400 | 401 | oIFS=$IFS 402 | IFS=/ 403 | $posix_glob set -f 404 | set fnord $dstdir 405 | shift 406 | $posix_glob set +f 407 | IFS=$oIFS 408 | 409 | prefixes= 410 | 411 | for d 412 | do 413 | test X"$d" = X && continue 414 | 415 | prefix=$prefix$d 416 | if test -d "$prefix"; then 417 | prefixes= 418 | else 419 | if $posix_mkdir; then 420 | (umask=$mkdir_umask && 421 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 422 | # Don't fail if two instances are running concurrently. 423 | test -d "$prefix" || exit 1 424 | else 425 | case $prefix in 426 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 427 | *) qprefix=$prefix;; 428 | esac 429 | prefixes="$prefixes '$qprefix'" 430 | fi 431 | fi 432 | prefix=$prefix/ 433 | done 434 | 435 | if test -n "$prefixes"; then 436 | # Don't fail if two instances are running concurrently. 437 | (umask $mkdir_umask && 438 | eval "\$doit_exec \$mkdirprog $prefixes") || 439 | test -d "$dstdir" || exit 1 440 | obsolete_mkdir_used=true 441 | fi 442 | fi 443 | fi 444 | 445 | if test -n "$dir_arg"; then 446 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 447 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 448 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 449 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 450 | else 451 | 452 | # Make a couple of temp file names in the proper directory. 453 | dsttmp=$dstdir/_inst.$$_ 454 | rmtmp=$dstdir/_rm.$$_ 455 | 456 | # Trap to clean up those temp files at exit. 457 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 458 | 459 | # Copy the file name to the temp name. 460 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 461 | 462 | # and set any options; do chmod last to preserve setuid bits. 463 | # 464 | # If any of these fail, we abort the whole thing. If we want to 465 | # ignore errors from any of these, just make sure not to ignore 466 | # errors from the above "$doit $cpprog $src $dsttmp" command. 467 | # 468 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 469 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 470 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 471 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 472 | 473 | # If -C, don't bother to copy if it wouldn't change the file. 474 | if $copy_on_change && 475 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 476 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 477 | 478 | eval "$initialize_posix_glob" && 479 | $posix_glob set -f && 480 | set X $old && old=:$2:$4:$5:$6 && 481 | set X $new && new=:$2:$4:$5:$6 && 482 | $posix_glob set +f && 483 | 484 | test "$old" = "$new" && 485 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 486 | then 487 | rm -f "$dsttmp" 488 | else 489 | # Rename the file to the real destination. 490 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 491 | 492 | # The rename failed, perhaps because mv can't rename something else 493 | # to itself, or perhaps because mv is so ancient that it does not 494 | # support -f. 495 | { 496 | # Now remove or move aside any old file at destination location. 497 | # We try this two ways since rm can't unlink itself on some 498 | # systems and the destination file might be busy for other 499 | # reasons. In this case, the final cleanup might fail but the new 500 | # file should still install successfully. 501 | { 502 | test ! -f "$dst" || 503 | $doit $rmcmd -f "$dst" 2>/dev/null || 504 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 505 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 506 | } || 507 | { echo "$0: cannot unlink or rename $dst" >&2 508 | (exit 1); exit 1 509 | } 510 | } && 511 | 512 | # Now rename the file to the real destination. 513 | $doit $mvcmd "$dsttmp" "$dst" 514 | } 515 | fi || exit 1 516 | 517 | trap '' 0 518 | fi 519 | done 520 | 521 | # Local variables: 522 | # eval: (add-hook 'write-file-hooks 'time-stamp) 523 | # time-stamp-start: "scriptversion=" 524 | # time-stamp-format: "%:y-%02m-%02d.%02H" 525 | # time-stamp-time-zone: "UTC" 526 | # time-stamp-end: "; # UTC" 527 | # End: 528 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2012-01-06.13; # UTC 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 7 | # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | if test $# -eq 0; then 29 | echo 1>&2 "Try \`$0 --help' for more information" 30 | exit 1 31 | fi 32 | 33 | run=: 34 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 35 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 36 | 37 | # In the cases where this matters, `missing' is being run in the 38 | # srcdir already. 39 | if test -f configure.ac; then 40 | configure_ac=configure.ac 41 | else 42 | configure_ac=configure.in 43 | fi 44 | 45 | msg="missing on your system" 46 | 47 | case $1 in 48 | --run) 49 | # Try to run requested program, and just exit if it succeeds. 50 | run= 51 | shift 52 | "$@" && exit 0 53 | # Exit code 63 means version mismatch. This often happens 54 | # when the user try to use an ancient version of a tool on 55 | # a file that requires a minimum version. In this case we 56 | # we should proceed has if the program had been absent, or 57 | # if --run hadn't been passed. 58 | if test $? = 63; then 59 | run=: 60 | msg="probably too old" 61 | fi 62 | ;; 63 | 64 | -h|--h|--he|--hel|--help) 65 | echo "\ 66 | $0 [OPTION]... PROGRAM [ARGUMENT]... 67 | 68 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 69 | error status if there is no known handling for PROGRAM. 70 | 71 | Options: 72 | -h, --help display this help and exit 73 | -v, --version output version information and exit 74 | --run try to run the given command, and emulate it if it fails 75 | 76 | Supported PROGRAM values: 77 | aclocal touch file \`aclocal.m4' 78 | autoconf touch file \`configure' 79 | autoheader touch file \`config.h.in' 80 | autom4te touch the output file, or create a stub one 81 | automake touch all \`Makefile.in' files 82 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 83 | flex create \`lex.yy.c', if possible, from existing .c 84 | help2man touch the output file 85 | lex create \`lex.yy.c', if possible, from existing .c 86 | makeinfo touch the output file 87 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 88 | 89 | Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and 90 | \`g' are ignored when checking the name. 91 | 92 | Send bug reports to ." 93 | exit $? 94 | ;; 95 | 96 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 97 | echo "missing $scriptversion (GNU Automake)" 98 | exit $? 99 | ;; 100 | 101 | -*) 102 | echo 1>&2 "$0: Unknown \`$1' option" 103 | echo 1>&2 "Try \`$0 --help' for more information" 104 | exit 1 105 | ;; 106 | 107 | esac 108 | 109 | # normalize program name to check for. 110 | program=`echo "$1" | sed ' 111 | s/^gnu-//; t 112 | s/^gnu//; t 113 | s/^g//; t'` 114 | 115 | # Now exit if we have it, but it failed. Also exit now if we 116 | # don't have it and --version was passed (most likely to detect 117 | # the program). This is about non-GNU programs, so use $1 not 118 | # $program. 119 | case $1 in 120 | lex*|yacc*) 121 | # Not GNU programs, they don't have --version. 122 | ;; 123 | 124 | *) 125 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 126 | # We have it, but it failed. 127 | exit 1 128 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 129 | # Could not run --version or --help. This is probably someone 130 | # running `$TOOL --version' or `$TOOL --help' to check whether 131 | # $TOOL exists and not knowing $TOOL uses missing. 132 | exit 1 133 | fi 134 | ;; 135 | esac 136 | 137 | # If it does not exist, or fails to run (possibly an outdated version), 138 | # try to emulate it. 139 | case $program in 140 | aclocal*) 141 | echo 1>&2 "\ 142 | WARNING: \`$1' is $msg. You should only need it if 143 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 144 | to install the \`Automake' and \`Perl' packages. Grab them from 145 | any GNU archive site." 146 | touch aclocal.m4 147 | ;; 148 | 149 | autoconf*) 150 | echo 1>&2 "\ 151 | WARNING: \`$1' is $msg. You should only need it if 152 | you modified \`${configure_ac}'. You might want to install the 153 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 154 | archive site." 155 | touch configure 156 | ;; 157 | 158 | autoheader*) 159 | echo 1>&2 "\ 160 | WARNING: \`$1' is $msg. You should only need it if 161 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 162 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 163 | from any GNU archive site." 164 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 165 | test -z "$files" && files="config.h" 166 | touch_files= 167 | for f in $files; do 168 | case $f in 169 | *:*) touch_files="$touch_files "`echo "$f" | 170 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 171 | *) touch_files="$touch_files $f.in";; 172 | esac 173 | done 174 | touch $touch_files 175 | ;; 176 | 177 | automake*) 178 | echo 1>&2 "\ 179 | WARNING: \`$1' is $msg. You should only need it if 180 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 181 | You might want to install the \`Automake' and \`Perl' packages. 182 | Grab them from any GNU archive site." 183 | find . -type f -name Makefile.am -print | 184 | sed 's/\.am$/.in/' | 185 | while read f; do touch "$f"; done 186 | ;; 187 | 188 | autom4te*) 189 | echo 1>&2 "\ 190 | WARNING: \`$1' is needed, but is $msg. 191 | You might have modified some files without having the 192 | proper tools for further handling them. 193 | You can get \`$1' as part of \`Autoconf' from any GNU 194 | archive site." 195 | 196 | file=`echo "$*" | sed -n "$sed_output"` 197 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 198 | if test -f "$file"; then 199 | touch $file 200 | else 201 | test -z "$file" || exec >$file 202 | echo "#! /bin/sh" 203 | echo "# Created by GNU Automake missing as a replacement of" 204 | echo "# $ $@" 205 | echo "exit 0" 206 | chmod +x $file 207 | exit 1 208 | fi 209 | ;; 210 | 211 | bison*|yacc*) 212 | echo 1>&2 "\ 213 | WARNING: \`$1' $msg. You should only need it if 214 | you modified a \`.y' file. You may need the \`Bison' package 215 | in order for those modifications to take effect. You can get 216 | \`Bison' from any GNU archive site." 217 | rm -f y.tab.c y.tab.h 218 | if test $# -ne 1; then 219 | eval LASTARG=\${$#} 220 | case $LASTARG in 221 | *.y) 222 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 223 | if test -f "$SRCFILE"; then 224 | cp "$SRCFILE" y.tab.c 225 | fi 226 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 227 | if test -f "$SRCFILE"; then 228 | cp "$SRCFILE" y.tab.h 229 | fi 230 | ;; 231 | esac 232 | fi 233 | if test ! -f y.tab.h; then 234 | echo >y.tab.h 235 | fi 236 | if test ! -f y.tab.c; then 237 | echo 'main() { return 0; }' >y.tab.c 238 | fi 239 | ;; 240 | 241 | lex*|flex*) 242 | echo 1>&2 "\ 243 | WARNING: \`$1' is $msg. You should only need it if 244 | you modified a \`.l' file. You may need the \`Flex' package 245 | in order for those modifications to take effect. You can get 246 | \`Flex' from any GNU archive site." 247 | rm -f lex.yy.c 248 | if test $# -ne 1; then 249 | eval LASTARG=\${$#} 250 | case $LASTARG in 251 | *.l) 252 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 253 | if test -f "$SRCFILE"; then 254 | cp "$SRCFILE" lex.yy.c 255 | fi 256 | ;; 257 | esac 258 | fi 259 | if test ! -f lex.yy.c; then 260 | echo 'main() { return 0; }' >lex.yy.c 261 | fi 262 | ;; 263 | 264 | help2man*) 265 | echo 1>&2 "\ 266 | WARNING: \`$1' is $msg. You should only need it if 267 | you modified a dependency of a manual page. You may need the 268 | \`Help2man' package in order for those modifications to take 269 | effect. You can get \`Help2man' from any GNU archive site." 270 | 271 | file=`echo "$*" | sed -n "$sed_output"` 272 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 273 | if test -f "$file"; then 274 | touch $file 275 | else 276 | test -z "$file" || exec >$file 277 | echo ".ab help2man is required to generate this page" 278 | exit $? 279 | fi 280 | ;; 281 | 282 | makeinfo*) 283 | echo 1>&2 "\ 284 | WARNING: \`$1' is $msg. You should only need it if 285 | you modified a \`.texi' or \`.texinfo' file, or any other file 286 | indirectly affecting the aspect of the manual. The spurious 287 | call might also be the consequence of using a buggy \`make' (AIX, 288 | DU, IRIX). You might want to install the \`Texinfo' package or 289 | the \`GNU make' package. Grab either from any GNU archive site." 290 | # The file to touch is that specified with -o ... 291 | file=`echo "$*" | sed -n "$sed_output"` 292 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 293 | if test -z "$file"; then 294 | # ... or it is the one specified with @setfilename ... 295 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 296 | file=`sed -n ' 297 | /^@setfilename/{ 298 | s/.* \([^ ]*\) *$/\1/ 299 | p 300 | q 301 | }' $infile` 302 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 303 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 304 | fi 305 | # If the file does not exist, the user really needs makeinfo; 306 | # let's fail without touching anything. 307 | test -f $file || exit 1 308 | touch $file 309 | ;; 310 | 311 | *) 312 | echo 1>&2 "\ 313 | WARNING: \`$1' is needed, and is $msg. 314 | You might have modified some files without having the 315 | proper tools for further handling them. Check the \`README' file, 316 | it often tells you about the needed prerequisites for installing 317 | this package. You may also peek at any GNU archive site, in case 318 | some other package would contain this missing \`$1' program." 319 | exit 1 320 | ;; 321 | esac 322 | 323 | exit 0 324 | 325 | # Local variables: 326 | # eval: (add-hook 'write-file-hooks 'time-stamp) 327 | # time-stamp-start: "scriptversion=" 328 | # time-stamp-format: "%:y-%02m-%02d.%02H" 329 | # time-stamp-time-zone: "UTC" 330 | # time-stamp-end: "; # UTC" 331 | # End: 332 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = infact 2 | -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.14.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994-2013 Free Software Foundation, Inc. 5 | 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | VPATH = @srcdir@ 17 | am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 18 | am__make_running_with_option = \ 19 | case $${target_option-} in \ 20 | ?) ;; \ 21 | *) echo "am__make_running_with_option: internal error: invalid" \ 22 | "target option '$${target_option-}' specified" >&2; \ 23 | exit 1;; \ 24 | esac; \ 25 | has_opt=no; \ 26 | sane_makeflags=$$MAKEFLAGS; \ 27 | if $(am__is_gnu_make); then \ 28 | sane_makeflags=$$MFLAGS; \ 29 | else \ 30 | case $$MAKEFLAGS in \ 31 | *\\[\ \ ]*) \ 32 | bs=\\; \ 33 | sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ 34 | | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ 35 | esac; \ 36 | fi; \ 37 | skip_next=no; \ 38 | strip_trailopt () \ 39 | { \ 40 | flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ 41 | }; \ 42 | for flg in $$sane_makeflags; do \ 43 | test $$skip_next = yes && { skip_next=no; continue; }; \ 44 | case $$flg in \ 45 | *=*|--*) continue;; \ 46 | -*I) strip_trailopt 'I'; skip_next=yes;; \ 47 | -*I?*) strip_trailopt 'I';; \ 48 | -*O) strip_trailopt 'O'; skip_next=yes;; \ 49 | -*O?*) strip_trailopt 'O';; \ 50 | -*l) strip_trailopt 'l'; skip_next=yes;; \ 51 | -*l?*) strip_trailopt 'l';; \ 52 | -[dEDm]) skip_next=yes;; \ 53 | -[JT]) skip_next=yes;; \ 54 | esac; \ 55 | case $$flg in \ 56 | *$$target_option*) has_opt=yes; break;; \ 57 | esac; \ 58 | done; \ 59 | test $$has_opt = yes 60 | am__make_dryrun = (target_option=n; $(am__make_running_with_option)) 61 | am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 62 | pkgdatadir = $(datadir)/@PACKAGE@ 63 | pkgincludedir = $(includedir)/@PACKAGE@ 64 | pkglibdir = $(libdir)/@PACKAGE@ 65 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 66 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 67 | install_sh_DATA = $(install_sh) -c -m 644 68 | install_sh_PROGRAM = $(install_sh) -c 69 | install_sh_SCRIPT = $(install_sh) -c 70 | INSTALL_HEADER = $(INSTALL_DATA) 71 | transform = $(program_transform_name) 72 | NORMAL_INSTALL = : 73 | PRE_INSTALL = : 74 | POST_INSTALL = : 75 | NORMAL_UNINSTALL = : 76 | PRE_UNINSTALL = : 77 | POST_UNINSTALL = : 78 | subdir = src 79 | DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am 80 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 81 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 82 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 83 | $(ACLOCAL_M4) 84 | mkinstalldirs = $(install_sh) -d 85 | CONFIG_HEADER = $(top_builddir)/config.h 86 | CONFIG_CLEAN_FILES = 87 | CONFIG_CLEAN_VPATH_FILES = 88 | AM_V_P = $(am__v_P_@AM_V@) 89 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) 90 | am__v_P_0 = false 91 | am__v_P_1 = : 92 | AM_V_GEN = $(am__v_GEN_@AM_V@) 93 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) 94 | am__v_GEN_0 = @echo " GEN " $@; 95 | am__v_GEN_1 = 96 | AM_V_at = $(am__v_at_@AM_V@) 97 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) 98 | am__v_at_0 = @ 99 | am__v_at_1 = 100 | SOURCES = 101 | DIST_SOURCES = 102 | RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ 103 | ctags-recursive dvi-recursive html-recursive info-recursive \ 104 | install-data-recursive install-dvi-recursive \ 105 | install-exec-recursive install-html-recursive \ 106 | install-info-recursive install-pdf-recursive \ 107 | install-ps-recursive install-recursive installcheck-recursive \ 108 | installdirs-recursive pdf-recursive ps-recursive \ 109 | tags-recursive uninstall-recursive 110 | am__can_run_installinfo = \ 111 | case $$AM_UPDATE_INFO_DIR in \ 112 | n|no|NO) false;; \ 113 | *) (install-info --version) >/dev/null 2>&1;; \ 114 | esac 115 | RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ 116 | distclean-recursive maintainer-clean-recursive 117 | am__recursive_targets = \ 118 | $(RECURSIVE_TARGETS) \ 119 | $(RECURSIVE_CLEAN_TARGETS) \ 120 | $(am__extra_recursive_targets) 121 | AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ 122 | distdir 123 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) 124 | # Read a list of newline-separated strings from the standard input, 125 | # and print each of them once, without duplicates. Input order is 126 | # *not* preserved. 127 | am__uniquify_input = $(AWK) '\ 128 | BEGIN { nonempty = 0; } \ 129 | { items[$$0] = 1; nonempty = 1; } \ 130 | END { if (nonempty) { for (i in items) print i; }; } \ 131 | ' 132 | # Make sure the list of sources is unique. This is necessary because, 133 | # e.g., the same source file might be shared among _SOURCES variables 134 | # for different programs/libraries. 135 | am__define_uniq_tagged_files = \ 136 | list='$(am__tagged_files)'; \ 137 | unique=`for i in $$list; do \ 138 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 139 | done | $(am__uniquify_input)` 140 | ETAGS = etags 141 | CTAGS = ctags 142 | DIST_SUBDIRS = $(SUBDIRS) 143 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 144 | am__relativize = \ 145 | dir0=`pwd`; \ 146 | sed_first='s,^\([^/]*\)/.*$$,\1,'; \ 147 | sed_rest='s,^[^/]*/*,,'; \ 148 | sed_last='s,^.*/\([^/]*\)$$,\1,'; \ 149 | sed_butlast='s,/*[^/]*$$,,'; \ 150 | while test -n "$$dir1"; do \ 151 | first=`echo "$$dir1" | sed -e "$$sed_first"`; \ 152 | if test "$$first" != "."; then \ 153 | if test "$$first" = ".."; then \ 154 | dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ 155 | dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ 156 | else \ 157 | first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ 158 | if test "$$first2" = "$$first"; then \ 159 | dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ 160 | else \ 161 | dir2="../$$dir2"; \ 162 | fi; \ 163 | dir0="$$dir0"/"$$first"; \ 164 | fi; \ 165 | fi; \ 166 | dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ 167 | done; \ 168 | reldir="$$dir2" 169 | ACLOCAL = @ACLOCAL@ 170 | AMTAR = @AMTAR@ 171 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 172 | AR = @AR@ 173 | AUTOCONF = @AUTOCONF@ 174 | AUTOHEADER = @AUTOHEADER@ 175 | AUTOMAKE = @AUTOMAKE@ 176 | AWK = @AWK@ 177 | CC = @CC@ 178 | CCDEPMODE = @CCDEPMODE@ 179 | CFLAGS = @CFLAGS@ 180 | CPP = @CPP@ 181 | CPPFLAGS = @CPPFLAGS@ 182 | CXX = @CXX@ 183 | CXXDEPMODE = @CXXDEPMODE@ 184 | CXXFLAGS = @CXXFLAGS@ 185 | CYGPATH_W = @CYGPATH_W@ 186 | DEFS = @DEFS@ 187 | DEPDIR = @DEPDIR@ 188 | ECHO_C = @ECHO_C@ 189 | ECHO_N = @ECHO_N@ 190 | ECHO_T = @ECHO_T@ 191 | EGREP = @EGREP@ 192 | EXEEXT = @EXEEXT@ 193 | GREP = @GREP@ 194 | INSTALL = @INSTALL@ 195 | INSTALL_DATA = @INSTALL_DATA@ 196 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 197 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 198 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 199 | LDFLAGS = @LDFLAGS@ 200 | LIBOBJS = @LIBOBJS@ 201 | LIBS = @LIBS@ 202 | LTLIBOBJS = @LTLIBOBJS@ 203 | MAKEINFO = @MAKEINFO@ 204 | MKDIR_P = @MKDIR_P@ 205 | OBJEXT = @OBJEXT@ 206 | PACKAGE = @PACKAGE@ 207 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 208 | PACKAGE_NAME = @PACKAGE_NAME@ 209 | PACKAGE_STRING = @PACKAGE_STRING@ 210 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 211 | PACKAGE_URL = @PACKAGE_URL@ 212 | PACKAGE_VERSION = @PACKAGE_VERSION@ 213 | PATH_SEPARATOR = @PATH_SEPARATOR@ 214 | RANLIB = @RANLIB@ 215 | SED = @SED@ 216 | SET_MAKE = @SET_MAKE@ 217 | SHELL = @SHELL@ 218 | STRIP = @STRIP@ 219 | VERSION = @VERSION@ 220 | abs_builddir = @abs_builddir@ 221 | abs_srcdir = @abs_srcdir@ 222 | abs_top_builddir = @abs_top_builddir@ 223 | abs_top_srcdir = @abs_top_srcdir@ 224 | ac_ct_AR = @ac_ct_AR@ 225 | ac_ct_CC = @ac_ct_CC@ 226 | ac_ct_CXX = @ac_ct_CXX@ 227 | am__include = @am__include@ 228 | am__leading_dot = @am__leading_dot@ 229 | am__quote = @am__quote@ 230 | am__tar = @am__tar@ 231 | am__untar = @am__untar@ 232 | bindir = @bindir@ 233 | build_alias = @build_alias@ 234 | builddir = @builddir@ 235 | datadir = @datadir@ 236 | datarootdir = @datarootdir@ 237 | docdir = @docdir@ 238 | dvidir = @dvidir@ 239 | exec_prefix = @exec_prefix@ 240 | host_alias = @host_alias@ 241 | htmldir = @htmldir@ 242 | includedir = @includedir@ 243 | infodir = @infodir@ 244 | install_sh = @install_sh@ 245 | libdir = @libdir@ 246 | libexecdir = @libexecdir@ 247 | localedir = @localedir@ 248 | localstatedir = @localstatedir@ 249 | mandir = @mandir@ 250 | mkdir_p = @mkdir_p@ 251 | oldincludedir = @oldincludedir@ 252 | pdfdir = @pdfdir@ 253 | prefix = @prefix@ 254 | program_transform_name = @program_transform_name@ 255 | psdir = @psdir@ 256 | sbindir = @sbindir@ 257 | sharedstatedir = @sharedstatedir@ 258 | srcdir = @srcdir@ 259 | sysconfdir = @sysconfdir@ 260 | target_alias = @target_alias@ 261 | top_build_prefix = @top_build_prefix@ 262 | top_builddir = @top_builddir@ 263 | top_srcdir = @top_srcdir@ 264 | SUBDIRS = infact 265 | all: all-recursive 266 | 267 | .SUFFIXES: 268 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 269 | @for dep in $?; do \ 270 | case '$(am__configure_deps)' in \ 271 | *$$dep*) \ 272 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 273 | && { if test -f $@; then exit 0; else break; fi; }; \ 274 | exit 1;; \ 275 | esac; \ 276 | done; \ 277 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ 278 | $(am__cd) $(top_srcdir) && \ 279 | $(AUTOMAKE) --foreign src/Makefile 280 | .PRECIOUS: Makefile 281 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 282 | @case '$?' in \ 283 | *config.status*) \ 284 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 285 | *) \ 286 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 287 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 288 | esac; 289 | 290 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 291 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 292 | 293 | $(top_srcdir)/configure: $(am__configure_deps) 294 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 295 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 296 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 297 | $(am__aclocal_m4_deps): 298 | 299 | # This directory's subdirectories are mostly independent; you can cd 300 | # into them and run 'make' without going through this Makefile. 301 | # To change the values of 'make' variables: instead of editing Makefiles, 302 | # (1) if the variable is set in 'config.status', edit 'config.status' 303 | # (which will cause the Makefiles to be regenerated when you run 'make'); 304 | # (2) otherwise, pass the desired values on the 'make' command line. 305 | $(am__recursive_targets): 306 | @fail=; \ 307 | if $(am__make_keepgoing); then \ 308 | failcom='fail=yes'; \ 309 | else \ 310 | failcom='exit 1'; \ 311 | fi; \ 312 | dot_seen=no; \ 313 | target=`echo $@ | sed s/-recursive//`; \ 314 | case "$@" in \ 315 | distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ 316 | *) list='$(SUBDIRS)' ;; \ 317 | esac; \ 318 | for subdir in $$list; do \ 319 | echo "Making $$target in $$subdir"; \ 320 | if test "$$subdir" = "."; then \ 321 | dot_seen=yes; \ 322 | local_target="$$target-am"; \ 323 | else \ 324 | local_target="$$target"; \ 325 | fi; \ 326 | ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ 327 | || eval $$failcom; \ 328 | done; \ 329 | if test "$$dot_seen" = "no"; then \ 330 | $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ 331 | fi; test -z "$$fail" 332 | 333 | ID: $(am__tagged_files) 334 | $(am__define_uniq_tagged_files); mkid -fID $$unique 335 | tags: tags-recursive 336 | TAGS: tags 337 | 338 | tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 339 | set x; \ 340 | here=`pwd`; \ 341 | if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ 342 | include_option=--etags-include; \ 343 | empty_fix=.; \ 344 | else \ 345 | include_option=--include; \ 346 | empty_fix=; \ 347 | fi; \ 348 | list='$(SUBDIRS)'; for subdir in $$list; do \ 349 | if test "$$subdir" = .; then :; else \ 350 | test ! -f $$subdir/TAGS || \ 351 | set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ 352 | fi; \ 353 | done; \ 354 | $(am__define_uniq_tagged_files); \ 355 | shift; \ 356 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ 357 | test -n "$$unique" || unique=$$empty_fix; \ 358 | if test $$# -gt 0; then \ 359 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 360 | "$$@" $$unique; \ 361 | else \ 362 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 363 | $$unique; \ 364 | fi; \ 365 | fi 366 | ctags: ctags-recursive 367 | 368 | CTAGS: ctags 369 | ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 370 | $(am__define_uniq_tagged_files); \ 371 | test -z "$(CTAGS_ARGS)$$unique" \ 372 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 373 | $$unique 374 | 375 | GTAGS: 376 | here=`$(am__cd) $(top_builddir) && pwd` \ 377 | && $(am__cd) $(top_srcdir) \ 378 | && gtags -i $(GTAGS_ARGS) "$$here" 379 | cscopelist: cscopelist-recursive 380 | 381 | cscopelist-am: $(am__tagged_files) 382 | list='$(am__tagged_files)'; \ 383 | case "$(srcdir)" in \ 384 | [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ 385 | *) sdir=$(subdir)/$(srcdir) ;; \ 386 | esac; \ 387 | for i in $$list; do \ 388 | if test -f "$$i"; then \ 389 | echo "$(subdir)/$$i"; \ 390 | else \ 391 | echo "$$sdir/$$i"; \ 392 | fi; \ 393 | done >> $(top_builddir)/cscope.files 394 | 395 | distclean-tags: 396 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 397 | 398 | distdir: $(DISTFILES) 399 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 400 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 401 | list='$(DISTFILES)'; \ 402 | dist_files=`for file in $$list; do echo $$file; done | \ 403 | sed -e "s|^$$srcdirstrip/||;t" \ 404 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 405 | case $$dist_files in \ 406 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 407 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 408 | sort -u` ;; \ 409 | esac; \ 410 | for file in $$dist_files; do \ 411 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 412 | if test -d $$d/$$file; then \ 413 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 414 | if test -d "$(distdir)/$$file"; then \ 415 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 416 | fi; \ 417 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 418 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 419 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 420 | fi; \ 421 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 422 | else \ 423 | test -f "$(distdir)/$$file" \ 424 | || cp -p $$d/$$file "$(distdir)/$$file" \ 425 | || exit 1; \ 426 | fi; \ 427 | done 428 | @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ 429 | if test "$$subdir" = .; then :; else \ 430 | $(am__make_dryrun) \ 431 | || test -d "$(distdir)/$$subdir" \ 432 | || $(MKDIR_P) "$(distdir)/$$subdir" \ 433 | || exit 1; \ 434 | dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ 435 | $(am__relativize); \ 436 | new_distdir=$$reldir; \ 437 | dir1=$$subdir; dir2="$(top_distdir)"; \ 438 | $(am__relativize); \ 439 | new_top_distdir=$$reldir; \ 440 | echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ 441 | echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ 442 | ($(am__cd) $$subdir && \ 443 | $(MAKE) $(AM_MAKEFLAGS) \ 444 | top_distdir="$$new_top_distdir" \ 445 | distdir="$$new_distdir" \ 446 | am__remove_distdir=: \ 447 | am__skip_length_check=: \ 448 | am__skip_mode_fix=: \ 449 | distdir) \ 450 | || exit 1; \ 451 | fi; \ 452 | done 453 | check-am: all-am 454 | check: check-recursive 455 | all-am: Makefile 456 | installdirs: installdirs-recursive 457 | installdirs-am: 458 | install: install-recursive 459 | install-exec: install-exec-recursive 460 | install-data: install-data-recursive 461 | uninstall: uninstall-recursive 462 | 463 | install-am: all-am 464 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 465 | 466 | installcheck: installcheck-recursive 467 | install-strip: 468 | if test -z '$(STRIP)'; then \ 469 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 470 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 471 | install; \ 472 | else \ 473 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 474 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 475 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 476 | fi 477 | mostlyclean-generic: 478 | 479 | clean-generic: 480 | 481 | distclean-generic: 482 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 483 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 484 | 485 | maintainer-clean-generic: 486 | @echo "This command is intended for maintainers to use" 487 | @echo "it deletes files that may require special tools to rebuild." 488 | clean: clean-recursive 489 | 490 | clean-am: clean-generic mostlyclean-am 491 | 492 | distclean: distclean-recursive 493 | -rm -f Makefile 494 | distclean-am: clean-am distclean-generic distclean-tags 495 | 496 | dvi: dvi-recursive 497 | 498 | dvi-am: 499 | 500 | html: html-recursive 501 | 502 | html-am: 503 | 504 | info: info-recursive 505 | 506 | info-am: 507 | 508 | install-data-am: 509 | 510 | install-dvi: install-dvi-recursive 511 | 512 | install-dvi-am: 513 | 514 | install-exec-am: 515 | 516 | install-html: install-html-recursive 517 | 518 | install-html-am: 519 | 520 | install-info: install-info-recursive 521 | 522 | install-info-am: 523 | 524 | install-man: 525 | 526 | install-pdf: install-pdf-recursive 527 | 528 | install-pdf-am: 529 | 530 | install-ps: install-ps-recursive 531 | 532 | install-ps-am: 533 | 534 | installcheck-am: 535 | 536 | maintainer-clean: maintainer-clean-recursive 537 | -rm -f Makefile 538 | maintainer-clean-am: distclean-am maintainer-clean-generic 539 | 540 | mostlyclean: mostlyclean-recursive 541 | 542 | mostlyclean-am: mostlyclean-generic 543 | 544 | pdf: pdf-recursive 545 | 546 | pdf-am: 547 | 548 | ps: ps-recursive 549 | 550 | ps-am: 551 | 552 | uninstall-am: 553 | 554 | .MAKE: $(am__recursive_targets) install-am install-strip 555 | 556 | .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ 557 | check-am clean clean-generic cscopelist-am ctags ctags-am \ 558 | distclean distclean-generic distclean-tags distdir dvi dvi-am \ 559 | html html-am info info-am install install-am install-data \ 560 | install-data-am install-dvi install-dvi-am install-exec \ 561 | install-exec-am install-html install-html-am install-info \ 562 | install-info-am install-man install-pdf install-pdf-am \ 563 | install-ps install-ps-am install-strip installcheck \ 564 | installcheck-am installdirs installdirs-am maintainer-clean \ 565 | maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ 566 | pdf-am ps ps-am tags tags-am uninstall uninstall-am 567 | 568 | 569 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 570 | # Otherwise a system limit (for SysV at least) may be exceeded. 571 | .NOEXPORT: 572 | -------------------------------------------------------------------------------- /src/infact/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I. -Wall 2 | 3 | testdir=${exec_prefix}/test-bin 4 | test_PROGRAMS = bin/stream-tokenizer-test \ 5 | bin/environment-test \ 6 | bin/interpreter-test 7 | 8 | SRCS = error.cc stream-tokenizer.cc environment.cc environment-impl.cc \ 9 | factory.cc interpreter.cc 10 | 11 | lib_LIBRARIES = lib/libinfact.a 12 | lib_libinfact_a_SOURCES = $(SRCS) 13 | 14 | # The following are test executables (similar to unit tescibts). 15 | bin_stream_tokenizer_test_SOURCES = $(SRCS) stream-tokenizer-test.cc 16 | bin_environment_test_SOURCES = $(SRCS) example.cc environment-test.cc 17 | bin_interpreter_test_SOURCES = $(SRCS) example.cc interpreter-test.cc 18 | -------------------------------------------------------------------------------- /src/infact/environment-impl.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Implementation of the Environment class. 34 | /// \author dbikel@google.com (Dan Bikel) 35 | 36 | #include "environment-impl.h" 37 | #include "factory.h" 38 | 39 | namespace infact { 40 | 41 | EnvironmentImpl::EnvironmentImpl(int debug) { 42 | debug_ = debug; 43 | 44 | // Set up VarMap instances for each of the primitive types and their vectors. 45 | var_map_["bool"] = new VarMap("bool", this); 46 | var_map_["int"] = new VarMap("int", this); 47 | var_map_["double"] = new VarMap("double", this); 48 | var_map_["string"] = new VarMap("string", this); 49 | var_map_["bool[]"] = new VarMap >("bool[]", "bool", this); 50 | var_map_["int[]"] = new VarMap >("int[]", "int", this); 51 | var_map_["double[]"] = 52 | new VarMap >("double[]", "double", this); 53 | var_map_["string[]"] = 54 | new VarMap >("string[]", "string", this); 55 | 56 | // Set up VarMap instances for each of the Factory-constructible types 57 | // and their vectors. 58 | for (FactoryContainer::iterator factory_it = FactoryContainer::begin(); 59 | factory_it != FactoryContainer::end(); ++factory_it) { 60 | unordered_set registered; 61 | (*factory_it)->CollectRegistered(registered); 62 | string base_name = (*factory_it)->BaseName(); 63 | 64 | // Create type-specific VarMap from the Factory and add to var_map_. 65 | VarMapBase *obj_var_map = (*factory_it)->CreateVarMap(this); 66 | var_map_[obj_var_map->Name()] = obj_var_map; 67 | 68 | if (debug_ >= 3) { 69 | cerr << "Environment: created VarMap for " << obj_var_map->Name() 70 | << endl; 71 | } 72 | 73 | // Create VarMap for vectors of shared_object of T and add to var_map_. 74 | VarMapBase *obj_vector_var_map = (*factory_it)->CreateVectorVarMap(this); 75 | var_map_[obj_vector_var_map->Name()] = obj_vector_var_map; 76 | 77 | if (debug_ >= 3) { 78 | cerr << "Environment: created VarMap for " << obj_vector_var_map->Name() 79 | << endl; 80 | } 81 | 82 | for (unordered_set::const_iterator it = registered.begin(); 83 | it != registered.end(); ++it) { 84 | const string &concrete_type_name = *it; 85 | 86 | unordered_map::const_iterator concrete_to_factory_it = 87 | concrete_to_factory_type_.find(concrete_type_name); 88 | if (concrete_to_factory_it != concrete_to_factory_type_.end()) { 89 | // Warn user that there are two entries for the same concrete type 90 | // (presumably due to different abstract factory types). 91 | cerr << "Environment: WARNING: trying to override existing " 92 | << "concrete-to-factory type mapping [" 93 | << concrete_type_name << " --> " << concrete_to_factory_it->second 94 | << "] with [" << concrete_type_name << " --> " << base_name 95 | << endl; 96 | } 97 | concrete_to_factory_type_[concrete_type_name] = base_name; 98 | 99 | if (debug_ >= 3) { 100 | cerr << "Environment: associating concrete typename " 101 | << concrete_type_name 102 | << " with factory for " << base_name << endl; 103 | } 104 | } 105 | } 106 | } 107 | 108 | void 109 | EnvironmentImpl::ReadAndSet(const string &varname, StreamTokenizer &st, 110 | const string type) { 111 | bool is_vector = 112 | st.PeekTokenType() == StreamTokenizer::RESERVED_CHAR && 113 | st.Peek() == "{"; 114 | 115 | if (is_vector) { 116 | // Consume open brace. 117 | st.Next(); 118 | } else if (st.PeekTokenType() == StreamTokenizer::RESERVED_CHAR || 119 | (st.PeekTokenType() == StreamTokenizer::RESERVED_WORD && 120 | st.Peek() != "true" && st.Peek() != "false" && 121 | st.Peek() != "nullptr" && st.Peek() != "NULL")) { 122 | ostringstream err_ss; 123 | err_ss << "Environment: error: expected literal or Factory-constructible " 124 | << "type but found token \"" << st.Peek() << "\" of type " 125 | << StreamTokenizer::TypeName(st.PeekTokenType()); 126 | Error(err_ss.str()); 127 | } 128 | 129 | string next_tok = st.Peek(); 130 | bool is_object_type = false; 131 | 132 | string inferred_type = InferType(varname, st, is_vector, &is_object_type); 133 | 134 | if (is_vector) { 135 | st.Putback(); 136 | next_tok = st.Peek(); 137 | } 138 | 139 | if (debug_ >= 2) { 140 | cerr << "Environment::ReadAndSet: next_tok=\"" << next_tok 141 | << "\"; explicit type=\"" << type << "\"; " 142 | << "inferred_type=\"" << inferred_type << "\"" << endl; 143 | } 144 | 145 | if (type == "" && inferred_type == "") { 146 | ostringstream err_ss; 147 | err_ss << "Environment: error: no explicit type specifier and could not " 148 | << "infer type for variable " << varname; 149 | Error(err_ss.str()); 150 | } 151 | if (type != "" && inferred_type != "" && type != inferred_type) { 152 | ostringstream err_ss; 153 | err_ss << "Environment: error: explicit type " << type 154 | << " and inferred type " << inferred_type 155 | << " disagree for variable " << varname; 156 | Error(err_ss.str()); 157 | } 158 | 159 | // If no explicit type specifier, then the inferred_type is the type. 160 | string varmap_type = type == "" ? inferred_type : type; 161 | 162 | // Check that varmap_type is a key in var_map_. 163 | var_map_[varmap_type]->ReadAndSet(varname, st); 164 | types_[varname] = varmap_type; 165 | } 166 | 167 | string 168 | EnvironmentImpl::InferType(const string &varname, 169 | const StreamTokenizer &st, bool is_vector, 170 | bool *is_object_type) { 171 | *is_object_type = false; 172 | string next_tok = st.Peek(); 173 | switch (st.PeekTokenType()) { 174 | case StreamTokenizer::RESERVED_WORD: 175 | if (next_tok == "true" || next_tok == "false") { 176 | return is_vector ? "bool[]" : "bool"; 177 | } else { 178 | return ""; 179 | } 180 | break; 181 | case StreamTokenizer::STRING: 182 | return is_vector ? "string[]" : "string"; 183 | break; 184 | case StreamTokenizer::NUMBER: 185 | { 186 | // If a token is a NUMBER, it is a double iff it contains a 187 | // decimal point. 188 | size_t dot_pos = next_tok.find('.'); 189 | if (dot_pos != string::npos) { 190 | return is_vector ? "double[]" : "double"; 191 | } else { 192 | return is_vector ? "int[]" : "int"; 193 | } 194 | } 195 | break; 196 | case StreamTokenizer::IDENTIFIER: 197 | { 198 | string type = ""; 199 | 200 | // Find out if next_tok is a concrete typename or a variable. 201 | unordered_map::const_iterator factory_type_it = 202 | concrete_to_factory_type_.find(next_tok); 203 | unordered_map::const_iterator var_type_it = 204 | types_.find(next_tok); 205 | if (factory_type_it != concrete_to_factory_type_.end()) { 206 | // Set type to be abstract factory type. 207 | if (debug_ >= 2) { 208 | cerr << "Environment::InferType: concrete type is " << next_tok 209 | << "; mapping to abstract Factory type " 210 | << factory_type_it->second << endl; 211 | } 212 | type = factory_type_it->second; 213 | *is_object_type = true; 214 | type = is_vector ? type + "[]" : type; 215 | 216 | if (debug_ >= 2) { 217 | cerr << "Environment::InferType: type " 218 | << (is_vector ? "is" : "isn't") 219 | << " a vector, so final inferred type is " << type << endl; 220 | } 221 | } else if (var_type_it != types_.end()) { 222 | // Could be a variable, in which case we need not only to return 223 | // the variable's type, but also set is_object_type and is_vector 224 | // based on the variable's type string. 225 | string append = is_vector ? "[]" : ""; 226 | type = var_type_it->second + append; 227 | if (debug_ >= 2) { 228 | cerr << "Environment::InferType: found variable " 229 | << var_type_it->first << " of type " << var_type_it->second 230 | << "; type is " << type << endl; 231 | } 232 | } else { 233 | ostringstream err_ss; 234 | err_ss << "Environment: error: token " << next_tok 235 | << " is neither a variable nor a concrete object typename"; 236 | Error(err_ss.str()); 237 | } 238 | return type; 239 | } 240 | break; 241 | default: 242 | return ""; 243 | } 244 | return ""; 245 | } 246 | 247 | void 248 | EnvironmentImpl::PrintFactories(ostream &os) const { 249 | FactoryContainer::Print(os); 250 | } 251 | 252 | } // namespace infact 253 | -------------------------------------------------------------------------------- /src/infact/environment-impl.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides an environment for variables and their values, either primitive 34 | /// or Factory-constructible objects, or vectors thereof. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #ifndef INFACT_ENVIRONMENT_IMPL_H_ 38 | #define INFACT_ENVIRONMENT_IMPL_H_ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "environment.h" 47 | #include "error.h" 48 | 49 | namespace infact { 50 | 51 | using std::ostringstream; 52 | using std::string; 53 | using std::unordered_map; 54 | using std::unordered_set; 55 | 56 | /// Provides a set of named variables and their types, as well as the values 57 | /// for those variables. 58 | /// 59 | /// \see Interpreter 60 | class EnvironmentImpl : public Environment { 61 | public: 62 | /// Constructs a new, empty environment. 63 | /// 64 | /// \param debug the debug level; if greater than 0, various debugging 65 | /// messages will be output to std::cerr 66 | EnvironmentImpl(int debug = 0); 67 | 68 | /// Destroys this environment. 69 | virtual ~EnvironmentImpl() { 70 | for (unordered_map::iterator it = var_map_.begin(); 71 | it != var_map_.end(); ++it) { 72 | delete it->second; 73 | } 74 | } 75 | 76 | /// Returns whether the specified variable has been defined in this 77 | /// environment. 78 | virtual bool Defined(const string &varname) const { 79 | unordered_map::const_iterator it = types_.find(varname); 80 | return it != types_.end(); 81 | } 82 | 83 | /// Sets the specified variable to the value obtained from the following 84 | /// tokens available from the specified token stream. 85 | virtual void ReadAndSet(const string &varname, StreamTokenizer &st, 86 | const string type); 87 | 88 | virtual const string &GetType(const string &varname) const { 89 | unordered_map::const_iterator type_it = 90 | types_.find(varname); 91 | if (type_it == types_.end()) { 92 | // Error or warning. 93 | } 94 | return type_it->second; 95 | } 96 | 97 | virtual VarMapBase *GetVarMap(const string &varname) { 98 | return GetVarMapForType(GetType(varname)); 99 | } 100 | 101 | /// Retrieves the VarMap instance for the specified type. 102 | virtual VarMapBase *GetVarMapForType(const string &type) { 103 | string lookup_type = type; 104 | // First, check if this is a concrete Factory-constructible type. 105 | // If so, map to its abstract type name. 106 | unordered_map::const_iterator factory_type_it = 107 | concrete_to_factory_type_.find(type); 108 | if (factory_type_it != concrete_to_factory_type_.end()) { 109 | lookup_type = factory_type_it->second; 110 | } 111 | 112 | unordered_map::const_iterator var_map_it = 113 | var_map_.find(lookup_type); 114 | if (var_map_it == var_map_.end()) { 115 | return nullptr; 116 | } 117 | return var_map_it->second; 118 | } 119 | 120 | /// \copydoc infact::Environment::Print 121 | virtual void Print(ostream &os) const { 122 | for (unordered_map::const_iterator var_map_it = 123 | var_map_.begin(); 124 | var_map_it != var_map_.end(); ++var_map_it) { 125 | var_map_it->second->Print(os); 126 | } 127 | } 128 | 129 | /// \copydoc infact::Environment::PrintFactories 130 | virtual void PrintFactories(ostream &os) const; 131 | 132 | /// \copydoc infact::Environment::Copy 133 | virtual Environment *Copy() const { 134 | EnvironmentImpl *new_env = new EnvironmentImpl(*this); 135 | // Now go through and create copies of each VarMap. 136 | for (unordered_map::iterator new_env_var_map_it = 137 | new_env->var_map_.begin(); 138 | new_env_var_map_it != new_env->var_map_.end(); ++new_env_var_map_it) { 139 | new_env_var_map_it->second = new_env_var_map_it->second->Copy(new_env); 140 | } 141 | return new_env; 142 | } 143 | 144 | /// Retrieves the value of the variable with the specified name and puts 145 | /// into into the object pointed to by the value parameter. 146 | /// 147 | /// \param varname the name of the variable whose value is to be 148 | /// retrieved 149 | /// \param[out] value a pointer to the object whose value is to be set 150 | /// \return whether the specified variable exists and its value was 151 | /// successfully set by this method 152 | template 153 | bool Get(const string &varname, T *value) const; 154 | 155 | private: 156 | /// Infer the type based on the next token and its token type. 157 | string InferType(const string &varname, 158 | const StreamTokenizer &st, bool is_vector, 159 | bool *is_object_type); 160 | 161 | /// A map from all variable names to their types. 162 | unordered_map types_; 163 | 164 | /// A map from type name strings (as returned by the \link TypeName \endlink 165 | /// method) to VarMap instances for those types. 166 | unordered_map var_map_; 167 | 168 | /// A map from concrete Factory-constructible type names to their abstract 169 | /// Factory type names. 170 | unordered_map concrete_to_factory_type_; 171 | 172 | int debug_; 173 | }; 174 | 175 | template 176 | bool 177 | EnvironmentImpl::Get(const string &varname, T *value) const { 178 | unordered_map::const_iterator type_it = 179 | types_.find(varname); 180 | if (type_it == types_.end()) { 181 | if (debug_ >= 2) { 182 | ostringstream err_ss; 183 | err_ss << "Environment::Get: error: no value for variable " 184 | << varname; 185 | cerr << err_ss.str() << endl; 186 | } 187 | return false; 188 | } 189 | 190 | // Now that we have the type, look up the VarMap. 191 | const string &type = type_it->second; 192 | unordered_map::const_iterator var_map_it = 193 | var_map_.find(type); 194 | 195 | if (var_map_it == var_map_.end()) { 196 | ostringstream err_ss; 197 | err_ss << "Environment::Get: error: types_ and var_map_ data members " 198 | << "are out of sync"; 199 | Error(err_ss.str()); 200 | } 201 | 202 | // Do a dynamic_cast down to the type-specific VarMap. 203 | VarMapBase *var_map = var_map_it->second; 204 | VarMap *typed_var_map = dynamic_cast *>(var_map); 205 | 206 | if (typed_var_map == nullptr) { 207 | ostringstream err_ss; 208 | err_ss << "Environment::Get: error: no value for variable " 209 | << varname << " of type " << typeid(*value).name() 210 | << "; perhaps you meant " << type << "?"; 211 | cerr << err_ss.str() << endl; 212 | return false; 213 | } 214 | bool success = typed_var_map->Get(varname, value); 215 | if (!success) { 216 | ostringstream err_ss; 217 | err_ss << "Environment::Get: error: no value for variable " 218 | << varname << " of type " << typeid(*value).name() 219 | << "; types_ and var_map_ data members are out of sync"; 220 | Error(err_ss.str()); 221 | } 222 | return success; 223 | } 224 | 225 | } // namespace infact 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /src/infact/environment-test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | /// \file 32 | /// Test driver for the Environment class. 33 | /// \author dbikel@google.com (Dan Bikel) 34 | 35 | #include 36 | #include 37 | 38 | #include "environment-impl.h" 39 | 40 | using namespace std; 41 | using namespace infact; 42 | 43 | int 44 | main(int argc, char **argv) { 45 | int debug = 1; 46 | Environment *env = new EnvironmentImpl(debug); 47 | delete env; 48 | } 49 | -------------------------------------------------------------------------------- /src/infact/environment.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Contains the implementation of the static method to construct an empty 34 | /// Environment instance. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #include "environment.h" 38 | #include "environment-impl.h" 39 | 40 | namespace infact { 41 | 42 | Environment * 43 | Environment::CreateEmpty() { 44 | return new EnvironmentImpl(); 45 | } 46 | 47 | } // namespace infact 48 | -------------------------------------------------------------------------------- /src/infact/environment.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides an interface for an Environment, which contains a map 34 | /// from variables of a specific type (primitives, \link 35 | /// infact::Factory Factory\endlink-constructible objects, or 36 | /// vectors thereof) to their values. 37 | /// \author dbikel@google.com (Dan Bikel) 38 | 39 | #ifndef INFACT_ENVIRONMENT_H_ 40 | #define INFACT_ENVIRONMENT_H_ 41 | 42 | #define VAR_MAP_DEBUG 0 43 | 44 | #include 45 | #include 46 | 47 | #include "error.h" 48 | #include "stream-init.h" 49 | #include "stream-tokenizer.h" 50 | 51 | namespace infact { 52 | 53 | using std::cerr; 54 | using std::endl; 55 | using std::ostream; 56 | using std::ostringstream; 57 | using std::shared_ptr; 58 | using std::unordered_map; 59 | using std::unordered_set; 60 | using std::vector; 61 | 62 | class Environment; 63 | 64 | /// A base class for a mapping from variables of a specific type to their 65 | /// values. 66 | class VarMapBase { 67 | public: 68 | /// Constructs a base class for a concrete implementation providing 69 | /// a mapping from variables of a particular type to their values. 70 | /// 71 | /// \param name the type name of the variables in this instance 72 | /// \param env the \link infact::Environment Environment \endlink 73 | /// that wraps this VarMapBase instance 74 | /// \param is_primitive whether this instance contains primitive or primitive 75 | /// vector variables 76 | VarMapBase(const string &name, Environment *env, bool is_primitive) : 77 | name_(name), env_(env), is_primitive_(is_primitive) { } 78 | 79 | virtual ~VarMapBase() { } 80 | 81 | /// Returns whether this instance contains primitive or primtive 82 | /// vector variables. 83 | virtual bool IsPrimitive() const { return is_primitive_; } 84 | 85 | /// Returns the type name of the variables of this instance. 86 | virtual const string &Name() const { return name_; } 87 | 88 | /// Returns whether the specified variable has a definition in this 89 | /// environment. 90 | virtual bool Defined(const string &varname) const = 0; 91 | 92 | /// Reads the next value (primitive or spec for constructing a \link 93 | /// infact::Factory Factory\endlink-constructible object) from the 94 | /// specified stream tokenizer and sets the specified variable to 95 | /// that value. 96 | virtual void ReadAndSet(const string &varname, StreamTokenizer &st) = 0; 97 | 98 | /// Prints out a human-readable string to the specified output 99 | /// stream containing the variables, their type and, if primitive, 100 | /// their values. 101 | virtual void Print(ostream &os) const = 0; 102 | 103 | /// Returns a newly constructed copy of this VarMap. 104 | virtual VarMapBase *Copy(Environment *env) const = 0; 105 | 106 | protected: 107 | /// To allow proper implementation of Copy in VarMapBase implementation, 108 | /// since we don't get copying of base class' members for free. 109 | void SetMembers(const string &name, Environment *env, bool is_primitive) { 110 | name_ = name; 111 | env_ = env; 112 | is_primitive_ = is_primitive; 113 | } 114 | 115 | /// The type name of this VarMap. 116 | string name_; 117 | /// The Environment that holds this VarMap instance. 118 | Environment *env_; 119 | /// Whether this VarMap instance holds variables of primitive type 120 | /// or vector of primitives. 121 | bool is_primitive_; 122 | }; 123 | 124 | /// An interface for an environment in which variables of various 125 | /// types are mapped to their values. 126 | class Environment { 127 | public: 128 | virtual ~Environment() { } 129 | 130 | /// Returns whether the specified variable has been defined in this 131 | /// environment. 132 | virtual bool Defined(const string &varname) const = 0; 133 | 134 | /// Sets the specified variable to the value obtained from the following 135 | /// tokens available from the specified token stream. 136 | virtual void ReadAndSet(const string &varname, StreamTokenizer &st, 137 | const string type = "") = 0; 138 | 139 | /// Retrieves the type name of the specified variable. 140 | virtual const string &GetType(const string &varname) const = 0; 141 | 142 | /// Retrieves the VarMap instance for the specified variable. 143 | virtual VarMapBase *GetVarMap(const string &varname) = 0; 144 | 145 | /// Retrieves the VarMap instance for the specified type, or nullptr if 146 | /// there is no such VarMap. The specified type must either be a 147 | /// primitive type, a primitive vector type, a \link 148 | /// infact::Factory Factory\endlink-constructible type or a vector 149 | /// of \link infact::Factory Factory\endlink-constructible types. 150 | /// 151 | /// If the specified type is a concrete implementation of a \link 152 | /// infact::Factory Factory\endlink-constructible type, then the 153 | /// pointer to the VarMap for its abstract base type is returned; 154 | /// for example, if the specified type is "RankFeatureExtactor" 155 | /// then this method will return the VarMap containing 156 | /// "FeatureExtractor" instances. 157 | /// 158 | /// TODO(dbikel): Support returning the VarMap for vectors of 159 | /// abstract type when the user specifies a vector of concrete type. 160 | /// E.g., if the specified type is "RankFeatureExtractor[]" then 161 | /// this method should return the VarMap containing 162 | /// "FeatureExtractor[]" instances. 163 | virtual VarMapBase *GetVarMapForType(const string &type) = 0; 164 | 165 | /// Prints a human-readable string of all the variables in this environment, 166 | /// their types and, if primitive, their values. 167 | virtual void Print(ostream &os) const = 0; 168 | 169 | /// Returns a copy of this environment. 170 | virtual Environment *Copy() const = 0; 171 | 172 | /// Prints out a human-readable string with the names of all abstract base 173 | /// types and their concrete implementations that may be constructed. 174 | /// \see infact::FactoryContainer::Print 175 | virtual void PrintFactories(ostream &os) const = 0; 176 | 177 | /// A static factory method to create a new, empty Environment instance. 178 | static Environment *CreateEmpty(); 179 | }; 180 | 181 | /// A template class that helps print out values with ostream& operator 182 | /// support and vectors of those values. 183 | /// 184 | /// \tparam T the type to print to an ostream 185 | template 186 | class ValueString { 187 | public: 188 | string ToString(const T &value) const { 189 | ostringstream oss; 190 | oss << value; 191 | return oss.str(); 192 | } 193 | }; 194 | 195 | /// A specialization of the ValueString class to support printing of 196 | /// string values. 197 | template<> 198 | class ValueString { 199 | public: 200 | string ToString(const string &value) const { 201 | return "\"" + value + "\""; 202 | } 203 | }; 204 | 205 | /// A specialization of the ValueString class to support printing of 206 | /// boolean values. 207 | template<> 208 | class ValueString { 209 | public: 210 | string ToString(const bool &value) const { 211 | return value ? "true" : "false"; 212 | } 213 | }; 214 | 215 | /// A partial specialization of the ValueString class to support 216 | /// printing of shared_ptr's to objects, where we simply print the typeid 217 | /// name followed by a colon character followed by the pointer address. 218 | template 219 | class ValueString > { 220 | public: 221 | string ToString(const shared_ptr &value) const { 222 | ostringstream oss; 223 | oss << "<" << typeid(shared_ptr).name() << ":" << value.get() << ">"; 224 | return oss.str(); 225 | } 226 | }; 227 | 228 | /// A partial specialization of the ValueString class to support 229 | /// printing of vectors of values. 230 | /// 231 | /// \tparam T the element type for a vector to be printed out to an ostream 232 | template 233 | class ValueString > { 234 | public: 235 | string ToString(const vector &value) const { 236 | ostringstream oss; 237 | oss << "{"; 238 | typename vector::const_iterator it = value.begin(); 239 | ValueString value_string; 240 | if (it != value.end()) { 241 | oss << value_string.ToString(*it); 242 | ++it; 243 | } 244 | for (; it != value.end(); ++it) { 245 | oss << ", " << value_string.ToString(*it); 246 | } 247 | oss << "}"; 248 | return oss.str(); 249 | } 250 | }; 251 | 252 | /// A partial implementation of the VarMapBase interface that is common 253 | /// to both VarMap and the VarMap > partial specialization. 254 | /// 255 | /// In a delightful twist, this partial implementation of VarMapBase 256 | /// uses the curiously recurring template pattern (CRTP) in order to 257 | /// implement the \link infact::VarMapBase::Copy VarMapBase::Copy 258 | /// \endlink method, as well as the protected method \link 259 | /// ReadAndSetFromExistingVariable\endlink. 260 | /// 261 | /// \tparam T the type of variables stored in this (partial 262 | /// implementation of a) variable map 263 | /// \tparam Derived the type of the class using this as its base class 264 | /// (a.k.a. CRTP, or the "curiously recurring template pattern") 265 | template 266 | class VarMapImpl : public VarMapBase { 267 | public: 268 | VarMapImpl(const string &name, Environment *env, bool is_primitive = true) : 269 | VarMapBase(name, env, is_primitive) { } 270 | 271 | virtual ~VarMapImpl() { } 272 | 273 | // Accessor methods 274 | 275 | /// Assigns the value of the specified variable to the object pointed to 276 | /// by the value parameter. 277 | /// 278 | /// \return whether the specified variable exists and the assignment 279 | /// was successful 280 | bool Get(const string &varname, T *value) const { 281 | typename unordered_map::const_iterator it = vars_.find(varname); 282 | if (it == vars_.end()) { 283 | return false; 284 | } else { 285 | *value = it->second; 286 | return true; 287 | } 288 | } 289 | 290 | /// \copydoc VarMapBase::Defined 291 | virtual bool Defined(const string &varname) const { 292 | return vars_.find(varname) != vars_.end(); 293 | } 294 | 295 | /// Sets the specified variable to the specified value. 296 | void Set(const string &varname, T value) { 297 | vars_[varname] = value; 298 | } 299 | 300 | /// \copydoc VarMapBase::Print 301 | virtual void Print(ostream &os) const { 302 | ValueString value_string; 303 | for (typename unordered_map::const_iterator it = vars_.begin(); 304 | it != vars_.end(); ++it) { 305 | const T& value = it->second; 306 | os << Name() << " " 307 | << it->first 308 | << " = " 309 | << value_string.ToString(value) 310 | << ";\n"; 311 | } 312 | os.flush(); 313 | } 314 | 315 | /// \copydoc VarMapBase::Copy 316 | virtual VarMapBase *Copy(Environment *env) const { 317 | // Invoke Derived class' copy constructor. 318 | const Derived *derived = dynamic_cast(this); 319 | if (derived == nullptr) { 320 | Error("bad dynamic cast"); 321 | } 322 | Derived *var_map_copy = new Derived(*derived); 323 | var_map_copy->SetMembers(name_, env, is_primitive_); 324 | return var_map_copy; 325 | } 326 | protected: 327 | /// Checks if the next token is an identifier and is a variable in 328 | /// the environment, and, if so, sets varname to the variable’s value. 329 | bool ReadAndSetFromExistingVariable(const string &varname, 330 | StreamTokenizer &st) { 331 | if (env()->Defined(st.Peek())) { 332 | VarMapBase *var_map = env()->GetVarMap(st.Peek()); 333 | Derived *typed_var_map = dynamic_cast(var_map); 334 | if (typed_var_map != nullptr) { 335 | // Finally consume variable. 336 | string rhs_variable = st.Next(); 337 | T value = T(); 338 | // Retrieve rhs variable's value. 339 | bool success = typed_var_map->Get(rhs_variable, &value); 340 | // Set varname to the same value. 341 | if (VAR_MAP_DEBUG >= 1) { 342 | cerr << "VarMap<" << Name() << ">::ReadAndSet: " 343 | << "setting variable " 344 | << varname << " to same value as rhs variable " << rhs_variable 345 | << endl; 346 | } 347 | if (success) { 348 | Set(varname, value); 349 | } else { 350 | // Error: we couldn't find the varname in this VarMap. 351 | if (VAR_MAP_DEBUG >= 1) { 352 | cerr << "VarMap<" << Name() << ">::ReadAndSet: no variable " 353 | << rhs_variable << " found " << endl; 354 | } 355 | } 356 | } else { 357 | // Error: inferred or declared type of varname is different 358 | // from the type of the rhs variable. 359 | if (VAR_MAP_DEBUG >= 1) { 360 | cerr << "VarMap<" << Name() << ">::ReadAndSet: variable " 361 | << st.Peek() << " is of type " << var_map->Name() 362 | << " but expecting " << typeid(T).name() << endl; 363 | } 364 | } 365 | return true; 366 | } else { 367 | return false; 368 | } 369 | } 370 | 371 | /// A protected method to access the environment contained by this 372 | /// VarMapBase instance, for the two concrete VarMap implementations, below. 373 | Environment *env() { return VarMapBase::env_; } 374 | 375 | private: 376 | unordered_map vars_; 377 | }; 378 | 379 | /// A container to hold the mapping between named variables of a specific 380 | /// type and their values. 381 | /// 382 | /// \tparam T the type of variables held by this variable map 383 | template 384 | class VarMap : public VarMapImpl > { 385 | public: 386 | typedef VarMapImpl > Base; 387 | 388 | /// Constructs a mapping from variables of a particular type to their values. 389 | /// 390 | /// \param name the type name of the variables in this instance 391 | /// \param env the \link infact::Environment Environment \endlink 392 | /// that contains this VarMap instance 393 | /// \param is_primitive whether this instance contains primitive or primitive 394 | /// vector variables 395 | VarMap(const string &name, Environment *env, bool is_primitive = true) : 396 | Base(name, env, is_primitive) { } 397 | 398 | virtual ~VarMap() { } 399 | 400 | /// \copydoc VarMapBase::ReadAndSet 401 | virtual void ReadAndSet(const string &varname, StreamTokenizer &st) { 402 | if (VAR_MAP_DEBUG >= 1) { 403 | cerr << "VarMap<" << Base::Name() << ">::ReadAndSet: " 404 | << "about to set varname " << varname << " of type " 405 | << typeid(T).name() 406 | << "; prev_token=" << st.PeekPrev() << "; next_tok=" << st.Peek() 407 | << endl; 408 | } 409 | 410 | if (!Base::ReadAndSetFromExistingVariable(varname, st)) { 411 | T value; 412 | Initializer initializer(&value); 413 | initializer.Init(st, Base::env()); 414 | this->Set(varname, value); 415 | 416 | if (VAR_MAP_DEBUG >= 1) { 417 | ValueString value_string; 418 | cerr << "VarMap<" << Base::Name() << ">::ReadAndSet: set varname " 419 | << varname << " to value " << value_string.ToString(value)<< endl; 420 | } 421 | } 422 | } 423 | }; 424 | 425 | /// A partial specialization to allow initialization of a vector of 426 | /// values, where the values can either be literals (if T is a 427 | /// primitive type), spec strings for constructing 428 | /// \link Factory\endlink-constructible objects, or variable names (where each 429 | /// variable must be of type T). 430 | /// 431 | /// TODO(dbikel): Avoid repeating much of the unchanged implementation 432 | /// from the non-specialized VarMap, above, by using the PIMPL 433 | /// design pattern (i.e., create VarMapImpl that does the generic 434 | /// stuff and have VarMap contain a VarMapImpl data member, and 435 | /// have VarMap> contain a VarMapImpl> data 436 | /// member. 437 | /// 438 | /// \tparam T the element type for vectors stored in this variable map 439 | template 440 | class VarMap > : public VarMapImpl, VarMap > > { 441 | public: 442 | typedef VarMapImpl, VarMap > > Base; 443 | 444 | /// Constructs a mapping from variables of a particular type to their values. 445 | /// 446 | /// \param name the type name of the variables in this instance 447 | /// \param element_typename the type name of the elements of the vectors 448 | /// held by this instance 449 | /// \param env the \link infact::Environment Environment \endlink 450 | /// that contains this VarMap instance 451 | /// \param is_primitive whether the variables held in this variable map 452 | /// are primitives or vectors of primitives 453 | VarMap(const string &name, const string &element_typename, Environment *env, 454 | bool is_primitive = true) 455 | : Base(name, env, is_primitive), element_typename_(element_typename) { } 456 | 457 | virtual ~VarMap() { } 458 | 459 | virtual void ReadAndSet(const string &varname, StreamTokenizer &st) { 460 | // First check if next token is an identifier and is a variable in 461 | // the environment, set varname to its value. 462 | if (!Base::ReadAndSetFromExistingVariable(varname, st)) { 463 | // This entire block reads the array of values. 464 | 465 | // Either the next token is an open brace (if reading tokens from 466 | // within a Factory-constructible object's member init list), or 467 | // else we just read an open brace (if Interpreter is reading tokens). 468 | if (st.Peek() == "{") { 469 | // Consume open brace. 470 | st.Next(); 471 | } else { 472 | ostringstream err_ss; 473 | err_ss << "VarMap>: " 474 | << "error: expected '{' at stream position " 475 | << st.PeekPrevTokenStart() << " but found \"" 476 | << st.PeekPrev() << "\""; 477 | Error(err_ss.str()); 478 | } 479 | 480 | vector value; 481 | int element_idx = 0; 482 | while (st.Peek() != "}") { 483 | // Copy the environment, since we create fake names for each element. 484 | shared_ptr env_ptr(Base::env()->Copy()); 485 | ostringstream element_name_oss; 486 | element_name_oss << "____" << varname << "_" << (element_idx++) 487 | << "____"; 488 | string element_name = element_name_oss.str(); 489 | 490 | env_ptr->ReadAndSet(element_name, st, element_typename_); 491 | VarMapBase *element_var_map = 492 | env_ptr->GetVarMapForType(element_typename_); 493 | VarMap *typed_element_var_map = 494 | dynamic_cast *>(element_var_map); 495 | T element; 496 | if (typed_element_var_map->Get(element_name, &element)) { 497 | value.push_back(element); 498 | } else { 499 | ostringstream err_ss; 500 | err_ss << "VarMap<" << Base::Name() << ">::ReadAndSet: trouble " 501 | << "initializing element " << (element_idx - 1) 502 | << " of variable " << varname; 503 | Error(err_ss.str()); 504 | } 505 | // Each vector element initializer must be followed by a comma 506 | // or the final closing parenthesis. 507 | if (st.Peek() != "," && st.Peek() != "}") { 508 | ostringstream err_ss; 509 | err_ss << "Initializer>: " 510 | << "error: expected ',' or '}' at stream position " 511 | << st.PeekTokenStart() << " but found \"" << st.Peek() << "\""; 512 | Error(err_ss.str()); 513 | } 514 | // Read comma, if present. 515 | if (st.Peek() == ",") { 516 | st.Next(); 517 | } 518 | } 519 | // Consume close brace. 520 | st.Next(); 521 | 522 | 523 | // Finally, set the newly-constructed value. 524 | this->Set(varname, value); 525 | } 526 | } 527 | private: 528 | string element_typename_; 529 | }; 530 | 531 | } // namespace infact 532 | 533 | #endif 534 | -------------------------------------------------------------------------------- /src/infact/error.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides an implementation of the primary error handling function for th 34 | // InFact library. 35 | 36 | #include "error.h" 37 | 38 | #ifdef INFACT_THROW_EXCEPTIONS 39 | #include 40 | #else 41 | #include 42 | #include 43 | #endif 44 | 45 | namespace infact { 46 | 47 | void Error(const std::string &message) { 48 | #ifdef INFACT_THROW_EXCEPTIONS 49 | throw std::runtime_error(message); 50 | #else 51 | std::cerr << message << std::endl; 52 | assert(false); 53 | #endif 54 | } 55 | 56 | } // namespace infact 57 | -------------------------------------------------------------------------------- /src/infact/error.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides an error handling function that optionally throws 34 | /// an exception. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #ifndef INFACT_ERROR_H_ 38 | #define INFACT_ERROR_H_ 39 | 40 | /// Determines whether the Error function, and therefore the entire InFact 41 | /// library, throws an exception when an error occurs. 42 | #define INFACT_THROW_EXCEPTIONS 43 | 44 | #include 45 | 46 | /// The namespace for the entire InFact library. 47 | namespace infact { 48 | 49 | /// Reports an error encountered during parsing and/or construction 50 | /// of an object. Optionally throws an exception, according to the value 51 | /// of \link INFACT_THROW_EXCEPTIONS\endlink. 52 | void Error(const std::string &message); 53 | 54 | } // namespace infact 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/infact/example.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides implementations of the various example classes. 34 | 35 | #include "example.h" 36 | #include "environment-impl.h" 37 | 38 | namespace infact { 39 | 40 | // Normally, the various IMPLEMENT_FACTORY declarations would be 41 | // separate from the various REGISTER_* declarations, which would 42 | // usually appear in the separate concrete implementations' .C files. 43 | // For compactness, we have this single .C file, so everything is 44 | // lumped together. 45 | 46 | IMPLEMENT_FACTORY(Date) 47 | REGISTER_DATE(DateImpl) 48 | 49 | IMPLEMENT_FACTORY(Person) 50 | REGISTER_PERSON(PersonImpl) 51 | 52 | IMPLEMENT_FACTORY(Animal) 53 | REGISTER_ANIMAL(Cow) 54 | REGISTER_ANIMAL(Sheep) 55 | 56 | IMPLEMENT_FACTORY(PetOwner) 57 | REGISTER_PET_OWNER(HumanPetOwner) 58 | 59 | void Sheep::PostInit(const Environment *env, const string &init_str) { 60 | int env_age; 61 | // Note how we need to cast Environment down to EnvironmentImpl, 62 | // because only the implementation has the templated \link 63 | // EnvironmentImpl::Get \endlink method, because only an 64 | // implementation can be aware of the all the \link 65 | // Factory\endlink-constructible types. 66 | const EnvironmentImpl *env_impl = dynamic_cast(env); 67 | if (env_impl != nullptr && 68 | env_impl->Get("age", &env_age)) { 69 | age_ = env_age * 2; 70 | } 71 | } 72 | 73 | } // namespace infact 74 | -------------------------------------------------------------------------------- /src/infact/example.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides various example class headers. Please note the presence 34 | /// of the various REGISTER_* macros sprinkled throughout 35 | /// this file. The convention is for a REGISTER_type 36 | /// macro to be placed just below the declaration of the type 37 | /// interface declaration. 38 | /// \author dbikel@google.com (Dan Bikel) 39 | 40 | #ifndef INFACT_EXAMPLE_H_ 41 | #define INFACT_EXAMPLE_H_ 42 | 43 | #include 44 | 45 | #include "factory.h" 46 | 47 | namespace infact { 48 | 49 | /// An interface to represent a date. 50 | class Date : public FactoryConstructible { 51 | public: 52 | /// Constructs this date. 53 | Date() {} 54 | /// Destroys this date. 55 | virtual ~Date() {} 56 | 57 | /// Returns the year. 58 | virtual int year() const = 0; 59 | /// Returns the month. 60 | virtual int month() const = 0; 61 | /// Returns the day. 62 | virtual int day() const = 0; 63 | }; 64 | 65 | /// The macro by which \link infact::Date Date \endlink implementations may 66 | /// register themselves with the \link infact::Factory Factory \endlink that can 67 | /// construct \link infact::Date Date \endlink instances. 68 | #define REGISTER_DATE(TYPE) \ 69 | REGISTER_NAMED(TYPE,TYPE,Date) 70 | 71 | /// An implementation of the Date interface that can be constructed by 72 | /// a \link Factory \endlink (because of the 73 | /// REGISTER_DATE(DateImpl) declaration in 74 | /// example.cc). 75 | class DateImpl : public Date { 76 | public: 77 | /// Constructs this instance. 78 | DateImpl() : Date() {} 79 | /// Destroys this instance. 80 | virtual ~DateImpl() {} 81 | 82 | /// Registers three required initializers. 83 | virtual void RegisterInitializers(Initializers &initializers) { 84 | INFACT_ADD_REQUIRED_PARAM_(year); 85 | INFACT_ADD_REQUIRED_PARAM_(month); 86 | INFACT_ADD_REQUIRED_PARAM_(day); 87 | } 88 | 89 | /// \copydoc Date::year 90 | virtual int year() const { return year_; } 91 | /// \copydoc Date::month 92 | virtual int month() const { return month_; } 93 | /// \copydoc Date::day 94 | virtual int day() const { return day_; } 95 | 96 | private: 97 | int year_; 98 | int month_; 99 | int day_; 100 | }; 101 | 102 | /// An interface representing a person. 103 | class Person : public FactoryConstructible { 104 | public: 105 | /// Constructs this abstract person. 106 | Person() {} 107 | /// Destroys this abstract person. 108 | virtual ~Person() {} 109 | 110 | /// Returns the name of this person. 111 | virtual const string &name() const = 0; 112 | /// Returns the height in centimeters of this person. 113 | virtual const int cm_height() const = 0; 114 | /// Returns the birthday of this person. 115 | virtual shared_ptr birthday() const = 0; 116 | }; 117 | 118 | /// The macro by which \link infact::Person Person \endlink 119 | /// implementations may register themselves with the \link 120 | /// infact::Factory Factory \endlink that can construct \link 121 | /// infact::Person Person \endlink instances. 122 | #define REGISTER_PERSON(TYPE) \ 123 | REGISTER_NAMED(TYPE,TYPE,Person) 124 | 125 | /// A concrete implementation of the Person interface that can be 126 | /// constructed by a \link Factory \endlink (because of the 127 | /// REGISTER_PERSON(PersonImpl) declaration in 128 | /// example.cc). 129 | class PersonImpl : public Person { 130 | public: 131 | /// Constructs this person. 132 | PersonImpl() : Person() {} 133 | /// Destroys this person. 134 | virtual ~PersonImpl() {} 135 | 136 | /// Registers one required and two optional initializers. 137 | virtual void RegisterInitializers(Initializers &initializers) { 138 | INFACT_ADD_REQUIRED_PARAM_(name); 139 | INFACT_ADD_PARAM_(cm_height); 140 | INFACT_ADD_PARAM_(birthday); 141 | } 142 | 143 | /// \copydoc Person::name 144 | virtual const string &name() const { return name_; } 145 | /// \copydoc Person::cm_height 146 | virtual const int cm_height() const { return cm_height_; } 147 | /// \copydoc Person::birthday 148 | virtual shared_ptr birthday() const { return birthday_; } 149 | 150 | private: 151 | string name_; 152 | int cm_height_; 153 | shared_ptr birthday_; 154 | }; 155 | 156 | /// A very simple class to represent an animal. 157 | class Animal : public FactoryConstructible { 158 | public: 159 | /// Constructs a generic animal. 160 | Animal() {} 161 | /// Destroys this animal. 162 | virtual ~Animal() {} 163 | 164 | /// Returns the name of this animal. 165 | virtual const string &name() const = 0; 166 | 167 | /// Returns the age of this animal. 168 | virtual int age() const = 0; 169 | }; 170 | 171 | /// Registers the \link infact::Animal Animal \endlink with the 172 | /// specified subtype TYPE and NAME with the \link 173 | /// infact::Animal Animal \endlink \link infact::Factory 174 | /// Factory\endlink. 175 | #define REGISTER_ANIMAL(TYPE) \ 176 | REGISTER_NAMED(TYPE,TYPE,Animal) 177 | 178 | /// A class to represent a cow. 179 | class Cow : public Animal { 180 | public: 181 | /// Constructs a cow. 182 | Cow() : Animal() { 183 | age_ = 2; // default age, since age is optional 184 | } 185 | 186 | // Destroys this instance. 187 | virtual ~Cow() {} 188 | 189 | virtual void RegisterInitializers(Initializers &initializers) { 190 | INFACT_ADD_REQUIRED_PARAM_(name); 191 | INFACT_ADD_PARAM_(age); 192 | } 193 | 194 | /// Returns the name of this animal. 195 | virtual const string &name() const { return name_; } 196 | virtual int age() const { return age_; } 197 | private: 198 | string name_; 199 | int age_; 200 | }; 201 | 202 | /// A sheep. Unlike other animals, sheep are always twice the age you 203 | /// specify (for the purposes of this example, anyway). Please see 204 | /// how we do this by looking at the implementations of the \link 205 | /// infact::Sheep::RegisterInitializers RegisterInitializers \endlink 206 | /// and \link infact::Sheep::PostInit PostInit \endlink methods. 207 | class Sheep : public Animal { 208 | public: 209 | /// Constructs a sheep. 210 | Sheep() : Animal() {} 211 | /// Destroys a sheep. 212 | virtual ~Sheep() {} 213 | 214 | /// Registers one required and two optional inititalizers. Please 215 | /// note the use of a temporary variable being initialized in this 216 | /// method, for use inside the \link infact::Sheep::PostInit 217 | /// PostInit \endlink method. 218 | virtual void RegisterInitializers(Initializers &initializers) { 219 | INFACT_ADD_REQUIRED_PARAM_(name); 220 | INFACT_ADD_PARAM_(counts); 221 | // We can pass in a nullptr, if we don't want to directly 222 | // initialize a data member of this class, but instead want to 223 | // simply grab something from the Environment after this method 224 | // has been invoked; see the PostInit method declared below 225 | // (defined in example.cc). 226 | // 227 | // As of v1.0.6, the new INFACT_ADD_TEMPORARY macro makes it very 228 | // easy to add such temporary variables in a very readable way. 229 | INFACT_ADD_TEMPORARY(int, age); 230 | } 231 | 232 | /// Grabs the variable named "age" from the Environment (set up by 233 | /// \link infact::Sheep::RegisterInitializers 234 | /// RegisterInitializers\endlink) and sets this sheep’s age to 235 | /// be twice that value. 236 | virtual void PostInit(const Environment *env, const string &init_str); 237 | 238 | /// \copydoc Animal::name 239 | virtual const string &name() const { return name_; } 240 | /// \copydoc Animal::age 241 | virtual int age() const { 242 | return -1; // Always returns -1, because sheep are timeless. 243 | } 244 | /// Returns the counts of this sheep. 245 | const vector &counts() { return counts_; } 246 | private: 247 | string name_; 248 | int age_; 249 | // The various times people have counted this sheep when falling asleep. 250 | vector counts_; 251 | }; 252 | 253 | /// An owner of a pet. 254 | class PetOwner : public FactoryConstructible { 255 | public: 256 | /// Constructs a generic pet owner. 257 | PetOwner() {} 258 | 259 | /// Destroys this pet owner. 260 | virtual ~PetOwner() {} 261 | 262 | /// Returns the number of pets owned by this pet owner. 263 | virtual int GetNumberOfPets() = 0; 264 | 265 | /// Gets the pet with the specified index owned by this pet owner. 266 | virtual shared_ptr GetPet(int i) = 0; 267 | }; 268 | 269 | /// The macro by which \link infact::PetOwner PetOwner \endlink 270 | /// implementations may register themselves with the \link 271 | /// infact::Factory Factory \endlink that can construct \link 272 | /// infact::PetOwner PetOwner \endlink instances. 273 | #define REGISTER_PET_OWNER(TYPE) \ 274 | REGISTER_NAMED(TYPE,TYPE,PetOwner) 275 | 276 | /// A concrete type of PetOwner that can be constructed by a \link 277 | /// Factory\endlink\<\link PetOwner \endlink\> instance. 278 | class HumanPetOwner : public PetOwner { 279 | public: 280 | /// Constructs a human pet owner. 281 | HumanPetOwner() : PetOwner() {} 282 | 283 | /// Destroys a human pet owner. 284 | virtual ~HumanPetOwner() {} 285 | 286 | /// Registers a single required initializer. 287 | virtual void RegisterInitializers(Initializers &initializers) { 288 | initializers.Add("pets", &pets_, true); 289 | } 290 | 291 | /// Returns the number of pets owned by this pet owner. 292 | virtual int GetNumberOfPets() { 293 | return pets_.size(); 294 | } 295 | 296 | /// Gets the pet with the specified index owned by this pet owner. 297 | virtual shared_ptr GetPet(int i) { 298 | return pets_.at(i); 299 | } 300 | 301 | private: 302 | vector > pets_; 303 | }; 304 | 305 | } // namespace infact 306 | 307 | #endif 308 | -------------------------------------------------------------------------------- /src/infact/factory.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Implementation of a generic dynamic object factory. 34 | /// \author dbikel@google.com (Dan Bikel) 35 | 36 | #include "factory.h" 37 | 38 | namespace infact { 39 | 40 | int 41 | FactoryContainer::initialized_ = 0; 42 | 43 | vector * 44 | FactoryContainer::factories_ = 0; 45 | 46 | } // namespace infact 47 | -------------------------------------------------------------------------------- /src/infact/interpreter.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Interpreter implementation. 34 | /// Author: dbikel@google.com (Dan Bikel) 35 | 36 | #include 37 | 38 | #include "error.h" 39 | #include "interpreter.h" 40 | 41 | using namespace std; 42 | 43 | namespace infact { 44 | 45 | using std::ostringstream; 46 | 47 | // TODO(dbikel): Use std::make_unique here when we start using C++14. 48 | unique_ptr 49 | DefaultIStreamBuilder::Build(const string &filename, 50 | std::ios_base::openmode mode) const { 51 | return unique_ptr(new std::ifstream(filename, mode)); 52 | } 53 | 54 | bool 55 | Interpreter::IsAbsolute(const string &filename) const { 56 | return filename.length() > 0 && filename[0] == '/'; 57 | } 58 | 59 | bool 60 | Interpreter::CanReadFile(const string &filename) const { 61 | unique_ptr file = istream_builder_->Build(filename); 62 | return file->good(); 63 | } 64 | 65 | bool 66 | Interpreter::CanReadFile(const string &f1, const string &f2, 67 | string *filename) const { 68 | if (CanReadFile(f1)) { 69 | *filename = f1; 70 | return true; 71 | } else if (CanReadFile(f2)) { 72 | *filename = f2; 73 | return true; 74 | } else { 75 | return false; 76 | } 77 | } 78 | 79 | bool 80 | Interpreter::HasCycle(const string &filename, 81 | const vector &filenames) const { 82 | for (const string &f : filenames) { 83 | if (filename == f) { 84 | return true; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | void 91 | Interpreter::Eval(const string &filename) { 92 | if (!CanReadFile(filename)) { 93 | ostringstream err_ss; 94 | err_ss << "infact::Interpreter: error: cannot read file " 95 | << "\"" << filename << "\" (or file does not exist)\n"; 96 | Error(err_ss.str()); 97 | } 98 | EvalFile(filename); 99 | } 100 | 101 | // This is the implementation of the private EvalFile method, used 102 | // both the top-level Eval method above, as well as for importing 103 | // files. 104 | void 105 | Interpreter::EvalFile(const string &filename) { 106 | filenames_.push_back(filename); 107 | unique_ptr file = istream_builder_->Build(curr_filename()); 108 | Eval(*file); 109 | filenames_.pop_back(); 110 | } 111 | 112 | void 113 | Interpreter::Import(StreamTokenizer &st) { 114 | // Consume reserved word "import". 115 | st.Next(); 116 | 117 | if (st.PeekTokenType() != StreamTokenizer::STRING) { 118 | string expected_type = 119 | string(StreamTokenizer::TypeName(StreamTokenizer::RESERVED_WORD)); 120 | string found_type = StreamTokenizer::TypeName(st.PeekTokenType()); 121 | WrongTokenTypeError(st, st.PeekTokenStart(), expected_type, found_type, 122 | st.Peek()); 123 | } 124 | 125 | if (debug_ >= 1) { 126 | std::cerr << "infact::Interpreter: from file \"" << curr_filename() 127 | << "\" importing \"" << st.Peek() << "\"\n"; 128 | } 129 | 130 | // Grab the string naming the file to be imported. 131 | string original_import_filename = st.Next(); 132 | string relative_import_filename = original_import_filename; 133 | 134 | // Test to see if the named file exists. If the path is not 135 | // absolute, we try to get the dirname of current file, if it 136 | // exists, and create a relative path, which takes precedence 137 | // over a path relative to the current working directory. 138 | bool relative = false; 139 | if (!IsAbsolute(original_import_filename)) { 140 | size_t slash_pos = curr_filename().rfind('/'); 141 | if (slash_pos != string::npos) { 142 | string dirname = curr_filename().substr(0, slash_pos); 143 | relative_import_filename = dirname + '/' + original_import_filename; 144 | relative = true; 145 | } 146 | } 147 | 148 | string import_filename; 149 | if (!CanReadFile(relative_import_filename, original_import_filename, 150 | &import_filename)) { 151 | ostringstream err_ss; 152 | err_ss << "infact::Interpreter: " << filestack(st, st.tellg()) 153 | << "error: cannot read file \""; 154 | if (relative) { 155 | err_ss << relative_import_filename << "\" or \""; 156 | } 157 | err_ss << original_import_filename << "\" (or file does not exist)\n"; 158 | Error(err_ss.str()); 159 | } else { 160 | if (debug_ >= 1) { 161 | std::cerr << "infact::Interpreter: tested paths \"" 162 | << relative_import_filename << "\" and \"" 163 | << original_import_filename << "\" and found that \"" 164 | << import_filename << "\" exists and is readable\n"; 165 | } 166 | } 167 | 168 | if (HasCycle(import_filename, filenames_)) { 169 | ostringstream err_ss; 170 | err_ss << "infact::Interpreter: " << filestack(st, st.tellg()) 171 | << "attempted import of file \"" << import_filename << "\" " 172 | << "from file \"" << curr_filename() << "\" introduces cycle"; 173 | Error(err_ss.str()); 174 | } 175 | 176 | // Finally, evaluate file using the private EvalFile method. The imported 177 | // file gets interpreted using the current Environment. 178 | EvalFile(import_filename); 179 | 180 | if (st.Peek() != ";") { 181 | WrongTokenError(st, st.PeekTokenStart(), ";", st.Peek(), 182 | st.PeekTokenType()); 183 | } 184 | 185 | // Consume semicolon. 186 | st.Next(); 187 | } 188 | 189 | void 190 | Interpreter::Eval(StreamTokenizer &st) { 191 | // Keeps reading import or assignment statements until there are no 192 | // more tokens. 193 | while (st.PeekTokenType() != StreamTokenizer::EOF_TYPE) { 194 | #ifdef INFACT_THROW_EXCEPTIONS 195 | try { 196 | #endif 197 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 198 | // First, see if we have an import statement. 199 | if (token_type == StreamTokenizer::RESERVED_WORD && st.Peek() == "import") { 200 | Import(st); 201 | // Now continue this loop reading either assignment or import statements. 202 | continue; 203 | } 204 | // Read variable name or type specifier. 205 | VarMapBase *varmap = env_->GetVarMapForType(st.Peek()); 206 | bool is_type_specifier = varmap != nullptr; 207 | if (token_type != StreamTokenizer::IDENTIFIER && !is_type_specifier) { 208 | string expected_type = 209 | string(StreamTokenizer::TypeName(StreamTokenizer::IDENTIFIER)) + 210 | " or type specifier"; 211 | string found_type = StreamTokenizer::TypeName(token_type); 212 | WrongTokenTypeError(st, st.PeekTokenStart(), expected_type, found_type, 213 | st.Peek()); 214 | } 215 | 216 | string type = ""; 217 | if (is_type_specifier) { 218 | // Consume and remember the type specifier. 219 | st.Next(); // Explicit type could be a concrete type. 220 | type = varmap->Name(); // Remember the abstract type. 221 | 222 | // Check that next token is a variable name. 223 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 224 | if (token_type != StreamTokenizer::IDENTIFIER) { 225 | WrongTokenTypeError(st, st.PeekTokenStart(), 226 | StreamTokenizer::IDENTIFIER, token_type, st.Peek()); 227 | } 228 | } 229 | 230 | string varname = st.Next(); 231 | 232 | // Next, read equals sign. 233 | token_type = st.PeekTokenType(); 234 | if (st.Peek() != "=") { 235 | WrongTokenError(st, st.PeekTokenStart(), "=", st.Peek(), 236 | st.PeekTokenType()); 237 | } 238 | 239 | // Consume equals sign. 240 | st.Next(); 241 | 242 | if (st.PeekTokenType() == StreamTokenizer::EOF_TYPE) { 243 | ostringstream err_ss; 244 | err_ss << "infact::Interpreter: " << filestack(st, st.tellg()) 245 | << "error: unexpected EOF"; 246 | Error(err_ss.str()); 247 | } 248 | 249 | // Consume and set the value for this variable in the environment. 250 | env_->ReadAndSet(varname, st, type); 251 | 252 | token_type = st.PeekTokenType(); 253 | if (st.Peek() != ";") { 254 | WrongTokenError(st, st.PeekTokenStart(), ";", st.Peek(), 255 | st.PeekTokenType()); 256 | } 257 | // Consume semicolon. 258 | st.Next(); 259 | #ifdef INFACT_THROW_EXCEPTIONS 260 | } 261 | catch (std::runtime_error &e) { 262 | cerr << "infact::Interpreter: caught exception\n" 263 | << filestack(st, st.tellg()) 264 | << "==================\n" 265 | << "Exception message:\n" 266 | << "==================\n" << e.what() << "\n" 267 | << endl; 268 | // For now, we simply give up. 269 | break; 270 | } 271 | #endif 272 | } 273 | } 274 | 275 | string 276 | Interpreter::filestack(StreamTokenizer &st, size_t pos) const { 277 | ostringstream message; 278 | size_t line_pos = (st.PeekPrevTokenLineStart() <= pos ? 279 | pos - st.PeekPrevTokenLineStart() : pos); 280 | message << "in file \"" << curr_filename() << "\" " 281 | << "(line: " << st.PeekPrevTokenLineNumber() + 1 282 | << "; line pos: " << line_pos << "; stream pos: " << pos << "):\n"; 283 | auto it = filenames_.rbegin(); 284 | if (it != filenames_.rend()) { 285 | ++it; 286 | } 287 | for (; it != filenames_.rend(); ++it) { 288 | const string &filename = *it; 289 | message << "\timported from \"" << filename << "\"\n"; 290 | } 291 | string line = st.line(); 292 | message << "here:\n" 293 | << line << "\n"; 294 | if (st.PeekPrevTokenLineStart() <= pos) { 295 | for (int i = line_pos; i > 0; --i) { 296 | message << " "; 297 | } 298 | } 299 | message << "^\n"; 300 | return message.str(); 301 | } 302 | 303 | void 304 | Interpreter::WrongTokenError(StreamTokenizer &st, 305 | size_t pos, 306 | const string &expected, 307 | const string &found, 308 | StreamTokenizer::TokenType found_type) const { 309 | // If possible, consume the wrong token. 310 | if (st.HasNext()) { 311 | st.Next(); 312 | } 313 | ostringstream err_ss; 314 | err_ss << "infact::Interpreter: " << filestack(st, pos) 315 | << "expected token \"" << expected << "\" but found \"" << found 316 | << "\" (token type: " << StreamTokenizer::TypeName(found_type) 317 | << ")"; 318 | Error(err_ss.str()); 319 | } 320 | 321 | void 322 | Interpreter::WrongTokenTypeError(StreamTokenizer &st, 323 | size_t pos, 324 | StreamTokenizer::TokenType expected, 325 | StreamTokenizer::TokenType found, 326 | const string &token) const { 327 | WrongTokenTypeError(st, pos, 328 | StreamTokenizer::TypeName(expected), 329 | StreamTokenizer::TypeName(found), 330 | token); 331 | } 332 | 333 | void 334 | Interpreter::WrongTokenTypeError(StreamTokenizer &st, 335 | size_t pos, 336 | const string &expected_type, 337 | const string &found_type, 338 | const string &token) const { 339 | // If possible, consume the wrong token. 340 | if (st.HasNext()) { 341 | st.Next(); 342 | } 343 | ostringstream err_ss; 344 | err_ss << "infact::Interpreter: " << filestack(st, pos) 345 | << "expected token type " << expected_type 346 | << " but found " << found_type 347 | << "; token=\"" << token << "\""; 348 | Error(err_ss.str()); 349 | } 350 | 351 | } // namespace infact 352 | -------------------------------------------------------------------------------- /src/infact/interpreter.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides an interpreter for assigning primitives and Factory-constructible 34 | /// objects to named variables, as well as vectors thereof. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #ifndef INFACT_INTERPRETER_H_ 38 | #define INFACT_INTERPRETER_H_ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "environment-impl.h" 48 | 49 | namespace infact { 50 | 51 | using std::ifstream; 52 | using std::istream; 53 | using std::unique_ptr; 54 | 55 | /// An interface for classes that can build istreams for named files. 56 | class IStreamBuilder { 57 | public: 58 | virtual ~IStreamBuilder() = default; 59 | 60 | virtual unique_ptr Build( 61 | const string &filename, 62 | std::ios_base::openmode mode = std::ios_base::in) const = 0; 63 | }; 64 | 65 | /// The default implementation for the IStreamBuilder interface, returning 66 | /// std::ifstream instances. 67 | class DefaultIStreamBuilder : public IStreamBuilder { 68 | public: 69 | ~DefaultIStreamBuilder() override = default; 70 | 71 | unique_ptr Build(const string &filename, 72 | std::ios_base::openmode mode = std::ios_base::in) 73 | const override; 74 | }; 75 | 76 | class EnvironmentImpl; 77 | 78 | /// Provides an interpreter for assigning primitives and 79 | /// Factory-constructible objects to named variables, as well as 80 | /// vectors thereof. The interpreter maintains an internal 81 | /// environment whereby previously defined variables may be used in 82 | /// the definition of subsequent ones. The syntax of this language 83 | /// extends the syntax of the \link infact::Factory Factory \endlink 84 | /// class, described in the documentation of the \link 85 | /// infact::Factory::CreateOrDie Factory::CreateOrDie \endlink 86 | /// method. 87 | /// 88 | /// Statements in this language look like the following: 89 | /// \code 90 | /// // This is a comment. 91 | /// bool b = true; // assigns the value true to the boolean variable "b" 92 | /// int f = 1; // assigns the int value 1 to the variable "f" 93 | /// double g = 2.4; // assigns the double value 2.4 to the variable "g" 94 | /// string n = "foo" // assigns the string value "foo" to the variable "n" 95 | /// bool[] b_vec = {true, false, true}; // assigns a vector of bool to "b_vec" 96 | /// 97 | /// // Constructs an object of abstract type Model and assigns it to "m1" 98 | /// Model m1 = PerceptronModel(name("foo")); 99 | /// 100 | /// // Constructs an object of type Model and assigns it to "m2", crucially 101 | /// // using the previously defined string variable "n" as the value for 102 | /// // the PerceptronModel's name parameter. 103 | /// Model m2 = PerceptronModel(name(n)); 104 | /// 105 | /// // Constructs a vector of Model objects and assigns it to "m_vec". 106 | /// Model[] m_vec = {m2, PerceptronModel(name("bar"))}; 107 | /// \endcode 108 | /// 109 | /// Additionally, the interpreter can do type inference, so all the type 110 | /// specifiers in the previous examples are optional. For example, one may 111 | /// write the following statements: 112 | /// \code 113 | /// b = true; // assigns the value true to the boolean variable "b" 114 | /// 115 | /// // Constructs an object of abstract type Model and assigns it to "m1" 116 | /// m1 = PerceptronModel(name("foo")); 117 | /// 118 | /// // Constructs a vector of Model objects and assigns it to "m_vec". 119 | /// m_vec = {m1, PerceptronModel(name("bar"))}; 120 | /// \endcode 121 | /// 122 | /// Here's an example of using the interpreter after it has read the 123 | /// three statements from the previous example from a file called 124 | /// "example.infact": 125 | /// \code 126 | /// #include "interpreter.h" 127 | /// // ... 128 | /// Interpreter i; 129 | /// i.Eval("example.infact"); 130 | /// shared_ptr model; 131 | /// vector > model_vector; 132 | /// bool b; 133 | /// // The next statement only assigns a value to b if a variable "b" 134 | /// // exists in the interpreter's environment. 135 | /// i.Get("b", &b); 136 | /// i.Get("m1", &model); 137 | /// i.Get("m_vec", &model_vector); 138 | /// \endcode 139 | /// 140 | /// More formally, a statement in this language must conform to the 141 | /// following grammar, defined on top of the BNF syntax in the 142 | /// documentation of the \link infact::Factory::CreateOrDie 143 | /// Factory::CreateOrDie \endlink method: 144 | /// 145 | /// 146 | /// 147 | /// 148 | /// 149 | /// 150 | /// 151 | /// 152 | /// 153 | /// 154 | /// 155 | /// 156 | /// 157 | /// 158 | /// 159 | /// 160 | /// 161 | /// 162 | /// 163 | /// 166 | /// 167 | /// 168 | /// 169 | /// 170 | /// 178 | /// 179 | /// 180 | /// 181 | /// 182 | /// 183 | /// 184 | /// 185 | /// 186 | /// 187 | /// 190 | /// 191 | ///
\::=[ \ ]*
\::=[ \ | \ ]
\::='import' \ ';'
\::= 164 | /// [ \ ] \ '=' \ ';' 165 | ///
\::= 171 | /// 172 | /// 174 | /// 176 | ///
"bool" | "int" | "string" | "double" | "bool[]" | "int[]" 173 | /// "string[]" | "double[]" | T | T[]
where T is any \link infact::Factory 175 | /// Factory\endlink-constructible type.
177 | ///
\::=any valid C++ identifier
\::=\ | '{' \ '}' |
188 | /// \ | '{' \ '}'
189 | ///
192 | /// 193 | /// The above grammar doesn’t contain rules covering C++ style 194 | /// line comments, but they have the same behavior in this language as 195 | /// they do in C++, i.e., everything after the // to the end 196 | /// of the current line is treated as a comment and ignored. There 197 | /// are no C-style comments in this language. 198 | /// 199 | /// There are very simple rules for finding the files specified by 200 | /// imports: if a path is absolute, the Interpreter tries the path as-is. 201 | /// If it is relative, the Interpreter tries the path relative to the 202 | /// directory of the file with the import statement. If that does not 203 | /// succeed, the system simply tries the relative path as-is. 204 | /// 205 | /// An imported file is evaluated in situ, meaning it is 206 | /// evaluated in the current Environment; it is just as though you 207 | /// pasted the contents of the imported file right at the import 208 | /// statement. As such, an imported file can refer to variables that 209 | /// might be set prior to the import being evaluated. As a corollary, 210 | /// if an imported file uses the name of an unset variable, it is an 211 | /// error. 212 | class Interpreter { 213 | public: 214 | /// Constructs a new instance with the specified debug level. The 215 | /// wrapped \link infact::Environment Environment \endlink will 216 | /// also have the specified debug level. 217 | Interpreter(int debug = 0) : 218 | Interpreter(unique_ptr(new DefaultIStreamBuilder()), 219 | debug) { } 220 | 221 | /// Constructs a new instance with the specified IStreamBuilder and 222 | /// debug level. The wrapped \link infact::Environment Environment 223 | /// \endlink will also have the specified debug level. 224 | Interpreter(unique_ptr istream_builder, int debug = 0) : 225 | env_(new EnvironmentImpl(debug)), 226 | istream_builder_(std::move(istream_builder)), 227 | debug_(debug) { } 228 | 229 | /// Destroys this interpreter. 230 | virtual ~Interpreter() = default; 231 | 232 | /// Sets the IStreamBuilder object, to be owned by this object. 233 | void SetIStreamBuilder(unique_ptr istream_builder) { 234 | istream_builder_ = std::move(istream_builder); 235 | } 236 | 237 | /// Evaluates the statements in the specified text file. 238 | void Eval(const string &filename); 239 | 240 | /// Evaluates the statements in the specified string. 241 | void EvalString(const string& input) { 242 | StreamTokenizer st(input); 243 | Eval(st); 244 | } 245 | 246 | /// Evaluates the statements in the specified stream. 247 | void Eval(istream &is) { 248 | StreamTokenizer st(is); 249 | Eval(st); 250 | } 251 | 252 | void PrintEnv(ostream &os) const { 253 | env_->Print(os); 254 | } 255 | 256 | void PrintFactories(ostream &os) const { 257 | env_->PrintFactories(os); 258 | } 259 | 260 | /// The base case for the variadic template method GetMany defined below. 261 | bool GetMany() { return true; } 262 | 263 | /// Retrieves values for many variables, specified as a sequence of 264 | /// pairs of arguments. It is an error to invoke this method with 265 | /// an odd number of arguments. 266 | /// 267 | /// Example: 268 | /// \code 269 | /// Interpreter i; 270 | /// 271 | /// // Evaluate a short string defining two variables. 272 | /// i.EvalString("i = 6; f = \"foo\";"); 273 | /// int my_int; 274 | /// string my_string; 275 | /// i.GetMany("i", &my_int, "f", &my_string); 276 | /// \endcode 277 | /// 278 | /// \param[in] varname the name of a variable to be retrieved 279 | /// \param[out] var a pointer to a value for the variable named by \c varname 280 | /// \param rest the remaining arguments 281 | /// 282 | /// \tparam T the type of value to be assigned; the value of 283 | /// \c varname, if it has a binding in the Environment, 284 | /// must be assignable to \c T 285 | /// \tparam Args a variadic list of arguments, where each successive 286 | /// pair of arguments must be a variable name of type 287 | /// const string & and a pointer to an 288 | /// arbitrary type T to 289 | /// which the value of the variable may be assigned 290 | /// 291 | /// \return whether this method has succeeded in assigning values to 292 | /// all named variables 293 | template 294 | bool GetMany(const string &varname, T *var, 295 | Args &&...rest) { 296 | bool success = Get(varname, var); 297 | if (!success) { 298 | std::ostringstream err_ss; 299 | err_ss << "infact::Interpreter: no variable with name '" 300 | << varname << "'"; 301 | Error(err_ss.str()); 302 | return false; 303 | } 304 | return GetMany(std::forward(rest)...); // compile-time recursion ftw 305 | } 306 | 307 | /// Retrieves the value of the specified variable. It is an error 308 | /// if the type of the specified pointer to a value object is different 309 | /// from the specified variable in this interpreter’s environment. 310 | /// 311 | /// \tparam the type of value object being set by this method 312 | /// 313 | /// \param varname the name of the variable for which to retrieve the value 314 | /// \param value a pointer to the object whose value to be set by this 315 | /// method 316 | template 317 | bool Get(const string &varname, T *value) const { 318 | return env_->Get(varname, value); 319 | } 320 | 321 | /// Returns a pointer to the environment of this interpreter. 322 | /// Crucially, this method returns a pointer to the Environment 323 | /// implementation class, \link infact::EnvironmentImpl 324 | /// EnvironmentImpl\endlink, so that its templated \link 325 | /// infact::EnvironmentImpl::Get EnvironmentImpl::Get \endlink 326 | /// method may be invoked. 327 | EnvironmentImpl *env() { return env_.get(); } 328 | 329 | private: 330 | /// Returns whether \c filename is an absolute path. 331 | bool IsAbsolute(const string &filename) const; 332 | 333 | /// Returns wheterh \c filename is a file that exists and can be read. 334 | bool CanReadFile(const string &filename) const; 335 | 336 | /// Returns whether either f1 or f2 can be read, trying them in that 337 | /// order. If one of them can be read (according to the result of 338 | /// CanReadFile(const string &)), then the resulting 339 | /// name is output to filename. 340 | /// 341 | /// \param[in] f1 the first filename to check for readability 342 | /// \param[in] f2 the second filename to check for readability 343 | /// \param[out] filename the name of the readable file, either \c f1 or \c f2 344 | /// 345 | /// \return whether either \c f1 or \c f2 are readable and the 346 | /// output parameter \c filename has been set 347 | bool CanReadFile(const string &f1, const string &f2, string *filename) const; 348 | 349 | /// Returns whether \c filename introduces a cycle in the specified 350 | /// stack of \c filenames. Used for determining file import cycles. 351 | bool HasCycle(const string &filename, const vector &filenames) const; 352 | 353 | /// Evaluates the expressions contained the named file. 354 | void EvalFile(const string &filename); 355 | 356 | /// Evalutes the expressions contained in the specified token stream. 357 | void Eval(StreamTokenizer &st); 358 | 359 | /// Reads and evaluates an import statement. 360 | void Import(StreamTokenizer &st); 361 | 362 | /// Returns the name of the current file being interpreted, or the empty 363 | /// string if there is no such file. 364 | string curr_filename() const { 365 | return filenames_.size() > 0 ? filenames_.back() : ""; 366 | } 367 | 368 | /// Returns a human-readable form of the stack of filenames, useful for 369 | /// error messages and/or debugging. 370 | /// 371 | /// \param st the current StreamTokenizer 372 | /// \param pos the stream position of the current file (at the top 373 | /// of the statck) 374 | string filestack(StreamTokenizer &st, size_t pos) const; 375 | 376 | void WrongTokenError(StreamTokenizer &st, 377 | size_t pos, 378 | const string &expected, 379 | const string &found, 380 | StreamTokenizer::TokenType found_type) const; 381 | 382 | void WrongTokenTypeError(StreamTokenizer &st, 383 | size_t pos, 384 | StreamTokenizer::TokenType expected, 385 | StreamTokenizer::TokenType found, 386 | const string &token) const; 387 | 388 | void WrongTokenTypeError(StreamTokenizer &st, 389 | size_t pos, 390 | const string &expected_type, 391 | const string &found_type, 392 | const string &token) const; 393 | 394 | /// The environment of this interpreter. 395 | unique_ptr env_; 396 | 397 | /// The stack of files being interpreted, where the back of the 398 | /// vector is the top of the stack. The string on the top of the 399 | /// stack is the name of the current file being interpreted, or the 400 | /// empty string if there is no file associated with the stream 401 | /// being interpreted. 402 | vector filenames_; 403 | 404 | // The object for building new istream objects from named files. 405 | unique_ptr istream_builder_; 406 | 407 | // The debug level of this interpreter. 408 | int debug_; 409 | }; 410 | 411 | } // namespace infact 412 | 413 | #endif 414 | -------------------------------------------------------------------------------- /src/infact/stream-init.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides a generic dynamic object factory. 34 | /// \author dbikel@google.com (Dan Bikel) 35 | 36 | #ifndef INFACT_STREAM_INIT_H_ 37 | #define INFACT_STREAM_INIT_H_ 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "error.h" 49 | #include "stream-tokenizer.h" 50 | 51 | namespace infact { 52 | 53 | using std::ostringstream; 54 | using std::shared_ptr; 55 | using std::unordered_map; 56 | using std::vector; 57 | 58 | class Environment; 59 | 60 | /// \class StreamInitializer 61 | /// 62 | /// An interface that allows for a primitive, \link infact::Factory 63 | /// Factory\endlink-constructible object or vector thereof to be 64 | /// initialized based on the next token or tokens from a token stream. 65 | /// The data member may be an int, a double, a 66 | /// string or a shared_ptr to another 67 | /// Factory-constructible type. 68 | class StreamInitializer { 69 | public: 70 | StreamInitializer() { } 71 | virtual ~StreamInitializer() { } 72 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) = 0; 73 | }; 74 | 75 | template class Factory; 76 | 77 | /// \class Initializer 78 | /// 79 | /// A class to initialize a \link Factory\endlink-constructible 80 | /// object. 81 | /// 82 | /// \tparam T a shared_ptr to any type constructible by a Factory 83 | template 84 | class Initializer : public StreamInitializer { 85 | public: 86 | Initializer(T *member) : member_(member) { } 87 | virtual ~Initializer() { } 88 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) { 89 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 90 | bool is_null = 91 | token_type == StreamTokenizer::RESERVED_WORD && 92 | (st.Peek() == "nullptr" || st.Peek() == "nullptr"); 93 | if (!(is_null || token_type == StreamTokenizer::IDENTIFIER)) { 94 | ostringstream err_ss; 95 | err_ss << "FactoryInitializer: expected \"nullptr\", \"nullptr\" or " 96 | << "IDENTIFIER token at stream " 97 | << "position " << st.PeekTokenStart() << " but found " 98 | << StreamTokenizer::TypeName(token_type) << " token: \"" 99 | << st.Peek() << "\""; 100 | Error(err_ss.str()); 101 | } 102 | Factory factory; 103 | (*member_) = factory.CreateOrDie(st, env); 104 | } 105 | private: 106 | T *member_; 107 | }; 108 | 109 | /// A specialization to allow Factory-constructible objects to initialize 110 | /// int data members. 111 | template<> 112 | class Initializer : public StreamInitializer { 113 | public: 114 | Initializer(int *member) : member_(member) { } 115 | virtual ~Initializer() { } 116 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) { 117 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 118 | if (token_type != StreamTokenizer::NUMBER) { 119 | ostringstream err_ss; 120 | err_ss << "IntInitializer: expected NUMBER token at stream " 121 | << "position " << st.PeekTokenStart() << " but found " 122 | << StreamTokenizer::TypeName(token_type) << " token: \"" 123 | << st.Peek() << "\""; 124 | Error(err_ss.str()); 125 | } 126 | (*member_) = atoi(st.Next().c_str()); 127 | } 128 | private: 129 | int *member_; 130 | }; 131 | 132 | /// A specialization to initialize double data members. 133 | template<> 134 | class Initializer : public StreamInitializer { 135 | public: 136 | Initializer(double *member) : member_(member) { } 137 | virtual ~Initializer() { } 138 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) { 139 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 140 | if (token_type != StreamTokenizer::NUMBER) { 141 | ostringstream err_ss; 142 | err_ss << "DoubleInitializer: expected NUMBER token at stream " 143 | << "position " << st.PeekTokenStart() << " but found " 144 | << StreamTokenizer::TypeName(token_type) << " token: \"" 145 | << st.Peek() << "\""; 146 | Error(err_ss.str()); 147 | } 148 | (*member_) = atof(st.Next().c_str()); 149 | } 150 | private: 151 | double *member_; 152 | }; 153 | 154 | /// A specialization to initialize bool data members. 155 | template<> 156 | class Initializer : public StreamInitializer { 157 | public: 158 | Initializer(bool *member) : member_(member) { } 159 | virtual ~Initializer() { } 160 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) { 161 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 162 | if (token_type != StreamTokenizer::RESERVED_WORD) { 163 | ostringstream err_ss; 164 | err_ss << "BoolInitializer: expected RESERVED_WORD token at stream " 165 | << "position " << st.PeekTokenStart() << " but found " 166 | << StreamTokenizer::TypeName(token_type) << " token: \"" 167 | << st.Peek() << "\""; 168 | Error(err_ss.str()); 169 | } 170 | size_t next_tok_start = st.PeekTokenStart(); 171 | string next_tok = st.Next(); 172 | if (next_tok == "false") { 173 | (*member_) = false; 174 | } else if (next_tok == "true") { 175 | (*member_) = true; 176 | } else { 177 | ostringstream err_ss; 178 | err_ss << "Initializer: expected either \"true\" or \"false\" " 179 | << "token at stream position " << next_tok_start << " but found " 180 | << "token: \"" << next_tok << "\""; 181 | Error(err_ss.str()); 182 | } 183 | } 184 | private: 185 | bool *member_; 186 | }; 187 | 188 | /// A specialization to initialize string data members. 189 | template<> 190 | class Initializer : public StreamInitializer { 191 | public: 192 | Initializer(string *member) : member_(member) { } 193 | virtual ~Initializer() { } 194 | virtual void Init(StreamTokenizer &st, Environment *env = nullptr) { 195 | StreamTokenizer::TokenType token_type = st.PeekTokenType(); 196 | if (token_type != StreamTokenizer::STRING) { 197 | ostringstream err_ss; 198 | err_ss << "StringInitializer: expected STRING token at stream " 199 | << "position " << st.PeekTokenStart() << " but found " 200 | << StreamTokenizer::TypeName(token_type) << " token: \"" 201 | << st.Peek() << "\""; 202 | Error(err_ss.str()); 203 | } 204 | (*member_) = st.Next(); 205 | } 206 | private: 207 | string *member_; 208 | }; 209 | 210 | } // namespace infact 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /src/infact/stream-tokenizer-test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Test driver for the \link infact::StreamTokenizer StreamTokenizer \endlink 34 | /// class. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #include 38 | #include 39 | 40 | #include "stream-tokenizer.h" 41 | 42 | using namespace std; 43 | using namespace infact; 44 | 45 | int 46 | main(int argc, char **argv) { 47 | cerr << "Testing StreamTokenizer with string arg constructor:" << endl; 48 | std::string test_string = "foo(bar, baz(34), bleh(\"fleh with spaces\"))"; 49 | StreamTokenizer st1(test_string); 50 | while (st1.HasNext()) { 51 | StreamTokenizer::TokenType type = st1.PeekTokenType(); 52 | size_t start = st1.PeekTokenStart(); 53 | size_t line_number = st1.PeekTokenLineNumber(); 54 | cout << "token: \"" << st1.Next() << "\"" 55 | << "; type=" << StreamTokenizer::TypeName(type) 56 | << "; start=" << start 57 | << "; line=" << line_number 58 | << endl; 59 | cout << "chars so far: '" << st1.str() << "'" << endl; 60 | } 61 | cerr << "Done." << endl; 62 | 63 | cerr << "\nTesting Putback:" << endl; 64 | st1.Putback(); 65 | while (st1.HasNext()) { 66 | StreamTokenizer::TokenType type = st1.PeekTokenType(); 67 | size_t start = st1.PeekTokenStart(); 68 | size_t line_number = st1.PeekTokenLineNumber(); 69 | cout << "token: \"" << st1.Next() << "\"" 70 | << "; type=" << StreamTokenizer::TypeName(type) 71 | << "; start=" << start 72 | << "; line=" << line_number 73 | << endl; 74 | cout << "chars so far: '" << st1.str() << "'" << endl; 75 | } 76 | 77 | cerr << "\nTesting Rewind(3):" << endl; 78 | st1.Rewind(3); 79 | while (st1.HasNext()) { 80 | StreamTokenizer::TokenType type = st1.PeekTokenType(); 81 | size_t start = st1.PeekTokenStart(); 82 | size_t line_number = st1.PeekTokenLineNumber(); 83 | cout << "token: \"" << st1.Next() << "\"" 84 | << "; type=" << StreamTokenizer::TypeName(type) 85 | << "; start=" << start 86 | << "; line=" << line_number 87 | << endl; 88 | cout << "chars so far: '" << st1.str() << "'" << endl; 89 | } 90 | 91 | cerr << "Testing Rewind():" << endl; 92 | st1.Rewind(); 93 | while (st1.HasNext()) { 94 | StreamTokenizer::TokenType type = st1.PeekTokenType(); 95 | size_t start = st1.PeekTokenStart(); 96 | size_t line_number = st1.PeekTokenLineNumber(); 97 | cout << "token: \"" << st1.Next() << "\"" 98 | << "; type=" << StreamTokenizer::TypeName(type) 99 | << "; start=" << start 100 | << "; line=" << line_number 101 | << endl; 102 | cout << "chars so far: '" << st1.str() << "'" << endl; 103 | } 104 | 105 | cerr << "\nReading from stdin until EOF:" << endl; 106 | 107 | StreamTokenizer st2(cin); 108 | while (st2.HasNext()) { 109 | StreamTokenizer::TokenType type = st2.PeekTokenType(); 110 | cout << "token: \"" << st2.Next() << "\"" 111 | << "; type=" << StreamTokenizer::TypeName(type) << endl; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/infact/stream-tokenizer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Implementation of the \link infact::StreamTokenizer StreamTokenizer 34 | /// \endlink class. 35 | /// \author dbikel@google.com (Dan Bikel) 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include "stream-tokenizer.h" 42 | 43 | namespace infact { 44 | 45 | void 46 | StreamTokenizer::ConsumeChar(char c) { 47 | oss_ << c; 48 | ++num_read_; 49 | if (c == '\n') { 50 | ++line_number_; 51 | line_start_pos_ = num_read_; 52 | } 53 | } 54 | 55 | bool 56 | StreamTokenizer::ReadChar(char *c) { 57 | (*c) = is_.get(); 58 | if (!is_.good()) { 59 | eof_reached_ = true; 60 | return false; 61 | } else { 62 | ConsumeChar(*c); 63 | return true; 64 | } 65 | } 66 | 67 | bool 68 | StreamTokenizer::GetNext(Token *next) { 69 | if (!is_.good()) { 70 | eof_reached_ = true; 71 | return false; 72 | } 73 | // Get first character of next token. 74 | char c; 75 | bool is_whitespace = true; 76 | while (is_whitespace) { 77 | if (!ReadChar(&c)) { 78 | return false; 79 | } 80 | is_whitespace = isspace(c); 81 | 82 | // If we find a comment character, then read to the end of the line. 83 | if (!is_whitespace && c == '/' && is_.peek() == '/') { 84 | while (c != '\n') { 85 | if (!ReadChar(&c)) { 86 | return false; 87 | } 88 | } 89 | is_whitespace = true; 90 | } 91 | } 92 | 93 | // In case we're successful in reading the next token, we fill in 94 | // the two stream state data available now. 95 | next->start = num_read_ - 1; 96 | next->line_number = line_number_; 97 | next->line_start_pos = line_start_pos_; 98 | 99 | bool next_tok_complete = false; 100 | next->tok.clear(); 101 | if (ReservedChar(c)) { 102 | next->tok += c; 103 | next_tok_complete = true; 104 | next->type = RESERVED_CHAR; 105 | } else if (c == '"') { 106 | // We've got a string literal, so keep reading characters, 107 | // until hitting a non-escaped double quote. 108 | streampos string_literal_start_pos = num_read_ - 1; 109 | bool found_closing_quote = false; 110 | while (is_.good()) { 111 | bool success = ReadChar(&c); 112 | if (success) { 113 | if (c == '"') { 114 | found_closing_quote = true; 115 | break; 116 | } else if (c == '\\') { 117 | success = ReadChar(&c); 118 | } 119 | } 120 | if (success) { 121 | next->tok += c; 122 | } 123 | } 124 | if (!found_closing_quote) { 125 | ostringstream err_ss; 126 | err_ss << "StreamTokenizer: error: could not find closing " 127 | << "double quote for string literal beginning at stream index " 128 | << string_literal_start_pos 129 | << "; partial string literal read: \"" 130 | << next->tok; 131 | Error(err_ss.str()); 132 | } 133 | next_tok_complete = true; 134 | next->type = STRING; 135 | } else { 136 | // This is a number, a reserved word or C++ identifier token, so 137 | // add first character; the remainder of the token will be handled 138 | // in the next block. 139 | next->tok += c; 140 | next->type = (c == '-' || (c >= '0' && c <= '9')) ? NUMBER : IDENTIFIER; 141 | } 142 | if (!next_tok_complete) { 143 | // The current token is a number, a reserved word or C++ 144 | // identifier, so we keep reading characters until hitting a 145 | // "reserved character", a whitespace character or EOF. 146 | bool done = false; 147 | while (!done && is_.good()) { 148 | // We don't call ReadChar below because the next character might 149 | // tell us that the current token has ended (i.e., if it's a 150 | // reserved character, a double quote or a whitespace 151 | // character). 152 | int peek = is_.peek(); 153 | if (peek != EOF) { 154 | char next_char = static_cast(peek); 155 | if (ReservedChar(next_char) || next_char == '"' || isspace(next_char)) { 156 | // Now that we've finished reading something that is not a 157 | // string literal, change its type to be RESERVED_WORD if it 158 | // exactly matches something in the set of reserved words. 159 | if (reserved_words_.count(next->tok) != 0) { 160 | next->type = RESERVED_WORD; 161 | } 162 | done = true; 163 | } else { 164 | ReadChar(&c); 165 | next->tok += c; 166 | } 167 | } else { 168 | eof_reached_ = true; 169 | } 170 | } 171 | } 172 | // We're about to return a successfully read token, so we make sure to record 173 | // the stream position at this point in the Token object. 174 | next->curr_pos = num_read_; 175 | 176 | return true; 177 | } 178 | 179 | namespace { 180 | 181 | /// Returns the line beginning at \c pos. 182 | string getline(const string &str, size_t pos) { 183 | string curr_line; 184 | for (; pos < str.length() && str[pos] != '\n'; ++pos) { 185 | curr_line += str[pos]; 186 | } 187 | return curr_line; 188 | } 189 | 190 | } 191 | 192 | string 193 | StreamTokenizer::line() { 194 | if (HasPrev()) { 195 | return getline(str(), token_[next_token_idx_ - 1].line_start_pos); 196 | } else { 197 | return ""; 198 | } 199 | } 200 | 201 | } // namespace infact 202 | -------------------------------------------------------------------------------- /src/infact/stream-tokenizer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // ----------------------------------------------------------------------------- 30 | // 31 | // 32 | /// \file 33 | /// Provides the \link infact::StreamTokenizer StreamTokenizer \endlink class. 34 | /// \author dbikel@google.com (Dan Bikel) 35 | 36 | #ifndef INFACT_STREAM_TOKENIZER_H_ 37 | #define INFACT_STREAM_TOKENIZER_H_ 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "error.h" 48 | 49 | namespace infact { 50 | 51 | using std::istream; 52 | using std::istringstream; 53 | using std::ostringstream; 54 | using std::set; 55 | using std::streampos; 56 | using std::string; 57 | using std::vector; 58 | using std::cerr; 59 | using std::endl; 60 | 61 | /// Default set of reserved words for the StreamTokenizer class. 62 | /// Use the \link infact::StreamTokenizer::set_reserved_words 63 | /// StreamTokenizer::set_reserved_words \endlink 64 | /// to customize this set. 65 | static const char *default_reserved_words[] = { 66 | "-", 67 | "nullptr", 68 | "NULL", 69 | "import", 70 | "false", 71 | "true", 72 | "bool", 73 | "int", 74 | "double", 75 | "string", 76 | "bool[]", 77 | "int[]", 78 | "double[]", 79 | "string[]", 80 | }; 81 | 82 | /// Default set of reserved characters for the StreamTokenizer class. 83 | #define DEFAULT_RESERVED_CHARS "(){},=;/" 84 | 85 | /// \class StreamTokenizer 86 | /// 87 | /// A simple class for tokenizing a stream of tokens for the formally 88 | /// specified language used to construct objects for the InFact 89 | /// framework. 90 | class StreamTokenizer { 91 | public: 92 | /// The set of types of tokens read by this stream tokenizer. 93 | /// 94 | /// \see PeekTokenType 95 | enum TokenType { 96 | EOF_TYPE, 97 | RESERVED_CHAR, 98 | RESERVED_WORD, 99 | STRING, 100 | NUMBER, 101 | IDENTIFIER 102 | }; 103 | 104 | /// Returns a string type name for the specified TokenType constant. 105 | static const char *TypeName(TokenType token_type) { 106 | static const char *names[] = { 107 | "EOF", "RESERVED_CHAR", "RESERVED_WORD", "STRING", "NUMBER", "IDENTIFIER" 108 | }; 109 | return names[token_type]; 110 | } 111 | 112 | /// Information about a token read from the underlying stream. 113 | struct Token { 114 | /// The token itself. 115 | string tok; 116 | /// The token’s type. 117 | TokenType type; 118 | 119 | // The following three fields capture information about the underlying 120 | // byte stream at the time this token was read from it. 121 | 122 | /// The starting byte of the token in the underlying stream. 123 | size_t start; 124 | /// The line number of the first byte of the token in the underlying stream. 125 | size_t line_number; 126 | /// The stream position of the start of the line of this token. 127 | size_t line_start_pos; 128 | /// The current position in the underlying stream just after reading this 129 | /// token. 130 | size_t curr_pos; 131 | }; 132 | 133 | /// Constructs a new instance around the specified byte stream. 134 | /// 135 | /// \param is the input byte stream for this stream tokenizer to 136 | /// use 137 | /// \param reserved_chars the set of single characters serving as 138 | /// “reserved characters” 139 | StreamTokenizer(istream &is, 140 | const char *reserved_chars = DEFAULT_RESERVED_CHARS) : 141 | is_(is) { 142 | Init(reserved_chars); 143 | } 144 | 145 | /// Constructs a new instance around the specified string. 146 | /// 147 | /// \param s the string providing the stream of characters 148 | /// for this stream tokenizer to use 149 | /// \param reserved_chars the set of single characters serving as 150 | /// “reserved characters” 151 | StreamTokenizer(const string &s, 152 | const char *reserved_chars = DEFAULT_RESERVED_CHARS) : 153 | sstream_(s), is_(sstream_) { 154 | Init(reserved_chars); 155 | } 156 | 157 | /// Sets the set of “reserved words” used by this stream 158 | /// tokenizer. Should be invoked just after construction time. 159 | void set_reserved_words(set &reserved_words) { 160 | reserved_words_ = reserved_words; 161 | } 162 | 163 | /// Destroys this instance. 164 | virtual ~StreamTokenizer() { 165 | delete[] reserved_chars_; 166 | } 167 | 168 | /// Returns the entire sequence of characters read so far by this 169 | /// stream tokenizer as a newly constructed string object. 170 | string str() { return oss_.str(); } 171 | 172 | /// Returns the number of bytes read from the underlying byte 173 | /// stream just after scanning the most recent token, or 0 if this stream 174 | /// is just about to return the first token. 175 | size_t tellg() const { 176 | return HasPrev() ? token_[next_token_idx_ - 1].curr_pos : 0; 177 | } 178 | 179 | /// Returns the number of lines read from the underlying byte stream, 180 | /// where a line is any number of bytes followed by a newline character 181 | /// (i.e., this is ASCII-centric). 182 | size_t line_number() const { 183 | return HasNext() ? token_[next_token_idx_].line_number : line_number_; 184 | } 185 | 186 | /// Returns a string consisting of the characters read so far of the current 187 | /// line containing the most recently returned token, or the empty string 188 | /// if no tokens have been read yet. 189 | string line(); 190 | 191 | /// Returns the stream position of the current line in the underlying 192 | /// byte stream. This value may be equal to the number of bytes read 193 | /// if the most recently consumed character is a newline and there are 194 | /// no more tokens in the stream. 195 | size_t line_start() { 196 | return HasNext() ? token_[next_token_idx_].line_start_pos : 0; 197 | } 198 | 199 | /// Returns whether there is another token in the token stream. 200 | bool HasNext() const { return next_token_idx_ < token_.size(); } 201 | 202 | /// Returns whether there is a previous token in the stream. 203 | bool HasPrev() const { return next_token_idx_ > 0; } 204 | 205 | /// Returns the previous token, or the empty string if there is no 206 | /// previous token. 207 | string PeekPrev() const { 208 | return HasPrev() ? token_[next_token_idx_ - 1].tok : ""; 209 | } 210 | 211 | /// Returns the line number of the previous token, or 0 if there is no 212 | /// previous token. 213 | size_t PeekPrevTokenLineNumber() const { 214 | return HasPrev() ? token_[next_token_idx_ - 1].line_number : 0; 215 | } 216 | 217 | /// Returns the stream position of the most recent line start of the 218 | /// previous token, or 0 if this stream is just about to return the 219 | /// first token. 220 | size_t PeekPrevTokenLineStart() const { 221 | return HasPrev() ? token_[next_token_idx_ - 1].line_start_pos : 0; 222 | } 223 | 224 | /// Returns the stream position of the first byte of the previous 225 | /// token, or 0 if there is no previous token. 226 | size_t PeekPrevTokenStart() const { 227 | return HasPrev() ? token_[next_token_idx_ - 1].start : 0; 228 | } 229 | 230 | /// Returns the type of the previous token, or EOF_TYPE if there 231 | /// is no previous token. 232 | TokenType PeekPrevTokenType() const { 233 | return HasPrev() ? token_[next_token_idx_ - 1].type : EOF_TYPE; 234 | } 235 | 236 | /// Returns the next token in the token stream. 237 | string Next() { 238 | if (!HasNext()) { 239 | Error("invoking StreamTokenizer::Next when HasNext returns false"); 240 | } 241 | 242 | size_t curr_token_idx = next_token_idx_; 243 | 244 | // Try to get the next token of the stream if we're about to run out of 245 | // tokens. 246 | if (!eof_reached_ && next_token_idx_ + 1 == token_.size()) { 247 | Token next; 248 | if (GetNext(&next)) { 249 | token_.push_back(next); 250 | } 251 | } 252 | // Ensure that we only advance if we haven't already reached token_.size(). 253 | if (next_token_idx_ < token_.size()) { 254 | ++next_token_idx_; 255 | } 256 | 257 | return token_[curr_token_idx].tok; 258 | } 259 | 260 | /// Rewinds this token stream to the beginning. If the underlying stream 261 | /// has no tokens, this is a no-op. 262 | void Rewind() { 263 | next_token_idx_ = 0; 264 | } 265 | 266 | /// Rewinds this token stream by the specified number of tokens. If the 267 | /// specified number of tokens is greater than the number of tokens read 268 | /// so far, invoking this method will be functionally equivalent to invoking 269 | /// the no-argument Rewind() method. 270 | void Rewind(size_t num_tokens) { 271 | // Cannot rewind more than the number of tokens read so far. 272 | if (num_tokens > next_token_idx_) { 273 | num_tokens = next_token_idx_; 274 | } 275 | next_token_idx_ -= num_tokens; 276 | } 277 | 278 | /// A synonym for Rewind(1). 279 | void Putback() { 280 | Rewind(1); 281 | } 282 | 283 | /// Returns the next token’s start position, or the byte position 284 | /// of the underlying byte stream if there is no next token. 285 | size_t PeekTokenStart() const { 286 | return HasNext() ? token_[next_token_idx_].start : num_read_; 287 | } 288 | 289 | /// Returns the type of the next token, or EOF_TYPE if there is no next 290 | /// token. 291 | TokenType PeekTokenType() const { 292 | return HasNext() ? token_[next_token_idx_].type : EOF_TYPE; 293 | } 294 | 295 | /// Returns the line number of the first byte of the next token, or 296 | /// the current line number of the underlying stream if there is no 297 | /// next token. 298 | size_t PeekTokenLineNumber() const { 299 | return HasNext() ? token_[next_token_idx_].line_number : line_number_; 300 | } 301 | 302 | /// Returns the next token that would be returned by the \link Next 303 | /// \endlink method. The return value of this method is only valid 304 | /// when \link HasNext \endlink returns true. 305 | string Peek() const { return HasNext() ? token_[next_token_idx_].tok : ""; } 306 | 307 | private: 308 | void Init(const char *reserved_chars) { 309 | num_reserved_chars_ = strlen(reserved_chars); 310 | reserved_chars_ = new char[num_reserved_chars_ + 1]; 311 | strcpy(reserved_chars_, reserved_chars); 312 | int num_reserved_words = sizeof(default_reserved_words)/sizeof(const char*); 313 | for (int i = 0; i < num_reserved_words; ++i) { 314 | reserved_words_.insert(string(default_reserved_words[i])); 315 | } 316 | Token next; 317 | if (GetNext(&next)) { 318 | token_.push_back(next); 319 | } 320 | } 321 | 322 | void ConsumeChar(char c); 323 | 324 | bool ReadChar(char *c); 325 | 326 | /// Retrieves the next token from the istream wrapped by this 327 | /// stream tokenizer. 328 | /// 329 | /// \param next the token object to be filled in if there is a next token 330 | /// 331 | /// \return whether there was a next token in the underlying stream and 332 | /// it was successfully gotten 333 | bool GetNext(Token *next); 334 | 335 | /// Returns whether the specified character represents a 336 | /// “reserved character”. 337 | bool ReservedChar(char c) const { 338 | for (size_t i = 0; i < num_reserved_chars_; ++i) { 339 | if (c == reserved_chars_[i]) { 340 | return true; 341 | } 342 | } 343 | return false; 344 | } 345 | 346 | // data members 347 | 348 | // The stream itself. 349 | /// This data member is for use when we need to construct the is_ data member 350 | /// from a string at construction time. 351 | istringstream sstream_; 352 | /// The underlying byte stream of this token stream. 353 | istream &is_; 354 | 355 | // Information about special tokens. 356 | char *reserved_chars_; 357 | size_t num_reserved_chars_; 358 | set reserved_words_; 359 | 360 | // Information about the current state of the underlying byte stream. 361 | size_t num_read_ = 0; 362 | size_t line_number_ = 0; 363 | size_t line_start_pos_ = 0; 364 | bool eof_reached_ = false; 365 | ostringstream oss_; 366 | 367 | // The sequence of tokens read so far. 368 | vector token_; 369 | 370 | // The index of the next token in this stream in token_, or token_.size() 371 | // if there are no more tokens left in this stream. Note that invocations 372 | // of the Rewind and Putback methods alter this data member. 373 | size_t next_token_idx_ = 0; 374 | }; 375 | 376 | } // namespace infact 377 | 378 | #endif 379 | --------------------------------------------------------------------------------