Mercurial > hg > octave-nkf
changeset 16155:0259254a3ccc classdef
maint: periodic merge of default to classdef
* lex.h, lex.ll, parse.h, oct-parse.yy: Resolve conflicts by adapting
classdef changes to new octave_parser and lexical_feedback classes.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 28 Feb 2013 02:04:24 -0500 |
parents | fc3cb570ac46 (current diff) aa5e1e8dce66 (diff) |
children | a8f9eb92fa6e |
files | libinterp/Makefile.am libinterp/interp-core/pt-jit.cc libinterp/interpfcn/symtab.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov.cc libinterp/octave.cc libinterp/parse-tree/lex.h libinterp/parse-tree/lex.ll libinterp/parse-tree/oct-parse.yy libinterp/parse-tree/parse.h libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h libinterp/parse-tree/token.h test/classes/classes.tst test/classes/module.mk |
diffstat | 87 files changed, 3423 insertions(+), 3162 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgsubstate +++ b/.hgsubstate @@ -1,1 +1,1 @@ -0eef0a2a05e22ac8ef2aad06dda200f7def83396 gnulib-hg +c75939cb6254833830cdbeaf84e666360a34ccf1 gnulib-hg
--- a/.hgtags +++ b/.hgtags @@ -74,3 +74,4 @@ faefa1bea8ddae3cab170afdeab68d3d15c4e623 ss-3-7-2 0000000000000000000000000000000000000000 ss-3-7-2 23a7661e529ae9bfc91693618f8c314c31f695ca ss-3-7-2 +cc5a7d1233f3acea85648baeb754fc0e8f225225 rc-3-6-4-2
--- a/bootstrap.conf +++ b/bootstrap.conf @@ -36,6 +36,7 @@ floorf fnmatch fopen + fpucw fseek ftell getcwd
--- a/build-aux/common.mk +++ b/build-aux/common.mk @@ -3,12 +3,15 @@ AWK = @AWK@ export AWK -SED = @SED@ -export SED +GREP = @GREP@ +export GREP FIND = @FIND@ export FIND +SED = @SED@ +export SED + PERL = @PERL@ export PERL @@ -113,7 +116,7 @@ DEPEND_FLAGS = @DEPEND_FLAGS@ DEPEND_EXTRA_SED_PATTERN = @DEPEND_EXTRA_SED_PATTERN@ INCLUDE_DEPS = @INCLUDE_DEPS@ -# ifeq ($(INCLUDE_DEPS),false) +# ifeq ($(INCLUDE_DEPS),no) # omit_deps = true; # endif @@ -278,9 +281,9 @@ ## Order matters, at least on some systems (Cygwin, for example). SPARSE_XLIBS = \ - $(CHOLMOD_LIBS) $(UMFPACK_LIBS) \ - $(AMD_LIBS) $(CAMD_LIBS) $(COLAMD_LIBS) \ - $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) + $(CHOLMOD_LIBS) $(UMFPACK_LIBS) \ + $(AMD_LIBS) $(CAMD_LIBS) $(COLAMD_LIBS) \ + $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) TERM_LIBS = @TERM_LIBS@ @@ -696,42 +699,13 @@ -e "s|%AWK%|${AWK}|g" \ -e "s|%FIND%|${FIND}|g" \ -e "s|%SED%|${SED}|g" \ - -e "s|%library_path_var%|${library_path_var}|g" \ - -e "s|%liboctinterp%|${SHLPRE}octinterp.${SHLEXT}|g" \ - -e "s|%liboctave%|${SHLPRE}octave.${SHLEXT}|g" \ - -e "s|%ldpreloadsep%|${ldpreloadsep}|g" \ - -e "s|%srcdir%|${srcdir}|" \ - -e "s|%top_srcdir%|${top_srcdir}|" \ -e "s|%abs_top_srcdir%|${abs_top_srcdir}|" \ -e "s|%builddir%|$(shell pwd)|" > $@-t $(simple_move_if_change_rule) endef -define do_script_install -$(top_srcdir)/build-aux/mkinstalldirs $(DESTDIR)$(fcnfiledir)/$(script_sub_dir) -for f in $(FCN_FILES); do \ - fbase=`basename $$f`; \ - rm -f $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/$$fbase; \ - $(INSTALL_DATA) $$f $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/$$fbase; \ -done -$(top_srcdir)/mkpkgadd $(DESTDIR)$(fcnfiledir)/$(script_sub_dir) > $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD.t -if [ -n "`cat $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD.t`" ]; then \ - $(INSTALL_DATA) $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD.t $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD ; \ -else \ - rm -f $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD.t ; \ -fi -endef - -define do_script_uninstall -for f in $(FCN_FILES_NO_DIR); \ - do rm -f $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/$$f; \ -done -rm -f $(DESTDIR)$(fcnfiledir)/$(script_sub_dir)/PKG_ADD --rmdir $(DESTDIR)$(fcnfiledir)/$(script_sub_dir) -endef - define test-file-commands -( echo "## DO NOT EDIT! Generated automatically from $(<F) by Make."; grep '^%!' $< ) > $@-t +( echo "## DO NOT EDIT! Generated automatically from $(<F) by Make."; $(GREP) '^%!' $< ) > $@-t mv $@-t $@ endef
--- a/build-aux/find-files-with-tests.sh +++ b/build-aux/find-files-with-tests.sh @@ -1,6 +1,7 @@ #! /bin/sh set -e +GREP=${GREP:-grep} SED=${SED:-sed} srcdir="$1" @@ -13,7 +14,7 @@ else file="$srcdir/$arg" fi - if [ "`grep -l '^%!' $file`" ]; then + if [ "`$GREP -l '^%!' $file`" ]; then echo "$file" | $SED "s,\\$srcdir/,,"; fi done
--- a/configure.ac +++ b/configure.ac @@ -97,6 +97,7 @@ ## Programs used in Makefiles. AC_PROG_AWK +AC_PROG_GREP OCTAVE_PROG_FIND OCTAVE_PROG_SED OCTAVE_PROG_PERL @@ -180,24 +181,24 @@ ### matrix classes. This slows down some operations a bit, so it is turned off ### by default. -BOUNDS_CHECKING=false +BOUNDS_CHECKING=no AC_ARG_ENABLE([bounds-check], [AS_HELP_STRING([--enable-bounds-check], [enable bounds checking for indexing in internal array classes])], - [if test "$enableval" = yes; then BOUNDS_CHECKING=true; fi], []) -if $BOUNDS_CHECKING; then + [if test "$enableval" = yes; then BOUNDS_CHECKING=yes; fi], []) +if test $BOUNDS_CHECKING = yes; then AC_DEFINE(BOUNDS_CHECKING, 1, [Define to 1 to use internal bounds checking.]) fi ### Use Octave's built-in memory allocator rather than straightforward malloc. ### Disabled by default. -USE_OCTAVE_ALLOCATOR=false +USE_OCTAVE_ALLOCATOR=no AC_ARG_ENABLE([octave-allocator], [AS_HELP_STRING([--enable-octave-allocator], [use the obsolete octave_allocator class for many of Octave's objects (mostly octave_value types). You probably do NOT want to enable this feature.])], - [if test "$enableval" = yes; then USE_OCTAVE_ALLOCATOR=true; fi], []) -if $USE_OCTAVE_ALLOCATOR; then + [if test "$enableval" = yes; then USE_OCTAVE_ALLOCATOR=yes; fi], []) +if test $USE_OCTAVE_ALLOCATOR = yes; then AC_DEFINE(USE_OCTAVE_ALLOCATOR, 1, [Define to 1 to use octave_allocator class.]) fi @@ -206,12 +207,12 @@ ### for thread-safe behavior but incurs a significant slowdown, and is thus ### disabled by default. -USE_ATOMIC_REFCOUNT=false +USE_ATOMIC_REFCOUNT=no AC_ARG_ENABLE([atomic-refcount], [AS_HELP_STRING([--enable-atomic-refcount], [use atomic operations for internal reference counting. This is required for thread-safe behavior but does not by itself make Octave internals thread safe.])], - [if test "$enableval" = yes; then USE_ATOMIC_REFCOUNT=true; fi], []) -if $USE_ATOMIC_REFCOUNT; then + [if test "$enableval" = yes; then USE_ATOMIC_REFCOUNT=yes; fi], []) +if test $USE_ATOMIC_REFCOUNT = yes; then AC_DEFINE(USE_ATOMIC_REFCOUNT, 1, [Define to 1 to use atomic operations for reference counting.]) fi @@ -232,13 +233,13 @@ ### If possible, use a 64-bit integer type for array dimensions and indexing. -USE_64_BIT_IDX_T=false +USE_64_BIT_IDX_T=no OCTAVE_IDX_TYPE=int AC_ARG_ENABLE(64, [AS_HELP_STRING([--enable-64], [(EXPERIMENTAL) use 64-bit integers for array dimensions and indexing])], - [if test "$enableval" = yes; then USE_64_BIT_IDX_T=true; fi], []) -if $USE_64_BIT_IDX_T; then + [if test "$enableval" = yes; then USE_64_BIT_IDX_T=yes; fi], []) +if test $USE_64_BIT_IDX_T = yes; then AC_CHECK_SIZEOF([void *]) AC_CHECK_SIZEOF([int]) AC_CHECK_SIZEOF([long]) @@ -251,18 +252,18 @@ else warn_64_bit="no suitable type found for octave_idx_type so disabling 64-bit features" OCTAVE_CONFIGURE_WARNING([warn_64_bit]) - USE_64_BIT_IDX_T=false + USE_64_BIT_IDX_T=no fi else warn_64_bit="pointers are not 64-bits wide; disabling 64-bit features" OCTAVE_CONFIGURE_WARNING([warn_64_bit]) - USE_64_BIT_IDX_T=false + USE_64_BIT_IDX_T=no fi fi AC_SUBST(OCTAVE_IDX_TYPE) AC_DEFINE_UNQUOTED(OCTAVE_IDX_TYPE, [$OCTAVE_IDX_TYPE], [Define to the type of octave_idx_type (64 or 32 bit signed integer).]) -if $USE_64_BIT_IDX_T; then +if test $USE_64_BIT_IDX_T = yes; then AC_DEFINE(USE_64_BIT_IDX_T, 1, [Define to 1 if using 64-bit integers for array dimensions and indexing.]) fi @@ -350,7 +351,7 @@ ### Determine the compiler flag necessary to create dependencies ## Assume GCC. -INCLUDE_DEPS=true +INCLUDE_DEPS=yes DEPEND_FLAGS="-M" DEPEND_EXTRA_SED_PATTERN="" if test "$GCC" != yes; then @@ -363,11 +364,11 @@ ;; *-*-mingw*) if test $have_msvc = no; then - INCLUDE_DEPS=false + INCLUDE_DEPS=no fi ;; *) - INCLUDE_DEPS=false + INCLUDE_DEPS=no ;; esac fi @@ -466,12 +467,12 @@ ### Test whether the compiler supports OpenMP. This is experimental so disable ### it by default. Enable it with the flag --enable-openmp. -USE_OPENMP=false +USE_OPENMP=no AC_ARG_ENABLE([openmp], [AS_HELP_STRING([--enable-openmp], [(EXPERIMENTAL) use OpenMP SMP multi-threading])], - [if test "$enableval" = yes; then USE_OPENMP=true; fi], []) -if $USE_OPENMP; then + [if test "$enableval" = yes; then USE_OPENMP=yes; fi], []) +if test $USE_OPENMP = yes; then case $host_os in mingw* | cygwin* | *-gnu*) OCTAVE_CHECK_OPENMP(-fopenmp) @@ -538,18 +539,18 @@ AC_F77_DUMMY_MAIN AC_F77_WRAPPERS -F77_TOLOWER=true -F77_APPEND_UNDERSCORE=true -F77_APPEND_EXTRA_UNDERSCORE=true +F77_TOLOWER=yes +F77_APPEND_UNDERSCORE=yes +F77_APPEND_EXTRA_UNDERSCORE=yes case $ac_cv_f77_mangling in - "upper case") F77_TOLOWER=false ;; + "upper case") F77_TOLOWER=no ;; esac case $ac_cv_f77_mangling in - "no underscore") F77_APPEND_UNDERSCORE=false ;; + "no underscore") F77_APPEND_UNDERSCORE=no ;; esac case $ac_cv_f77_mangling in - "no extra underscore") F77_APPEND_EXTRA_UNDERSCORE=false ;; + "no extra underscore") F77_APPEND_EXTRA_UNDERSCORE=no ;; esac case $canonical_host_type in @@ -593,7 +594,7 @@ OCTAVE_CHECK_SIZEOF_FORTRAN_INTEGER if test $octave_cv_sizeof_fortran_integer = no; then - if $USE_64_BIT_IDX_T; then + if test $USE_64_BIT_IDX_T = yes; then case $F77 in *gfortran*) case $F77_INTEGER_8_FLAG in @@ -703,12 +704,12 @@ ### Check for the LLVM library -build_jit=false +build_jit=no AC_ARG_ENABLE([jit], [AS_HELP_STRING([--enable-jit], [(EXPERIMENTAL) enable JIT compiler])], [if test "$enableval" = yes; then - build_jit=true + build_jit=yes fi], []) @@ -717,7 +718,7 @@ LLVM_LDFLAGS= LLVM_LIBS= -if test $build_jit = true; then +if test $build_jit = yes; then ## Find llvm-config program from environment variable or by searching AC_ARG_VAR([LLVM_CONFIG], [path to llvm-config utility]) @@ -763,7 +764,7 @@ if test -z "$warn_llvm"; then AC_DEFINE(HAVE_LLVM, 1, [Define to 1 if LLVM is available.]) else - build_jit=false + build_jit=no LLVM_CPPFLAGS= LLVM_CXXFLAGS= LLVM_LDFLAGS= @@ -816,16 +817,16 @@ ## Check for the multithreaded FFTW library. ## Fallback to singlethreaded if not found or disabled -build_fftw_threads=true +build_fftw_threads=yes AC_ARG_ENABLE([fftw-threads], [AS_HELP_STRING([--disable-fftw-threads], [disable Multi-threaded FFTW])], [if test "$enableval" = no; then - build_fftw_threads=false + build_fftw_threads=no fi], []) -if test $build_fftw_threads = true; then +if test $build_fftw_threads = yes; then OCTAVE_CHECK_FFTW_THREADS(fftw3, fftw_plan_with_nthreads) OCTAVE_CHECK_FFTW_THREADS(fftw3f, fftwf_plan_with_nthreads) fi @@ -861,18 +862,18 @@ if test -z "$warn_curl"; then ## Additional check on cURL library that was found AC_CACHE_CHECK([for CURLOPT_DIRLISTONLY in curl/curl.h], - [octave_cv_header_define_curlopt_dirlistonly], + [octave_cv_curl_has_curlopt_dirlistonly], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <curl/curl.h> ]], [[ curl_easy_setopt ((CURL*)NULL, CURLOPT_DIRLISTONLY, 0); ]])], - [octave_cv_header_define_curlopt_dirlistonly=no], - [octave_cv_header_define_curlopt_dirlistonly=yes]) + [octave_cv_curl_has_curlopt_dirlistonly=yes], + [octave_cv_curl_has_curlopt_dirlistonly=no]) ]) - if test $octave_cv_header_define_curlopt_dirlistonly = yes; then + if test $octave_cv_curl_has_curlopt_dirlistonly = no; then AC_DEFINE(CURLOPT_DIRLISTONLY, CURLOPT_FTPLISTONLY, - [Define to the legacy option name if using an older version of cURL.])] + [Define to the legacy option name if using an older version of cURL.]) fi fi LIBS="$save_LIBS" @@ -977,24 +978,24 @@ ### Check for list of libraries needed for native graphics renderer. -native_graphics=true +native_graphics=yes warn_freetype="" -check_opengl=false +check_opengl=no AC_ARG_WITH([opengl], [AS_HELP_STRING([--without-opengl], [don't use OpenGL libraries, disable native graphics])], [if test x"$withval" = x"no"; then - native_graphics=false + native_graphics=no warn_opengl="--without-opengl specified. Native graphics will be disabled." OCTAVE_CONFIGURE_WARNING([warn_opengl]) else - check_opengl=true + check_opengl=yes fi], - [check_opengl=true]) + [check_opengl=yes]) ## Check for OpenGL library -if $check_opengl; then +if test $check_opengl = yes; then OCTAVE_CHECK_LIB_OPENGL fi @@ -1002,8 +1003,8 @@ GRAPHICS_CFLAGS= if test -z "$OPENGL_LIBS"; then - if $check_opengl; then - native_graphics=false + if test $check_opengl = yes; then + native_graphics=no warn_fltk_opengl="OpenGL libs (GL and GLU) not found. Native graphics will be disabled." OCTAVE_CONFIGURE_WARNING([warn_fltk_opengl]) fi @@ -1030,7 +1031,7 @@ if test -n "$warn_freetype"; then OCTAVE_CONFIGURE_WARNING([warn_freetype]) - native_graphics=false + native_graphics=no fi ## Check for fontconfig library @@ -1047,7 +1048,7 @@ fi if test -n "$warn_fontconfig"; then - native_graphics=false + native_graphics=no OCTAVE_CONFIGURE_WARNING([warn_fontconfig]) fi @@ -1085,7 +1086,7 @@ warn_fltk_opengl="" if test "$FLTK_CONFIG" = no; then - native_graphics=false + native_graphics=no warn_fltk_config="FLTK config script not found. Native graphics will be disabled." OCTAVE_CONFIGURE_WARNING([warn_fltk_config]) else @@ -1121,7 +1122,7 @@ GRAPHICS_CFLAGS="$FLTK_CFLAGS" GRAPHICS_LIBS="$FLTK_LDFLAGS" else - native_graphics=false + native_graphics=no OCTAVE_CONFIGURE_WARNING([warn_fltk_opengl]) fi fi @@ -1154,15 +1155,15 @@ LT_INIT([disable-static dlopen win32-dll]) if test x"$enable_shared" = x"yes"; then - SHARED_LIBS=true + SHARED_LIBS=yes else - SHARED_LIBS=false + SHARED_LIBS=no fi if test x"$enable_static" = x"yes"; then - STATIC_LIBS=true + STATIC_LIBS=yes else - STATIC_LIBS=false + STATIC_LIBS=no fi XTRA_CRUFT_SH_LDFLAGS= @@ -1244,7 +1245,7 @@ fi if test $ax_blas_f77_func_ok = no; then - if $USE_64_BIT_IDX_T && test $ax_blas_integer_size_ok = no; then + if test $USE_64_BIT_IDX_T = yes && test $ax_blas_integer_size_ok = no; then ## Attempt to be more informative. AC_MSG_ERROR([BLAS doesn't seem to support 64-bit integers. This is incompatible with --enable-64.]) else @@ -1432,13 +1433,13 @@ [AS_HELP_STRING([--disable-dl], [disable loading of dynamically linked modules])], [case $enableval in - yes) ENABLE_DYNAMIC_LINKING=true ;; - no) ENABLE_DYNAMIC_LINKING=false ;; + yes) ENABLE_DYNAMIC_LINKING=yes ;; + no) ENABLE_DYNAMIC_LINKING=no ;; *) AC_MSG_ERROR([bad value $enableval for --enable-dl]) ;; esac], - [ENABLE_DYNAMIC_LINKING=true]) - -if ! $STATIC_LIBS && ! $SHARED_LIBS; then + [ENABLE_DYNAMIC_LINKING=no]) + +if test $STATIC_LIBS = no && test $SHARED_LIBS = no; then AC_MSG_ERROR([You can't disable building both static AND shared libraries!]) fi @@ -1472,7 +1473,7 @@ OCTGRAPHICS_DLL_DEFS= library_path_var=LD_LIBRARY_PATH ldpreloadsep=" " -BUILD_COMPILED_AUX_PROGRAMS=false +BUILD_COMPILED_AUX_PROGRAMS=no case $canonical_host_type in *-*-386bsd* | *-*-netbsd*) SH_LD=ld @@ -1525,7 +1526,7 @@ ldpreloadsep=":" ;; *-*-mingw*) - BUILD_COMPILED_AUX_PROGRAMS=true + BUILD_COMPILED_AUX_PROGRAMS=yes if test $have_msvc = yes; then DL_LDFLAGS="-shared" CPICFLAG= @@ -1545,7 +1546,6 @@ fi NO_OCT_FILE_STRIP=true library_path_var=PATH - NO_OCT_FILE_STRIP=true ## Extra compilation flags. CRUFT_DLL_DEFS="-DCRUFT_DLL" OCTAVE_DLL_DEFS="-DOCTAVE_DLL" @@ -1567,7 +1567,7 @@ ;; *-*-msdosmsvc) - BUILD_COMPILED_AUX_PROGRAMS=true + BUILD_COMPILED_AUX_PROGRAMS=yes DL_LDFLAGS="-shared" CPICFLAG= CXXPICFLAG= @@ -1586,7 +1586,6 @@ fi NO_OCT_FILE_STRIP=true library_path_var=PATH - NO_OCT_FILE_STRIP=true ## Extra compilation flags. CRUFT_DLL_DEFS="-DCRUFT_DLL" OCTAVE_DLL_DEFS="-DOCTAVE_DLL" @@ -1666,7 +1665,7 @@ esac AM_CONDITIONAL([AMCOND_BUILD_COMPILED_AUX_PROGRAMS], - [test x$BUILD_COMPILED_AUX_PROGRAMS = xtrue]) + [test $BUILD_COMPILED_AUX_PROGRAMS = yes]) AC_MSG_NOTICE([defining FPICFLAG to be $FPICFLAG]) AC_MSG_NOTICE([defining CPICFLAG to be $CPICFLAG]) @@ -1745,13 +1744,13 @@ [AS_HELP_STRING([--enable-link-all-dependencies], [link Octave and its shared libraries with all dependencies, not just those immediately referenced (should not be needed on most systems)])], [case $enableval in - yes) link_all_deps=true ;; - no) link_all_deps=false ;; + yes) link_all_deps=yes ;; + no) link_all_deps=no ;; *) AC_MSG_ERROR([bad value $enableval for --enable-link-all-depenencies]) ;; esac], - [link_all_deps=false]) -AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS], [test $link_all_deps = true]) + [link_all_deps=no]) +AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS], [test $link_all_deps = yes]) ## Dynamic linking is now enabled only if we are building shared ## libs and some API for dynamic linking has been detected. @@ -1762,35 +1761,35 @@ LD_CXX='$(CXX)' RDYNAMIC_FLAG= DL_API_MSG="" -dlopen_api=false -shl_load_api=false -loadlibrary_api=false -dyld_api=false - -if $SHARED_LIBS || $ENABLE_DYNAMIC_LINKING; then +dlopen_api=no +shl_load_api=no +loadlibrary_api=no +dyld_api=no + +if test $SHARED_LIBS = yes || test $ENABLE_DYNAMIC_LINKING = yes; then case $lt_cv_dlopen in dlopen) - dlopen_api=true + dlopen_api=yes DL_API_MSG="(dlopen)" AC_DEFINE(HAVE_DLOPEN_API, 1, [Define to 1 if your system has dlopen, dlsym, dlerror, and dlclose for dynamic linking.]) OCTAVE_CXX_FLAG([-rdynamic], [RDYNAMIC_FLAG=-rdynamic]) ;; shl_load) - shl_load_api=true + shl_load_api=yes DL_API_MSG="(shl_load)" AC_DEFINE(HAVE_SHL_LOAD_API, 1, [Define to 1 if your system has shl_load and shl_findsym for dynamic linking.]) ;; LoadLibrary) - loadlibrary_api=true + loadlibrary_api=yes DL_API_MSG="(LoadLibrary)" AC_DEFINE(HAVE_LOADLIBRARY_API, 1, [Define to 1 if your system has LoadLibrary for dynamic linking.]) ;; dyld) - dyld_api=true + dyld_api=yes DL_API_MSG="(dyld)" AC_DEFINE(HAVE_DYLD_API, 1, [Define to 1 if your system has dyld for dynamic linking.]) @@ -1801,21 +1800,25 @@ AC_SUBST(DL_LIBS) ## Disable dynamic linking if capability is not present. - if $dlopen_api || $shl_load_api || $loadlibrary_api || $dyld_api; then - : # some form of dynamic linking present + if test $dlopen_api = yes \ + || test $shl_load_api = yes \ + || test $loadlibrary_api = yes \ + || test $dyld_api = yes; then + # some form of dynamic linking present + ENABLE_DYNAMIC_LINKING=yes else - ENABLE_DYNAMIC_LINKING=false + ENABLE_DYNAMIC_LINKING=no fi fi -if $ENABLE_DYNAMIC_LINKING; then +if test $ENABLE_DYNAMIC_LINKING = yes; then AC_DEFINE(ENABLE_DYNAMIC_LINKING, 1, [Define to 1 if using dynamic linking.]) fi AM_CONDITIONAL([AMCOND_ENABLE_DYNAMIC_LINKING], - [test x"$ENABLE_DYNAMIC_LINKING" = x"true"]) - -if $SHARED_LIBS; then + [test $ENABLE_DYNAMIC_LINKING = yes]) + +if test $SHARED_LIBS = yes; then LIBOCTINTERP="-loctinterp$SHLLINKEXT" LIBOCTAVE="-loctave$SHLLINKEXT" else @@ -1895,8 +1898,8 @@ ## C headers dnl Use multiple AC_CHECKs to avoid line continuations '\' in list -AC_CHECK_HEADERS([curses.h direct.h dlfcn.h floatingpoint.h grp.h]) -AC_CHECK_HEADERS([ieeefp.h inttypes.h locale.h memory.h ncurses.h]) +AC_CHECK_HEADERS([curses.h direct.h dlfcn.h floatingpoint.h fpu_control.h]) +AC_CHECK_HEADERS([grp.h ieeefp.h inttypes.h locale.h memory.h ncurses.h]) AC_CHECK_HEADERS([poll.h pthread.h pwd.h sunmath.h sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/resource.h ]) AC_CHECK_HEADERS([sys/select.h sys/utsname.h termcap.h]) @@ -2211,17 +2214,17 @@ GXX_EXTRA_FLAGS="-Wall -W -Wshadow -Wold-style-cast -Wformat -Wpointer-arith -Wwrite-strings -Wcast-align -Wcast-qual" -try_extra_warning_flags=true +try_extra_warning_flags=yes AC_ARG_ENABLE([extra-warning-flags], [AS_HELP_STRING([--disable-extra-warning-flags], [don't add -Wall, -W, -Wshadow, and -Wold-style-cast options to CFLAGS and CXXFLAGS])], [if test "$enableval" = no; then - try_extra_warning_flags=false + try_extra_warning_flags=no fi], []) -if $try_extra_warning_flags; then +if test $try_extra_warning_flags = yes; then for flag in $GCC_EXTRA_FLAGS; do OCTAVE_CC_FLAG([$flag], [ WARN_CFLAGS="$WARN_CFLAGS $flag"; @@ -2238,17 +2241,17 @@ GXX_STRICT_FLAGS="-Wconversion -Weffc++" -try_strict_warning_flags=false +try_strict_warning_flags=no AC_ARG_ENABLE([strict-warning-flags], [AS_HELP_STRING([--enable-strict-warning-flags], [add extra strict warning options to CFLAGS and CXXFLAGS])], [if test "$enableval" = yes; then - try_strict_warning_flags=true + try_strict_warning_flags=yes fi], []) -if $try_strict_warning_flags; then +if test $try_strict_warning_flags = yes; then for flag in $GCC_STRICT_FLAGS; do OCTAVE_CC_FLAG([$flag], [ WARN_CFLAGS="$WARN_CFLAGS $flag"; @@ -2266,12 +2269,12 @@ ### Check for Java. -build_java=true +build_java=yes AC_ARG_ENABLE([java], [AS_HELP_STRING([--disable-java], [disable Java interface])], [if test "$enableval" = no; then - build_java=false + build_java=no fi], []) @@ -2302,10 +2305,10 @@ JAVA_LIBS= ## Fake loop so that "break" can be used to skip code blocks. -while test $build_java = true +while test $build_java = yes do ## Unset build_java. Variable is set only if all configuration tests pass. - build_java=false + build_java=no ## Warn if JAVA_HOME is unset. It is *strongly* advised to specify JAVA_HOME. if test -z "$JAVA_HOME"; then @@ -2384,7 +2387,7 @@ ## the required paths to compile and link against JDK. case $host_os in msdosmsvc) - build_java=true + build_java=yes JAVA_LIBS=-ladvapi32 AC_DEFINE(HAVE_JAVA, 1, [Define to 1 if Java is available and is at least version 1.5]) @@ -2392,7 +2395,7 @@ ;; mingw*) if test $have_msvc = yes; then - build_java=true + build_java=yes JAVA_LIBS=-ladvapi32 AC_DEFINE(HAVE_JAVA, 1, [Define to 1 if Java is available and is at least version 1.5]) @@ -2509,11 +2512,11 @@ ## Verify jni.h include file exists. JNI_PATH=`echo $JAVA_CPPFLAGS | sed -e 's/-I//g'` - have_jni=false + have_jni=no for dir in $JNI_PATH; do - if test -f "${dir}/jni.h"; then have_jni=true; break; fi + if test -f "${dir}/jni.h"; then have_jni=yes; break; fi done - if test $have_jni = true; then + if test $have_jni = yes; then AC_MSG_RESULT([$dir]) else AC_MSG_RESULT([not found]) @@ -2522,13 +2525,13 @@ fi ## Passed all configuration tests. A workable Java installation was found. - build_java=true + build_java=yes AC_DEFINE(HAVE_JAVA, 1, [Define to 1 if Java is available and is at least version 1.5]) break done -AM_CONDITIONAL([AMCOND_HAVE_JAVA], [test $build_java = true]) +AM_CONDITIONAL([AMCOND_HAVE_JAVA], [test $build_java = yes]) AC_SUBST(JAVA) AC_SUBST(JAVAC) AC_SUBST(JAR) @@ -2982,15 +2985,15 @@ OCTAVE_CONFIGURE_WARNING_SUMMARY -if $ENABLE_DYNAMIC_LINKING; then - if test $SHARED_LIBS = false; then +if test $ENABLE_DYNAMIC_LINKING = yes; then + if test $SHARED_LIBS = no; then AC_MSG_WARN([You used --enable-dl but not --enable-shared.]) AC_MSG_WARN([Are you sure that is what you want to do?]) warn_msg_printed=true fi fi -if $USE_64_BIT_IDX_T; then +if test $USE_64_BIT_IDX_T = yes; then AC_MSG_WARN([]) AC_MSG_WARN([You used the EXPERIMENTAL --enable-64 option.]) AC_MSG_WARN([Are you sure that is what you want to do?]) @@ -3007,7 +3010,7 @@ warn_msg_printed=true fi -if $USE_OPENMP; then +if test $USE_OPENMP = yes; then AC_MSG_WARN([]) AC_MSG_WARN([You used the EXPERIMENTAL --enable-openmp option.]) AC_MSG_WARN([Are you sure that is what you want to do?]) @@ -3020,7 +3023,7 @@ warn_msg_printed=true fi -if test $native_graphics = false; then +if test $native_graphics != yes; then AC_MSG_WARN([]) AC_MSG_WARN([I didn't find the necessary libraries to compile native]) AC_MSG_WARN([graphics. It isn't necessary to have native graphics,]) @@ -3031,7 +3034,7 @@ fi if test -n "$warn_gnuplot"; then - if $native_graphics; then + if test $native_graphics = yes; then AC_MSG_WARN([]) AC_MSG_WARN([I didn't find gnuplot. Plotting commands will use the]) AC_MSG_WARN([native graphics toolkit.]) @@ -3055,7 +3058,7 @@ warn_msg_printed=true fi -if $USE_ATOMIC_REFCOUNT; then +if test $USE_ATOMIC_REFCOUNT = yes; then AC_MSG_WARN([]) AC_MSG_WARN([Using atomic reference counting.]) AC_MSG_WARN([This feature allows access to Octave data safely from]) @@ -3063,7 +3066,7 @@ AC_MSG_WARN([results in a small performance penalty in the Octave]) AC_MSG_WARN([interpreter.]) AC_MSG_WARN([]) - if $USE_OCTAVE_ALLOCATOR; then + if test $USE_OCTAVE_ALLOCATOR = yes; then AC_MSG_WARN([Thread-safe behavior is not guaranteed unless you also]) AC_MSG_WARN([disable the use of the octave_allocator class.]) AC_MSG_WARN([])
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -10,6 +10,7 @@ Alexander Barth David Bateman Heinz Bauschke +Julien Bect Roman Belov Karl Berry David Billinghurst
--- a/doc/interpreter/octave.texi +++ b/doc/interpreter/octave.texi @@ -90,7 +90,8 @@ @sp 2 @multitable @columnfractions 0.4 0.025 0.65 @item -@flushright @image{octave_logo,2.1in} @end flushright +@flushright @image{octave_logo,2.1in} +@end flushright @tab @c this is a spacer column @tab @@ -497,6 +498,9 @@ * Plot Annotations:: * Multiple Plots on One Page:: * Multiple Plot Windows:: +* Use of axis@comma{} line@comma{} and patch Functions:: +* Manipulation of Plot Windows:: +* Use of the @code{interpreter} Property:: * Printing and Saving Plots:: * Interacting with Plots:: * Test Plotting Functions::
--- a/doc/interpreter/plot.txi +++ b/doc/interpreter/plot.txi @@ -62,6 +62,9 @@ * Plot Annotations:: * Multiple Plots on One Page:: * Multiple Plot Windows:: +* Use of axis@comma{} line@comma{} and patch Functions:: +* Manipulation of Plot Windows:: +* Use of the @code{interpreter} Property:: * Printing and Saving Plots:: * Interacting with Plots:: * Test Plotting Functions:: @@ -517,8 +520,9 @@ the second a cosine wave. Figure numbers must be positive integers. @DOCSTRING(figure) -@subsection Use of @code{axis}, @code{line}, and @code{patch} functions -@cindex use of @code{axis}, @code{line}, and @code{patch} functions + +@node Use of axis@comma{} line@comma{} and patch Functions +@subsection Use of axis@comma{} line@comma{} and patch Functions You can create axes, line, and patch objects directly using the @code{axes}, @code{line}, and @code{patch} functions. These objects @@ -532,8 +536,8 @@ @DOCSTRING(surface) -@subsection Manipulation of plot windows -@cindex manipulation of plot windows +@node Manipulation of Plot Windows +@subsection Manipulation of Plot Windows By default, Octave refreshes the plot window when a prompt is printed, or when waiting for input. The @@ -591,8 +595,8 @@ @DOCSTRING(closereq) +@node Use of the @code{interpreter} Property @subsection Use of the @code{interpreter} Property -@cindex use of the @code{interpreter} property All text objects, including titles, labels, legends, and text, include the property 'interpreter', this property determines the manner in which @@ -2573,15 +2577,15 @@ A character indicating a plot marker to be place at each data point, or @code{"none"}, meaning no markers should be displayed. -@itemx markeredgecolor +@item markeredgecolor The color of the edge around the marker, or @code{"auto"}, meaning that the edge color is the same as the face color. @xref{Colors}. -@itemx markerfacecolor +@item markerfacecolor The color of the marker, or @code{"none"} to indicate that the marker should not be filled. @xref{Colors}. -@itemx markersize +@item markersize A number specifying the size of the marker. The default is 1. A value of 2 is twice as large as the default, etc. @end table
--- a/doc/interpreter/tips.txi +++ b/doc/interpreter/tips.txi @@ -296,20 +296,20 @@ When choosing variable names try to adhere to the following guidelines. @table @asis -@item -vectors : x,y,z,t,w +@item vectors : +x,y,z,t,w -@item -matrices : A,B,M +@item matrices : +A,B,M -@item -strings : @nospell{str},s +@item strings : +@nospell{str},s -@item -filenames : @nospell{fname} +@item filenames : +@nospell{fname} -@item -cells,@nospell{cellstrs} : c,@nospell{cstr} +@item cells,@nospell{cellstrs} : +c,@nospell{cstr} @end table @item
--- a/libgui/src/files-dockwidget.cc +++ b/libgui/src/files-dockwidget.cc @@ -36,7 +36,7 @@ #include <QHeaderView> files_dock_widget::files_dock_widget (QWidget *p) - : QDockWidget (p) + : octave_dock_widget (p) { setObjectName ("FilesDockWidget"); setWindowIcon (QIcon(":/actions/icons/logo.png")); @@ -114,11 +114,6 @@ completer = new QCompleter (_file_system_model, this); _current_directory->setCompleter (completer); - connect (this, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_visibility_changed (bool))); - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); - setFocusProxy (_current_directory); } @@ -203,28 +198,3 @@ //if (settings.value ("showHiddenFiles").toBool ()) // TODO: React on option for hidden files. } - -void -files_dock_widget::handle_visibility_changed (bool visible) -{ - if (visible) - emit active_changed (true); -} - -void -files_dock_widget::closeEvent (QCloseEvent *e) -{ - emit active_changed (false); - QDockWidget::closeEvent (e); -} - -// slot for signal that is emitted when floating property changes -void -files_dock_widget::top_level_changed (bool floating) -{ - if(floating) - { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it - } -}
--- a/libgui/src/files-dockwidget.h +++ b/libgui/src/files-dockwidget.h @@ -35,14 +35,14 @@ #include <QAction> #include <QTreeView> -#include <QDockWidget> #include <QLineEdit> +#include "octave-dock-widget.h" /** \class files_dock_widget \brief Dock widget to display files in the current directory. */ -class files_dock_widget : public QDockWidget +class files_dock_widget : public octave_dock_widget { Q_OBJECT public: @@ -51,6 +51,7 @@ ~files_dock_widget (); public slots: + /** Slot for handling a change in directory via double click. */ void item_double_clicked (const QModelIndex & index); @@ -68,12 +69,6 @@ /** Tells the widget to react on changed settings. */ void notice_settings (); - /** Slot to steer changing visibility from outside. */ - void handle_visibility_changed (bool visible); - - /** Slot when floating property changes */ - void top_level_changed (bool floating); - signals: /** Emitted, whenever the user requested to open a file. */ void open_file (const QString& fileName); @@ -81,11 +76,7 @@ /** Emitted, whenever the currently displayed directory changed. */ void displayed_directory_changed (const QString& directory); - /** Custom signal that tells if a user has clicke away that dock widget. */ - void active_changed (bool active); - protected: - void closeEvent (QCloseEvent *event); private: // TODO: Add toolbar with buttons for navigating the path, creating dirs, etc
--- a/libgui/src/history-dockwidget.cc +++ b/libgui/src/history-dockwidget.cc @@ -37,7 +37,7 @@ #include "octave-link.h" history_dock_widget::history_dock_widget (QWidget * p) - : QDockWidget (p) + : octave_dock_widget (p) { setObjectName ("HistoryDockWidget"); construct (); @@ -71,26 +71,15 @@ widget ()->setLayout (vbox_layout); - connect (_filter_line_edit, - SIGNAL (textEdited (QString)), - &_sort_filter_proxy_model, - SLOT (setFilterWildcard (QString))); - - connect (_history_list_view, - SIGNAL (doubleClicked (QModelIndex)), - this, - SLOT (handle_double_click (QModelIndex))); + connect (_filter_line_edit, SIGNAL (textEdited (QString)), + &_sort_filter_proxy_model, SLOT (setFilterWildcard (QString))); - connect (this, - SIGNAL (visibilityChanged (bool)), - this, - SLOT (handle_visibility_changed (bool))); + connect (_history_list_view, SIGNAL (doubleClicked (QModelIndex)), + this, SLOT (handle_double_click (QModelIndex))); - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); - - _update_history_model_timer.setInterval (200); - _update_history_model_timer.setSingleShot (true); + _update_event_enabled = true; + _update_history_model_timer.setInterval (500); + _update_history_model_timer.setSingleShot (false); connect (&_update_history_model_timer, SIGNAL (timeout ()), @@ -142,16 +131,13 @@ } void -history_dock_widget::handle_visibility_changed (bool visible) -{ - if (visible) - emit active_changed (true); -} - -void history_dock_widget::request_history_model_update () { - octave_link::post_event (this, &history_dock_widget::update_history_callback); + if (_update_event_enabled) + { + _update_event_enabled = false; // no more update until this one is processed + octave_link::post_event (this, &history_dock_widget::update_history_callback); + } } void @@ -161,24 +147,6 @@ } void -history_dock_widget::closeEvent (QCloseEvent *e) -{ - emit active_changed (false); - QDockWidget::closeEvent (e); -} - -// slot for signal that is emitted when floating property changes -void -history_dock_widget::top_level_changed (bool floating) -{ - if(floating) - { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it - } -} - -void history_dock_widget::update_history_callback (void) { static bool scroll_window = false; @@ -218,7 +186,7 @@ _history_list_view->scrollToBottom (); } - // Post a new update event in a given time. This prevents flooding the - // event queue. - _update_history_model_timer.start (); + // update is processed, re-enable further updates events triggered by timer + _update_event_enabled = true; + }
--- a/libgui/src/history-dockwidget.h +++ b/libgui/src/history-dockwidget.h @@ -23,25 +23,22 @@ #ifndef HISTORYDOCKWIDGET_H #define HISTORYDOCKWIDGET_H -#include <QDockWidget> #include <QLineEdit> #include <QListView> #include <QSortFilterProxyModel> #include <QStringListModel> #include <QTimer> +#include "octave-dock-widget.h" -class history_dock_widget : public QDockWidget +class history_dock_widget : public octave_dock_widget { Q_OBJECT public: history_dock_widget (QWidget *parent = 0); public slots: - void handle_visibility_changed (bool visible); void request_history_model_update (); void reset_model (); - /** Slot when floating property changes */ - void top_level_changed (bool floating); signals: void information (const QString& message); @@ -49,10 +46,8 @@ /** Emitted, whenever the user double-clicked a command in the history. */ void command_double_clicked (const QString& command); - /** Custom signal that tells if a user has clicked away that dock widget. */ - void active_changed (bool active); protected: - void closeEvent (QCloseEvent *event); + private slots: void handle_double_click (QModelIndex modelIndex); void handle_contextmenu_copy(bool flag); @@ -71,6 +66,7 @@ QTimer _update_history_model_timer; void update_history_callback (void); + bool _update_event_enabled; }; #endif // HISTORYDOCKWIDGET_H
--- a/libgui/src/m-editor/file-editor-interface.h +++ b/libgui/src/m-editor/file-editor-interface.h @@ -23,22 +23,19 @@ #ifndef FILEEDITORINTERFACE_H #define FILEEDITORINTERFACE_H -#include <QDockWidget> #include <QMenu> #include <QToolBar> +#include "octave-dock-widget.h" -class file_editor_interface : public QDockWidget +class file_editor_interface : public octave_dock_widget { Q_OBJECT public: file_editor_interface (QWidget *p) - : QDockWidget (p) + : octave_dock_widget (p) { setObjectName ("FileEditor"); - - connect (this, SIGNAL (visibilityChanged (bool)), this, - SLOT (handle_visibility_changed (bool))); } virtual ~file_editor_interface () { } @@ -56,22 +53,12 @@ virtual void request_open_file () = 0; virtual void request_open_file (const QString& fileName) = 0; -signals: - void active_changed (bool active); +//signals: -protected: - void closeEvent (QCloseEvent *e) - { - emit active_changed (false); - QDockWidget::closeEvent (e); - } +//protected: -protected slots: - void handle_visibility_changed (bool visible) - { - if (visible) - emit active_changed (true); - } +//protected slots: + }; #endif // FILEEDITORINTERFACE_H
--- a/libgui/src/m-editor/file-editor.cc +++ b/libgui/src/m-editor/file-editor.cc @@ -517,17 +517,6 @@ emit fetab_settings_changed (); } -// slot for signal that is emitted when floating property changes -void -file_editor::top_level_changed (bool floating) -{ - if(floating) - { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlag hides it - } -} - void file_editor::construct () { @@ -751,8 +740,6 @@ SIGNAL (tabCloseRequested (int)), this, SLOT (handle_tab_close_request (int))); connect (_tab_widget, SIGNAL (currentChanged(int)), this, SLOT (active_tab_changed (int))); - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); resize (500, 400); setWindowIcon (QIcon(":/actions/icons/logo.png"));
--- a/libgui/src/m-editor/file-editor.h +++ b/libgui/src/m-editor/file-editor.h @@ -123,9 +123,6 @@ void handle_mru_add_file (const QString& file_name); void check_conflict_save (const QString& fileName, bool remove_on_success); - /** Slot when floating property changes */ - void top_level_changed (bool floating); - /** Tells the editor to react on changed settings. */ void notice_settings ();
--- a/libgui/src/module.mk +++ b/libgui/src/module.mk @@ -73,7 +73,8 @@ src/moc-workspace-view.cc \ src/octave-adapter/moc-octave-main-thread.cc \ src/qtinfo/moc-parser.cc \ - src/qtinfo/moc-webinfo.cc + src/qtinfo/moc-webinfo.cc \ + src/moc-octave-dock-widget.cc octave_gui_RC = src/qrc-resource.cc @@ -86,6 +87,7 @@ BUILT_SOURCES += $(octave_gui_UI_H) noinst_HEADERS += \ + src/octave-dock-widget.h \ src/documentation-dockwidget.h \ src/files-dockwidget.h \ src/history-dockwidget.h \
new file mode 100644 --- /dev/null +++ b/libgui/src/octave-dock-widget.h @@ -0,0 +1,81 @@ +/* + +Copyright (C) 2012-2013 Richard Crozier + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifndef OCTAVEDOCKWIDGET_H +#define OCTAVEDOCKWIDGET_H + +#include <QDockWidget> +//#include <QMenu> +//#include <QToolBar> + +class octave_dock_widget : public QDockWidget +{ + Q_OBJECT + + public: + octave_dock_widget (QWidget *p) + : QDockWidget (p) + { + connect (this, SIGNAL (visibilityChanged (bool)), + this, SLOT (handle_visibility_changed (bool))); + + connect (this, SIGNAL (topLevelChanged(bool)), + this, SLOT(top_level_changed(bool))); + } + + virtual ~octave_dock_widget () { } + +signals: + /** Custom signal that tells if a user has clicked away + * that dock widget, i.e the active dock widget has + * changed. */ + virtual void active_changed (bool active); + +protected: + virtual void closeEvent (QCloseEvent *e) + { + emit active_changed (false); + QDockWidget::closeEvent (e); + } + +protected slots: + + /** Slot to steer changing visibility from outside. */ + virtual void handle_visibility_changed (bool visible) + { + if (visible) + emit active_changed (true); + } + + /** Slot when floating property changes */ + virtual void top_level_changed (bool floating) + { + if(floating) + { + setWindowFlags(Qt::Window); // make a window from the widget when floating + show(); // make it visible again since setWindowFlags hides it + } + } + +}; + +#endif // OCTAVEDOCKWIDGET_H
--- a/libgui/src/terminal-dockwidget.cc +++ b/libgui/src/terminal-dockwidget.cc @@ -27,7 +27,7 @@ #include "terminal-dockwidget.h" terminal_dock_widget::terminal_dock_widget (QTerminal *terminal, QWidget *p) - : QDockWidget (p) + : octave_dock_widget (p) { setObjectName ("TerminalDockWidget"); setWindowIcon (QIcon(":/actions/icons/logo.png")); @@ -39,27 +39,3 @@ connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); } -void -terminal_dock_widget::closeEvent (QCloseEvent *e) -{ - emit active_changed (false); - QDockWidget::closeEvent (e); -} - -void -terminal_dock_widget::handle_visibility_changed (bool visible) -{ - if (visible) - emit active_changed (true); -} - -// slot for signal that is emitted when floating property changes -void -terminal_dock_widget::top_level_changed (bool floating) -{ - if(floating) - { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it - } -}
--- a/libgui/src/terminal-dockwidget.h +++ b/libgui/src/terminal-dockwidget.h @@ -23,25 +23,21 @@ #ifndef TERMINALDOCKWIDGET_H #define TERMINALDOCKWIDGET_H -#include <QDockWidget> #include "QTerminal.h" +#include "octave-dock-widget.h" -class terminal_dock_widget : public QDockWidget +class terminal_dock_widget : public octave_dock_widget { Q_OBJECT public: terminal_dock_widget (QTerminal *terminal, QWidget *parent = 0); signals: - void active_changed (bool active); public slots: - void handle_visibility_changed (bool visible); - /** Slot when floating property changes */ - void top_level_changed (bool floating); protected: - void closeEvent (QCloseEvent *event); + };
--- a/libgui/src/workspace-model.cc +++ b/libgui/src/workspace-model.cc @@ -1,3 +1,4 @@ + /* Copyright (C) 2011-2012 Jacob Dawid @@ -51,8 +52,9 @@ this, SLOT (request_update_workspace())); + _update_event_enabled = true; _update_workspace_model_timer.setInterval (500); - _update_workspace_model_timer.setSingleShot (true); + _update_workspace_model_timer.setSingleShot (false); _update_workspace_model_timer.start (); } @@ -64,7 +66,11 @@ void workspace_model::request_update_workspace () { - octave_link::post_event (this, &workspace_model::update_workspace_callback); + if (_update_event_enabled) + { + _update_event_enabled = false; // no more update until this one is processed + octave_link::post_event (this, &workspace_model::update_workspace_callback); + } } QModelIndex @@ -222,8 +228,7 @@ endResetModel(); emit model_changed(); - // Post a new event in a given time. - // This prevents flooding the event queue when no events are being processed. - _update_workspace_model_timer.start (); + // update is processed, re-enable further updates events triggered by timer + _update_event_enabled = true; + } -
--- a/libgui/src/workspace-model.h +++ b/libgui/src/workspace-model.h @@ -140,6 +140,8 @@ private: + bool _update_event_enabled; + void update_workspace_callback (void); /** Timer for periodically updating the workspace model from the current
--- a/libinterp/Makefile.am +++ b/libinterp/Makefile.am @@ -356,7 +356,9 @@ DOCSTRINGS \ $(BUILT_NODISTFILES) \ $(OCT_FILES) \ - $(OCT_STAMP_FILES) + $(OCT_STAMP_FILES) \ + $(TST_FILES) MAINTAINERCLEANFILES = \ $(BUILT_DISTFILES) +
--- a/libinterp/corefcn/mappers.cc +++ b/libinterp/corefcn/mappers.cc @@ -1882,7 +1882,10 @@ DEFUNX ("signbit", Fsignbit, args, , "-*- texinfo -*-\n\ @deftypefn {Mapping Function} {} signbit (@var{x})\n\ -Return a nonzero value if the value of @var{x} has its sign bit set.\n\ +Return logical true if the value of @var{x} has its sign bit set.\n\ +Otherwise return logical false. This behavior is consistent with the other\n\ +logical functions. See@ref{Logical Values}. The behavior differs from the\n\ +C language function which returns non-zero if the sign bit is set.\n\ \n\ This is not the same as @code{x < 0.0}, because IEEE 754 floating point\n\ allows zero to be signed. The comparison @code{-0.0 < 0.0} is false,\n\ @@ -1891,8 +1894,9 @@ @end deftypefn") { octave_value retval; - if (args.length () == 1) + if (args.length () == 1) { retval = args(0).xsignbit (); + retval = (retval != 0); } else print_usage ();
--- a/libinterp/interp-core/dynamic-ld.cc +++ b/libinterp/interp-core/dynamic-ld.cc @@ -197,109 +197,6 @@ instance->do_display (); } -class -octave_mex_file_list -{ -public: - - typedef std::list<octave_shlib>::iterator iterator; - typedef std::list<octave_shlib>::const_iterator const_iterator; - - static void append (const octave_shlib& shl); - - static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - -private: - - octave_mex_file_list (void) : file_list () { } - - ~octave_mex_file_list (void) { } - - void do_append (const octave_shlib& shl); - - void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - - static octave_mex_file_list *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static bool instance_ok (void); - - // List of libraries we have loaded. - std::list<octave_shlib> file_list; - - // No copying! - - octave_mex_file_list (const octave_mex_file_list&); - - octave_mex_file_list& operator = (const octave_mex_file_list&); -}; - -octave_mex_file_list *octave_mex_file_list::instance = 0; - -void -octave_mex_file_list::do_append (const octave_shlib& shl) -{ - file_list.push_back (shl); -} - -void -octave_mex_file_list::do_remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - for (iterator p = file_list.begin (); p != file_list.end (); p++) - { - if (*p == shl) - { - // Erase first to avoid potentially invalidating the pointer by the - // following hooks. - file_list.erase (p); - - shl.close (cl_hook); - - break; - } - } -} - -bool -octave_mex_file_list::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_mex_file_list (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create shared library list object!"); - - retval = false; - } - - return retval; -} - -void -octave_mex_file_list::append (const octave_shlib& shl) -{ - if (instance_ok ()) - instance->do_append (shl); -} - -void -octave_mex_file_list::remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - if (instance_ok ()) - instance->do_remove (shl, cl_hook); -} - octave_dynamic_loader *octave_dynamic_loader::instance = 0; bool octave_dynamic_loader::doing_load = false; @@ -444,8 +341,6 @@ bool have_fmex = false; - octave_mex_file_list::append (mex_file); - function = mex_file.search (fcn_name, mex_mangler); if (! function) @@ -513,7 +408,7 @@ retval = shl.remove (fcn_name); if (shl.number_of_functions_loaded () == 0) - octave_mex_file_list::remove (shl); + octave_shlib_list::remove (shl); } return retval;
--- a/libinterp/interp-core/oct-stream.h +++ b/libinterp/interp-core/oct-stream.h @@ -371,12 +371,6 @@ virtual std::ostream *output_stream (void) { return 0; } - // If the derived class is locale-aware, it must implement this function - // in order to set a new locale. By default, this function avoids messing - // with locales and ignores its input argument. - virtual std::locale imbue ( const std::locale &) - { return std::locale::classic (); } - // Return TRUE if this stream is open. bool is_open (void) const { return open_state; } @@ -619,23 +613,7 @@ { return rep ? rep->output_stream () : 0; } - - std::locale imbue (const std::locale & loc ) - { - if (!rep) return std::locale::classic (); - - std::istream *is = rep->input_stream (); - std::ostream *os = rep->output_stream (); - - if (os) - { - if (is) - (void) is->imbue (loc); - return os->imbue (loc); - } - return is ? is->imbue (loc) : std::locale::classic (); - } - + void clearerr (void) { if (rep) rep->clearerr (); } private:
--- a/libinterp/interp-core/pt-jit.cc +++ b/libinterp/interp-core/pt-jit.cc @@ -36,12 +36,12 @@ #include "symtab.h" #include "variables.h" +#ifdef HAVE_LLVM + static bool Venable_jit_debugging = false; static bool Venable_jit_compiler = true; -#ifdef HAVE_LLVM - #include <llvm/Analysis/CallGraph.h> #include <llvm/Analysis/Passes.h> #include <llvm/Analysis/Verifier.h>
--- a/libinterp/interpfcn/data.cc +++ b/libinterp/interpfcn/data.cc @@ -4729,7 +4729,17 @@ } if (nargin == 3) - npoints = args(2).idx_type_value (); + { + // Apparently undocumented Matlab. If the third arg is an empty + // numeric value, the number of points defaults to 1. + + octave_value arg_3 = args(2); + + if (arg_3.is_numeric_type () && arg_3.is_empty ()) + npoints = 1; + else + npoints = arg_3.idx_type_value (); + } if (! error_state) { @@ -4770,6 +4780,8 @@ %assert (linspace ([1, 2; 3, 4], 5, 6), linspace (1, 5, 6)) +%assert (linspace (0, 1, []), 1) + %!error linspace () %!error linspace (1, 2, 3, 4) */
--- a/libinterp/interpfcn/dirfns.cc +++ b/libinterp/interpfcn/dirfns.cc @@ -556,9 +556,9 @@ Within a pattern\n\ \n\ @table @code\n\ -@itemx *\n\ +@item *\n\ matches any string, including the null string,\n\ -@itemx ?\n\ +@item ?\n\ matches any single character, and\n\ \n\ @item [@dots{}]\n\
--- a/libinterp/interpfcn/file-io.cc +++ b/libinterp/interpfcn/file-io.cc @@ -43,9 +43,7 @@ #include <iostream> #include <limits> -#include <locale> #include <stack> -#include <stdexcept> #include <vector> #include <fcntl.h> @@ -646,23 +644,23 @@ The parameter @var{arch} is a string specifying the default data format\n\ for the file. Valid values for @var{arch} are:\n\ \n\ -@table @asis\n\ -@samp{native}\n\ +@table @samp\n\ +@item native\n\ The format of the current machine (this is the default).\n\ \n\ -@samp{ieee-be}\n\ +@item ieee-be\n\ IEEE big endian format.\n\ \n\ -@samp{ieee-le}\n\ +@item ieee-le\n\ IEEE little endian format.\n\ \n\ -@samp{vaxd}\n\ +@item vaxd\n\ VAX D floating format.\n\ \n\ -@samp{vaxg}\n\ +@item vaxg\n\ VAX G floating format.\n\ \n\ -@samp{cray}\n\ +@item cray\n\ Cray floating format.\n\ @end table\n\ \n\ @@ -1087,7 +1085,7 @@ DEFUN (fscanf, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}] =} fscanf (@var{fid}, @var{template}, @var{size})\n\ -@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} fscanf (@var{fid}, @var{template}, @var{locale})\n\ +@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}] =} fscanf (@var{fid}, @var{template}, \"C\")\n\ In the first form, read from @var{fid} according to @var{template},\n\ returning the result in the matrix @var{val}.\n\ \n\ @@ -1126,10 +1124,7 @@ with each conversion specifier in @var{template} corresponding to a\n\ single scalar return value. This form is more `C-like', and also\n\ compatible with previous versions of Octave. The number of successful\n\ -conversions is returned in @var{count}. It permits to explicitly\n\ -specify a locale to take into account language specific features, \n\ -such as decimal separator. This operation restores the previous locales\n\ -setting at the end of the conversion.\n\ +conversions is returned in @var{count}\n\ @ifclear OCTAVE_MANUAL\n\ \n\ See the Formatted Input section of the GNU Octave manual for a\n\ @@ -1151,25 +1146,7 @@ if (! error_state) { if (args(1).is_string ()) - { - std::locale oldloc; - try - { - // Use args(2) val as the new locale setting. Keep - // old val for restoring afterwards. - oldloc = - os.imbue (std::locale (args(2).string_value ().c_str ())); - - } - catch (std::runtime_error) - { - // Display a warning if the specified locale is unknown - warning ("fscanf: invalid locale. Try 'locale -a' for a list of supported values."); - oldloc = std::locale::classic (); - } - retval = os.oscanf (args(1), who); - os.imbue (oldloc); - } + retval = os.oscanf (args(1), who); else ::error ("%s: format TEMPLATE must be a string", who.c_str ()); } @@ -1237,7 +1214,7 @@ DEFUN (sscanf, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}, @var{pos}] =} sscanf (@var{string}, @var{template}, @var{size})\n\ -@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} sscanf (@var{string}, @var{template}, @var{locale})\n\ +@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}] =} sscanf (@var{string}, @var{template}, \"C\")\n\ This is like @code{fscanf}, except that the characters are taken from the\n\ string @var{string} instead of from a stream. Reaching the end of the\n\ string is treated as an end-of-file condition. In addition to the values\n\ @@ -1262,22 +1239,8 @@ if (os.is_valid ()) { - if (args(1).is_string ()) - { - // Use args(2) val as the new locale setting. As the os - // object is short lived, we don't need to restore - // locale afterwards. - try - { - os.imbue (std::locale (args(2).string_value ().c_str ())); - } - catch (std::runtime_error) - { - // Display a warning if the specified locale is unknown - warning ("sscanf: invalid locale. Try 'locale -a' for a list of supported values."); - } - retval = os.oscanf (args(1), who); - } + if (args(1).is_string ()) + retval = os.oscanf (args(1), who); else ::error ("%s: format TEMPLATE must be a string", who.c_str ()); } @@ -1345,16 +1308,10 @@ return retval; } -/* -%!test -%! assert (sscanf ("1,2", "%f", "C"), 1) -%! assert (sscanf ("1,2", "%f", "fr_FR"), 1.2) -*/ - DEFUN (scanf, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}] =} scanf (@var{template}, @var{size})\n\ -@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} scanf (@var{template}, @var{locale})\n\ +@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}]] =} scanf (@var{template}, \"C\")\n\ This is equivalent to calling @code{fscanf} with @var{fid} = @code{stdin}.\n\ \n\ It is currently not useful to call @code{scanf} in interactive\n\
--- a/libinterp/interpfcn/input.cc +++ b/libinterp/interpfcn/input.cc @@ -100,10 +100,6 @@ // TRUE means get input from current_eval_string. bool get_input_from_eval_string = false; -// TRUE means we haven't been asked for the input from -// current_eval_string yet. -bool input_from_eval_string_pending = false; - // TRUE means that input is coming from a file that was named on // the command line. bool input_from_command_line_file = false; @@ -191,16 +187,16 @@ } std::string -gnu_readline (const std::string& s, bool force_readline) +gnu_readline (const std::string& s, bool& eof, bool force_readline) { octave_quit (); + eof = false; + std::string retval; if (line_editing || force_readline) { - bool eof; - retval = command_editor::readline (s, eof); if (! eof && retval.empty ()) @@ -221,14 +217,22 @@ if (reading_fcn_file || reading_script_file || reading_classdef_file) curr_stream = ff_instream; - retval = octave_fgets (curr_stream); + retval = octave_fgets (curr_stream, eof); } return retval; } +extern std::string +gnu_readline (const std::string& s, bool force_readline) +{ + bool eof = false; + + return gnu_readline (s, eof, force_readline); +} + static inline std::string -interactive_input (const std::string& s, bool force_readline = false) +interactive_input (const std::string& s, bool& eof, bool force_readline) { Vlast_prompt_time.stamp (); @@ -247,14 +251,24 @@ return "\n"; } - return gnu_readline (s, force_readline); + return gnu_readline (s, eof, force_readline); +} + +static inline std::string +interactive_input (const std::string& s, bool force_readline = false) +{ + bool eof = false; + + return interactive_input (s, eof, force_readline); } static std::string -octave_gets (void) +octave_gets (bool& eof) { octave_quit (); + eof = false; + std::string retval; bool history_skip_auto_repeated_debugging_command = false; @@ -280,7 +294,7 @@ octave_diary << prompt; - retval = interactive_input (prompt); + retval = interactive_input (prompt, eof, false); // There is no need to update the load_path cache if there is no // user input. @@ -301,7 +315,7 @@ } } else - retval = gnu_readline (""); + retval = gnu_readline ("", eof, false); current_input_line = retval; @@ -329,99 +343,35 @@ // Read a line from the input stream. -static std::string -get_user_input (void) +std::string +get_user_input (bool& eof) { octave_quit (); + eof = false; + std::string retval; if (get_input_from_eval_string) { - if (input_from_eval_string_pending) - { - input_from_eval_string_pending = false; + retval = current_eval_string; - retval = current_eval_string; + size_t len = retval.length (); - size_t len = retval.length (); + // Clear the global eval string so that the next call will return + // an empty character string with EOF = true. + current_eval_string = ""; - if (len > 0 && retval[len-1] != '\n') - retval.append ("\n"); - } + eof = true; } else - retval = octave_gets (); + retval = octave_gets (eof); current_input_line = retval; return retval; } -int -octave_read (char *buf, unsigned max_size) -{ - // FIXME -- is this a safe way to buffer the input? - - static const char * const eol = "\n"; - static std::string input_buf; - static const char *pos = 0; - static size_t chars_left = 0; - - int status = 0; - if (chars_left == 0) - { - pos = 0; - - input_buf = get_user_input (); - - chars_left = input_buf.length (); - - pos = input_buf.c_str (); - } - - if (chars_left > 0) - { - size_t len = max_size > chars_left ? chars_left : max_size; - assert (len > 0); - - memcpy (buf, pos, len); - - chars_left -= len; - pos += len; - - // Make sure input ends with a new line character. - if (chars_left == 0 && buf[len-1] != '\n') - { - if (len < max_size) - { - // There is enough room to plug the newline character in - // the buffer. - buf[len++] = '\n'; - } - else - { - // There isn't enough room to plug the newline character - // in the buffer so make sure it is returned on the next - // octave_read call. - pos = eol; - chars_left = 1; - } - } - - status = len; - - } - else if (chars_left == 0) - { - status = 0; - } - else - status = -1; - - return status; -} - // Fix things up so that input can come from file 'name', printing a // warning if the file doesn't exist. @@ -717,35 +667,33 @@ frame.protect_var (get_input_from_eval_string); get_input_from_eval_string = false; - - YY_BUFFER_STATE old_buf = current_buffer (); - YY_BUFFER_STATE new_buf = create_buffer (get_input_from_stdin ()); + } - // FIXME: are these safe? - frame.add_fcn (switch_to_buffer, old_buf); - frame.add_fcn (delete_buffer, new_buf); + // octave_parser constructor sets this for us. + frame.protect_var (CURR_LEXER); - switch_to_buffer (new_buf); - } + octave_parser *curr_parser = new octave_parser (); + frame.add_fcn (octave_parser::cleanup, curr_parser); while (Vdebugging) { + unwind_protect middle_frame; + reset_error_handler (); - reset_parser (); + curr_parser->reset (); // Save current value of global_command. - frame.protect_var (global_command); + middle_frame.protect_var (global_command); global_command = 0; // Do this with an unwind-protect cleanup function so that the // forced variables will be unmarked in the event of an interrupt. symbol_table::scope_id scope = symbol_table::top_scope (); - frame.add_fcn (symbol_table::unmark_forced_variables, scope); + middle_frame.add_fcn (symbol_table::unmark_forced_variables, scope); - // This is the same as yyparse in parse.y. - int retval = octave_parse (); + int retval = curr_parser->run (); if (retval == 0 && global_command) { @@ -763,10 +711,6 @@ octave_completion_matches_called = false; } - // Unmark forced variables. - // Restore previous value of global_command. - frame.run (2); - octave_quit (); } } @@ -843,8 +787,8 @@ DEFUN (input, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} input (@var{prompt})\n\ -@deftypefnx {Built-in Function} {} input (@var{prompt}, \"s\")\n\ +@deftypefn {Built-in Function} {@var{ans} =} input (@var{prompt})\n\ +@deftypefnx {Built-in Function} {@var{ans} =} input (@var{prompt}, \"s\")\n\ Print a prompt and wait for user input. For example,\n\ \n\ @example\n\ @@ -874,7 +818,8 @@ Because there may be output waiting to be displayed by the pager, it is\n\ a good idea to always call @code{fflush (stdout)} before calling\n\ @code{input}. This will ensure that all pending output is written to\n\ -the screen before your prompt. @xref{Input and Output}.\n\ +the screen before your prompt.\n\ +@seealso{yes_or_no, kbhit}\n\ @end deftypefn") { octave_value_list retval; @@ -909,12 +854,14 @@ DEFUN (yes_or_no, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} yes_or_no (@var{prompt})\n\ -Ask the user a yes-or-no question. Return 1 if the answer is yes.\n\ -Takes one argument, which is the string to display to ask the\n\ -question. It should end in a space; @samp{yes-or-no-p} adds\n\ -@samp{(yes or no) } to it. The user must confirm the answer with\n\ -RET and can edit it until it has been confirmed.\n\ +@deftypefn {Built-in Function} {@var{ans} =} yes_or_no (\"@var{prompt}\")\n\ +Ask the user a yes-or-no question. Return logical true if the answer is yes\n\ +or false if the answer is no. Takes one argument, @var{prompt}, which is\n\ +the string to display when asking the question. @var{prompt} should end in\n\ +a space; @code{yes-or-no} adds the string @samp{(yes or no) } to it. The\n\ +user must confirm the answer with @key{RET} and can edit it until it has\n\ +been confirmed.\n\ +@seealso{input}\n\ @end deftypefn") { octave_value retval; @@ -986,7 +933,7 @@ DEFUN (keyboard, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} keyboard ()\n\ -@deftypefnx {Built-in Function} {} keyboard (@var{prompt})\n\ +@deftypefnx {Built-in Function} {} keyboard (\"@var{prompt}\")\n\ This function is normally used for simple debugging. When the\n\ @code{keyboard} function is executed, Octave prints a prompt and waits\n\ for user input. The input strings are then evaluated and the results\n\ @@ -1241,31 +1188,28 @@ static int input_event_hook (void) { - if (! lexer_flags.defining_func) - { - hook_fcn_map_type::iterator p = hook_fcn_map.begin (); + hook_fcn_map_type::iterator p = hook_fcn_map.begin (); - while (p != hook_fcn_map.end ()) - { - std::string hook_fcn = p->first; - octave_value user_data = p->second; + while (p != hook_fcn_map.end ()) + { + std::string hook_fcn = p->first; + octave_value user_data = p->second; - hook_fcn_map_type::iterator q = p++; + hook_fcn_map_type::iterator q = p++; - if (is_valid_function (hook_fcn)) - { - if (user_data.is_defined ()) - feval (hook_fcn, user_data, 0); - else - feval (hook_fcn, octave_value_list (), 0); - } + if (is_valid_function (hook_fcn)) + { + if (user_data.is_defined ()) + feval (hook_fcn, user_data, 0); else - hook_fcn_map.erase (q); + feval (hook_fcn, octave_value_list (), 0); } + else + hook_fcn_map.erase (q); + } - if (hook_fcn_map.empty ()) - command_editor::remove_event_hook (input_event_hook); - } + if (hook_fcn_map.empty ()) + command_editor::remove_event_hook (input_event_hook); return 0; }
--- a/libinterp/interpfcn/input.h +++ b/libinterp/interpfcn/input.h @@ -35,8 +35,11 @@ class octave_value; -extern OCTINTERP_API int octave_read (char *buf, unsigned max_size); -extern OCTINTERP_API FILE *get_input_from_file (const std::string& name, int warn = 1); +extern OCTINTERP_API std::string get_user_input (bool& eof); + +extern OCTINTERP_API FILE *get_input_from_file (const std::string& name, + int warn = 1); + extern OCTINTERP_API FILE *get_input_from_stdin (void); // Global pointer for eval(). @@ -45,10 +48,6 @@ // TRUE means get input from current_eval_string. extern bool get_input_from_eval_string; -// TRUE means we haven't been asked for the input from -// current_eval_string yet. -extern bool input_from_eval_string_pending; - // TRUE means that input is coming from a file that was named on // the command line. extern bool input_from_command_line_file;
--- a/libinterp/interpfcn/oct-hist.cc +++ b/libinterp/interpfcn/oct-hist.cc @@ -377,7 +377,9 @@ int hist_count = hlist.length () - 1; // switch to zero-based indexing // The current command line is already part of the history list by - // the time we get to this point. Delete it from the list. + // the time we get to this point. Delete the cmd from the list when + // executing 'edit_history' so that it doesn't show up in the history + // but the actual commands performed will. if (! insert_curr) command_history::remove (hist_count); @@ -521,13 +523,15 @@ continue; } - if (first) - { - first = 0; - edit_history_repl_hist (line); - } - else - edit_history_add_hist (line); + // Command 'edit history' has already been removed in + // mk_tmp_hist_file () + //if (first) + // { + // first = 0; + // edit_history_repl_hist (line); + // } + //else + edit_history_add_hist (line); delete [] line; } @@ -638,27 +642,30 @@ DEFUN (history, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Command} history options\n\ -@deftypefnx {Built-in Function} {@var{h} = } history (@var{opt1}, @var{opt2}, @dots{})\n\ +@deftypefn {Command} {} history\n\ +@deftypefnx {Command} {} history @var{opt1} @dots{}\n\ +@deftypefnx {Built-in Function} {@var{h} =} history ()\n\ +@deftypefnx {Built-in Function} {@var{h} =} history (@var{opt1}, @dots{})\n\ If invoked with no arguments, @code{history} displays a list of commands\n\ that you have executed. Valid options are:\n\ \n\ @table @code\n\ -@item -w @var{file}\n\ -Write the current history to the file @var{file}. If the name is\n\ -omitted, use the default history file (normally @file{~/.octave_hist}).\n\ +@item @var{n}\n\ +@itemx -@var{n}\n\ +Display only the most recent @var{n} lines of history.\n\ +\n\ +@item -q\n\ +Don't number the displayed lines of history. This is useful for cutting\n\ +and pasting commands using the X Window System.\n\ \n\ @item -r @var{file}\n\ Read the file @var{file}, appending its contents to the current\n\ history list. If the name is omitted, use the default history file\n\ (normally @file{~/.octave_hist}).\n\ \n\ -@item @var{n}\n\ -Display only the most recent @var{n} lines of history.\n\ -\n\ -@item -q\n\ -Don't number the displayed lines of history. This is useful for cutting\n\ -and pasting commands using the X Window System.\n\ +@item -w @var{file}\n\ +Write the current history to the file @var{file}. If the name is\n\ +omitted, use the default history file (normally @file{~/.octave_hist}).\n\ @end table\n\ \n\ For example, to display the five most recent commands that you have\n\
--- a/libinterp/interpfcn/symtab.cc +++ b/libinterp/interpfcn/symtab.cc @@ -1049,20 +1049,12 @@ symbol_table::set_class_relationship (const std::string& sup_class, const std::string& inf_class) { - class_precedence_table_const_iterator p - = class_precedence_table.find (inf_class); - - if (p != class_precedence_table.end ()) - { - const std::set<std::string>& inferior_classes = p->second; + if (is_superiorto (inf_class, sup_class)) + return false; - std::set<std::string>::const_iterator q - = inferior_classes.find (sup_class); - - if (q != inferior_classes.end ()) - return false; - } - + // If sup_class doesn't have an entry in the precedence table, + // this will automatically create it, and associate to it a + // singleton set {inf_class} of inferior classes. class_precedence_table[sup_class].insert (inf_class); return true; @@ -1070,7 +1062,7 @@ // Has class A been marked as superior to class B? Also returns // TRUE if B has been marked as inferior to A, since we only keep -// one table, and convert inferiort information to a superiorto +// one table, and convert inferiorto information to a superiorto // relationship. Two calls are required to determine whether there // is no relationship between two classes: // @@ -1084,20 +1076,14 @@ bool symbol_table::is_superiorto (const std::string& a, const std::string& b) { - bool retval = false; - class_precedence_table_const_iterator p = class_precedence_table.find (a); + // If a has no entry in the precedence table, return false + if (p == class_precedence_table.end ()) + return false; - if (p != class_precedence_table.end ()) - { - const std::set<std::string>& inferior_classes = p->second; - std::set<std::string>::const_iterator q = inferior_classes.find (b); - - if (q != inferior_classes.end ()) - retval = true; - } - - return retval; + const std::set<std::string>& inferior_classes = p->second; + std::set<std::string>::const_iterator q = inferior_classes.find (b); + return (q != inferior_classes.end ()); } static std::string @@ -1516,7 +1502,7 @@ { if (ours.is_global () || ours.is_persistent ()) ::error ("global and persistent may only be used in the topmost level in which a nested variable is used"); - + if (! ours.is_formal ()) { ours.invalidate ();
--- a/libinterp/interpfcn/sysdep.cc +++ b/libinterp/interpfcn/sysdep.cc @@ -619,8 +619,9 @@ DEFUN (kbhit, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} kbhit ()\n\ -Read a single keystroke from the keyboard. If called with one\n\ +@deftypefn {Built-in Function} {} kbhit ()\n\ +@deftypefnx {Built-in Function} {} kbhit (1)\n\ +Read a single keystroke from the keyboard. If called with an\n\ argument, don't wait for a keypress. For example,\n\ \n\ @example\n\ @@ -636,8 +637,9 @@ @end example\n\ \n\ @noindent\n\ -identical to the above example, but don't wait for a keypress,\n\ +is identical to the above example, but doesn't wait for a keypress,\n\ returning the empty string if no key is available.\n\ +@seealso{input}\n\ @end deftypefn") { octave_value retval; @@ -653,7 +655,7 @@ if (c == -1) c = 0; - char s[2] = {c, '\0'}; + char s[2] = { static_cast<char> (c), '\0' }; retval = s; }
--- a/libinterp/interpfcn/sysdep.h +++ b/libinterp/interpfcn/sysdep.h @@ -30,9 +30,9 @@ #include "lo-ieee.h" #include "lo-sysdep.h" -extern void sysdep_init (void); +extern OCTINTERP_API void sysdep_init (void); -extern void sysdep_cleanup (void); +extern OCTINTERP_API void sysdep_cleanup (void); extern OCTINTERP_API void raw_mode (bool, bool wait = true);
--- a/libinterp/interpfcn/toplev.cc +++ b/libinterp/interpfcn/toplev.cc @@ -559,16 +559,24 @@ // The big loop. + unwind_protect frame; + + // octave_parser constructor sets this for us. + frame.protect_var (CURR_LEXER); + + octave_parser *curr_parser = new octave_parser (); + frame.add_fcn (octave_parser::cleanup, curr_parser); + int retval = 0; do { try { - unwind_protect frame; + unwind_protect inner_frame; reset_error_handler (); - reset_parser (); + curr_parser->reset (); if (symbol_table::at_top_level ()) tree_evaluator::reset_debug_state (); @@ -577,14 +585,13 @@ // the forced variables will be unmarked in the event of an // interrupt. symbol_table::scope_id scope = symbol_table::top_scope (); - frame.add_fcn (symbol_table::unmark_forced_variables, scope); + inner_frame.add_fcn (symbol_table::unmark_forced_variables, scope); - frame.protect_var (global_command); + inner_frame.protect_var (global_command); global_command = 0; - // This is the same as yyparse in parse.y. - retval = octave_parse (); + retval = curr_parser->run (); if (retval == 0) { @@ -632,7 +639,7 @@ command_editor::increment_current_command_number (); } } - else if (parser_end_of_input) + else if (curr_parser->end_of_input) break; } }
--- a/libinterp/octave-value/ov-base-diag.cc +++ b/libinterp/octave-value/ov-base-diag.cc @@ -109,7 +109,7 @@ if (idx0.is_scalar () && idx1.is_scalar ()) { - retval = matrix.elem (idx0(0), idx1(0)); + retval = matrix.checkelem (idx0(0), idx1(0)); } else {
--- a/libinterp/octave-value/ov-cell.cc +++ b/libinterp/octave-value/ov-cell.cc @@ -136,7 +136,8 @@ octave_value_list octave_cell::subsref (const std::string& type, const std::list<octave_value_list>& idx, - int nargout) + int nargout, + const std::list<octave_lvalue> *lvalue_list) { octave_value_list retval; @@ -178,7 +179,9 @@ // octave_user_function::subsref. if (idx.size () > 1) - retval = retval(0).next_subsref (nargout, type, idx); + retval = (lvalue_list + ? retval(0).next_subsref (nargout, type, idx, lvalue_list) + : retval(0).next_subsref (nargout, type, idx)); return retval; }
--- a/libinterp/octave-value/ov-cell.h +++ b/libinterp/octave-value/ov-cell.h @@ -79,7 +79,16 @@ } octave_value_list subsref (const std::string& type, - const std::list<octave_value_list>& idx, int); + const std::list<octave_value_list>& idx, + int nargout) + { + return subsref (type, idx, nargout, 0); + } + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, + const std::list<octave_lvalue> *lvalue_list); octave_value subsref (const std::string& type, const std::list<octave_value_list>& idx,
--- a/libinterp/octave-value/ov-class.cc +++ b/libinterp/octave-value/ov-class.cc @@ -2191,42 +2191,34 @@ octave_value retval; octave_function *fcn = octave_call_stack::caller (); - - if (fcn && fcn->is_class_constructor ()) + if ((! fcn) || (! fcn->is_class_constructor ())) { - for (int i = 0; i < args.length (); i++) - { - std::string class_name = args(i).string_value (); - - if (! error_state) - { - if (! is_built_in_class (class_name)) - { - std::string this_class_name = fcn->name (); + error ("superiorto: invalid call from outside class constructor"); + return retval; + } - if (! symbol_table::set_class_relationship (this_class_name, - class_name)) - { - error ("superiorto: precedence already set for %s and %s", - this_class_name.c_str (), class_name.c_str ()); - break; - } - } - else - { - // User defined classes always have higher precedence - // than built-in classes. - } - } - else - { + for (int i = 0; i < args.length (); i++) + { + std::string inf_class = args(i).string_value (); + if (error_state) + { error ("superiorto: expecting argument to be class name"); break; - } + } + + // User defined classes always have higher precedence + // than built-in classes + if (is_built_in_class (inf_class)) + break; + + std::string sup_class = fcn->name (); + if (! symbol_table::set_class_relationship (sup_class, inf_class)) + { + error ("superiorto: opposite precedence already set for %s and %s", + sup_class.c_str (), inf_class.c_str ()); + break; } } - else - error ("superiorto: invalid call from outside class constructor"); return retval; } @@ -2243,45 +2235,36 @@ octave_value retval; octave_function *fcn = octave_call_stack::caller (); - - if (fcn && fcn->is_class_constructor ()) + if ((! fcn) || (! fcn->is_class_constructor ())) { - for (int i = 0; i < args.length (); i++) - { - std::string class_name = args(i).string_value (); - - if (! error_state) - { - if (! is_built_in_class (class_name)) - { - std::string this_class_name = fcn->name (); - - symbol_table::set_class_relationship (class_name, - this_class_name); + error ("inferiorto: invalid call from outside class constructor"); + return retval; + } - if (! symbol_table::set_class_relationship (this_class_name, - class_name)) - { - error ("inferiorto: precedence already set for %s and %s", - this_class_name.c_str (), class_name.c_str ()); - break; - } - } - else - { - error ("inferiorto: cannot give user-defined class lower precedence than built-in class"); - break; - } - } - else - { - error ("inferiorto: expecting argument to be class name"); - break; - } + for (int i = 0; i < args.length (); i++) + { + std::string sup_class = args(i).string_value (); + if (error_state) + { + error ("inferiorto: expecting argument to be class name"); + break; + } + + if (is_built_in_class (sup_class)) + { + error ("inferiorto: cannot give user-defined class lower " + "precedence than built-in class"); + break; + } + + std::string inf_class = fcn->name (); + if (! symbol_table::set_class_relationship (sup_class, inf_class)) + { + error ("inferiorto: opposite precedence already set for %s and %s", + inf_class.c_str (), sup_class.c_str ()); + break; } } - else - error ("inferiorto: invalid call from outside class constructor"); return retval; }
--- a/libinterp/octave-value/ov-java.cc +++ b/libinterp/octave-value/ov-java.cc @@ -26,6 +26,11 @@ #include "defun.h" #include "error.h" +#include "fpucw.h" + +#if HAVE_FPU_CONTROL_H +#include <fpu_control.h> +#endif #if defined HAVE_JAVA @@ -392,6 +397,22 @@ return retval; } +#ifndef _FPU_DEFAULT +#if defined __i386__ || defined __x86_64__ +#define _FPU_DEFAULT 0x037f +#else +#define _FPU_DEFAULT 0 +#endif +#endif + +static void +restore_fpu_state (void) +{ + fpucw_t cw = GET_FPUCW (); + if (cw != _FPU_DEFAULT) + SET_FPUCW (_FPU_DEFAULT); +} + static void initialize_jvm (void) { @@ -583,6 +604,8 @@ if (jvm_lib) jvm_lib.close (); + + restore_fpu_state (); } } @@ -742,6 +765,8 @@ idx++; } + restore_fpu_state (); + return dv; } @@ -798,6 +823,8 @@ else retval = check_exception (jni_env); + restore_fpu_state (); + return retval; } @@ -826,6 +853,8 @@ else retval = check_exception (jni_env); + restore_fpu_state (); + return retval; } @@ -862,6 +891,8 @@ jstring_ref fieldName (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (field, f_getName_ID))); name_list.push_back (jstring_to_string (jni_env, fieldName)); } + + restore_fpu_state (); } string_vector v (name_list); @@ -921,6 +952,8 @@ } else error ("unable to convert Java object to string"); + + restore_fpu_state (); } return retval; @@ -1155,6 +1188,8 @@ if (retval.is_undefined ()) retval = octave_value (new octave_java (jobj, jcls)); + restore_fpu_state (); + return retval; } @@ -1381,6 +1416,8 @@ jclass_ref cls (current_env, find_octave_class (current_env, "org/octave/Octave")); jmethodID mID = current_env->GetStaticMethodID (cls, "checkPendingAction", "()V"); current_env->CallStaticVoidMethod (cls, mID); + + restore_fpu_state (); } return 0; @@ -1406,6 +1443,8 @@ { error (msg.c_str ()); } + + restore_fpu_state (); } } @@ -1738,6 +1777,8 @@ else retval = check_exception (jni_env); } + + restore_fpu_state (); } return retval; @@ -1768,6 +1809,8 @@ else retval = check_exception (jni_env); } + + restore_fpu_state (); } return retval; @@ -1797,6 +1840,8 @@ else check_exception (jni_env); } + + restore_fpu_state (); } return retval; @@ -1820,6 +1865,8 @@ retval = box (jni_env, resObj); else retval = check_exception (jni_env); + + restore_fpu_state (); } return retval; @@ -1844,6 +1891,8 @@ retval = box (jni_env, resObj); else retval = check_exception (jni_env); + + restore_fpu_state (); } return retval; @@ -1869,6 +1918,8 @@ jni_env->CallStaticObjectMethod (helperClass, mID, to_java (), jstring (fName), jobject (jobj)); check_exception (jni_env); } + + restore_fpu_state (); } return retval; @@ -1895,6 +1946,8 @@ jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName), jstring (fName), jobject (jobj)); check_exception (jni_env); } + + restore_fpu_state (); } return retval;
--- a/libinterp/octave-value/ov-usr-fcn.cc +++ b/libinterp/octave-value/ov-usr-fcn.cc @@ -517,7 +517,9 @@ tree_expression *expr = special_expr (); if (expr) - retval = expr->rvalue (nargout); + retval = (lvalue_list + ? expr->rvalue (nargout, lvalue_list) + : expr->rvalue (nargout)); } else cmd_list->accept (*current_evaluator); @@ -1042,4 +1044,24 @@ %!test %! [x, y] = try_isargout (); %! assert ([x, y], [1, 2]); +%! +%% It should work without (): +%!test +%! [~, y] = try_isargout; +%! assert (y, -2); +%! +%% It should work in function handles, anonymous functions, and cell +%% arrays of handles or anonymous functions. +%!test +%! fh = @try_isargout; +%! af = @() try_isargout; +%! c = {fh, af}; +%! [~, y] = fh (); +%! assert (y, -2); +%! [~, y] = af (); +%! assert (y, -2); +%! [~, y] = c{1}(); +%! assert (y, -2); +%! [~, y] = c{2}(); +%! assert (y, -2); */
--- a/libinterp/octave-value/ov.cc +++ b/libinterp/octave-value/ov.cc @@ -1313,6 +1313,23 @@ return *this; } +octave_value_list +octave_value::next_subsref (int nargout, const std::string& type, + const std::list<octave_value_list>& idx, + const std::list<octave_lvalue> *lvalue_list, + size_t skip) +{ + if (! error_state && idx.size () > skip) + { + std::list<octave_value_list> new_idx (idx); + for (size_t i = 0; i < skip; i++) + new_idx.erase (new_idx.begin ()); + return subsref (type.substr (skip), new_idx, nargout, lvalue_list); + } + else + return *this; +} + octave_value octave_value::next_subsref (bool auto_add, const std::string& type, const std::list<octave_value_list>& idx,
--- a/libinterp/octave-value/ov.h +++ b/libinterp/octave-value/ov.h @@ -419,6 +419,12 @@ std::list<octave_value_list>& idx, size_t skip = 1); + octave_value_list next_subsref (int nargout, + const std::string& type, const + std::list<octave_value_list>& idx, + const std::list<octave_lvalue> *lvalue_list, + size_t skip = 1); + octave_value next_subsref (bool auto_add, const std::string& type, const std::list<octave_value_list>& idx, size_t skip = 1);
--- a/libinterp/octave.cc +++ b/libinterp/octave.cc @@ -1000,9 +1000,6 @@ // Now argv should have the full set of args. intern_argv (octave_cmdline_argc, octave_cmdline_argv); - if (! octave_embedded) - switch_to_buffer (create_buffer (get_input_from_stdin ())); - // Force input to be echoed if not really interactive, but the user // has forced interactive behavior.
--- a/libinterp/parse-tree/lex.h +++ b/libinterp/parse-tree/lex.h @@ -24,35 +24,34 @@ #define octave_lex_h 1 #include <list> +#include <set> #include <stack> -// FIXME -- these input buffer things should be members of a -// parser input stream class. - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -// Associate a buffer with a new file to read. -extern OCTINTERP_API YY_BUFFER_STATE create_buffer (FILE *f); - -// Report the current buffer. -extern OCTINTERP_API YY_BUFFER_STATE current_buffer (void); - -// Connect to new buffer buffer. -extern OCTINTERP_API void switch_to_buffer (YY_BUFFER_STATE buf); - -// Delete a buffer. -extern OCTINTERP_API void delete_buffer (YY_BUFFER_STATE buf); - -extern OCTINTERP_API void clear_all_buffers (void); - extern OCTINTERP_API void cleanup_parser (void); // Is the given string a keyword? extern bool is_keyword (const std::string& s); -extern void prep_lexer_for_script_file (void); -extern void prep_lexer_for_function_file (void); -extern void prep_lexer_for_classdef_file (void); +class +stream_reader +{ +public: + virtual int getc (void) = 0; + virtual int ungetc (int c) = 0; + +protected: + stream_reader (void) { } + ~stream_reader (void) { } + +private: + + // No copying! + stream_reader (const stream_reader&); + stream_reader& operator = (const stream_reader&); +}; + +// Forward decl for lexical_feedback::token_stack. +class token; // For communication between the lexer and parser. @@ -61,53 +60,234 @@ { public: - lexical_feedback (void) + // Did eat_whitespace or eat_continuation eat a space or tab, or a + // newline, or both? + // + // Functions that return this type will return a logical OR of the + // following values: + // + // NO_WHITESPACE no spaces to eat + // SPACE_OR_TAB space or tab in input + // NEWLINE bare new line in input + + enum whitespace_type + { + NO_WHITESPACE = 1, + SPACE_OR_TAB = 2, + NEWLINE = 4 + }; + + // Track nesting of square brackets, curly braces, and parentheses. + + class bbp_nesting_level + { + private: - : bracketflag (0), braceflag (0), looping (0), - convert_spaces_to_comma (true), at_beginning_of_statement (true), - defining_func (0), looking_at_function_handle (0), - looking_at_anon_fcn_args (true), - looking_at_return_list (false), looking_at_parameter_list (false), - looking_at_decl_list (false), looking_at_initializer_expression (false), - looking_at_matrix_or_assign_lhs (false), looking_at_object_index (), - looking_for_object_index (false), do_comma_insert (false), - looking_at_indirect_ref (false), parsed_function_name (), - parsing_class_method (false), maybe_classdef_get_set_method (false), - parsing_classdef (false), parsing_classdef_get_method (false), - parsing_classdef_set_method (false), quote_is_transpose (false), - pending_local_variables () + enum bracket_type + { + BRACKET = 1, + BRACE = 2, + PAREN = 3 + }; + + public: + + bbp_nesting_level (void) : context () { } + + bbp_nesting_level (const bbp_nesting_level& nl) : context (nl.context) { } + bbp_nesting_level& operator = (const bbp_nesting_level& nl) { - init (); + if (&nl != this) + context = nl.context; + + return *this; + } + + ~bbp_nesting_level (void) { } + + void bracket (void) { context.push (BRACKET); } + + bool is_bracket (void) + { + return ! context.empty () && context.top () == BRACKET; } - ~lexical_feedback (void) { } + void brace (void) { context.push (BRACE); } + + bool is_brace (void) + { + return ! context.empty () && context.top () == BRACE; + } + + void paren (void) { context.push (PAREN); } + + bool is_paren (void) + { + return ! context.empty () && context.top () == PAREN; + } + + bool is_bracket_or_brace (void) + { + return (! context.empty () + && (context.top () == BRACKET || context.top () == BRACE)); + } + + bool none (void) { return context.empty (); } + + void remove (void) + { + if (! context.empty ()) + context.pop (); + } + + void clear (void) + { + while (! context.empty ()) + context.pop (); + } + + private: + + std::stack<int> context; + }; + + lexical_feedback (void) + : scanner (0), convert_spaces_to_comma (true), + do_comma_insert (false), at_beginning_of_statement (true), + looking_at_anon_fcn_args (false), looking_at_return_list (false), + looking_at_parameter_list (false), looking_at_decl_list (false), + looking_at_initializer_expression (false), + looking_at_matrix_or_assign_lhs (false), + looking_for_object_index (false), + looking_at_indirect_ref (false), parsing_class_method (false), + maybe_classdef_get_set_method (false), parsing_classdef (false), + quote_is_transpose (false), + input_line_number (1), current_input_column (1), + bracketflag (0), braceflag (0), + looping (0), defining_func (0), looking_at_function_handle (0), + block_comment_nesting_level (0), + looking_at_object_index (), parsed_function_name (), + pending_local_variables (), nesting_level () + { + init (); + } + + ~lexical_feedback (void); void init (void); - // Square bracket level count. - int bracketflag; + void reset (void); + + void prep_for_script_file (void); + + void prep_for_function_file (void); + + void prep_for_classdef_file (void); + + int octave_read (char *buf, unsigned int max_size); + + char *flex_yytext (void); + + int flex_yyleng (void); + + void do_comma_insert_check (void); + + int text_yyinput (void); + + void xunput (char c, char *buf); + + void xunput (char c); + + void fixup_column_count (char *s); + + bool inside_any_object_index (void); + + int is_keyword_token (const std::string& s); + + bool is_variable (const std::string& name); + + std::string grab_block_comment (stream_reader& reader, bool& eof); + + std::string grab_comment_block (stream_reader& reader, bool at_bol, + bool& eof); + + int process_comment (bool start_in_block, bool& eof); + + bool next_token_is_sep_op (void); + + bool next_token_is_postfix_unary_op (bool spc_prev); + + bool next_token_is_bin_op (bool spc_prev); + + void scan_for_comments (const char *text); + + int eat_whitespace (void); + + void handle_number (void); - // Curly brace level count. - int braceflag; + bool have_continuation (bool trailing_comments_ok = true); + + bool have_ellipsis_continuation (bool trailing_comments_ok = true); + + int eat_continuation (void); + + int handle_string (char delim); + + bool next_token_is_assign_op (void); + + bool next_token_is_index_op (void); + + int handle_close_bracket (bool spc_gobbled, int bracket_type); + + void maybe_unput_comma (int spc_gobbled); + + bool next_token_can_follow_bin_op (void); + + bool looks_like_command_arg (void); + + int handle_superclass_identifier (void); + + int handle_meta_identifier (void); - // TRUE means we're in the middle of defining a loop. - int looping; + int handle_identifier (void); + + void maybe_warn_separator_insert (char sep); + + void gripe_single_quote_string (void); + + void gripe_matlab_incompatible (const std::string& msg); + + void maybe_gripe_matlab_incompatible_comment (char c); + + void gripe_matlab_incompatible_continuation (void); + + void gripe_matlab_incompatible_operator (const std::string& op); + + void push_token (token *); + + token *current_token (void); + + void display_token (int tok); + + void fatal_error (const char *msg); + + void lexer_debug (const char *pattern, const char *text); + + // Internal state of the flex-generated lexer. + void *scanner; // TRUE means that we should convert spaces to a comma inside a // matrix definition. bool convert_spaces_to_comma; + // GAG. Stupid kludge so that [[1,2][3,4]] will work. + bool do_comma_insert; + // TRUE means we are at the beginning of a statement, where a // command name is possible. bool at_beginning_of_statement; - // Nonzero means we're in the middle of defining a function. - int defining_func; - - // Nonzero means we are parsing a function handle. - int looking_at_function_handle; - // TRUE means we are parsing an anonymous function argument list. bool looking_at_anon_fcn_args; @@ -129,25 +309,13 @@ // multi-value assignment statement. bool looking_at_matrix_or_assign_lhs; - // If the front of the list is TRUE, the closest paren, brace, or - // bracket nesting is an index for an object. - std::list<bool> looking_at_object_index; - // Object index not possible until we've seen something. bool looking_for_object_index; - // GAG. Stupid kludge so that [[1,2][3,4]] will work. - bool do_comma_insert; - // TRUE means we're looking at an indirect reference to a // structure element. bool looking_at_indirect_ref; - // If the top of the stack is TRUE, then we've already seen the name - // of the current function. Should only matter if - // current_function_level > 0 - std::stack<bool> parsed_function_name; - // TRUE means we are parsing a class method in function or classdef file. bool parsing_class_method; @@ -168,41 +336,61 @@ // Return transpose or start a string? bool quote_is_transpose; + // The current input line number. + int input_line_number; + + // The column of the current token. + int current_input_column; + + // Square bracket level count. + int bracketflag; + + // Curly brace level count. + int braceflag; + + // TRUE means we're in the middle of defining a loop. + int looping; + + // Nonzero means we're in the middle of defining a function. + int defining_func; + + // Nonzero means we are parsing a function handle. + int looking_at_function_handle; + + // Nestng level for blcok comments. + int block_comment_nesting_level; + + // If the front of the list is TRUE, the closest paren, brace, or + // bracket nesting is an index for an object. + std::list<bool> looking_at_object_index; + + // If the top of the stack is TRUE, then we've already seen the name + // of the current function. Should only matter if + // current_function_level > 0 + std::stack<bool> parsed_function_name; + // Set of identifiers that might be local variable names. std::set<std::string> pending_local_variables; + // Is the closest nesting level a square bracket, squiggly brace or + // a paren? + bbp_nesting_level nesting_level; + + // For unwind protect. + static void cleanup (lexical_feedback *lexer) { delete lexer; } + private: + // Stack to hold tokens so that we can delete them when the parser is + // reset and avoid growing forever just because we are stashing some + // information. + std::stack <token*> token_stack; + + // No copying! + lexical_feedback (const lexical_feedback&); lexical_feedback& operator = (const lexical_feedback&); }; -class -stream_reader -{ -public: - virtual int getc (void) = 0; - virtual int ungetc (int c) = 0; - -protected: - stream_reader (void) { } - ~stream_reader (void) { } - -private: - - // No copying! - stream_reader (const stream_reader&); - stream_reader& operator = (const stream_reader&); -}; - -extern std::string -grab_comment_block (stream_reader& reader, bool at_bol, bool& eof); - -// TRUE means that we have encountered EOF on the input stream. -extern bool parser_end_of_input; - -// Flags that need to be shared between the lexer and parser. -extern lexical_feedback lexer_flags; - #endif
--- a/libinterp/parse-tree/lex.ll +++ b/libinterp/parse-tree/lex.ll @@ -20,7 +20,21 @@ */ +/* +We are using the pure parser interface and the reentrant lexer +interface but the Octave parser and lexer are NOT properly +reentrant because both still use many global variables. It should be +safe to create a parser object and call it while anotehr parser +object is active (to parse a callback function while the main +interactive parser is waiting for input, for example) if you take +care to properly save and restore (typically with an unwind_protect +object) relevant global values before and after the nested call. +*/ + %option prefix = "octave_" +%option noyywrap +%option reentrant +%option bison-bridge %top { #ifdef HAVE_CONFIG_H @@ -54,9 +68,9 @@ #include "quit.h" #include "lo-mappers.h" -// These would be alphabetical, but y.tab.h must be included before -// oct-gperf.h and y.tab.h must be included after token.h and the tree -// class declarations. We can't include y.tab.h in oct-gperf.h +// These would be alphabetical, but oct-parse.h must be included before +// oct-gperf.h and oct-parse.h must be included after token.h and the tree +// class declarations. We can't include oct-parse.h in oct-gperf.h // because it may not be protected to allow it to be included multiple // times. @@ -96,7 +110,8 @@ #error lex.l requires flex version 2.5.4 or later #endif -#define yylval octave_lval +#define YY_EXTRA_TYPE lexical_feedback * +#define curr_lexer yyextra // Arrange to get input via readline. @@ -104,35 +119,26 @@ #undef YY_INPUT #endif #define YY_INPUT(buf, result, max_size) \ - if ((result = octave_read (buf, max_size)) < 0) \ - YY_FATAL_ERROR ("octave_read () in flex scanner failed"); + result = curr_lexer->octave_read (buf, max_size) // Try to avoid crashing out completely on fatal scanner errors. -// The call to yy_fatal_error should never happen, but it avoids a -// 'static function defined but not used' warning from gcc. #ifdef YY_FATAL_ERROR #undef YY_FATAL_ERROR #endif #define YY_FATAL_ERROR(msg) \ - do \ - { \ - error (msg); \ - OCTAVE_QUIT; \ - yy_fatal_error (msg); \ - } \ - while (0) + (yyget_extra (yyscanner))->fatal_error (msg) #define DISPLAY_TOK_AND_RETURN(tok) \ do \ { \ int tok_val = tok; \ if (Vdisplay_tokens) \ - display_token (tok_val); \ + curr_lexer->display_token (tok_val); \ if (lexer_debug_flag) \ { \ std::cerr << "R: "; \ - display_token (tok_val); \ + curr_lexer->display_token (tok_val); \ std::cerr << std::endl; \ } \ return tok_val; \ @@ -150,9 +156,9 @@ #define TOK_RETURN(tok) \ do \ { \ - current_input_column += yyleng; \ - lexer_flags.quote_is_transpose = false; \ - lexer_flags.convert_spaces_to_comma = true; \ + curr_lexer->current_input_column += yyleng; \ + curr_lexer->quote_is_transpose = false; \ + curr_lexer->convert_spaces_to_comma = true; \ COUNT_TOK_AND_RETURN (tok); \ } \ while (0) @@ -160,9 +166,9 @@ #define TOK_PUSH_AND_RETURN(name, tok) \ do \ { \ - yylval.tok_val = new token (name, input_line_number, \ - current_input_column); \ - token_stack.push (yylval.tok_val); \ + curr_lexer->push_token \ + (new token (name, curr_lexer->input_line_number, \ + curr_lexer->current_input_column)); \ TOK_RETURN (tok); \ } \ while (0) @@ -170,13 +176,14 @@ #define BIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ do \ { \ - yylval.tok_val = new token (input_line_number, current_input_column); \ - token_stack.push (yylval.tok_val); \ - current_input_column += yyleng; \ - lexer_flags.quote_is_transpose = qit; \ - lexer_flags.convert_spaces_to_comma = convert; \ - lexer_flags.looking_for_object_index = false; \ - lexer_flags.at_beginning_of_statement = bos; \ + curr_lexer->push_token \ + (new token (curr_lexer->input_line_number, \ + curr_lexer->current_input_column)); \ + curr_lexer->current_input_column += yyleng; \ + curr_lexer->quote_is_transpose = qit; \ + curr_lexer->convert_spaces_to_comma = convert; \ + curr_lexer->looking_for_object_index = false; \ + curr_lexer->at_beginning_of_statement = bos; \ COUNT_TOK_AND_RETURN (tok); \ } \ while (0) @@ -184,7 +191,7 @@ #define XBIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ do \ { \ - gripe_matlab_incompatible_operator (yytext); \ + curr_lexer->gripe_matlab_incompatible_operator (yytext); \ BIN_OP_RETURN_INTERNAL (tok, convert, bos, qit); \ } \ while (0) @@ -199,7 +206,7 @@ #define XBIN_OP_RETURN(tok, convert, bos) \ do \ { \ - gripe_matlab_incompatible_operator (yytext); \ + curr_lexer->gripe_matlab_incompatible_operator (yytext); \ BIN_OP_RETURN (tok, convert, bos); \ } \ while (0) @@ -208,129 +215,21 @@ do \ { \ if (lexer_debug_flag) \ - lexer_debug (pattern, yytext); \ + curr_lexer->lexer_debug (pattern, yytext); \ } \ while (0) -// TRUE means that we have encountered EOF on the input stream. -bool parser_end_of_input = false; - -// Flags that need to be shared between the lexer and parser. -lexical_feedback lexer_flags; - -// Stack to hold tokens so that we can delete them when the parser is -// reset and avoid growing forever just because we are stashing some -// information. This has to appear before lex.h is included, because -// one of the macros defined there uses token_stack. -// -// FIXME -- this should really be static, but that causes -// problems on some systems. -std::stack <token*> token_stack; - -// Did eat_whitespace() eat a space or tab, or a newline, or both? - -typedef int yum_yum; - -const yum_yum ATE_NOTHING = 0; -const yum_yum ATE_SPACE_OR_TAB = 1; -const yum_yum ATE_NEWLINE = 2; - -// Is the closest nesting level a square bracket, squiggly brace or a paren? - -class bracket_brace_paren_nesting_level -{ -public: - - bracket_brace_paren_nesting_level (void) : context () { } - - ~bracket_brace_paren_nesting_level (void) { } - - void bracket (void) { context.push (BRACKET); } - bool is_bracket (void) - { return ! context.empty () && context.top () == BRACKET; } - - void brace (void) { context.push (BRACE); } - bool is_brace (void) - { return ! context.empty () && context.top () == BRACE; } - - void paren (void) { context.push (PAREN); } - bool is_paren (void) - { return ! context.empty () && context.top () == PAREN; } - - bool is_bracket_or_brace (void) - { return (! context.empty () - && (context.top () == BRACKET || context.top () == BRACE)); } - - bool none (void) { return context.empty (); } - - void remove (void) { if (! context.empty ()) context.pop (); } - - void clear (void) { while (! context.empty ()) context.pop (); } - -private: - - std::stack<int> context; - - static const int BRACKET; - static const int BRACE; - static const int PAREN; - - bracket_brace_paren_nesting_level (const bracket_brace_paren_nesting_level&); - - bracket_brace_paren_nesting_level& - operator = (const bracket_brace_paren_nesting_level&); -}; - -const int bracket_brace_paren_nesting_level::BRACKET = 1; -const int bracket_brace_paren_nesting_level::BRACE = 2; -const int bracket_brace_paren_nesting_level::PAREN = 3; - -static bracket_brace_paren_nesting_level nesting_level; - static bool Vdisplay_tokens = false; static unsigned int Vtoken_count = 0; -// The start state that was in effect when the beginning of a block -// comment was noticed. -static int block_comment_nesting_level = 0; - // Internal variable for lexer debugging state. static bool lexer_debug_flag = false; // Forward declarations for functions defined at the bottom of this -// file. - -static int text_yyinput (void); -static void xunput (char c, char *buf); -static void fixup_column_count (char *s); -static void do_comma_insert_check (void); -static int is_keyword_token (const std::string& s); -static int process_comment (bool start_in_block, bool& eof); -static bool match_any (char c, const char *s); -static bool next_token_is_sep_op (void); -static bool next_token_is_bin_op (bool spc_prev); -static bool next_token_is_postfix_unary_op (bool spc_prev); +// file that are needed inside the lexer actions. + static std::string strip_trailing_whitespace (char *s); -static void handle_number (void); -static int handle_string (char delim); -static int handle_close_bracket (bool spc_gobbled, int bracket_type); -static int handle_superclass_identifier (void); -static int handle_meta_identifier (void); -static int handle_identifier (void); -static bool have_continuation (bool trailing_comments_ok = true); -static bool have_ellipsis_continuation (bool trailing_comments_ok = true); -static void scan_for_comments (const char *); -static yum_yum eat_whitespace (void); -static yum_yum eat_continuation (void); -static void maybe_warn_separator_insert (char sep); -static void gripe_single_quote_string (void); -static void gripe_matlab_incompatible (const std::string& msg); -static void maybe_gripe_matlab_incompatible_comment (char c); -static void gripe_matlab_incompatible_continuation (void); -static void gripe_matlab_incompatible_operator (const std::string& op); -static void display_token (int tok); -static void lexer_debug (const char *pattern, const char *text); %} @@ -362,7 +261,7 @@ LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>."); BEGIN (INITIAL); - xunput (yytext[0], yytext); + curr_lexer->xunput (yytext[0]); COUNT_TOK_AND_RETURN (SCRIPT_FILE); } @@ -370,7 +269,7 @@ LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>."); BEGIN (INITIAL); - xunput (yytext[0], yytext); + curr_lexer->xunput (yytext[0]); COUNT_TOK_AND_RETURN (FUNCTION_FILE); } @@ -378,7 +277,7 @@ LEXER_DEBUG ("<CLASSDEF_FILE_BEGIN>."); BEGIN (INITIAL); - xunput (yytext[0], yytext); + curr_lexer->xunput (yytext[0], yytext); COUNT_TOK_AND_RETURN (CLASSDEF_FILE); } @@ -390,13 +289,13 @@ LEXER_DEBUG ("<COMMAND_START>{NL}"); BEGIN (INITIAL); - input_line_number++; - current_input_column = 1; - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = true; + curr_lexer->input_line_number++; + curr_lexer->current_input_column = 1; + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = true; COUNT_TOK_AND_RETURN ('\n'); } @@ -404,8 +303,8 @@ <COMMAND_START>[\;\,] { LEXER_DEBUG ("<COMMAND_START>[\\;\\,]"); - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = true; BEGIN (INITIAL); @@ -418,10 +317,10 @@ <COMMAND_START>[\"\'] { LEXER_DEBUG ("<COMMAND_START>[\\\"\\']"); - lexer_flags.at_beginning_of_statement = false; - - current_input_column++; - int tok = handle_string (yytext[0]); + curr_lexer->at_beginning_of_statement = false; + + curr_lexer->current_input_column++; + int tok = curr_lexer->handle_string (yytext[0]); COUNT_TOK_AND_RETURN (tok); } @@ -431,8 +330,8 @@ std::string tok = strip_trailing_whitespace (yytext); - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; TOK_PUSH_AND_RETURN (tok, SQ_STRING); } @@ -454,21 +353,21 @@ <MATRIX_START>{SNLCMT}*\]{S}* { LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\]{S}*"); - scan_for_comments (yytext); - fixup_column_count (yytext); - - lexer_flags.looking_at_object_index.pop_front (); - - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->scan_for_comments (yytext); + curr_lexer->fixup_column_count (yytext); + + curr_lexer->looking_at_object_index.pop_front (); + + curr_lexer->looking_for_object_index = true; + curr_lexer->at_beginning_of_statement = false; int c = yytext[yyleng-1]; - int cont_is_spc = eat_continuation (); + bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE); bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); - int tok_to_return = handle_close_bracket (spc_gobbled, ']'); + int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, ']'); if (spc_gobbled) - xunput (' ', yytext); + curr_lexer->xunput (' '); COUNT_TOK_AND_RETURN (tok_to_return); } @@ -480,21 +379,21 @@ <MATRIX_START>{SNLCMT}*\}{S}* { LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\}{S}*"); - scan_for_comments (yytext); - fixup_column_count (yytext); - - lexer_flags.looking_at_object_index.pop_front (); - - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->scan_for_comments (yytext); + curr_lexer->fixup_column_count (yytext); + + curr_lexer->looking_at_object_index.pop_front (); + + curr_lexer->looking_for_object_index = true; + curr_lexer->at_beginning_of_statement = false; int c = yytext[yyleng-1]; - int cont_is_spc = eat_continuation (); + bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE); bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); - int tok_to_return = handle_close_bracket (spc_gobbled, '}'); + int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, '}'); if (spc_gobbled) - xunput (' ', yytext); + curr_lexer->xunput (' '); COUNT_TOK_AND_RETURN (tok_to_return); } @@ -508,22 +407,22 @@ <MATRIX_START>{S}*\,{S}* { LEXER_DEBUG ("<MATRIX_START>{S}*\\,{S}*"); - current_input_column += yyleng; - - int tmp = eat_continuation (); - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; - - if (! lexer_flags.looking_at_object_index.front ()) + curr_lexer->current_input_column += yyleng; + + int tmp = curr_lexer->eat_continuation (); + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; + + if (! curr_lexer->looking_at_object_index.front ()) { - if ((tmp & ATE_NEWLINE) == ATE_NEWLINE) + if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE) { - maybe_warn_separator_insert (';'); - - xunput (';', yytext); + curr_lexer->maybe_warn_separator_insert (';'); + + curr_lexer->xunput (';'); } } @@ -540,34 +439,34 @@ <MATRIX_START>{S}+ { LEXER_DEBUG ("<MATRIX_START>{S}+"); - current_input_column += yyleng; - - lexer_flags.at_beginning_of_statement = false; - - int tmp = eat_continuation (); - - if (! lexer_flags.looking_at_object_index.front ()) + curr_lexer->current_input_column += yyleng; + + curr_lexer->at_beginning_of_statement = false; + + int tmp = curr_lexer->eat_continuation (); + + if (! curr_lexer->looking_at_object_index.front ()) { - bool bin_op = next_token_is_bin_op (true); - bool postfix_un_op = next_token_is_postfix_unary_op (true); - bool sep_op = next_token_is_sep_op (); + bool bin_op = curr_lexer->next_token_is_bin_op (true); + bool postfix_un_op = curr_lexer->next_token_is_postfix_unary_op (true); + bool sep_op = curr_lexer->next_token_is_sep_op (); if (! (postfix_un_op || bin_op || sep_op) - && nesting_level.is_bracket_or_brace () - && lexer_flags.convert_spaces_to_comma) + && curr_lexer->nesting_level.is_bracket_or_brace () + && curr_lexer->convert_spaces_to_comma) { - if ((tmp & ATE_NEWLINE) == ATE_NEWLINE) + if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE) { - maybe_warn_separator_insert (';'); - - xunput (';', yytext); + curr_lexer->maybe_warn_separator_insert (';'); + + curr_lexer->xunput (';'); } - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - - maybe_warn_separator_insert (','); + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + + curr_lexer->maybe_warn_separator_insert (','); COUNT_TOK_AND_RETURN (','); } @@ -585,14 +484,14 @@ <MATRIX_START>{SNLCMT}*;{SNLCMT}* { LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*;{SNLCMT}*"); - scan_for_comments (yytext); - fixup_column_count (yytext); - eat_whitespace (); - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->scan_for_comments (yytext); + curr_lexer->fixup_column_count (yytext); + curr_lexer->eat_whitespace (); + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; COUNT_TOK_AND_RETURN (';'); } @@ -609,21 +508,21 @@ <MATRIX_START>{S}*{NL}{SNLCMT}* { LEXER_DEBUG ("<MATRIX_START>{S}*{COMMENT}{SNLCMT}*|<MATRIX_START>{S}*{NL}{SNLCMT}*"); - scan_for_comments (yytext); - fixup_column_count (yytext); - eat_whitespace (); - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.at_beginning_of_statement = false; - - if (nesting_level.none ()) + curr_lexer->scan_for_comments (yytext); + curr_lexer->fixup_column_count (yytext); + curr_lexer->eat_whitespace (); + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->at_beginning_of_statement = false; + + if (curr_lexer->nesting_level.none ()) return LEXICAL_ERROR; - if (! lexer_flags.looking_at_object_index.front () - && nesting_level.is_bracket_or_brace ()) + if (! curr_lexer->looking_at_object_index.front () + && curr_lexer->nesting_level.is_bracket_or_brace ()) { - maybe_warn_separator_insert (';'); + curr_lexer->maybe_warn_separator_insert (';'); COUNT_TOK_AND_RETURN (';'); } @@ -632,26 +531,26 @@ \[{S}* { LEXER_DEBUG ("\\[{S}*"); - nesting_level.bracket (); - - lexer_flags.looking_at_object_index.push_front (false); - - current_input_column += yyleng; - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; - - if (lexer_flags.defining_func - && ! lexer_flags.parsed_function_name.top ()) - lexer_flags.looking_at_return_list = true; + curr_lexer->nesting_level.bracket (); + + curr_lexer->looking_at_object_index.push_front (false); + + curr_lexer->current_input_column += yyleng; + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; + + if (curr_lexer->defining_func + && ! curr_lexer->parsed_function_name.top ()) + curr_lexer->looking_at_return_list = true; else - lexer_flags.looking_at_matrix_or_assign_lhs = true; + curr_lexer->looking_at_matrix_or_assign_lhs = true; promptflag--; - eat_whitespace (); - - lexer_flags.bracketflag++; + curr_lexer->eat_whitespace (); + + curr_lexer->bracketflag++; BEGIN (MATRIX_START); COUNT_TOK_AND_RETURN ('['); } @@ -659,12 +558,12 @@ \] { LEXER_DEBUG ("\\]"); - nesting_level.remove (); - - lexer_flags.looking_at_object_index.pop_front (); - - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->nesting_level.remove (); + + curr_lexer->looking_at_object_index.pop_front (); + + curr_lexer->looking_for_object_index = true; + curr_lexer->at_beginning_of_statement = false; TOK_RETURN (']'); } @@ -676,7 +575,7 @@ {NUMBER}{Im} { LEXER_DEBUG ("{NUMBER}{Im}"); - handle_number (); + curr_lexer->handle_number (); COUNT_TOK_AND_RETURN (IMAG_NUM); } @@ -688,7 +587,7 @@ {D}+/\.[\*/\\^\'] | {NUMBER} { LEXER_DEBUG ("{D}+/\\.[\\*/\\^\\']|{NUMBER}"); - handle_number (); + curr_lexer->handle_number (); COUNT_TOK_AND_RETURN (NUM); } @@ -698,7 +597,7 @@ %} {S}* { - current_input_column += yyleng; + curr_lexer->current_input_column += yyleng; } %{ @@ -710,11 +609,11 @@ LEXER_DEBUG ("{CONT}{S}*{NL}|{CONT}{S}*{COMMENT}"); if (yytext[0] == '\\') - gripe_matlab_incompatible_continuation (); - scan_for_comments (yytext); + curr_lexer->gripe_matlab_incompatible_continuation (); + curr_lexer->scan_for_comments (yytext); promptflag--; - input_line_number++; - current_input_column = 1; + curr_lexer->input_line_number++; + curr_lexer->current_input_column = 1; } %{ @@ -724,14 +623,14 @@ <<EOF>> { LEXER_DEBUG ("<<EOF>>"); - if (block_comment_nesting_level != 0) + if (curr_lexer->block_comment_nesting_level != 0) { warning ("block comment open at end of input"); if ((reading_fcn_file || reading_script_file || reading_classdef_file) && ! curr_fcn_file_name.empty ()) warning ("near line %d of file '%s.m'", - input_line_number, curr_fcn_file_name.c_str ()); + curr_lexer->input_line_number, curr_fcn_file_name.c_str ()); } TOK_RETURN (END_OF_INPUT); @@ -745,7 +644,7 @@ {IDENT}{S}* { LEXER_DEBUG ("{IDENT}{S}*"); - int id_tok = handle_identifier (); + int id_tok = curr_lexer->handle_identifier (); if (id_tok >= 0) COUNT_TOK_AND_RETURN (id_tok); @@ -759,11 +658,11 @@ {IDENT}@{IDENT}.{IDENT}{S}* { LEXER_DEBUG ("{IDENT}@{IDENT}{S}*|{IDENT}@{IDENT}.{IDENT}{S}*"); - int id_tok = handle_superclass_identifier (); + int id_tok = curr_lexer->handle_superclass_identifier (); if (id_tok >= 0) { - lexer_flags.looking_for_object_index = true; + curr_lexer->looking_for_object_index = true; COUNT_TOK_AND_RETURN (id_tok); } @@ -777,11 +676,11 @@ \?{IDENT}\.{IDENT}{S}* { LEXER_DEBUG ("\\?{IDENT}{S}*|\\?{IDENT}\\.{IDENT}{S}*"); - int id_tok = handle_meta_identifier (); + int id_tok = curr_lexer->handle_meta_identifier (); if (id_tok >= 0) { - lexer_flags.looking_for_object_index = true; + curr_lexer->looking_for_object_index = true; COUNT_TOK_AND_RETURN (id_tok); } @@ -794,13 +693,13 @@ "@" { LEXER_DEBUG ("@"); - current_input_column++; - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = false; - lexer_flags.looking_at_function_handle++; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->current_input_column++; + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = false; + curr_lexer->looking_at_function_handle++; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; COUNT_TOK_AND_RETURN ('@'); @@ -815,23 +714,23 @@ {NL} { LEXER_DEBUG ("{NL}"); - input_line_number++; - current_input_column = 1; - - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - - if (nesting_level.none ()) + curr_lexer->input_line_number++; + curr_lexer->current_input_column = 1; + + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + + if (curr_lexer->nesting_level.none ()) { - lexer_flags.at_beginning_of_statement = true; + curr_lexer->at_beginning_of_statement = true; COUNT_TOK_AND_RETURN ('\n'); } - else if (nesting_level.is_paren ()) + else if (curr_lexer->nesting_level.is_paren ()) { - lexer_flags.at_beginning_of_statement = false; - gripe_matlab_incompatible ("bare newline inside parentheses"); + curr_lexer->at_beginning_of_statement = false; + curr_lexer->gripe_matlab_incompatible ("bare newline inside parentheses"); } - else if (nesting_level.is_bracket_or_brace ()) + else if (curr_lexer->nesting_level.is_bracket_or_brace ()) return LEXICAL_ERROR; } @@ -843,17 +742,17 @@ "'" { LEXER_DEBUG ("'"); - current_input_column++; - lexer_flags.convert_spaces_to_comma = true; - - if (lexer_flags.quote_is_transpose) + curr_lexer->current_input_column++; + curr_lexer->convert_spaces_to_comma = true; + + if (curr_lexer->quote_is_transpose) { - do_comma_insert_check (); + curr_lexer->do_comma_insert_check (); COUNT_TOK_AND_RETURN (QUOTE); } else { - int tok = handle_string ('\''); + int tok = curr_lexer->handle_string ('\''); COUNT_TOK_AND_RETURN (tok); } } @@ -865,8 +764,8 @@ \" { LEXER_DEBUG ("\""); - current_input_column++; - int tok = handle_string ('"'); + curr_lexer->current_input_column++; + int tok = curr_lexer->handle_string ('"'); COUNT_TOK_AND_RETURN (tok); } @@ -878,12 +777,12 @@ {CCHAR} { LEXER_DEBUG ("{CCHAR}"); - lexer_flags.looking_for_object_index = false; - - xunput (yytext[0], yytext); + curr_lexer->looking_for_object_index = false; + + curr_lexer->xunput (yytext[0]); bool eof = false; - int tok = process_comment (false, eof); + int tok = curr_lexer->process_comment (false, eof); if (eof) TOK_RETURN (END_OF_INPUT); @@ -898,15 +797,15 @@ ^{S}*{CCHAR}\{{S}*{NL} { LEXER_DEBUG ("^{S}*{CCHAR}\\{{S}*{NL}"); - lexer_flags.looking_for_object_index = false; - - input_line_number++; - current_input_column = 1; - block_comment_nesting_level++; + curr_lexer->looking_for_object_index = false; + + curr_lexer->input_line_number++; + curr_lexer->current_input_column = 1; + curr_lexer->block_comment_nesting_level++; promptflag--; bool eof = false; - process_comment (true, eof); + curr_lexer->process_comment (true, eof); } %{ @@ -922,9 +821,9 @@ ".\\" { LEXER_DEBUG (".\\"); BIN_OP_RETURN (ELEFTDIV, false, false); } ".^" { LEXER_DEBUG (".^"); BIN_OP_RETURN (EPOW, false, false); } ".**" { LEXER_DEBUG (".**"); XBIN_OP_RETURN (EPOW, false, false); } -".'" { LEXER_DEBUG (".'"); do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, true, false); } -"++" { LEXER_DEBUG ("++"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (PLUS_PLUS, true, false, true); } -"--" { LEXER_DEBUG ("--"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (MINUS_MINUS, true, false, true); } +".'" { LEXER_DEBUG (".'"); curr_lexer->do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, true, false); } +"++" { LEXER_DEBUG ("++"); curr_lexer->do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (PLUS_PLUS, true, false, true); } +"--" { LEXER_DEBUG ("--"); curr_lexer->do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (MINUS_MINUS, true, false, true); } "<=" { LEXER_DEBUG ("<="); BIN_OP_RETURN (EXPR_LE, false, false); } "==" { LEXER_DEBUG ("=="); BIN_OP_RETURN (EXPR_EQ, false, false); } "~=" { LEXER_DEBUG ("~="); BIN_OP_RETURN (EXPR_NE, false, false); } @@ -940,7 +839,7 @@ "/" { LEXER_DEBUG ("/"); BIN_OP_RETURN ('/', false, false); } "\\" { LEXER_DEBUG ("\\"); BIN_OP_RETURN (LEFTDIV, false, false); } ";" { LEXER_DEBUG (";"); BIN_OP_RETURN (';', true, true); } -"," { LEXER_DEBUG (","); BIN_OP_RETURN (',', true, ! lexer_flags.looking_at_object_index.front ()); } +"," { LEXER_DEBUG (","); BIN_OP_RETURN (',', true, ! curr_lexer->looking_at_object_index.front ()); } "^" { LEXER_DEBUG ("^"); BIN_OP_RETURN (POW, false, false); } "**" { LEXER_DEBUG ("**"); XBIN_OP_RETURN (POW, false, false); } "=" { LEXER_DEBUG ("="); BIN_OP_RETURN ('=', true, false); } @@ -966,14 +865,14 @@ // is current (so that we can pop it off the stack when we find // the matching close paren). - lexer_flags.looking_at_object_index.push_front - (lexer_flags.looking_for_object_index); - - lexer_flags.looking_at_indirect_ref = false; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; - - nesting_level.paren (); + curr_lexer->looking_at_object_index.push_front + (curr_lexer->looking_for_object_index); + + curr_lexer->looking_at_indirect_ref = false; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; + + curr_lexer->nesting_level.paren (); promptflag--; TOK_RETURN ('('); @@ -982,22 +881,22 @@ ")" { LEXER_DEBUG (")"); - nesting_level.remove (); - current_input_column++; - - lexer_flags.looking_at_object_index.pop_front (); - - lexer_flags.quote_is_transpose = true; - lexer_flags.convert_spaces_to_comma - = (nesting_level.is_bracket_or_brace () - && ! lexer_flags.looking_at_anon_fcn_args); - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; - - if (lexer_flags.looking_at_anon_fcn_args) - lexer_flags.looking_at_anon_fcn_args = false; - - do_comma_insert_check (); + curr_lexer->nesting_level.remove (); + curr_lexer->current_input_column++; + + curr_lexer->looking_at_object_index.pop_front (); + + curr_lexer->quote_is_transpose = true; + curr_lexer->convert_spaces_to_comma + = (curr_lexer->nesting_level.is_bracket_or_brace () + && ! curr_lexer->looking_at_anon_fcn_args); + curr_lexer->looking_for_object_index = true; + curr_lexer->at_beginning_of_statement = false; + + if (curr_lexer->looking_at_anon_fcn_args) + curr_lexer->looking_at_anon_fcn_args = false; + + curr_lexer->do_comma_insert_check (); COUNT_TOK_AND_RETURN (')'); } @@ -1005,8 +904,8 @@ "." { LEXER_DEBUG ("."); - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; TOK_RETURN ('.'); } @@ -1031,21 +930,21 @@ \{{S}* { LEXER_DEBUG ("\\{{S}*"); - nesting_level.brace (); - - lexer_flags.looking_at_object_index.push_front - (lexer_flags.looking_for_object_index); - - current_input_column += yyleng; - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; + curr_lexer->nesting_level.brace (); + + curr_lexer->looking_at_object_index.push_front + (curr_lexer->looking_for_object_index); + + curr_lexer->current_input_column += yyleng; + curr_lexer->quote_is_transpose = false; + curr_lexer->convert_spaces_to_comma = true; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; promptflag--; - eat_whitespace (); - - lexer_flags.braceflag++; + curr_lexer->eat_whitespace (); + + curr_lexer->braceflag++; BEGIN (MATRIX_START); COUNT_TOK_AND_RETURN ('{'); } @@ -1053,12 +952,12 @@ "}" { LEXER_DEBUG ("}"); - lexer_flags.looking_at_object_index.pop_front (); - - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; - - nesting_level.remove (); + curr_lexer->looking_at_object_index.pop_front (); + + curr_lexer->looking_for_object_index = true; + curr_lexer->at_beginning_of_statement = false; + + curr_lexer->nesting_level.remove (); TOK_RETURN ('}'); } @@ -1070,17 +969,17 @@ . { LEXER_DEBUG ("."); - xunput (yytext[0], yytext); - - int c = text_yyinput (); + curr_lexer->xunput (yytext[0]); + + int c = curr_lexer->text_yyinput (); if (c != EOF) { - current_input_column++; + curr_lexer->current_input_column++; error ("invalid character '%s' (ASCII %d) near line %d, column %d", undo_string_escape (static_cast<char> (c)), c, - input_line_number, current_input_column); + curr_lexer->input_line_number, curr_lexer->current_input_column); return LEXICAL_ERROR; } @@ -1090,85 +989,6 @@ %% -// GAG. -// -// If we're reading a matrix and the next character is '[', make sure -// that we insert a comma ahead of it. - -void -do_comma_insert_check (void) -{ - int spc_gobbled = eat_continuation (); - - int c = text_yyinput (); - - xunput (c, yytext); - - if (spc_gobbled) - xunput (' ', yytext); - - lexer_flags.do_comma_insert = (! lexer_flags.looking_at_object_index.front () - && lexer_flags.bracketflag && c == '['); -} - -// Fix things up for errors or interrupts. The parser is never called -// recursively, so it is always safe to reinitialize its state before -// doing any parsing. - -void -reset_parser (void) -{ - // Start off on the right foot. - BEGIN (INITIAL); - - parser_end_of_input = false; - - parser_symtab_context.clear (); - - // We do want a prompt by default. - promptflag = 1; - - // We are not in a block comment. - block_comment_nesting_level = 0; - - // Error may have occurred inside some brackets, braces, or parentheses. - nesting_level.clear (); - - // Clear out the stack of token info used to track line and column - // numbers. - while (! token_stack.empty ()) - { - delete token_stack.top (); - token_stack.pop (); - } - - // Can be reset by defining a function. - if (! (reading_script_file || reading_fcn_file || reading_classdef_file)) - { - current_input_column = 1; - input_line_number = command_editor::current_command_number (); - } - - // Only ask for input from stdin if we are expecting interactive - // input. - - if (! quitting_gracefully - && (interactive || forced_interactive) - && ! (reading_fcn_file - || reading_classdef_file - || reading_script_file - || get_input_from_eval_string - || input_from_startup_file)) - yyrestart (stdin); - - // Clear the buffer for help text. - while (! help_buf.empty ()) - help_buf.pop (); - - // Reset other flags. - lexer_flags.init (); -} - static void display_character (char c) { @@ -1315,10 +1135,376 @@ } } -static int -text_yyinput (void) +void +cleanup_parser (void) +{ +} + +// Return 1 if the given character matches any character in the given +// string. + +static bool +match_any (char c, const char *s) +{ + char tmp; + while ((tmp = *s++) != '\0') + { + if (c == tmp) + return true; + } + return false; +} + +// Given information about the spacing surrounding an operator, +// return 1 if it looks like it should be treated as a binary +// operator. For example, +// +// [ 1 + 2 ] or [ 1+ 2] or [ 1+2 ] ==> binary +// +// [ 1 +2 ] ==> unary + +static bool +looks_like_bin_op (bool spc_prev, int next_char) +{ + bool spc_next = (next_char == ' ' || next_char == '\t'); + + return ((spc_prev && spc_next) || ! spc_prev); +} + +bool +is_keyword (const std::string& s) +{ + // Parsing function names like "set.property_name" inside + // classdef-style class definitions is simplified by handling the + // "set" and "get" portions of the names using the same mechanism as + // is used for keywords. However, they are not really keywords in + // the language, so omit them from the list of possible keywords. + + return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0 + && ! (s == "set" || s == "get")); +} + +DEFUN (iskeyword, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} iskeyword ()\n\ +@deftypefnx {Built-in Function} {} iskeyword (@var{name})\n\ +Return true if @var{name} is an Octave keyword. If @var{name}\n\ +is omitted, return a list of keywords.\n\ +@seealso{isvarname, exist}\n\ +@end deftypefn") +{ + octave_value retval; + + int argc = args.length () + 1; + + string_vector argv = args.make_argv ("iskeyword"); + + if (error_state) + return retval; + + if (argc == 1) + { + // Neither set and get are keywords. See the note in the + // is_keyword function for additional details. + + string_vector lst (TOTAL_KEYWORDS); + + int j = 0; + + for (int i = 0; i < TOTAL_KEYWORDS; i++) + { + std::string tmp = wordlist[i].name; + + if (! (tmp == "set" || tmp == "get")) + lst[j++] = tmp; + } + + lst.resize (j); + + retval = Cell (lst.sort ()); + } + else if (argc == 2) + { + retval = is_keyword (argv[1]); + } + else + print_usage (); + + return retval; +} + +/* + +%!assert (iskeyword ("for")) +%!assert (iskeyword ("fort"), false) +%!assert (iskeyword ("fft"), false) + +*/ + +// Used to delete trailing white space from tokens. + +static std::string +strip_trailing_whitespace (char *s) +{ + std::string retval = s; + + size_t pos = retval.find_first_of (" \t"); + + if (pos != std::string::npos) + retval.resize (pos); + + return retval; +} + +DEFUN (__display_tokens__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __display_tokens__ ()\n\ +Query or set the internal variable that determines whether Octave's\n\ +lexer displays tokens as they are read.\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (display_tokens); +} + +DEFUN (__token_count__, , , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __token_count__ ()\n\ +Number of language tokens processed since Octave startup.\n\ +@end deftypefn") +{ + return octave_value (Vtoken_count); +} + +DEFUN (__lexer_debug_flag__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val}))\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + retval = set_internal_variable (lexer_debug_flag, args, nargout, + "__lexer_debug_flag__"); + + return retval; +} + +class +flex_stream_reader : public stream_reader +{ +public: + flex_stream_reader (lexical_feedback *l, char *buf_arg) + : stream_reader (), lexer (l), buf (buf_arg) + { } + + int getc (void) { return lexer->text_yyinput (); } + int ungetc (int c) { lexer->xunput (c, buf); return 0; } + +private: + + // No copying! + + flex_stream_reader (const flex_stream_reader&); + + flex_stream_reader& operator = (const flex_stream_reader&); + + lexical_feedback *lexer; + + char *buf; +}; + +lexical_feedback::~lexical_feedback (void) { - int c = yyinput (); + // Clear out the stack of token info used to track line and + // column numbers. + + while (! token_stack.empty ()) + { + delete token_stack.top (); + token_stack.pop (); + } + + yylex_destroy (scanner); +} + +void +lexical_feedback::init (void) +{ + // The closest paren, brace, or bracket nesting is not an object + // index. + looking_at_object_index.push_front (false); + + yylex_init (&scanner); + + // Make lexical_feedback object available through yyextra in + // flex-generated lexer. + yyset_extra (this, scanner); +} + +// Inside Flex-generated functions, yyg is the scanner cast to its real +// type. The BEGIN macro uses yyg and we want to use that in +// lexical_feedback member functions. If we could set the start state +// by calling a function instead of using the BEGIN macro, we could +// eliminate the OCTAVE_YYG macro. + +#define OCTAVE_YYG \ + struct yyguts_t *yyg = static_cast<struct yyguts_t*> (scanner) + +void +lexical_feedback::reset (void) +{ + OCTAVE_YYG; + + // Start off on the right foot. + BEGIN (INITIAL); + + parser_symtab_context.clear (); + + // We do want a prompt by default. + promptflag = 1; + + // Only ask for input from stdin if we are expecting interactive + // input. + + if (! quitting_gracefully + && (interactive || forced_interactive) + && ! (reading_fcn_file + || reading_classdef_file + || reading_script_file + || get_input_from_eval_string + || input_from_startup_file)) + yyrestart (stdin, scanner); + + // Clear the buffer for help text. + while (! help_buf.empty ()) + help_buf.pop (); +} + +void +lexical_feedback::prep_for_script_file (void) +{ + OCTAVE_YYG; + + BEGIN (SCRIPT_FILE_BEGIN); +} + +void +lexical_feedback::prep_for_function_file (void) +{ + OCTAVE_YYG; + + BEGIN (FUNCTION_FILE_BEGIN); +} + +void +lexical_feedback::prep_for_classdef_file (void) +{ + OCTAVE_YYG; + + BEGIN (CLASSDEF_FILE_BEGIN); +} + +int +lexical_feedback::octave_read (char *buf, unsigned max_size) +{ + static const char * const eol = "\n"; + static std::string input_buf; + static const char *pos = 0; + static size_t chars_left = 0; + static bool eof = false; + + int status = 0; + + if (chars_left == 0) + { + pos = 0; + + input_buf = get_user_input (eof); + + chars_left = input_buf.length (); + + pos = input_buf.c_str (); + } + + if (chars_left > 0) + { + size_t len = max_size > chars_left ? chars_left : max_size; + assert (len > 0); + + memcpy (buf, pos, len); + + chars_left -= len; + pos += len; + + // Make sure input ends with a new line character. + if (chars_left == 0 && buf[len-1] != '\n') + { + if (len < max_size) + { + // There is enough room to plug the newline character in + // the buffer. + buf[len++] = '\n'; + } + else + { + // There isn't enough room to plug the newline character + // in the buffer so make sure it is returned on the next + // octave_read call. + pos = eol; + chars_left = 1; + } + } + + status = len; + } + else + { + status = YY_NULL; + + if (! eof) + fatal_error ("octave_read () in flex scanner failed"); + } + + return status; +} + +char * +lexical_feedback::flex_yytext (void) +{ + return yyget_text (scanner); +} + +int +lexical_feedback::flex_yyleng (void) +{ + return yyget_leng (scanner); +} + +// GAG. +// +// If we're reading a matrix and the next character is '[', make sure +// that we insert a comma ahead of it. + +void +lexical_feedback::do_comma_insert_check (void) +{ + bool spc_gobbled = (eat_continuation () != lexical_feedback::NO_WHITESPACE); + + int c = text_yyinput (); + + xunput (c); + + if (spc_gobbled) + xunput (' '); + + do_comma_insert = (! looking_at_object_index.front () + && bracketflag && c == '['); +} + +int +lexical_feedback::text_yyinput (void) +{ + int c = yyinput (scanner); if (lexer_debug_flag) { @@ -1331,7 +1517,7 @@ if (c == '\r') { - c = yyinput (); + c = yyinput (scanner); if (lexer_debug_flag) { @@ -1342,7 +1528,7 @@ if (c != '\n') { - xunput (c, yytext); + xunput (c); c = '\n'; } } @@ -1353,8 +1539,8 @@ return c; } -static void -xunput (char c, char *buf) +void +lexical_feedback::xunput (char c, char *buf) { if (lexer_debug_flag) { @@ -1366,14 +1552,22 @@ if (c == '\n') input_line_number--; - yyunput (c, buf); + yyunput (c, buf, scanner); +} + +void +lexical_feedback::xunput (char c) +{ + char *yytxt = flex_yytext (); + + xunput (c, yytxt); } // If we read some newlines, we need figure out what column we're // really looking at. -static void -fixup_column_count (char *s) +void +lexical_feedback::fixup_column_count (char *s) { char c; while ((c = *s++) != '\0') @@ -1388,89 +1582,13 @@ } } -// Include these so that we don't have to link to libfl.a. - -int -yywrap (void) -{ - return 1; -} - -// Tell us all what the current buffer is. - -YY_BUFFER_STATE -current_buffer (void) -{ - return YY_CURRENT_BUFFER; -} - -// Create a new buffer. - -YY_BUFFER_STATE -create_buffer (FILE *f) -{ - return yy_create_buffer (f, YY_BUF_SIZE); -} - -// Start reading a new buffer. - -void -switch_to_buffer (YY_BUFFER_STATE buf) -{ - yy_switch_to_buffer (buf); -} - -// Delete a buffer. - -void -delete_buffer (YY_BUFFER_STATE buf) -{ - yy_delete_buffer (buf); - - // Prevent invalid yyin from being used by yyrestart. - if (! current_buffer ()) - yyin = 0; -} - -// Delete all buffers from the stack. -void -clear_all_buffers (void) -{ - while (current_buffer ()) - octave_pop_buffer_state (); -} - -void -cleanup_parser (void) -{ - reset_parser (); - - clear_all_buffers (); -} - -// Restore a buffer (for unwind-prot). - -void -restore_input_buffer (void *buf) -{ - switch_to_buffer (static_cast<YY_BUFFER_STATE> (buf)); -} - -// Delete a buffer (for unwind-prot). - -void -delete_input_buffer (void *buf) -{ - delete_buffer (static_cast<YY_BUFFER_STATE> (buf)); -} - -static bool -inside_any_object_index (void) +bool +lexical_feedback::inside_any_object_index (void) { bool retval = false; - for (std::list<bool>::const_iterator i = lexer_flags.looking_at_object_index.begin (); - i != lexer_flags.looking_at_object_index.end (); i++) + for (std::list<bool>::const_iterator i = looking_at_object_index.begin (); + i != looking_at_object_index.end (); i++) { if (*i) { @@ -1484,8 +1602,8 @@ // Handle keywords. Return -1 if the keyword should be ignored. -static int -is_keyword_token (const std::string& s) +int +lexical_feedback::is_keyword_token (const std::string& s) { int l = input_line_number; int c = current_input_column; @@ -1496,7 +1614,7 @@ if (kw) { - yylval.tok_val = 0; + token *tok_val = 0; switch (kw->kw_id) { @@ -1507,7 +1625,7 @@ case otherwise_kw: case return_kw: case unwind_protect_cleanup_kw: - lexer_flags.at_beginning_of_statement = true; + at_beginning_of_statement = true; break; case static_kw: @@ -1536,78 +1654,78 @@ case end_kw: if (inside_any_object_index () || (! reading_classdef_file - && (lexer_flags.defining_func - && ! (lexer_flags.looking_at_return_list - || lexer_flags.parsed_function_name.top ())))) + && (defining_func + && ! (looking_at_return_list + || parsed_function_name.top ())))) return 0; - yylval.tok_val = new token (token::simple_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::simple_end, l, c); + at_beginning_of_statement = true; break; case end_try_catch_kw: - yylval.tok_val = new token (token::try_catch_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::try_catch_end, l, c); + at_beginning_of_statement = true; break; case end_unwind_protect_kw: - yylval.tok_val = new token (token::unwind_protect_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::unwind_protect_end, l, c); + at_beginning_of_statement = true; break; case endfor_kw: - yylval.tok_val = new token (token::for_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::for_end, l, c); + at_beginning_of_statement = true; break; case endfunction_kw: - yylval.tok_val = new token (token::function_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::function_end, l, c); + at_beginning_of_statement = true; break; case endif_kw: - yylval.tok_val = new token (token::if_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::if_end, l, c); + at_beginning_of_statement = true; break; case endparfor_kw: - yylval.tok_val = new token (token::parfor_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::parfor_end, l, c); + at_beginning_of_statement = true; break; case endswitch_kw: - yylval.tok_val = new token (token::switch_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::switch_end, l, c); + at_beginning_of_statement = true; break; case endwhile_kw: - yylval.tok_val = new token (token::while_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::while_end, l, c); + at_beginning_of_statement = true; break; case endclassdef_kw: - yylval.tok_val = new token (token::classdef_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::classdef_end, l, c); + at_beginning_of_statement = true; break; case endenumeration_kw: - yylval.tok_val = new token (token::enumeration_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::enumeration_end, l, c); + at_beginning_of_statement = true; break; case endevents_kw: - yylval.tok_val = new token (token::events_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::events_end, l, c); + at_beginning_of_statement = true; break; case endmethods_kw: - yylval.tok_val = new token (token::methods_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::methods_end, l, c); + at_beginning_of_statement = true; break; case endproperties_kw: - yylval.tok_val = new token (token::properties_end, l, c); - lexer_flags.at_beginning_of_statement = true; + tok_val = new token (token::properties_end, l, c); + at_beginning_of_statement = true; break; @@ -1615,18 +1733,18 @@ case parfor_kw: case while_kw: promptflag--; - lexer_flags.looping++; + looping++; break; case do_kw: - lexer_flags.at_beginning_of_statement = true; + at_beginning_of_statement = true; promptflag--; - lexer_flags.looping++; + looping++; break; case try_kw: case unwind_protect_kw: - lexer_flags.at_beginning_of_statement = true; + at_beginning_of_statement = true; promptflag--; break; @@ -1639,7 +1757,7 @@ case set_kw: // 'get' and 'set' are keywords in classdef method // declarations. - if (! lexer_flags.maybe_classdef_get_set_method) + if (! maybe_classdef_get_set_method) return 0; break; @@ -1649,7 +1767,7 @@ case properties_kw: // 'properties', 'methods' and 'events' are keywords for // classdef blocks. - if (! lexer_flags.parsing_classdef) + if (! parsing_classdef) return 0; // fall through ... @@ -1661,8 +1779,8 @@ case function_kw: promptflag--; - lexer_flags.defining_func++; - lexer_flags.parsed_function_name.push (false); + defining_func++; + parsed_function_name.push (false); if (! (reading_fcn_file || reading_script_file || reading_classdef_file)) @@ -1674,24 +1792,24 @@ if ((reading_fcn_file || reading_script_file || reading_classdef_file) && ! curr_fcn_file_full_name.empty ()) - yylval.tok_val = new token (curr_fcn_file_full_name, l, c); + tok_val = new token (curr_fcn_file_full_name, l, c); else - yylval.tok_val = new token ("stdin", l, c); + tok_val = new token ("stdin", l, c); } break; case magic_line_kw: - yylval.tok_val = new token (static_cast<double> (l), "", l, c); + tok_val = new token (static_cast<double> (l), "", l, c); break; default: panic_impossible (); } - if (! yylval.tok_val) - yylval.tok_val = new token (l, c); - - token_stack.push (yylval.tok_val); + if (! tok_val) + tok_val = new token (l, c); + + push_token (tok_val); return kw->tok; } @@ -1699,16 +1817,16 @@ return 0; } -static bool -is_variable (const std::string& name) +bool +lexical_feedback::is_variable (const std::string& name) { return (symbol_table::is_variable (name) - || (lexer_flags.pending_local_variables.find (name) - != lexer_flags.pending_local_variables.end ())); + || (pending_local_variables.find (name) + != pending_local_variables.end ())); } -static std::string -grab_block_comment (stream_reader& reader, bool& eof) +std::string +lexical_feedback::grab_block_comment (stream_reader& reader, bool& eof) { std::string buf; @@ -1814,8 +1932,8 @@ } std::string -grab_comment_block (stream_reader& reader, bool at_bol, - bool& eof) +lexical_feedback::grab_comment_block (stream_reader& reader, bool at_bol, + bool& eof) { std::string buf; @@ -1953,29 +2071,11 @@ return buf; } -class -flex_stream_reader : public stream_reader +int +lexical_feedback::process_comment (bool start_in_block, bool& eof) { -public: - flex_stream_reader (char *buf_arg) : stream_reader (), buf (buf_arg) { } - - int getc (void) { return ::text_yyinput (); } - int ungetc (int c) { ::xunput (c, buf); return 0; } - -private: - - // No copying! - - flex_stream_reader (const flex_stream_reader&); - - flex_stream_reader& operator = (const flex_stream_reader&); - - char *buf; -}; - -static int -process_comment (bool start_in_block, bool& eof) -{ + OCTAVE_YYG; + eof = false; std::string help_txt; @@ -1983,7 +2083,8 @@ if (! help_buf.empty ()) help_txt = help_buf.top (); - flex_stream_reader flex_reader (yytext); + char *yytxt = flex_yytext (); + flex_stream_reader flex_reader (this, yytxt); // process_comment is only supposed to be called when we are not // initially looking at a block comment. @@ -2006,9 +2107,9 @@ octave_comment_buffer::append (txt); current_input_column = 1; - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.at_beginning_of_statement = true; + quote_is_transpose = false; + convert_spaces_to_comma = true; + at_beginning_of_statement = true; if (YY_START == COMMAND_START) BEGIN (INITIAL); @@ -2021,42 +2122,11 @@ return 0; } -// Return 1 if the given character matches any character in the given -// string. - -static bool -match_any (char c, const char *s) -{ - char tmp; - while ((tmp = *s++) != '\0') - { - if (c == tmp) - return true; - } - return false; -} - -// Given information about the spacing surrounding an operator, -// return 1 if it looks like it should be treated as a binary -// operator. For example, -// -// [ 1 + 2 ] or [ 1+ 2] or [ 1+2 ] ==> binary -// -// [ 1 +2 ] ==> unary - -static bool -looks_like_bin_op (bool spc_prev, int next_char) -{ - bool spc_next = (next_char == ' ' || next_char == '\t'); - - return ((spc_prev && spc_next) || ! spc_prev); -} - // Recognize separators. If the separator is a CRLF pair, it is // replaced by a single LF. -static bool -next_token_is_sep_op (void) +bool +lexical_feedback::next_token_is_sep_op (void) { bool retval = false; @@ -2064,7 +2134,7 @@ retval = match_any (c, ",;\n]"); - xunput (c, yytext); + xunput (c); return retval; } @@ -2072,8 +2142,8 @@ // Try to determine if the next token should be treated as a postfix // unary operator. This is ugly, but it seems to do the right thing. -static bool -next_token_is_postfix_unary_op (bool spc_prev) +bool +lexical_feedback::next_token_is_postfix_unary_op (bool spc_prev) { bool un_op = false; @@ -2087,22 +2157,22 @@ { int c1 = text_yyinput (); un_op = (c1 == '\''); - xunput (c1, yytext); + xunput (c1); } else if (c0 == '+') { int c1 = text_yyinput (); un_op = (c1 == '+'); - xunput (c1, yytext); + xunput (c1); } else if (c0 == '-') { int c1 = text_yyinput (); un_op = (c1 == '-'); - xunput (c1, yytext); + xunput (c1); } - xunput (c0, yytext); + xunput (c0); return un_op; } @@ -2119,8 +2189,8 @@ // (e.g., the characters '[' 'a' ' ' '+' '\' LFD 'b' ']') will be // parsed as a binary operator. -static bool -next_token_is_bin_op (bool spc_prev) +bool +lexical_feedback::next_token_is_bin_op (bool spc_prev) { bool bin_op = false; @@ -2151,7 +2221,7 @@ break; } - xunput (c1, yytext); + xunput (c1); } break; @@ -2175,7 +2245,7 @@ // A structure element reference is a binary op. bin_op = true; - xunput (c1, yytext); + xunput (c1); } break; @@ -2205,7 +2275,7 @@ if (c1 == '=') bin_op = true; - xunput (c1, yytext); + xunput (c1); } break; @@ -2213,30 +2283,15 @@ break; } - xunput (c0, yytext); + xunput (c0); return bin_op; } -// Used to delete trailing white space from tokens. - -static std::string -strip_trailing_whitespace (char *s) -{ - std::string retval = s; - - size_t pos = retval.find_first_of (" \t"); - - if (pos != std::string::npos) - retval.resize (pos); - - return retval; -} - // FIXME -- we need to handle block comments here. -static void -scan_for_comments (const char *text) +void +lexical_feedback::scan_for_comments (const char *text) { std::string comment_buf; @@ -2293,19 +2348,13 @@ } // Discard whitespace, including comments and continuations. -// -// Return value is logical OR of the following values: -// -// ATE_NOTHING : no spaces to eat -// ATE_SPACE_OR_TAB : space or tab in input -// ATE_NEWLINE : bare new line in input // FIXME -- we need to handle block comments here. -static yum_yum -eat_whitespace (void) +int +lexical_feedback::eat_whitespace (void) { - yum_yum retval = ATE_NOTHING; + int retval = lexical_feedback::NO_WHITESPACE; std::string comment_buf; @@ -2327,11 +2376,11 @@ comment_buf += static_cast<char> (c); beginning_of_comment = false; } - retval |= ATE_SPACE_OR_TAB; + retval |= lexical_feedback::SPACE_OR_TAB; break; case '\n': - retval |= ATE_NEWLINE; + retval |= lexical_feedback::NEWLINE; if (in_comment) { comment_buf += static_cast<char> (c); @@ -2404,7 +2453,7 @@ octave_comment_buffer::append (comment_buf); done: - xunput (c, yytext); + xunput (c); current_input_column--; return retval; } @@ -2415,23 +2464,25 @@ return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')); } -static void -handle_number (void) +void +lexical_feedback::handle_number (void) { double value = 0.0; int nread = 0; - if (looks_like_hex (yytext, strlen (yytext))) + char *yytxt = flex_yytext (); + + if (looks_like_hex (yytxt, strlen (yytxt))) { unsigned long ival; - nread = sscanf (yytext, "%lx", &ival); + nread = sscanf (yytxt, "%lx", &ival); value = static_cast<double> (ival); } else { - char *tmp = strsave (yytext); + char *tmp = strsave (yytxt); char *idx = strpbrk (tmp, "Dd"); @@ -2447,17 +2498,15 @@ assert (nread == 1); - lexer_flags.quote_is_transpose = true; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; - lexer_flags.at_beginning_of_statement = false; - - yylval.tok_val = new token (value, yytext, input_line_number, - current_input_column); - - token_stack.push (yylval.tok_val); - - current_input_column += yyleng; + quote_is_transpose = true; + convert_spaces_to_comma = true; + looking_for_object_index = false; + at_beginning_of_statement = false; + + push_token (new token (value, yytxt, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); do_comma_insert_check (); } @@ -2473,8 +2522,8 @@ // FIXME -- we need to handle block comments here. -static bool -have_continuation (bool trailing_comments_ok) +bool +lexical_feedback::have_continuation (bool trailing_comments_ok) { std::ostringstream buf; @@ -2543,7 +2592,7 @@ } } - xunput (c, yytext); + xunput (c); return false; cleanup: @@ -2552,7 +2601,7 @@ int len = s.length (); while (len--) - xunput (s[len], yytext); + xunput (s[len]); return false; } @@ -2561,8 +2610,8 @@ // continuation. If so, this eats it, up to and including the new // line character. -static bool -have_ellipsis_continuation (bool trailing_comments_ok) +bool +lexical_feedback::have_ellipsis_continuation (bool trailing_comments_ok) { char c1 = text_yyinput (); if (c1 == '.') @@ -2572,25 +2621,23 @@ return true; else { - xunput (c2, yytext); - xunput (c1, yytext); + xunput (c2); + xunput (c1); } } else - xunput (c1, yytext); + xunput (c1); return false; } // See if we have a continuation line. If so, eat it and the leading // whitespace on the next line. -// -// Return value is the same as described for eat_whitespace(). - -static yum_yum -eat_continuation (void) + +int +lexical_feedback::eat_continuation (void) { - int retval = ATE_NOTHING; + int retval = lexical_feedback::NO_WHITESPACE; int c = text_yyinput (); @@ -2598,13 +2645,13 @@ || (c == '\\' && have_continuation ())) retval = eat_whitespace (); else - xunput (c, yytext); + xunput (c); return retval; } -static int -handle_string (char delim) +int +lexical_feedback::handle_string (char delim) { std::ostringstream buf; @@ -2661,26 +2708,25 @@ else { std::string s; - xunput (c, yytext); + xunput (c); if (delim == '\'') s = buf.str (); else s = do_string_escapes (buf.str ()); - lexer_flags.quote_is_transpose = true; - lexer_flags.convert_spaces_to_comma = true; - - yylval.tok_val = new token (s, bos_line, bos_col); - token_stack.push (yylval.tok_val); + quote_is_transpose = true; + convert_spaces_to_comma = true; + + push_token (new token (s, bos_line, bos_col)); if (delim == '"') gripe_matlab_incompatible ("\" used as string delimiter"); else if (delim == '\'') gripe_single_quote_string (); - lexer_flags.looking_for_object_index = true; - lexer_flags.at_beginning_of_statement = false; + looking_for_object_index = true; + at_beginning_of_statement = false; return delim == '"' ? DQ_STRING : SQ_STRING; } @@ -2697,8 +2743,8 @@ return LEXICAL_ERROR; } -static bool -next_token_is_assign_op (void) +bool +lexical_feedback::next_token_is_assign_op (void) { bool retval = false; @@ -2709,7 +2755,7 @@ case '=': { int c1 = text_yyinput (); - xunput (c1, yytext); + xunput (c1); if (c1 != '=') retval = true; } @@ -2724,7 +2770,7 @@ case '|': { int c1 = text_yyinput (); - xunput (c1, yytext); + xunput (c1); if (c1 == '=') retval = true; } @@ -2736,11 +2782,11 @@ if (match_any (c1, "+-*/\\")) { int c2 = text_yyinput (); - xunput (c2, yytext); + xunput (c2); if (c2 == '=') retval = true; } - xunput (c1, yytext); + xunput (c1); } break; @@ -2750,11 +2796,11 @@ if (c1 == '>') { int c2 = text_yyinput (); - xunput (c2, yytext); + xunput (c2); if (c2 == '=') retval = true; } - xunput (c1, yytext); + xunput (c1); } break; @@ -2764,11 +2810,11 @@ if (c1 == '<') { int c2 = text_yyinput (); - xunput (c2, yytext); + xunput (c2); if (c2 == '=') retval = true; } - xunput (c1, yytext); + xunput (c1); } break; @@ -2776,22 +2822,24 @@ break; } - xunput (c0, yytext); + xunput (c0); return retval; } -static bool -next_token_is_index_op (void) +bool +lexical_feedback::next_token_is_index_op (void) { int c = text_yyinput (); - xunput (c, yytext); + xunput (c); return c == '(' || c == '{'; } -static int -handle_close_bracket (bool spc_gobbled, int bracket_type) +int +lexical_feedback::handle_close_bracket (bool spc_gobbled, int bracket_type) { + OCTAVE_YYG; + int retval = bracket_type; if (! nesting_level.none ()) @@ -2799,27 +2847,27 @@ nesting_level.remove (); if (bracket_type == ']') - lexer_flags.bracketflag--; + bracketflag--; else if (bracket_type == '}') - lexer_flags.braceflag--; + braceflag--; else panic_impossible (); } - if (lexer_flags.bracketflag == 0 && lexer_flags.braceflag == 0) + if (bracketflag == 0 && braceflag == 0) BEGIN (INITIAL); if (bracket_type == ']' && next_token_is_assign_op () - && ! lexer_flags.looking_at_return_list) + && ! looking_at_return_list) { retval = CLOSE_BRACE; } - else if ((lexer_flags.bracketflag || lexer_flags.braceflag) - && lexer_flags.convert_spaces_to_comma + else if ((bracketflag || braceflag) + && convert_spaces_to_comma && (nesting_level.is_bracket () || (nesting_level.is_brace () - && ! lexer_flags.looking_at_object_index.front ()))) + && ! looking_at_object_index.front ()))) { bool index_op = next_token_is_index_op (); @@ -2843,24 +2891,24 @@ { maybe_warn_separator_insert (','); - xunput (',', yytext); + xunput (','); return retval; } } } - lexer_flags.quote_is_transpose = true; - lexer_flags.convert_spaces_to_comma = true; + quote_is_transpose = true; + convert_spaces_to_comma = true; return retval; } -static void -maybe_unput_comma (int spc_gobbled) +void +lexical_feedback::maybe_unput_comma (int spc_gobbled) { if (nesting_level.is_bracket () || (nesting_level.is_brace () - && ! lexer_flags.looking_at_object_index.front ())) + && ! looking_at_object_index.front ())) { int bin_op = next_token_is_bin_op (spc_gobbled); @@ -2869,8 +2917,8 @@ int c1 = text_yyinput (); int c2 = text_yyinput (); - xunput (c2, yytext); - xunput (c1, yytext); + xunput (c2); + xunput (c1); int sep_op = next_token_is_sep_op (); @@ -2890,12 +2938,12 @@ maybe_warn_separator_insert (','); - xunput (',', yytext); + xunput (','); } } -static bool -next_token_can_follow_bin_op (void) +bool +lexical_feedback::next_token_can_follow_bin_op (void) { std::stack<char> buf; @@ -2915,7 +2963,7 @@ // Restore input. while (! buf.empty ()) { - xunput (buf.top (), yytext); + xunput (buf.top ()); buf.pop (); } @@ -2936,8 +2984,8 @@ || tok == "NaN" || tok == "nan"); } -static bool -looks_like_command_arg (void) +bool +lexical_feedback::looks_like_command_arg (void) { bool retval = true; @@ -2958,12 +3006,12 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } else retval = false; - xunput (c1, yytext); + xunput (c1); } break; @@ -3013,12 +3061,12 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } break; } - xunput (c1, yytext); + xunput (c1); } break; @@ -3033,7 +3081,7 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c1, yytext); + xunput (c1); } break; @@ -3054,13 +3102,13 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c3, yytext); + xunput (c3); } else if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } else if (! match_any (c1, ",;\n") && (! isdigit (c1) && c1 != ' ' && c1 != '\t' @@ -3071,7 +3119,7 @@ retval = false; } - xunput (c1, yytext); + xunput (c1); } break; @@ -3090,13 +3138,13 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') && next_token_can_follow_bin_op ()) retval = false; - xunput (c1, yytext); + xunput (c1); } break; @@ -3114,13 +3162,13 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') && next_token_can_follow_bin_op ()) retval = false; - xunput (c1, yytext); + xunput (c1); } break; @@ -3139,13 +3187,13 @@ && next_token_can_follow_bin_op ()) retval = false; - xunput (c2, yytext); + xunput (c2); } else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') && next_token_can_follow_bin_op ()) retval = false; - xunput (c1, yytext); + xunput (c1); } break; @@ -3153,17 +3201,18 @@ break; } - xunput (c0, yytext); + xunput (c0); return retval; } -static int -handle_superclass_identifier (void) +int +lexical_feedback::handle_superclass_identifier (void) { - int c = yytext[yyleng-1]; - - std::string meth = strip_trailing_whitespace (yytext); + char *yytxt = flex_yytext (); + int c = yytxt[flex_yyleng()-1]; + + std::string meth = strip_trailing_whitespace (yytxt); int cont_is_spc = eat_continuation (); @@ -3189,23 +3238,23 @@ return LEXICAL_ERROR; } - yylval.tok_val = new token (meth, pkg, cls, input_line_number, - current_input_column); - token_stack.push (yylval.tok_val); + push_token (new token (meth, pkg, cls, input_line_number, + current_input_column)); do_comma_insert_check (); maybe_unput_comma (spc_gobbled); - current_input_column += yyleng; + current_input_column += flex_yyleng (); return SUPERCLASSREF; } -static int -handle_meta_identifier (void) +int +lexical_feedback::handle_meta_identifier (void) { - int c = yytext[yyleng-1]; - - std::string cls = strip_trailing_whitespace (yytext).substr (1); + char *yytxt = flex_yytext (); + int c = yytxt[flex_yyleng()-1]; + + std::string cls = strip_trailing_whitespace (yytxt).substr (1); int cont_is_spc = eat_continuation (); @@ -3226,13 +3275,12 @@ return LEXICAL_ERROR; } - yylval.tok_val = new token (pkg, cls, input_line_number, - current_input_column); - token_stack.push (yylval.tok_val); + push_token (new token (pkg, cls, input_line_number, + current_input_column)); do_comma_insert_check (); maybe_unput_comma (spc_gobbled); - current_input_column += yyleng; + current_input_column += flex_yyleng (); return METAQUERY; } @@ -3241,16 +3289,20 @@ // an identifier. Handles keywords. Return -1 if the identifier // should be ignored. -static int -handle_identifier (void) +int +lexical_feedback::handle_identifier (void) { - bool at_bos = lexer_flags.at_beginning_of_statement; - - std::string tok = strip_trailing_whitespace (yytext); - - int c = yytext[yyleng-1]; - - int cont_is_spc = eat_continuation (); + OCTAVE_YYG; + + bool at_bos = at_beginning_of_statement; + + char *yytxt = flex_yytext (); + + std::string tok = strip_trailing_whitespace (yytxt); + + int c = yytxt[flex_yyleng()-1]; + + bool cont_is_spc = (eat_continuation () != lexical_feedback::NO_WHITESPACE); int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); @@ -3259,30 +3311,28 @@ // a string that is also a valid identifier. But first, we have to // decide whether to insert a comma. - if (lexer_flags.looking_at_indirect_ref) + if (looking_at_indirect_ref) { do_comma_insert_check (); maybe_unput_comma (spc_gobbled); - yylval.tok_val = new token (tok, input_line_number, - current_input_column); - - token_stack.push (yylval.tok_val); - - lexer_flags.quote_is_transpose = true; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = true; - - current_input_column += yyleng; + push_token (new token (tok, input_line_number, + current_input_column)); + + quote_is_transpose = true; + convert_spaces_to_comma = true; + looking_for_object_index = true; + + current_input_column += flex_yyleng (); return STRUCT_ELT; } - lexer_flags.at_beginning_of_statement = false; + at_beginning_of_statement = false; // The is_keyword_token may reset - // lexer_flags.at_beginning_of_statement. For example, if it sees + // at_beginning_of_statement. For example, if it sees // an else token, then the next token is at the beginning of a // statement. @@ -3292,7 +3342,7 @@ // is already set. Otherwise, we won't be at the beginning of a // statement. - if (lexer_flags.looking_at_function_handle) + if (looking_at_function_handle) { if (kw_token) { @@ -3302,15 +3352,13 @@ } else { - yylval.tok_val = new token (tok, input_line_number, - current_input_column); - - token_stack.push (yylval.tok_val); - - current_input_column += yyleng; - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = true; + push_token (new token (tok, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + quote_is_transpose = false; + convert_spaces_to_comma = true; + looking_for_object_index = true; return FCN_HANDLE; } @@ -3323,10 +3371,10 @@ { if (kw_token >= 0) { - current_input_column += yyleng; - lexer_flags.quote_is_transpose = false; - lexer_flags.convert_spaces_to_comma = true; - lexer_flags.looking_for_object_index = false; + current_input_column += flex_yyleng (); + quote_is_transpose = false; + convert_spaces_to_comma = true; + looking_for_object_index = false; } return kw_token; @@ -3340,13 +3388,13 @@ if (c1 == '=') { int c2 = text_yyinput (); - xunput (c2, yytext); + xunput (c2); if (c2 != '=') next_tok_is_eq = true; } - xunput (c1, yytext); + xunput (c1); // Kluge alert. // @@ -3366,16 +3414,16 @@ BEGIN (COMMAND_START); } else if (next_tok_is_eq - || lexer_flags.looking_at_decl_list - || lexer_flags.looking_at_return_list - || (lexer_flags.looking_at_parameter_list - && ! lexer_flags.looking_at_initializer_expression)) + || looking_at_decl_list + || looking_at_return_list + || (looking_at_parameter_list + && ! looking_at_initializer_expression)) { symbol_table::force_variable (tok); } - else if (lexer_flags.looking_at_matrix_or_assign_lhs) + else if (looking_at_matrix_or_assign_lhs) { - lexer_flags.pending_local_variables.insert (tok); + pending_local_variables.insert (tok); } } @@ -3385,195 +3433,33 @@ if (tok == "end") tok = "__end__"; - yylval.tok_val = new token (&(symbol_table::insert (tok)), - input_line_number, current_input_column); - - token_stack.push (yylval.tok_val); + push_token (new token (&(symbol_table::insert (tok)), + input_line_number, current_input_column)); // After seeing an identifer, it is ok to convert spaces to a comma // (if needed). - lexer_flags.convert_spaces_to_comma = true; + convert_spaces_to_comma = true; if (! (next_tok_is_eq || YY_START == COMMAND_START)) { - lexer_flags.quote_is_transpose = true; + quote_is_transpose = true; do_comma_insert_check (); maybe_unput_comma (spc_gobbled); } - current_input_column += yyleng; + current_input_column += flex_yyleng (); if (tok != "__end__") - lexer_flags.looking_for_object_index = true; + looking_for_object_index = true; return NAME; } void -lexical_feedback::init (void) -{ - // Not initially defining a matrix list. - bracketflag = 0; - - // Not initially defining a cell array list. - braceflag = 0; - - // Not initially inside a loop or if statement. - looping = 0; - - // Not initially defining a function. - defining_func = 0; - - // Not parsing an object index. - while (! parsed_function_name.empty ()) - parsed_function_name.pop (); - - parsing_class_method = false; - - // Not initially defining a class with classdef. - maybe_classdef_get_set_method = false; - parsing_classdef = false; - parsing_classdef_get_method = false; - parsing_classdef_set_method = false; - - // Not initiallly looking at a function handle. - looking_at_function_handle = 0; - - // Not initiallly looking at an anonymous function argument list. - looking_at_anon_fcn_args = 0; - - // Not parsing a function return, parameter, or declaration list. - looking_at_return_list = false; - looking_at_parameter_list = false; - looking_at_decl_list = false; - - // Not looking at an argument list initializer expression. - looking_at_initializer_expression = false; - - // Not parsing a matrix or the left hand side of multi-value - // assignment statement. - looking_at_matrix_or_assign_lhs = false; - - // Not parsing an object index. - while (! looking_at_object_index.empty ()) - looking_at_object_index.pop_front (); - - looking_at_object_index.push_front (false); - - // Object index not possible until we've seen something. - looking_for_object_index = false; - - // Yes, we are at the beginning of a statement. - at_beginning_of_statement = true; - - // No need to do comma insert or convert spaces to comma at - // beginning of input. - convert_spaces_to_comma = true; - do_comma_insert = false; - - // Not initially looking at indirect references. - looking_at_indirect_ref = false; - - // Quote marks strings intially. - quote_is_transpose = false; - - // Set of identifiers that might be local variable names is empty. - pending_local_variables.clear (); -} - -bool -is_keyword (const std::string& s) -{ - // Parsing function names like "set.property_name" inside - // classdef-style class definitions is simplified by handling the - // "set" and "get" portions of the names using the same mechanism as - // is used for keywords. However, they are not really keywords in - // the language, so omit them from the list of possible keywords. - - return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0 - && ! (s == "set" || s == "get")); -} - -DEFUN (iskeyword, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} iskeyword ()\n\ -@deftypefnx {Built-in Function} {} iskeyword (@var{name})\n\ -Return true if @var{name} is an Octave keyword. If @var{name}\n\ -is omitted, return a list of keywords.\n\ -@seealso{isvarname, exist}\n\ -@end deftypefn") -{ - octave_value retval; - - int argc = args.length () + 1; - - string_vector argv = args.make_argv ("iskeyword"); - - if (error_state) - return retval; - - if (argc == 1) - { - // Neither set and get are keywords. See the note in the - // is_keyword function for additional details. - - string_vector lst (TOTAL_KEYWORDS); - - int j = 0; - - for (int i = 0; i < TOTAL_KEYWORDS; i++) - { - std::string tmp = wordlist[i].name; - - if (! (tmp == "set" || tmp == "get")) - lst[j++] = tmp; - } - - lst.resize (j); - - retval = Cell (lst.sort ()); - } - else if (argc == 2) - { - retval = is_keyword (argv[1]); - } - else - print_usage (); - - return retval; -} - -/* - -%!assert (iskeyword ("for")) -%!assert (iskeyword ("fort"), false) -%!assert (iskeyword ("fft"), false) - -*/ - -void -prep_lexer_for_script_file (void) -{ - BEGIN (SCRIPT_FILE_BEGIN); -} - -void -prep_lexer_for_function_file (void) -{ - BEGIN (FUNCTION_FILE_BEGIN); -} - -void -prep_lexer_for_classdef_file (void) -{ - BEGIN (CLASSDEF_FILE_BEGIN); -} - -static void -maybe_warn_separator_insert (char sep) +lexical_feedback::maybe_warn_separator_insert (char sep) { std::string nm = curr_fcn_file_full_name; @@ -3587,8 +3473,8 @@ sep, input_line_number, nm.c_str ()); } -static void -gripe_single_quote_string (void) +void +lexical_feedback::gripe_single_quote_string (void) { std::string nm = curr_fcn_file_full_name; @@ -3602,8 +3488,8 @@ input_line_number, nm.c_str ()); } -static void -gripe_matlab_incompatible (const std::string& msg) +void +lexical_feedback::gripe_matlab_incompatible (const std::string& msg) { std::string nm = curr_fcn_file_full_name; @@ -3617,21 +3503,21 @@ msg.c_str (), input_line_number, nm.c_str ()); } -static void -maybe_gripe_matlab_incompatible_comment (char c) +void +lexical_feedback::maybe_gripe_matlab_incompatible_comment (char c) { if (c == '#') gripe_matlab_incompatible ("# used as comment character"); } -static void -gripe_matlab_incompatible_continuation (void) +void +lexical_feedback::gripe_matlab_incompatible_continuation (void) { gripe_matlab_incompatible ("\\ used as line continuation marker"); } -static void -gripe_matlab_incompatible_operator (const std::string& op) +void +lexical_feedback::gripe_matlab_incompatible_operator (const std::string& op) { std::string t = op; int n = t.length (); @@ -3640,8 +3526,23 @@ gripe_matlab_incompatible (t + " used as operator"); } -static void -display_token (int tok) +void +lexical_feedback::push_token (token *tok) +{ + YYSTYPE *lval = yyget_lval (scanner); + lval->tok_val = tok; + token_stack.push (tok); +} + +token * +lexical_feedback::current_token (void) +{ + YYSTYPE *lval = yyget_lval (scanner); + return lval->tok_val; +} + +void +lexical_feedback::display_token (int tok) { switch (tok) { @@ -3693,16 +3594,24 @@ case NUM: case IMAG_NUM: - std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM") - << " [" << yylval.tok_val->number () << "]\n"; + { + token *tok_val = current_token (); + std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM") + << " [" << tok_val->number () << "]\n"; + } break; case STRUCT_ELT: - std::cerr << "STRUCT_ELT [" << yylval.tok_val->text () << "]\n"; break; + { + token *tok_val = current_token (); + std::cerr << "STRUCT_ELT [" << tok_val->text () << "]\n"; + } + break; case NAME: { - symbol_table::symbol_record *sr = yylval.tok_val->sym_rec (); + token *tok_val = current_token (); + symbol_table::symbol_record *sr = tok_val->sym_rec (); std::cerr << "NAME"; if (sr) std::cerr << " [" << sr->name () << "]"; @@ -3714,8 +3623,12 @@ case DQ_STRING: case SQ_STRING: - std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING") - << " [" << yylval.tok_val->text () << "]\n"; + { + token *tok_val = current_token (); + + std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING") + << " [" << tok_val->text () << "]\n"; + } break; case FOR: std::cerr << "FOR\n"; break; @@ -3768,11 +3681,11 @@ } static void -display_state (void) +display_state (int state) { std::cerr << "S: "; - switch (YY_START) + switch (state) { case INITIAL: std::cerr << "INITIAL" << std::endl; @@ -3804,46 +3717,25 @@ } } -static void -lexer_debug (const char *pattern, const char *text) +void +lexical_feedback::fatal_error (const char *msg) { + error (msg); + + OCTAVE_QUIT; + + yy_fatal_error (msg, scanner); +} + +void +lexical_feedback::lexer_debug (const char *pattern, const char *text) +{ + OCTAVE_YYG; + std::cerr << std::endl; - display_state (); + display_state (YY_START); std::cerr << "P: " << pattern << std::endl; std::cerr << "T: " << text << std::endl; } - -DEFUN (__display_tokens__, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} __display_tokens__ ()\n\ -Query or set the internal variable that determines whether Octave's\n\ -lexer displays tokens as they are read.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (display_tokens); -} - -DEFUN (__token_count__, , , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} __token_count__ ()\n\ -Number of language tokens processed since Octave startup.\n\ -@end deftypefn") -{ - return octave_value (Vtoken_count); -} - -DEFUN (__lexer_debug_flag__, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val}))\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value retval; - - retval = set_internal_variable (lexer_debug_flag, args, nargout, - "__lexer_debug_flag__"); - - return retval; -}
--- a/libinterp/parse-tree/oct-parse.yy +++ b/libinterp/parse-tree/oct-parse.yy @@ -79,6 +79,15 @@ #include "utils.h" #include "variables.h" +// oct-parse.h must be included after pt-all.h +#include <oct-parse.h> + +extern int octave_lex (YYSTYPE *, void *); + +// Global access to currently active lexer. +// FIXME -- to be removed after more parser+lexer refactoring. +lexical_feedback *CURR_LEXER = 0; + #if defined (GNULIB_NAMESPACE) // Calls to the following functions appear in the generated output from // Bison without the namespace tag. Redefine them so we will use them @@ -88,18 +97,9 @@ #define malloc GNULIB_NAMESPACE::malloc #endif -// The current input line number. -int input_line_number = 1; - -// The column of the current token. -int current_input_column = 1; - // Buffer for help text snagged from function files. std::stack<std::string> help_buf; -// Buffer for comments appearing before a function statement. -static std::string fcn_comment_header; - // TRUE means we are using readline. // (--no-line-editing) bool line_editing = true; @@ -110,297 +110,16 @@ // TRUE means input is coming from startup file. bool input_from_startup_file = false; -// = 0 currently outside any function. -// = 1 inside the primary function or a subfunction. -// > 1 means we are looking at a function definition that seems to be -// inside a function. Note that the function still might not be a -// nested function. -static int current_function_depth = 0; - -// A stack holding the nested function scopes being parsed. -// We don't use std::stack, because we want the clear method. Also, we -// must access one from the top -static std::vector<symbol_table::scope_id> function_scopes; - -// Maximum function depth detected. Just here to determine whether -// we have nested functions or just implicitly ended subfunctions. -static int max_function_depth = 0; - -// FALSE if we are still at the primary function. Subfunctions can -// only be declared inside function files. -static int parsing_subfunctions = false; - -// Have we found an explicit end to a function? -static bool endfunction_found = false; - // Keep track of symbol table information when parsing functions. symtab_context parser_symtab_context; -// Name of the current class when we are parsing class methods or -// constructors. -std::string current_class_name; - -// TRUE means we are in the process of autoloading a function. -static bool autoloading = false; - -// TRUE means the current function file was found in a relative path -// element. -static bool fcn_file_from_relative_lookup = false; - -// Pointer to the primary user function or user script function. -static octave_function *primary_fcn_ptr = 0; - -// Scope where we install all subfunctions and nested functions. Only -// used while reading function files. -static symbol_table::scope_id primary_fcn_scope; - -// Pointer to the classdef object we just parsed, if any. -static tree_classdef *classdef_object = 0; - // List of autoloads (function -> file mapping). static std::map<std::string, std::string> autoload_map; // Forward declarations for some functions defined at the bottom of // the file. -// Generic error messages. -static void -yyerror (const char *s); - -// Error mesages for mismatched end tokens. -static void -end_error (const char *type, token::end_tok_type ettype, int l, int c); - -// Check to see that end tokens are properly matched. -static bool -end_token_ok (token *tok, token::end_tok_type expected); - -// Maybe print a warning if an assignment expression is used as the -// test in a logical expression. -static void -maybe_warn_assign_as_truth_value (tree_expression *expr); - -// Maybe print a warning about switch labels that aren't constants. -static void -maybe_warn_variable_switch_label (tree_expression *expr); - -// Finish building a range. -static tree_expression * -finish_colon_expression (tree_colon_expression *e); - -// Build a constant. -static tree_constant * -make_constant (int op, token *tok_val); - -// Build a function handle. -static tree_fcn_handle * -make_fcn_handle (token *tok_val); - -// Build an anonymous function handle. -static tree_anon_fcn_handle * -make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt); - -// Build a binary expression. -static tree_expression * -make_binary_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2); - -// Build a boolean expression. -static tree_expression * -make_boolean_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2); - -// Build a prefix expression. -static tree_expression * -make_prefix_op (int op, tree_expression *op1, token *tok_val); - -// Build a postfix expression. -static tree_expression * -make_postfix_op (int op, tree_expression *op1, token *tok_val); - -// Build an unwind-protect command. -static tree_command * -make_unwind_command (token *unwind_tok, tree_statement_list *body, - tree_statement_list *cleanup, token *end_tok, - octave_comment_list *lc, octave_comment_list *mc); - -// Build a try-catch command. -static tree_command * -make_try_command (token *try_tok, tree_statement_list *body, - tree_statement_list *cleanup, token *end_tok, - octave_comment_list *lc, octave_comment_list *mc); - -// Build a while command. -static tree_command * -make_while_command (token *while_tok, tree_expression *expr, - tree_statement_list *body, token *end_tok, - octave_comment_list *lc); - -// Build a do-until command. -static tree_command * -make_do_until_command (token *until_tok, tree_statement_list *body, - tree_expression *expr, octave_comment_list *lc); - -// Build a for command. -static tree_command * -make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs, - tree_expression *expr, tree_expression *maxproc, - tree_statement_list *body, token *end_tok, - octave_comment_list *lc); - -// Build a break command. -static tree_command * -make_break_command (token *break_tok); - -// Build a continue command. -static tree_command * -make_continue_command (token *continue_tok); - -// Build a return command. -static tree_command * -make_return_command (token *return_tok); - -// Start an if command. -static tree_if_command_list * -start_if_command (tree_expression *expr, tree_statement_list *list); - -// Finish an if command. -static tree_if_command * -finish_if_command (token *if_tok, tree_if_command_list *list, - token *end_tok, octave_comment_list *lc); - -// Build an elseif clause. -static tree_if_clause * -make_elseif_clause (token *elseif_tok, tree_expression *expr, - tree_statement_list *list, octave_comment_list *lc); - -// Finish a switch command. -static tree_switch_command * -finish_switch_command (token *switch_tok, tree_expression *expr, - tree_switch_case_list *list, token *end_tok, - octave_comment_list *lc); - -// Build a switch case. -static tree_switch_case * -make_switch_case (token *case_tok, tree_expression *expr, - tree_statement_list *list, octave_comment_list *lc); - -// Build an assignment to a variable. -static tree_expression * -make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, - tree_expression *rhs); - -// Define a script. -static void -make_script (tree_statement_list *cmds, tree_statement *end_script); - -// Begin defining a function. -static octave_user_function * -start_function (tree_parameter_list *param_list, tree_statement_list *body, - tree_statement *end_function); - -// Create a no-op statement for end_function. -static tree_statement * -make_end (const std::string& type, int l, int c); - -// Do most of the work for defining a function. -static octave_user_function * -frob_function (const std::string& fname, octave_user_function *fcn); - -// Finish defining a function. -static tree_function_def * -finish_function (tree_parameter_list *ret_list, - octave_user_function *fcn, octave_comment_list *lc); - -// Reset state after parsing function. -static void -recover_from_parsing_function (void); - -// Make an index expression. -static tree_index_expression * -make_index_expression (tree_expression *expr, - tree_argument_list *args, char type); - -// Make an indirect reference expression. -static tree_index_expression * -make_indirect_ref (tree_expression *expr, const std::string&); - -// Make an indirect reference expression with dynamic field name. -static tree_index_expression * -make_indirect_ref (tree_expression *expr, tree_expression *field); - -// Make a declaration command. -static tree_decl_command * -make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst); - -// Validate argument list forming a matrix or cell row. -static tree_argument_list * -validate_matrix_row (tree_argument_list *row); - -// Finish building a matrix list. -static tree_expression * -finish_matrix (tree_matrix *m); - -// Finish building a cell list. -static tree_expression * -finish_cell (tree_cell *c); - -// Maybe print a warning. Duh. -static void -maybe_warn_missing_semi (tree_statement_list *); - -// Set the print flag for a statement based on the separator type. -static tree_statement_list * -set_stmt_print_flag (tree_statement_list *, char, bool); - -// Create a statement list. -static tree_statement_list *make_statement_list (tree_statement *stmt); - -// Append a statement to an existing statement list. -static tree_statement_list * -append_statement_list (tree_statement_list *list, char sep, - tree_statement *stmt, bool warn_missing_semi); - -static tree_funcall * -make_superclass_ref (const std::string& method_nm, - const std::string& package_nm, - const std::string& class_nm, - int l, int c); - -static tree_funcall * -make_meta_class_query (const std::string& package_nm, - const std::string& class_nm, - int l, int c); - -static tree_classdef * -make_classdef (token *tok_val, tree_classdef_attribute_list *a, - tree_identifier *id, tree_classdef_superclass_list *sc, - tree_classdef_body *body, token *end_tok, - octave_comment_list *lc); - -static tree_classdef_properties_block * -make_classdef_properties_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_property_list *plist, - token *end_tok, octave_comment_list *lc); - -static tree_classdef_methods_block * -make_classdef_methods_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_methods_list *mlist, - token *end_tok, octave_comment_list *lc); - -static tree_classdef_events_block * -make_classdef_events_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_events_list *elist, - token *end_tok, octave_comment_list *lc); - -static tree_classdef_enum_block * -make_classdef_enum_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_enum_list *elist, - token *end_tok, octave_comment_list *lc); +static void yyerror (octave_parser *curr_parser, const char *s); // Finish building a statement. template <class T> @@ -427,6 +146,9 @@ } \ while (0) +#define curr_lexer curr_parser->curr_lexer +#define scanner curr_lexer->scanner + %} // Bison declarations. @@ -436,6 +158,19 @@ %name-prefix="octave_" +// We are using the pure parser interface and the reentrant lexer +// interface but the Octave parser and lexer are NOT properly +// reentrant because both still use many global variables. It should be +// safe to create a parser object and call it while anotehr parser +// object is active (to parse a callback function while the main +// interactive parser is waiting for input, for example) if you take +// care to properly save and restore (typically with an unwind_protect +// object) relevant global values before and after the nested call. + +%define api.pure +%parse-param { octave_parser *curr_parser } +%lex-param { void *scanner } + %union { // The type of the basic tokens returned by the lexer. @@ -633,7 +368,7 @@ { $$ = 0; } | END_OF_INPUT { - parser_end_of_input = 1; + curr_parser->end_of_input = true; $$ = 0; } | simple_list @@ -645,13 +380,13 @@ ; simple_list : simple_list1 opt_sep_no_nl - { $$ = set_stmt_print_flag ($1, $2, false); } + { $$ = curr_parser->set_stmt_print_flag ($1, $2, false); } ; simple_list1 : statement - { $$ = make_statement_list ($1); } + { $$ = curr_parser->make_statement_list ($1); } | simple_list1 sep_no_nl statement - { $$ = append_statement_list ($1, $2, $3, false); } + { $$ = curr_parser->append_statement_list ($1, $2, $3, false); } ; opt_list : // empty @@ -661,13 +396,13 @@ ; list : list1 opt_sep - { $$ = set_stmt_print_flag ($1, $2, true); } + { $$ = curr_parser->set_stmt_print_flag ($1, $2, true); } ; list1 : statement - { $$ = make_statement_list ($1); } + { $$ = curr_parser->make_statement_list ($1); } | list1 sep statement - { $$ = append_statement_list ($1, $2, $3, true); } + { $$ = curr_parser->append_statement_list ($1, $2, $3, true); } ; statement : expression @@ -687,7 +422,7 @@ // WHILE, etc. word_list_cmd : identifier word_list - { $$ = make_index_expression ($1, $2, '('); } + { $$ = curr_parser->make_index_expression ($1, $2, '('); } ; word_list : string @@ -717,8 +452,9 @@ std::string package_nm = $1->superclass_package_name (); std::string class_nm = $1->superclass_class_name (); - $$ = make_superclass_ref (method_nm, package_nm, class_nm, - $1->line (), $1->column ()); + $$ = curr_parser->make_superclass_ref + (method_nm, package_nm, class_nm, + $1->line (), $1->column ()); } ; @@ -727,21 +463,22 @@ std::string package_nm = $1->meta_package_name (); std::string class_nm = $1->meta_class_name (); - $$ = make_meta_class_query (package_nm, class_nm, - $1->line (), $1->column ()); + $$ = curr_parser->make_meta_class_query + (package_nm, class_nm, + $1->line (), $1->column ()); } ; string : DQ_STRING - { $$ = make_constant (DQ_STRING, $1); } + { $$ = curr_parser->make_constant (DQ_STRING, $1); } | SQ_STRING - { $$ = make_constant (SQ_STRING, $1); } + { $$ = curr_parser->make_constant (SQ_STRING, $1); } ; constant : NUM - { $$ = make_constant (NUM, $1); } + { $$ = curr_parser->make_constant (NUM, $1); } | IMAG_NUM - { $$ = make_constant (IMAG_NUM, $1); } + { $$ = curr_parser->make_constant (IMAG_NUM, $1); } | string { $$ = $1; } ; @@ -749,26 +486,26 @@ matrix : '[' ']' { $$ = new tree_constant (octave_null_matrix::instance); - lexer_flags.looking_at_matrix_or_assign_lhs = false; - lexer_flags.pending_local_variables.clear (); + curr_lexer->looking_at_matrix_or_assign_lhs = false; + curr_lexer->pending_local_variables.clear (); } | '[' ';' ']' { $$ = new tree_constant (octave_null_matrix::instance); - lexer_flags.looking_at_matrix_or_assign_lhs = false; - lexer_flags.pending_local_variables.clear (); + curr_lexer->looking_at_matrix_or_assign_lhs = false; + curr_lexer->pending_local_variables.clear (); } | '[' ',' ']' { $$ = new tree_constant (octave_null_matrix::instance); - lexer_flags.looking_at_matrix_or_assign_lhs = false; - lexer_flags.pending_local_variables.clear (); + curr_lexer->looking_at_matrix_or_assign_lhs = false; + curr_lexer->pending_local_variables.clear (); } | '[' matrix_rows ']' { - $$ = finish_matrix ($2); - lexer_flags.looking_at_matrix_or_assign_lhs = false; - lexer_flags.pending_local_variables.clear (); + $$ = curr_parser->finish_matrix ($2); + curr_lexer->looking_at_matrix_or_assign_lhs = false; + curr_lexer->pending_local_variables.clear (); } ; @@ -792,7 +529,7 @@ | '{' ';' '}' { $$ = new tree_constant (octave_value (Cell ())); } | '{' cell_rows '}' - { $$ = finish_cell ($2); } + { $$ = curr_parser->finish_cell ($2); } ; cell_rows : cell_rows1 @@ -812,22 +549,22 @@ cell_or_matrix_row : arg_list - { $$ = validate_matrix_row ($1); } + { $$ = curr_parser->validate_matrix_row ($1); } | arg_list ',' // Ignore trailing comma. - { $$ = validate_matrix_row ($1); } + { $$ = curr_parser->validate_matrix_row ($1); } ; fcn_handle : '@' FCN_HANDLE { - $$ = make_fcn_handle ($2); - lexer_flags.looking_at_function_handle--; + $$ = curr_parser->make_fcn_handle ($2); + curr_lexer->looking_at_function_handle--; } ; anon_fcn_handle : '@' param_list statement { - lexer_flags.quote_is_transpose = false; - $$ = make_anon_fcn_handle ($2, $3); + curr_lexer->quote_is_transpose = false; + $$ = curr_parser->make_anon_fcn_handle ($2, $3); } ; @@ -886,69 +623,69 @@ ; indirect_ref_op : '.' - { lexer_flags.looking_at_indirect_ref = true; } + { curr_lexer->looking_at_indirect_ref = true; } ; oper_expr : primary_expr { $$ = $1; } | oper_expr PLUS_PLUS - { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } + { $$ = curr_parser->make_postfix_op (PLUS_PLUS, $1, $2); } | oper_expr MINUS_MINUS - { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } + { $$ = curr_parser->make_postfix_op (MINUS_MINUS, $1, $2); } | oper_expr '(' ')' - { $$ = make_index_expression ($1, 0, '('); } + { $$ = curr_parser->make_index_expression ($1, 0, '('); } | oper_expr '(' arg_list ')' - { $$ = make_index_expression ($1, $3, '('); } + { $$ = curr_parser->make_index_expression ($1, $3, '('); } | oper_expr '{' '}' - { $$ = make_index_expression ($1, 0, '{'); } + { $$ = curr_parser->make_index_expression ($1, 0, '{'); } | oper_expr '{' arg_list '}' - { $$ = make_index_expression ($1, $3, '{'); } + { $$ = curr_parser->make_index_expression ($1, $3, '{'); } | oper_expr QUOTE - { $$ = make_postfix_op (QUOTE, $1, $2); } + { $$ = curr_parser->make_postfix_op (QUOTE, $1, $2); } | oper_expr TRANSPOSE - { $$ = make_postfix_op (TRANSPOSE, $1, $2); } + { $$ = curr_parser->make_postfix_op (TRANSPOSE, $1, $2); } | oper_expr indirect_ref_op STRUCT_ELT - { $$ = make_indirect_ref ($1, $3->text ()); } + { $$ = curr_parser->make_indirect_ref ($1, $3->text ()); } | oper_expr indirect_ref_op '(' expression ')' - { $$ = make_indirect_ref ($1, $4); } + { $$ = curr_parser->make_indirect_ref ($1, $4); } | PLUS_PLUS oper_expr %prec UNARY - { $$ = make_prefix_op (PLUS_PLUS, $2, $1); } + { $$ = curr_parser->make_prefix_op (PLUS_PLUS, $2, $1); } | MINUS_MINUS oper_expr %prec UNARY - { $$ = make_prefix_op (MINUS_MINUS, $2, $1); } + { $$ = curr_parser->make_prefix_op (MINUS_MINUS, $2, $1); } | EXPR_NOT oper_expr %prec UNARY - { $$ = make_prefix_op (EXPR_NOT, $2, $1); } + { $$ = curr_parser->make_prefix_op (EXPR_NOT, $2, $1); } | '+' oper_expr %prec UNARY - { $$ = make_prefix_op ('+', $2, $1); } + { $$ = curr_parser->make_prefix_op ('+', $2, $1); } | '-' oper_expr %prec UNARY - { $$ = make_prefix_op ('-', $2, $1); } + { $$ = curr_parser->make_prefix_op ('-', $2, $1); } | oper_expr POW oper_expr - { $$ = make_binary_op (POW, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (POW, $1, $2, $3); } | oper_expr EPOW oper_expr - { $$ = make_binary_op (EPOW, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EPOW, $1, $2, $3); } | oper_expr '+' oper_expr - { $$ = make_binary_op ('+', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('+', $1, $2, $3); } | oper_expr '-' oper_expr - { $$ = make_binary_op ('-', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('-', $1, $2, $3); } | oper_expr '*' oper_expr - { $$ = make_binary_op ('*', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('*', $1, $2, $3); } | oper_expr '/' oper_expr - { $$ = make_binary_op ('/', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('/', $1, $2, $3); } | oper_expr EPLUS oper_expr - { $$ = make_binary_op ('+', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('+', $1, $2, $3); } | oper_expr EMINUS oper_expr - { $$ = make_binary_op ('-', $1, $2, $3); } + { $$ = curr_parser->make_binary_op ('-', $1, $2, $3); } | oper_expr EMUL oper_expr - { $$ = make_binary_op (EMUL, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EMUL, $1, $2, $3); } | oper_expr EDIV oper_expr - { $$ = make_binary_op (EDIV, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EDIV, $1, $2, $3); } | oper_expr LEFTDIV oper_expr - { $$ = make_binary_op (LEFTDIV, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (LEFTDIV, $1, $2, $3); } | oper_expr ELEFTDIV oper_expr - { $$ = make_binary_op (ELEFTDIV, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (ELEFTDIV, $1, $2, $3); } ; colon_expr : colon_expr1 - { $$ = finish_colon_expression ($1); } + { $$ = curr_parser->finish_colon_expression ($1); } ; colon_expr1 : oper_expr @@ -963,29 +700,29 @@ simple_expr : colon_expr { $$ = $1; } | simple_expr LSHIFT simple_expr - { $$ = make_binary_op (LSHIFT, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (LSHIFT, $1, $2, $3); } | simple_expr RSHIFT simple_expr - { $$ = make_binary_op (RSHIFT, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (RSHIFT, $1, $2, $3); } | simple_expr EXPR_LT simple_expr - { $$ = make_binary_op (EXPR_LT, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_LT, $1, $2, $3); } | simple_expr EXPR_LE simple_expr - { $$ = make_binary_op (EXPR_LE, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_LE, $1, $2, $3); } | simple_expr EXPR_EQ simple_expr - { $$ = make_binary_op (EXPR_EQ, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_EQ, $1, $2, $3); } | simple_expr EXPR_GE simple_expr - { $$ = make_binary_op (EXPR_GE, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_GE, $1, $2, $3); } | simple_expr EXPR_GT simple_expr - { $$ = make_binary_op (EXPR_GT, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_GT, $1, $2, $3); } | simple_expr EXPR_NE simple_expr - { $$ = make_binary_op (EXPR_NE, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_NE, $1, $2, $3); } | simple_expr EXPR_AND simple_expr - { $$ = make_binary_op (EXPR_AND, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_AND, $1, $2, $3); } | simple_expr EXPR_OR simple_expr - { $$ = make_binary_op (EXPR_OR, $1, $2, $3); } + { $$ = curr_parser->make_binary_op (EXPR_OR, $1, $2, $3); } | simple_expr EXPR_AND_AND simple_expr - { $$ = make_boolean_op (EXPR_AND_AND, $1, $2, $3); } + { $$ = curr_parser->make_boolean_op (EXPR_AND_AND, $1, $2, $3); } | simple_expr EXPR_OR_OR simple_expr - { $$ = make_boolean_op (EXPR_OR_OR, $1, $2, $3); } + { $$ = curr_parser->make_boolean_op (EXPR_OR_OR, $1, $2, $3); } ; // Arrange for the lexer to return CLOSE_BRACE for ']' by looking ahead @@ -999,47 +736,47 @@ | '[' arg_list opt_comma CLOSE_BRACE { $$ = $2; - lexer_flags.looking_at_matrix_or_assign_lhs = false; - for (std::set<std::string>::const_iterator p = lexer_flags.pending_local_variables.begin (); - p != lexer_flags.pending_local_variables.end (); + curr_lexer->looking_at_matrix_or_assign_lhs = false; + for (std::set<std::string>::const_iterator p = curr_lexer->pending_local_variables.begin (); + p != curr_lexer->pending_local_variables.end (); p++) { symbol_table::force_variable (*p); } - lexer_flags.pending_local_variables.clear (); + curr_lexer->pending_local_variables.clear (); } ; assign_expr : assign_lhs '=' expression - { $$ = make_assign_op ('=', $1, $2, $3); } + { $$ = curr_parser->make_assign_op ('=', $1, $2, $3); } | assign_lhs ADD_EQ expression - { $$ = make_assign_op (ADD_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (ADD_EQ, $1, $2, $3); } | assign_lhs SUB_EQ expression - { $$ = make_assign_op (SUB_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (SUB_EQ, $1, $2, $3); } | assign_lhs MUL_EQ expression - { $$ = make_assign_op (MUL_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (MUL_EQ, $1, $2, $3); } | assign_lhs DIV_EQ expression - { $$ = make_assign_op (DIV_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (DIV_EQ, $1, $2, $3); } | assign_lhs LEFTDIV_EQ expression - { $$ = make_assign_op (LEFTDIV_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (LEFTDIV_EQ, $1, $2, $3); } | assign_lhs POW_EQ expression - { $$ = make_assign_op (POW_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (POW_EQ, $1, $2, $3); } | assign_lhs LSHIFT_EQ expression - { $$ = make_assign_op (LSHIFT_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (LSHIFT_EQ, $1, $2, $3); } | assign_lhs RSHIFT_EQ expression - { $$ = make_assign_op (RSHIFT_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (RSHIFT_EQ, $1, $2, $3); } | assign_lhs EMUL_EQ expression - { $$ = make_assign_op (EMUL_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (EMUL_EQ, $1, $2, $3); } | assign_lhs EDIV_EQ expression - { $$ = make_assign_op (EDIV_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (EDIV_EQ, $1, $2, $3); } | assign_lhs ELEFTDIV_EQ expression - { $$ = make_assign_op (ELEFTDIV_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (ELEFTDIV_EQ, $1, $2, $3); } | assign_lhs EPOW_EQ expression - { $$ = make_assign_op (EPOW_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (EPOW_EQ, $1, $2, $3); } | assign_lhs AND_EQ expression - { $$ = make_assign_op (AND_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (AND_EQ, $1, $2, $3); } | assign_lhs OR_EQ expression - { $$ = make_assign_op (OR_EQ, $1, $2, $3); } + { $$ = curr_parser->make_assign_op (OR_EQ, $1, $2, $3); } ; expression : simple_expr @@ -1076,17 +813,17 @@ parsing_decl_list : // empty - { lexer_flags.looking_at_decl_list = true; } + { curr_lexer->looking_at_decl_list = true; } declaration : GLOBAL parsing_decl_list decl1 { - $$ = make_decl_command (GLOBAL, $1, $3); - lexer_flags.looking_at_decl_list = false; + $$ = curr_parser->make_decl_command (GLOBAL, $1, $3); + curr_lexer->looking_at_decl_list = false; } | PERSISTENT parsing_decl_list decl1 { - $$ = make_decl_command (PERSISTENT, $1, $3); - lexer_flags.looking_at_decl_list = false; + $$ = curr_parser->make_decl_command (PERSISTENT, $1, $3); + curr_lexer->looking_at_decl_list = false; } ; @@ -1100,13 +837,13 @@ ; decl_param_init : // empty - { lexer_flags.looking_at_initializer_expression = true; } + { curr_lexer->looking_at_initializer_expression = true; } decl2 : identifier { $$ = new tree_decl_elt ($1); } | identifier '=' decl_param_init expression { - lexer_flags.looking_at_initializer_expression = false; + curr_lexer->looking_at_initializer_expression = false; $$ = new tree_decl_elt ($1, $4); } | magic_tilde @@ -1131,7 +868,7 @@ if_command : IF stash_comment if_cmd_list END { - if (! ($$ = finish_if_command ($1, $3, $4, $2))) + if (! ($$ = curr_parser->finish_if_command ($1, $3, $4, $2))) ABORT_PARSE; } ; @@ -1149,7 +886,7 @@ { $1->mark_braindead_shortcircuit (curr_fcn_file_full_name); - $$ = start_if_command ($1, $3); + $$ = curr_parser->start_if_command ($1, $3); } | if_cmd_list1 elseif_clause { @@ -1162,7 +899,7 @@ { $4->mark_braindead_shortcircuit (curr_fcn_file_full_name); - $$ = make_elseif_clause ($1, $4, $6, $2); + $$ = curr_parser->make_elseif_clause ($1, $4, $6, $2); } ; @@ -1176,7 +913,7 @@ switch_command : SWITCH stash_comment expression opt_sep case_list END { - if (! ($$ = finish_switch_command ($1, $3, $5, $6, $2))) + if (! ($$ = curr_parser->finish_switch_command ($1, $3, $5, $6, $2))) ABORT_PARSE; } ; @@ -1204,7 +941,7 @@ ; switch_case : CASE stash_comment opt_sep expression opt_sep opt_list - { $$ = make_switch_case ($1, $4, $6, $2); } + { $$ = curr_parser->make_switch_case ($1, $4, $6, $2); } ; default_case : OTHERWISE stash_comment opt_sep opt_list @@ -1221,35 +958,35 @@ { $3->mark_braindead_shortcircuit (curr_fcn_file_full_name); - if (! ($$ = make_while_command ($1, $3, $5, $6, $2))) + if (! ($$ = curr_parser->make_while_command ($1, $3, $5, $6, $2))) ABORT_PARSE; } | DO stash_comment opt_sep opt_list UNTIL expression { - if (! ($$ = make_do_until_command ($5, $4, $6, $2))) + if (! ($$ = curr_parser->make_do_until_command ($5, $4, $6, $2))) ABORT_PARSE; } | FOR stash_comment assign_lhs '=' expression opt_sep opt_list END { - if (! ($$ = make_for_command (FOR, $1, $3, $5, 0, + if (! ($$ = curr_parser->make_for_command (FOR, $1, $3, $5, 0, $7, $8, $2))) ABORT_PARSE; } | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END { - if (! ($$ = make_for_command (FOR, $1, $4, $6, 0, + if (! ($$ = curr_parser->make_for_command (FOR, $1, $4, $6, 0, $9, $10, $2))) ABORT_PARSE; } | PARFOR stash_comment assign_lhs '=' expression opt_sep opt_list END { - if (! ($$ = make_for_command (PARFOR, $1, $3, $5, + if (! ($$ = curr_parser->make_for_command (PARFOR, $1, $3, $5, 0, $7, $8, $2))) ABORT_PARSE; } | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END { - if (! ($$ = make_for_command (PARFOR, $1, $4, $6, + if (! ($$ = curr_parser->make_for_command (PARFOR, $1, $4, $6, $8, $11, $12, $2))) ABORT_PARSE; } @@ -1261,17 +998,17 @@ jump_command : BREAK { - if (! ($$ = make_break_command ($1))) + if (! ($$ = curr_parser->make_break_command ($1))) ABORT_PARSE; } | CONTINUE { - if (! ($$ = make_continue_command ($1))) + if (! ($$ = curr_parser->make_continue_command ($1))) ABORT_PARSE; } | FUNC_RET { - if (! ($$ = make_return_command ($1))) + if (! ($$ = curr_parser->make_return_command ($1))) ABORT_PARSE; } ; @@ -1283,18 +1020,18 @@ except_command : UNWIND stash_comment opt_sep opt_list CLEANUP stash_comment opt_sep opt_list END { - if (! ($$ = make_unwind_command ($1, $4, $8, $9, $2, $6))) + if (! ($$ = curr_parser->make_unwind_command ($1, $4, $8, $9, $2, $6))) ABORT_PARSE; } | TRY stash_comment opt_sep opt_list CATCH stash_comment opt_sep opt_list END { - if (! ($$ = make_try_command ($1, $4, $8, $9, $2, $6))) + if (! ($$ = curr_parser->make_try_command ($1, $4, $8, $9, $2, $6))) ABORT_PARSE; } | TRY stash_comment opt_sep opt_list END { - if (! ($$ = make_try_command ($1, $4, 0, $5, $2, 0))) + if (! ($$ = curr_parser->make_try_command ($1, $4, 0, $5, $2, 0))) ABORT_PARSE; } ; @@ -1305,23 +1042,23 @@ push_fcn_symtab : // empty { - current_function_depth++; - - if (max_function_depth < current_function_depth) - max_function_depth = current_function_depth; + curr_parser->curr_fcn_depth++; + + if (curr_parser->max_fcn_depth < curr_parser->curr_fcn_depth) + curr_parser->max_fcn_depth = curr_parser->curr_fcn_depth; parser_symtab_context.push (); symbol_table::set_scope (symbol_table::alloc_scope ()); - function_scopes.push_back (symbol_table::current_scope ()); - - if (! reading_script_file && current_function_depth == 1 - && ! parsing_subfunctions) - primary_fcn_scope = symbol_table::current_scope (); - - if (reading_script_file && current_function_depth > 1) - yyerror ("nested functions not implemented in this context"); + curr_parser->function_scopes.push_back (symbol_table::current_scope ()); + + if (! reading_script_file && curr_parser->curr_fcn_depth == 1 + && ! curr_parser->parsing_subfunctions) + curr_parser->primary_fcn_scope = symbol_table::current_scope (); + + if (reading_script_file && curr_parser->curr_fcn_depth > 1) + curr_parser->bison_error ("nested functions not implemented in this context"); } ; @@ -1331,33 +1068,33 @@ param_list_beg : '(' { - lexer_flags.looking_at_parameter_list = true; - - if (lexer_flags.looking_at_function_handle) + curr_lexer->looking_at_parameter_list = true; + + if (curr_lexer->looking_at_function_handle) { parser_symtab_context.push (); symbol_table::set_scope (symbol_table::alloc_scope ()); - lexer_flags.looking_at_function_handle--; - lexer_flags.looking_at_anon_fcn_args = true; + curr_lexer->looking_at_function_handle--; + curr_lexer->looking_at_anon_fcn_args = true; } } ; param_list_end : ')' { - lexer_flags.looking_at_parameter_list = false; - lexer_flags.looking_for_object_index = false; + curr_lexer->looking_at_parameter_list = false; + curr_lexer->looking_for_object_index = false; } ; param_list : param_list_beg param_list1 param_list_end { - lexer_flags.quote_is_transpose = false; + curr_lexer->quote_is_transpose = false; $$ = $2; } | param_list_beg error { - yyerror ("invalid parameter list"); + curr_parser->bison_error ("invalid parameter list"); $$ = 0; ABORT_PARSE; } @@ -1390,12 +1127,12 @@ return_list : '[' ']' { - lexer_flags.looking_at_return_list = false; + curr_lexer->looking_at_return_list = false; $$ = new tree_parameter_list (); } | return_list1 { - lexer_flags.looking_at_return_list = false; + curr_lexer->looking_at_return_list = false; if ($1->validate (tree_parameter_list::out)) $$ = $1; else @@ -1403,7 +1140,7 @@ } | '[' return_list1 ']' { - lexer_flags.looking_at_return_list = false; + curr_lexer->looking_at_return_list = false; if ($2->validate (tree_parameter_list::out)) $$ = $2; else @@ -1427,10 +1164,11 @@ script_file : SCRIPT_FILE opt_list END_OF_INPUT { tree_statement *end_of_script - = make_end ("endscript", input_line_number, - current_input_column); - - make_script ($2, end_of_script); + = curr_parser->make_end ("endscript", + curr_lexer->input_line_number, + curr_lexer->current_input_column); + + curr_parser->make_script ($2, end_of_script); $$ = 0; } @@ -1456,20 +1194,20 @@ { $$ = $3; - if (reading_classdef_file || lexer_flags.parsing_classdef) - lexer_flags.maybe_classdef_get_set_method = true; + if (reading_classdef_file || curr_lexer->parsing_classdef) + curr_lexer->maybe_classdef_get_set_method = true; } ; function : function_beg function1 { - $$ = finish_function (0, $2, $1); - recover_from_parsing_function (); + $$ = curr_parser->finish_function (0, $2, $1); + curr_parser->recover_from_parsing_function (); } | function_beg return_list '=' function1 { - $$ = finish_function ($2, $4, $1); - recover_from_parsing_function (); + $$ = curr_parser->finish_function ($2, $4, $1); + curr_parser->recover_from_parsing_function (); } ; @@ -1477,23 +1215,23 @@ { std::string id_name = $1->name (); - lexer_flags.parsed_function_name.top () = true; - lexer_flags.maybe_classdef_get_set_method = false; + curr_lexer->parsed_function_name.top () = true; + curr_lexer->maybe_classdef_get_set_method = false; $$ = $1; } | GET '.' identifier { - lexer_flags.parsed_function_name.top () = true; - lexer_flags.maybe_classdef_get_set_method = false; - lexer_flags.parsing_classdef_get_method = true; + curr_lexer->parsed_function_name.top () = true; + curr_lexer->maybe_classdef_get_set_method = false; + curr_lexer->parsing_classdef_get_method = true; $$ = $3; } | SET '.' identifier { - lexer_flags.parsed_function_name.top () = true; - lexer_flags.maybe_classdef_get_set_method = false; - lexer_flags.parsing_classdef_set_method = true; + curr_lexer->parsed_function_name.top () = true; + curr_lexer->maybe_classdef_get_set_method = false; + curr_lexer->parsing_classdef_set_method = true; $$ = $3; } ; @@ -1504,22 +1242,22 @@ delete $1; - if (! ($$ = frob_function (fname, $2))) + if (! ($$ = curr_parser->frob_function (fname, $2))) ABORT_PARSE; } ; function2 : param_list opt_sep opt_list function_end - { $$ = start_function ($1, $3, $4); } + { $$ = curr_parser->start_function ($1, $3, $4); } | opt_sep opt_list function_end - { $$ = start_function (0, $2, $3); } + { $$ = curr_parser->start_function (0, $2, $3); } ; function_end : END { - endfunction_found = true; - if (end_token_ok ($1, token::function_end)) - $$ = make_end ("endfunction", $1->line (), $1->column ()); + curr_parser->endfunction_found = true; + if (curr_parser->end_token_ok ($1, token::function_end)) + $$ = curr_parser->make_end ("endfunction", $1->line (), $1->column ()); else ABORT_PARSE; } @@ -1528,13 +1266,13 @@ // A lot of tests are based on the assumption that this is OK // if (reading_script_file) // { -// yyerror ("function body open at end of script"); +// curr_parser->bison_error ("function body open at end of script"); // YYABORT; // } - if (endfunction_found) + if (curr_parser->endfunction_found) { - yyerror ("inconsistent function endings -- " + curr_parser->bison_error ("inconsistent function endings -- " "if one function is explicitly ended, " "so must all the others"); YYABORT; @@ -1543,18 +1281,19 @@ if (! (reading_fcn_file || reading_script_file || get_input_from_eval_string)) { - yyerror ("function body open at end of input"); + curr_parser->bison_error ("function body open at end of input"); YYABORT; } if (reading_classdef_file) { - yyerror ("classdef body open at end of input"); + curr_parser->bison_error ("classdef body open at end of input"); YYABORT; } - $$ = make_end ("endfunction", input_line_number, - current_input_column); + $$ = curr_parser->make_end ("endfunction", + curr_lexer->input_line_number, + curr_lexer->current_input_column); } ; @@ -1564,7 +1303,7 @@ classdef_file : CLASSDEF_FILE classdef opt_sep END_OF_INPUT { - classdef_object = $2; + curr_parser->classdef_object = $2; $$ = 0; } ; @@ -1577,19 +1316,19 @@ { if (! reading_classdef_file) { - yyerror ("classdef must appear inside a file containing only a class definition"); + curr_parser->bison_error ("classdef must appear inside a file containing only a class definition"); YYABORT; } - lexer_flags.parsing_classdef = true; + curr_lexer->parsing_classdef = true; $$ = $1; } ; classdef : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END { - lexer_flags.parsing_classdef = false; - if (! ($$ = make_classdef ($1, $3, $4, $5, $7, $9, $2))) + curr_lexer->parsing_classdef = false; + if (! ($$ = curr_parser->make_classdef ($1, $3, $4, $5, $7, $9, $2))) ABORT_PARSE; } ; @@ -1613,7 +1352,7 @@ { $$ = new tree_classdef_attribute ($1); } | identifier '=' decl_param_init expression { - lexer_flags.looking_at_initializer_expression = false; + curr_lexer->looking_at_initializer_expression = false; $$ = new tree_classdef_attribute ($1, $4); } | EXPR_NOT identifier @@ -1675,7 +1414,8 @@ properties_block : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END { - if (! ($$ = make_classdef_properties_block ($1, $3, $5, $7, $2))) + if (! ($$ = curr_parser->make_classdef_properties_block + ($1, $3, $5, $7, $2))) ABORT_PARSE; } ; @@ -1694,14 +1434,15 @@ { $$ = new tree_classdef_property ($1); } | identifier '=' decl_param_init expression ';' { - lexer_flags.looking_at_initializer_expression = false; + curr_lexer->looking_at_initializer_expression = false; $$ = new tree_classdef_property ($1, $4); } ; methods_block : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END { - if (! ($$ = make_classdef_methods_block ($1, $3, $5, $7, $2))) + if (! ($$ = curr_parser->make_classdef_methods_block + ($1, $3, $5, $7, $2))) ABORT_PARSE; } ; @@ -1728,7 +1469,8 @@ events_block : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END { - if (! ($$ = make_classdef_events_block ($1, $3, $5, $7, $2))) + if (! ($$ = curr_parser->make_classdef_events_block + ($1, $3, $5, $7, $2))) ABORT_PARSE; } ; @@ -1748,7 +1490,8 @@ enum_block : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END { - if (! ($$ = make_classdef_enum_block ($1, $3, $5, $7, $2))) + if (! ($$ = curr_parser->make_classdef_enum_block + ($1, $3, $5, $7, $2))) ABORT_PARSE; } ; @@ -1775,7 +1518,7 @@ ; parse_error : LEXICAL_ERROR - { yyerror ("parse error"); } + { curr_parser->bison_error ("parse error"); } | error ; @@ -1825,55 +1568,25 @@ // Generic error messages. +#undef curr_lexer + static void -yyerror (const char *s) +yyerror (octave_parser *curr_parser, const char *s) { - int err_col = current_input_column - 1; - - std::ostringstream output_buf; - - if (reading_fcn_file || reading_script_file || reading_classdef_file) - output_buf << "parse error near line " << input_line_number - << " of file " << curr_fcn_file_full_name; - else - output_buf << "parse error:"; - - if (s && strcmp (s, "parse error") != 0) - output_buf << "\n\n " << s; - - output_buf << "\n\n"; - - if (! current_input_line.empty ()) - { - size_t len = current_input_line.length (); - - if (current_input_line[len-1] == '\n') - current_input_line.resize (len-1); - - // Print the line, maybe with a pointer near the error token. - - output_buf << ">>> " << current_input_line << "\n"; - - if (err_col == 0) - err_col = len; - - for (int i = 0; i < err_col + 3; i++) - output_buf << " "; - - output_buf << "^"; - } - - output_buf << "\n"; - - std::string msg = output_buf.str (); - - parse_error ("%s", msg.c_str ()); + curr_parser->bison_error (s); +} + +int +octave_parser::run (void) +{ + return octave_parse (this); } // Error mesages for mismatched end tokens. -static void -end_error (const char *type, token::end_tok_type ettype, int l, int c) +void +octave_parser::end_error (const char *type, token::end_tok_type ettype, + int l, int c) { static const char *fmt = "'%s' command matched by '%s' near line %d column %d"; @@ -1924,8 +1637,8 @@ // Check to see that end tokens are properly matched. -static bool -end_token_ok (token *tok, token::end_tok_type expected) +bool +octave_parser::end_token_ok (token *tok, token::end_tok_type expected) { bool retval = true; @@ -1935,7 +1648,7 @@ { retval = false; - yyerror ("parse error"); + bison_error ("parse error"); int l = tok->line (); int c = tok->column (); @@ -1994,8 +1707,8 @@ // Maybe print a warning if an assignment expression is used as the // test in a logical expression. -static void -maybe_warn_assign_as_truth_value (tree_expression *expr) +void +octave_parser::maybe_warn_assign_as_truth_value (tree_expression *expr) { if (expr->is_assignment_expression () && expr->paren_count () < 2) @@ -2014,8 +1727,8 @@ // Maybe print a warning about switch labels that aren't constants. -static void -maybe_warn_variable_switch_label (tree_expression *expr) +void +octave_parser::maybe_warn_variable_switch_label (tree_expression *expr) { if (! expr->is_constant ()) { @@ -2121,8 +1834,8 @@ // Finish building a range. -static tree_expression * -finish_colon_expression (tree_colon_expression *e) +tree_expression * +octave_parser::finish_colon_expression (tree_colon_expression *e) { tree_expression *retval = e; @@ -2185,8 +1898,8 @@ // Make a constant. -static tree_constant * -make_constant (int op, token *tok_val) +tree_constant * +octave_parser::make_constant (int op, token *tok_val) { int l = tok_val->line (); int c = tok_val->column (); @@ -2248,8 +1961,8 @@ // Make a function handle. -static tree_fcn_handle * -make_fcn_handle (token *tok_val) +tree_fcn_handle * +octave_parser::make_fcn_handle (token *tok_val) { int l = tok_val->line (); int c = tok_val->column (); @@ -2261,12 +1974,13 @@ // Make an anonymous function handle. -static tree_anon_fcn_handle * -make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt) +tree_anon_fcn_handle * +octave_parser::make_anon_fcn_handle (tree_parameter_list *param_list, + tree_statement *stmt) { // FIXME -- need to get these from the location of the @ symbol. - int l = input_line_number; - int c = current_input_column; + int l = curr_lexer->input_line_number; + int c = curr_lexer->current_input_column; tree_parameter_list *ret_list = 0; @@ -2294,9 +2008,9 @@ // Build a binary expression. -static tree_expression * -make_binary_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2) +tree_expression * +octave_parser::make_binary_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2) { octave_value::binary_op t = octave_value::unknown_binary_op; @@ -2398,9 +2112,9 @@ // Build a boolean expression. -static tree_expression * -make_boolean_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2) +tree_expression * +octave_parser::make_boolean_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2) { tree_boolean_expression::type t; @@ -2430,8 +2144,8 @@ // Build a prefix expression. -static tree_expression * -make_prefix_op (int op, tree_expression *op1, token *tok_val) +tree_expression * +octave_parser::make_prefix_op (int op, tree_expression *op1, token *tok_val) { octave_value::unary_op t = octave_value::unknown_unary_op; @@ -2473,8 +2187,8 @@ // Build a postfix expression. -static tree_expression * -make_postfix_op (int op, tree_expression *op1, token *tok_val) +tree_expression * +octave_parser::make_postfix_op (int op, tree_expression *op1, token *tok_val) { octave_value::unary_op t = octave_value::unknown_unary_op; @@ -2512,10 +2226,13 @@ // Build an unwind-protect command. -static tree_command * -make_unwind_command (token *unwind_tok, tree_statement_list *body, - tree_statement_list *cleanup, token *end_tok, - octave_comment_list *lc, octave_comment_list *mc) +tree_command * +octave_parser::make_unwind_command (token *unwind_tok, + tree_statement_list *body, + tree_statement_list *cleanup_stmts, + token *end_tok, + octave_comment_list *lc, + octave_comment_list *mc) { tree_command *retval = 0; @@ -2526,7 +2243,7 @@ int l = unwind_tok->line (); int c = unwind_tok->column (); - retval = new tree_unwind_protect_command (body, cleanup, + retval = new tree_unwind_protect_command (body, cleanup_stmts, lc, mc, tc, l, c); } @@ -2535,10 +2252,12 @@ // Build a try-catch command. -static tree_command * -make_try_command (token *try_tok, tree_statement_list *body, - tree_statement_list *cleanup, token *end_tok, - octave_comment_list *lc, octave_comment_list *mc) +tree_command * +octave_parser::make_try_command (token *try_tok, tree_statement_list *body, + tree_statement_list *cleanup_stmts, + token *end_tok, + octave_comment_list *lc, + octave_comment_list *mc) { tree_command *retval = 0; @@ -2549,7 +2268,7 @@ int l = try_tok->line (); int c = try_tok->column (); - retval = new tree_try_catch_command (body, cleanup, + retval = new tree_try_catch_command (body, cleanup_stmts, lc, mc, tc, l, c); } @@ -2558,10 +2277,10 @@ // Build a while command. -static tree_command * -make_while_command (token *while_tok, tree_expression *expr, - tree_statement_list *body, token *end_tok, - octave_comment_list *lc) +tree_command * +octave_parser::make_while_command (token *while_tok, tree_expression *expr, + tree_statement_list *body, token *end_tok, + octave_comment_list *lc) { tree_command *retval = 0; @@ -2571,7 +2290,7 @@ { octave_comment_list *tc = octave_comment_buffer::get_comment (); - lexer_flags.looping--; + curr_lexer->looping--; int l = while_tok->line (); int c = while_tok->column (); @@ -2584,9 +2303,11 @@ // Build a do-until command. -static tree_command * -make_do_until_command (token *until_tok, tree_statement_list *body, - tree_expression *expr, octave_comment_list *lc) +tree_command * +octave_parser::make_do_until_command (token *until_tok, + tree_statement_list *body, + tree_expression *expr, + octave_comment_list *lc) { tree_command *retval = 0; @@ -2594,7 +2315,7 @@ octave_comment_list *tc = octave_comment_buffer::get_comment (); - lexer_flags.looping--; + curr_lexer->looping--; int l = until_tok->line (); int c = until_tok->column (); @@ -2606,11 +2327,13 @@ // Build a for command. -static tree_command * -make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs, - tree_expression *expr, tree_expression *maxproc, - tree_statement_list *body, token *end_tok, - octave_comment_list *lc) +tree_command * +octave_parser::make_for_command (int tok_id, token *for_tok, + tree_argument_list *lhs, + tree_expression *expr, + tree_expression *maxproc, + tree_statement_list *body, token *end_tok, + octave_comment_list *lc) { tree_command *retval = 0; @@ -2620,7 +2343,7 @@ { octave_comment_list *tc = octave_comment_buffer::get_comment (); - lexer_flags.looping--; + curr_lexer->looping--; int l = for_tok->line (); int c = for_tok->column (); @@ -2637,7 +2360,7 @@ else { if (parfor) - yyerror ("invalid syntax for parfor statement"); + bison_error ("invalid syntax for parfor statement"); else retval = new tree_complex_for_command (lhs, expr, body, lc, tc, l, c); @@ -2649,8 +2372,8 @@ // Build a break command. -static tree_command * -make_break_command (token *break_tok) +tree_command * +octave_parser::make_break_command (token *break_tok) { tree_command *retval = 0; @@ -2664,8 +2387,8 @@ // Build a continue command. -static tree_command * -make_continue_command (token *continue_tok) +tree_command * +octave_parser::make_continue_command (token *continue_tok) { tree_command *retval = 0; @@ -2679,8 +2402,8 @@ // Build a return command. -static tree_command * -make_return_command (token *return_tok) +tree_command * +octave_parser::make_return_command (token *return_tok) { tree_command *retval = 0; @@ -2694,8 +2417,9 @@ // Start an if command. -static tree_if_command_list * -start_if_command (tree_expression *expr, tree_statement_list *list) +tree_if_command_list * +octave_parser::start_if_command (tree_expression *expr, + tree_statement_list *list) { maybe_warn_assign_as_truth_value (expr); @@ -2706,9 +2430,9 @@ // Finish an if command. -static tree_if_command * -finish_if_command (token *if_tok, tree_if_command_list *list, - token *end_tok, octave_comment_list *lc) +tree_if_command * +octave_parser::finish_if_command (token *if_tok, tree_if_command_list *list, + token *end_tok, octave_comment_list *lc) { tree_if_command *retval = 0; @@ -2738,9 +2462,10 @@ // Build an elseif clause. -static tree_if_clause * -make_elseif_clause (token *elseif_tok, tree_expression *expr, - tree_statement_list *list, octave_comment_list *lc) +tree_if_clause * +octave_parser::make_elseif_clause (token *elseif_tok, tree_expression *expr, + tree_statement_list *list, + octave_comment_list *lc) { maybe_warn_assign_as_truth_value (expr); @@ -2752,10 +2477,10 @@ // Finish a switch command. -static tree_switch_command * -finish_switch_command (token *switch_tok, tree_expression *expr, - tree_switch_case_list *list, token *end_tok, - octave_comment_list *lc) +tree_switch_command * +octave_parser::finish_switch_command (token *switch_tok, tree_expression *expr, + tree_switch_case_list *list, + token *end_tok, octave_comment_list *lc) { tree_switch_command *retval = 0; @@ -2785,9 +2510,10 @@ // Build a switch case. -static tree_switch_case * -make_switch_case (token *case_tok, tree_expression *expr, - tree_statement_list *list, octave_comment_list *lc) +tree_switch_case * +octave_parser::make_switch_case (token *case_tok, tree_expression *expr, + tree_statement_list *list, + octave_comment_list *lc) { maybe_warn_variable_switch_label (expr); @@ -2799,9 +2525,9 @@ // Build an assignment to a variable. -static tree_expression * -make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, - tree_expression *rhs) +tree_expression * +octave_parser::make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, + tree_expression *rhs) { tree_expression *retval = 0; @@ -2888,15 +2614,16 @@ else if (t == octave_value::op_asn_eq) return new tree_multi_assignment (lhs, rhs, false, l, c); else - yyerror ("computed multiple assignment not allowed"); + bison_error ("computed multiple assignment not allowed"); return retval; } // Define a script. -static void -make_script (tree_statement_list *cmds, tree_statement *end_script) +void +octave_parser::make_script (tree_statement_list *cmds, + tree_statement *end_script) { std::string doc_string; @@ -2929,9 +2656,10 @@ // Begin defining a function. -static octave_user_function * -start_function (tree_parameter_list *param_list, tree_statement_list *body, - tree_statement *end_fcn_stmt) +octave_user_function * +octave_parser::start_function (tree_parameter_list *param_list, + tree_statement_list *body, + tree_statement *end_fcn_stmt) { // We'll fill in the return list later. @@ -2954,16 +2682,17 @@ return fcn; } -static tree_statement * -make_end (const std::string& type, int l, int c) +tree_statement * +octave_parser::make_end (const std::string& type, int l, int c) { return make_statement (new tree_no_op_command (type, l, c)); } // Do most of the work for defining a function. -static octave_user_function * -frob_function (const std::string& fname, octave_user_function *fcn) +octave_user_function * +octave_parser::frob_function (const std::string& fname, + octave_user_function *fcn) { std::string id_name = fname; @@ -2972,7 +2701,7 @@ // file. Matlab doesn't provide a diagnostic (it ignores the stated // name). if (! autoloading && reading_fcn_file - && current_function_depth == 1 && ! parsing_subfunctions) + && curr_fcn_depth == 1 && ! parsing_subfunctions) { // FIXME -- should curr_fcn_file_name already be // preprocessed when we get here? It seems to only be a @@ -3007,24 +2736,24 @@ if (fcn_file_from_relative_lookup) fcn->mark_relative (); - if (current_function_depth > 1 || parsing_subfunctions) + if (curr_fcn_depth > 1 || parsing_subfunctions) { fcn->stash_parent_fcn_name (curr_fcn_file_name); - if (current_function_depth > 1) + if (curr_fcn_depth > 1) fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]); else fcn->stash_parent_fcn_scope (primary_fcn_scope); } - if (lexer_flags.parsing_class_method) + if (curr_lexer->parsing_class_method) { - if (current_class_name == id_name) + if (curr_class_name == id_name) fcn->mark_as_class_constructor (); else fcn->mark_as_class_method (); - fcn->stash_dispatch_class (current_class_name); + fcn->stash_dispatch_class (curr_class_name); } std::string nm = fcn->fcn_file_name (); @@ -3044,9 +2773,10 @@ } fcn->stash_function_name (id_name); - fcn->stash_fcn_location (input_line_number, current_input_column); - - if (! help_buf.empty () && current_function_depth == 1 + fcn->stash_fcn_location (curr_lexer->input_line_number, + curr_lexer->current_input_column); + + if (! help_buf.empty () && curr_fcn_depth == 1 && ! parsing_subfunctions) { fcn->document (help_buf.top ()); @@ -3054,16 +2784,17 @@ help_buf.pop (); } - if (reading_fcn_file && current_function_depth == 1 + if (reading_fcn_file && curr_fcn_depth == 1 && ! parsing_subfunctions) primary_fcn_ptr = fcn; return fcn; } -static tree_function_def * -finish_function (tree_parameter_list *ret_list, - octave_user_function *fcn, octave_comment_list *lc) +tree_function_def * +octave_parser::finish_function (tree_parameter_list *ret_list, + octave_user_function *fcn, + octave_comment_list *lc) { tree_function_def *retval = 0; @@ -3086,7 +2817,7 @@ fcn->define_ret_list (ret_list); - if (current_function_depth > 1 || parsing_subfunctions) + if (curr_fcn_depth > 1 || parsing_subfunctions) { fcn->mark_as_subfunction (); @@ -3103,10 +2834,10 @@ primary_fcn_scope); } - if (current_function_depth == 1 && fcn) + if (curr_fcn_depth == 1 && fcn) symbol_table::update_nest (fcn->scope ()); - if (! reading_fcn_file && current_function_depth == 1) + if (! reading_fcn_file && curr_fcn_depth == 1) { // We are either reading a script file or defining a function // at the command line, so this definition creates a @@ -3131,38 +2862,204 @@ return retval; } -static void -recover_from_parsing_function (void) +void +octave_parser::recover_from_parsing_function (void) { if (parser_symtab_context.empty ()) panic_impossible (); parser_symtab_context.pop (); - if (reading_fcn_file && current_function_depth == 1 + if (reading_fcn_file && curr_fcn_depth == 1 && ! parsing_subfunctions) parsing_subfunctions = true; - current_function_depth--; + curr_fcn_depth--; function_scopes.pop_back (); - lexer_flags.defining_func--; - lexer_flags.parsed_function_name.pop (); - lexer_flags.looking_at_return_list = false; - lexer_flags.looking_at_parameter_list = false; + curr_lexer->defining_func--; + curr_lexer->parsed_function_name.pop (); + curr_lexer->looking_at_return_list = false; + curr_lexer->looking_at_parameter_list = false; +} + +tree_funcall * +octave_parser::make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(2) = class_nm; + args(1) = package_nm; + args(0) = method_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__superclass_reference__"); + + return new tree_funcall (fcn, args); +} + +tree_funcall * +octave_parser::make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(1) = class_nm; + args(0) = package_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__meta_class_query__"); + + return new tree_funcall (fcn, args); +} + +// A CLASSDEF block defines a class that has a constructor and other +// methods, but it is not an executable command. Parsing the block +// makes some changes in the symbol table (inserting the constructor +// and methods, and adding to the list of known objects) and creates +// a parse tree containing meta information about the class. + +tree_classdef * +octave_parser::make_classdef (token *tok_val, + tree_classdef_attribute_list *a, + tree_identifier *id, + tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc) +{ + tree_classdef *retval = 0; + + std::string cls_name = id->name (); + + std::string nm = curr_fcn_file_name; + + size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); + + if (pos != std::string::npos) + nm = curr_fcn_file_name.substr (pos+1); + + if (nm != cls_name) + { + bison_error ("invalid classdef definition, the class name must match the file name"); + return retval; + } + + if (end_token_ok (end_tok, token::classdef_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef (a, id, sc, body, lc, tc, l, c); + } + + return retval; +} + +tree_classdef_properties_block * +octave_parser::make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_properties_block *retval = 0; + + if (end_token_ok (end_tok, token::properties_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); + } + + return retval; +} + +tree_classdef_methods_block * +octave_parser::make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_methods_block *retval = 0; + + if (end_token_ok (end_tok, token::methods_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); + } + + return retval; +} + +tree_classdef_events_block * +octave_parser::make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_events_block *retval = 0; + + if (end_token_ok (end_tok, token::events_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); + } + + return retval; +} + +tree_classdef_enum_block * +octave_parser::make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_enum_block *retval = 0; + + if (end_token_ok (end_tok, token::enumeration_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); + } + + return retval; } // Make an index expression. -static tree_index_expression * -make_index_expression (tree_expression *expr, tree_argument_list *args, - char type) +tree_index_expression * +octave_parser::make_index_expression (tree_expression *expr, + tree_argument_list *args, char type) { tree_index_expression *retval = 0; if (args && args->has_magic_tilde ()) { - yyerror ("invalid use of empty argument (~) in index expression"); + bison_error ("invalid use of empty argument (~) in index expression"); return retval; } @@ -3188,8 +3085,9 @@ // Make an indirect reference expression. -static tree_index_expression * -make_indirect_ref (tree_expression *expr, const std::string& elt) +tree_index_expression * +octave_parser::make_indirect_ref (tree_expression *expr, + const std::string& elt) { tree_index_expression *retval = 0; @@ -3210,15 +3108,15 @@ else retval = new tree_index_expression (expr, elt, l, c); - lexer_flags.looking_at_indirect_ref = false; + curr_lexer->looking_at_indirect_ref = false; return retval; } // Make an indirect reference expression with dynamic field name. -static tree_index_expression * -make_indirect_ref (tree_expression *expr, tree_expression *elt) +tree_index_expression * +octave_parser::make_indirect_ref (tree_expression *expr, tree_expression *elt) { tree_index_expression *retval = 0; @@ -3239,15 +3137,16 @@ else retval = new tree_index_expression (expr, elt, l, c); - lexer_flags.looking_at_indirect_ref = false; + curr_lexer->looking_at_indirect_ref = false; return retval; } // Make a declaration command. -static tree_decl_command * -make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst) +tree_decl_command * +octave_parser::make_decl_command (int tok, token *tok_val, + tree_decl_init_list *lst) { tree_decl_command *retval = 0; @@ -3261,7 +3160,7 @@ break; case PERSISTENT: - if (current_function_depth > 0) + if (curr_fcn_depth > 0) retval = new tree_persistent_command (lst, l, c); else { @@ -3281,18 +3180,18 @@ return retval; } -static tree_argument_list * -validate_matrix_row (tree_argument_list *row) +tree_argument_list * +octave_parser::validate_matrix_row (tree_argument_list *row) { if (row && row->has_magic_tilde ()) - yyerror ("invalid use of tilde (~) in matrix expression"); + bison_error ("invalid use of tilde (~) in matrix expression"); return row; } // Finish building a matrix list. -static tree_expression * -finish_matrix (tree_matrix *m) +tree_expression * +octave_parser::finish_matrix (tree_matrix *m) { tree_expression *retval = m; @@ -3335,16 +3234,16 @@ // Finish building a cell list. -static tree_expression * -finish_cell (tree_cell *c) +tree_expression * +octave_parser::finish_cell (tree_cell *c) { return finish_matrix (c); } -static void -maybe_warn_missing_semi (tree_statement_list *t) +void +octave_parser::maybe_warn_missing_semi (tree_statement_list *t) { - if (current_function_depth > 0) + if (curr_fcn_depth > 0) { tree_statement *tmp = t->back (); @@ -3356,9 +3255,9 @@ } } -static tree_statement_list * -set_stmt_print_flag (tree_statement_list *list, char sep, - bool warn_missing_semi) +tree_statement_list * +octave_parser::set_stmt_print_flag (tree_statement_list *list, char sep, + bool warn_missing_semi) { tree_statement *tmp = list->back (); @@ -3393,15 +3292,16 @@ return list; } -static tree_statement_list * -make_statement_list (tree_statement *stmt) +tree_statement_list * +octave_parser::make_statement_list (tree_statement *stmt) { return new tree_statement_list (stmt); } -static tree_statement_list * -append_statement_list (tree_statement_list *list, char sep, - tree_statement *stmt, bool warn_missing_semi) +tree_statement_list * +octave_parser::append_statement_list (tree_statement_list *list, char sep, + tree_statement *stmt, + bool warn_missing_semi) { set_stmt_print_flag (list, sep, warn_missing_semi); @@ -3410,164 +3310,50 @@ return list; } -static tree_funcall * -make_superclass_ref (const std::string& method_nm, - const std::string& package_nm, - const std::string& class_nm, - int l, int c) -{ - octave_value_list args; - - args(2) = class_nm; - args(1) = package_nm; - args(0) = method_nm; - - octave_value fcn - = symbol_table::find_built_in_function ("__superclass_reference__"); - - return new tree_funcall (fcn, args); -} - -static tree_funcall * -make_meta_class_query (const std::string& package_nm, - const std::string& class_nm, - int l, int c) +void +octave_parser::bison_error (const char *s) + { - octave_value_list args; - - args(1) = class_nm; - args(0) = package_nm; - - octave_value fcn - = symbol_table::find_built_in_function ("__meta_class_query__"); - - return new tree_funcall (fcn, args); -} - -// A CLASSDEF block defines a class that has a constructor and other -// methods, but it is not an executable command. Parsing the block -// makes some changes in the symbol table (inserting the constructor -// and methods, and adding to the list of known objects) and creates -// a parse tree containing meta information about the class. - -static tree_classdef * -make_classdef (token *tok_val, tree_classdef_attribute_list *a, - tree_identifier *id, tree_classdef_superclass_list *sc, - tree_classdef_body *body, token *end_tok, - octave_comment_list *lc) -{ - tree_classdef *retval = 0; - - std::string cls_name = id->name (); - - std::string nm = curr_fcn_file_name; - - size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); - - if (pos != std::string::npos) - nm = curr_fcn_file_name.substr (pos+1); - - if (nm != cls_name) + int err_col = curr_lexer->current_input_column - 1; + + std::ostringstream output_buf; + + if (reading_fcn_file || reading_script_file || reading_classdef_file) + output_buf << "parse error near line " << curr_lexer->input_line_number + << " of file " << curr_fcn_file_full_name; + else + output_buf << "parse error:"; + + if (s && strcmp (s, "parse error") != 0) + output_buf << "\n\n " << s; + + output_buf << "\n\n"; + + if (! current_input_line.empty ()) { - yyerror ("invalid classdef definition, the class name must match the file name"); - return retval; - } - - if (end_token_ok (end_tok, token::classdef_end)) - { - octave_comment_list *tc = octave_comment_buffer::get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - retval = new tree_classdef (a, id, sc, body, lc, tc, l, c); + size_t len = current_input_line.length (); + + if (current_input_line[len-1] == '\n') + current_input_line.resize (len-1); + + // Print the line, maybe with a pointer near the error token. + + output_buf << ">>> " << current_input_line << "\n"; + + if (err_col == 0) + err_col = len; + + for (int i = 0; i < err_col + 3; i++) + output_buf << " "; + + output_buf << "^"; } - return retval; -} - -static tree_classdef_properties_block * -make_classdef_properties_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_property_list *plist, - token *end_tok, octave_comment_list *lc) -{ - tree_classdef_properties_block *retval = 0; - - if (end_token_ok (end_tok, token::properties_end)) - { - octave_comment_list *tc = octave_comment_buffer::get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); - } - - return retval; -} - -static tree_classdef_methods_block * -make_classdef_methods_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_methods_list *mlist, - token *end_tok, octave_comment_list *lc) -{ - tree_classdef_methods_block *retval = 0; - - if (end_token_ok (end_tok, token::methods_end)) - { - octave_comment_list *tc = octave_comment_buffer::get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); - } - - return retval; -} - -static tree_classdef_events_block * -make_classdef_events_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_events_list *elist, - token *end_tok, octave_comment_list *lc) -{ - tree_classdef_events_block *retval = 0; - - if (end_token_ok (end_tok, token::events_end)) - { - octave_comment_list *tc = octave_comment_buffer::get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); - } - - return retval; -} - -static tree_classdef_enum_block * -make_classdef_enum_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_enum_list *elist, - token *end_tok, octave_comment_list *lc) -{ - tree_classdef_enum_block *retval = 0; - - if (end_token_ok (end_tok, token::enumeration_end)) - { - octave_comment_list *tc = octave_comment_buffer::get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); - } - - return retval; + output_buf << "\n"; + + std::string msg = output_buf.str (); + + parse_error ("%s", msg.c_str ()); } static void @@ -3619,9 +3405,6 @@ } } - if (c == '\n') - input_line_number++; - return c; } @@ -3629,20 +3412,53 @@ stdio_stream_reader : public stream_reader { public: - stdio_stream_reader (FILE *f_arg) : stream_reader (), f (f_arg) { } - - int getc (void) { return ::text_getc (f); } + + stdio_stream_reader (FILE *f_arg, int& l, int& c) + : stream_reader (), f (f_arg), line_num (l), column_num (c) + { } + + int getc (void) + { + char c = ::text_getc (f); + + if (c == '\n') + { + line_num++; + column_num = 0; + } + else + { + // FIXME -- try to be smarter about tabs? + column_num++; + } + + return c; + } + int ungetc (int c) { if (c == '\n') - input_line_number--; + { + line_num--; + column_num = 0; + } + else + { + // FIXME -- try to be smarter about tabs? + column_num--; + } return ::ungetc (c, f); } private: + FILE *f; + int& line_num; + + int& column_num; + // No copying! stdio_stream_reader (const stdio_stream_reader&); @@ -3661,11 +3477,7 @@ { case ' ': case '\t': - current_input_column++; - break; - case '\n': - current_input_column = 1; break; default: @@ -3699,7 +3511,8 @@ } static std::string -gobble_leading_white_space (FILE *ffile, bool& eof) +gobble_leading_white_space (FILE *ffile, bool& eof, int& line_num, + int& column_num) { std::string help_txt; @@ -3710,7 +3523,7 @@ std::string txt; - stdio_stream_reader stdio_reader (ffile); + stdio_stream_reader stdio_reader (ffile, line_num, column_num); while (true) { @@ -3719,7 +3532,7 @@ if (eof) break; - txt = grab_comment_block (stdio_reader, true, eof); + txt = CURR_LEXER->grab_comment_block (stdio_reader, true, eof); if (txt.empty ()) break; @@ -3739,6 +3552,15 @@ return help_txt; } +static std::string +gobble_leading_white_space (FILE *ffile, bool& eof) +{ + int line_num = 1; + int column_num = 1; + + return gobble_leading_white_space (ffile, eof, line_num, column_num); +} + static bool looking_at_function_keyword (FILE *ffile) { @@ -3760,8 +3582,8 @@ static octave_function * parse_fcn_file (const std::string& ff, const std::string& dispatch_type, - bool force_script = false, bool require_file = true, - const std::string& warn_for = std::string ()) + bool require_file, bool force_script, bool autoload, + bool relative_lookup, const std::string& warn_for) { unwind_protect frame; @@ -3775,27 +3597,11 @@ frame.protect_var (ff_instream); - frame.protect_var (input_line_number); - frame.protect_var (current_input_column); frame.protect_var (reading_fcn_file); frame.protect_var (line_editing); - frame.protect_var (current_class_name); - frame.protect_var (current_function_depth); - frame.protect_var (function_scopes); - frame.protect_var (max_function_depth); - frame.protect_var (parsing_subfunctions); - frame.protect_var (endfunction_found); - - input_line_number = 1; - current_input_column = 1; + reading_fcn_file = true; line_editing = false; - current_class_name = dispatch_type; - current_function_depth = 0; - function_scopes.clear (); - max_function_depth = 0; - parsing_subfunctions = false; - endfunction_found = false; frame.add_fcn (command_history::ignore_entries, command_history::ignoring_entries ()); @@ -3810,7 +3616,21 @@ { bool eof; - std::string help_txt = gobble_leading_white_space (ffile, eof); + // octave_parser constructor sets this for us. + frame.protect_var (CURR_LEXER); + + octave_parser *curr_parser = new octave_parser (); + frame.add_fcn (octave_parser::cleanup, curr_parser); + + curr_parser->curr_class_name = dispatch_type; + curr_parser->autoloading = autoload; + curr_parser->fcn_file_from_relative_lookup = relative_lookup; + + std::string help_txt + = gobble_leading_white_space + (ffile, eof, + curr_parser->curr_lexer->input_line_number, + curr_parser->curr_lexer->current_input_column); if (! help_txt.empty ()) help_buf.push (help_txt); @@ -3820,15 +3640,12 @@ std::string file_type; frame.protect_var (get_input_from_eval_string); - frame.protect_var (parser_end_of_input); frame.protect_var (reading_fcn_file); frame.protect_var (reading_script_file); frame.protect_var (reading_classdef_file); frame.protect_var (Vecho_executing_commands); - get_input_from_eval_string = false; - parser_end_of_input = false; if (! force_script && looking_at_function_keyword (ffile)) { @@ -3861,22 +3678,6 @@ reading_script_file = true; } - YY_BUFFER_STATE old_buf = current_buffer (); - YY_BUFFER_STATE new_buf = create_buffer (ffile); - - frame.add_fcn (switch_to_buffer, old_buf); - frame.add_fcn (delete_buffer, new_buf); - - switch_to_buffer (new_buf); - - frame.protect_var (primary_fcn_ptr); - primary_fcn_ptr = 0; - - frame.protect_var (classdef_object); - classdef_object = 0; - - reset_parser (); - // Do this with an unwind-protect cleanup function so that // the forced variables will be unmarked in the event of an // interrupt. @@ -3887,19 +3688,19 @@ help_buf.push (help_txt); if (reading_script_file) - prep_lexer_for_script_file (); + curr_parser->curr_lexer->prep_for_script_file (); else if (reading_classdef_file) - prep_lexer_for_classdef_file (); + curr_parser->curr_lexer->prep_for_classdef_file (); else - prep_lexer_for_function_file (); - - lexer_flags.parsing_class_method = ! dispatch_type.empty (); + curr_parser->curr_lexer->prep_for_function_file (); + + curr_parser->curr_lexer->parsing_class_method = ! dispatch_type.empty (); frame.protect_var (global_command); global_command = 0; - int status = yyparse (); + int status = curr_parser->run (); // Use an unwind-protect cleanup function so that the // global_command list will be deleted in the event of an @@ -3907,11 +3708,11 @@ frame.add_fcn (cleanup_statement_list, &global_command); - fcn_ptr = primary_fcn_ptr; + fcn_ptr = curr_parser->primary_fcn_ptr; if (status == 0) { - if (reading_classdef_file && classdef_object) + if (reading_classdef_file && curr_parser->classdef_object) { // Convert parse tree for classdef object to // meta.class info (and stash it in the symbol @@ -3920,7 +3721,7 @@ if (fcn_ptr) panic_impossible (); - fcn_ptr = classdef_object->make_meta_class (); + fcn_ptr = curr_parser->classdef_object->make_meta_class (); } } else @@ -3931,12 +3732,15 @@ } else { + int l = curr_parser->curr_lexer->input_line_number; + int c = curr_parser->curr_lexer->current_input_column; + tree_statement *end_of_script - = make_end ("endscript", input_line_number, current_input_column); - - make_script (0, end_of_script); - - fcn_ptr = primary_fcn_ptr; + = curr_parser->make_end ("endscript", l, c); + + curr_parser->make_script (0, end_of_script); + + fcn_ptr = curr_parser->primary_fcn_ptr; } } else if (require_file) @@ -3971,7 +3775,9 @@ if (retval.empty ()) { - octave_function *fcn = parse_fcn_file (file, ""); + octave_function *fcn = parse_fcn_file (file, "", true, + false, false, + false, ""); if (fcn) { @@ -4049,9 +3855,7 @@ std::string file; - frame.protect_var (fcn_file_from_relative_lookup); - - fcn_file_from_relative_lookup = false; + bool relative_lookup = false; file = nm; @@ -4067,13 +3871,7 @@ nm = nm.substr (pos+1); } - if (autoload) - { - frame.protect_var (autoloading); - autoloading = true; - } - - fcn_file_from_relative_lookup = ! octave_env::absolute_pathname (file); + relative_lookup = ! octave_env::absolute_pathname (file); file = octave_env::make_absolute (file); @@ -4084,7 +3882,7 @@ if (autoload && ! fcn_name.empty ()) nm = fcn_name; - retval = octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup); + retval = octave_dynamic_loader::load_oct (nm, file, relative_lookup); } else if (len > 4 && file.substr (len-4, len-1) == ".mex") { @@ -4097,10 +3895,11 @@ curr_fcn_file_full_name = file.substr (0, len - 2); octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2), - dispatch_type, autoloading, - false); - - retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup); + dispatch_type, false, + autoload, autoload, + relative_lookup, ""); + + retval = octave_dynamic_loader::load_mex (nm, file, relative_lookup); if (tmpfcn) retval->document (tmpfcn->doc_string ()); @@ -4116,7 +3915,8 @@ curr_fcn_file_name = nm; curr_fcn_file_full_name = file; - retval = parse_fcn_file (file, dispatch_type, autoloading); + retval = parse_fcn_file (file, dispatch_type, true, autoload, + autoload, relative_lookup, ""); } if (retval) @@ -4319,8 +4119,9 @@ if (! error_state) { - octave_function *fcn = parse_fcn_file (file_full_name, "", true, - require_file, warn_for); + octave_function *fcn = parse_fcn_file (file_full_name, "", + require_file, true, false, + false, warn_for); if (! error_state) { @@ -4631,50 +4432,30 @@ unwind_protect frame; - frame.protect_var (input_line_number); - frame.protect_var (current_input_column); + // octave_parser constructor sets this for us. + frame.protect_var (CURR_LEXER); + + octave_parser *curr_parser = new octave_parser (); + frame.add_fcn (octave_parser::cleanup, curr_parser); + frame.protect_var (get_input_from_eval_string); - frame.protect_var (input_from_eval_string_pending); - frame.protect_var (parser_end_of_input); frame.protect_var (line_editing); frame.protect_var (current_eval_string); - frame.protect_var (current_function_depth); - frame.protect_var (function_scopes); - frame.protect_var (max_function_depth); - frame.protect_var (parsing_subfunctions); - frame.protect_var (endfunction_found); frame.protect_var (reading_fcn_file); frame.protect_var (reading_script_file); frame.protect_var (reading_classdef_file); - input_line_number = 1; - current_input_column = 1; get_input_from_eval_string = true; - input_from_eval_string_pending = true; - parser_end_of_input = false; line_editing = false; - current_function_depth = 0; - function_scopes.clear (); - max_function_depth = 0; - parsing_subfunctions = false; - endfunction_found = false; reading_fcn_file = false; reading_script_file = false; reading_classdef_file = false; current_eval_string = s; - YY_BUFFER_STATE old_buf = current_buffer (); - YY_BUFFER_STATE new_buf = create_buffer (0); - - frame.add_fcn (switch_to_buffer, old_buf); - frame.add_fcn (delete_buffer, new_buf); - - switch_to_buffer (new_buf); - do { - reset_parser (); + curr_parser->reset (); frame.protect_var (global_command); @@ -4686,7 +4467,7 @@ symbol_table::scope_id scope = symbol_table::top_scope (); frame.add_fcn (symbol_table::unmark_forced_variables, scope); - parse_status = yyparse (); + parse_status = curr_parser->run (); tree_statement_list *command_list = global_command; @@ -4748,7 +4529,7 @@ || tree_continue_command::continuing) break; } - else if (parser_end_of_input) + else if (curr_parser->end_of_input) break; } }
--- a/libinterp/parse-tree/parse.h +++ b/libinterp/parse-tree/parse.h @@ -28,28 +28,61 @@ #include <string> #include <stack> +#include <vector> +#include <map> -extern void reset_parser (void); -extern int octave_lex (void); -extern int octave_parse (void); +#include "lex.h" +#include "symtab.h" +#include "token.h" +class octave_comment_list; +class octave_function; +class octave_user_function; class tree; -class tree_matrix; +class tree_anon_fcn_handle; +class tree_argument_list; +class tree_cell; +class tree_classdef; +class tree_classdef_attribute_list; +class tree_classdef_body; +class tree_classdef_enum_block; +class tree_classdef_enum_list; +class tree_classdef_events_block; +class tree_classdef_events_list; +class tree_classdef_methods_block; +class tree_classdef_methods_list; +class tree_classdef_properties_block; +class tree_classdef_property_list; +class tree_classdef_superclass_list; +class tree_colon_expression; +class tree_command; +class tree_constant; +class tree_decl_command; +class tree_decl_init_list; +class tree_expression; +class tree_fcn_handle; +class tree_funcall; +class tree_function_def; class tree_identifier; +class tree_if_clause; +class tree_if_command; +class tree_if_command_list; +class tree_index_expression; +class tree_matrix; +class tree_matrix; +class tree_parameter_list; +class tree_statement; class tree_statement_list; -class octave_function; +class tree_statement_listtree_statement; +class tree_switch_case; +class tree_switch_case_list; +class tree_switch_command; #include "oct-obj.h" // Nonzero means print parser debugging info (-d). extern int octave_debug; -// The current input line number. -extern int input_line_number; - -// The column of the current token. -extern int current_input_column; - // Buffer for help text snagged from function files. extern std::stack<std::string> help_buf; @@ -62,10 +95,6 @@ // TRUE means input is coming from startup file. extern bool input_from_startup_file; -// Name of the current class when we are parsing class methods or -// constructors. -extern std::string current_class_name; - extern OCTINTERP_API std::string get_help_from_file (const std::string& nm, bool& symbol_found, std::string& file); @@ -113,4 +142,320 @@ extern OCTINTERP_API void cleanup_statement_list (tree_statement_list **lst); +// Global access to currently active lexer. +// FIXME -- to be removed after more parser+lexer refactoring. +extern lexical_feedback *CURR_LEXER; + +class +octave_parser +{ +public: + + octave_parser (void) + : end_of_input (false), endfunction_found (false), + autoloading (false), fcn_file_from_relative_lookup (false), + parsing_subfunctions (false), max_fcn_depth (0), + curr_fcn_depth (0), primary_fcn_scope (-1), + curr_class_name (), function_scopes (), primary_fcn_ptr (0), + classdef_object (0), curr_lexer (new lexical_feedback ()) + { + CURR_LEXER = curr_lexer; + } + + ~octave_parser (void) + { + delete curr_lexer; + } + + void reset (void) + { + curr_lexer->reset (); + } + + int run (void); + + // Error mesages for mismatched end tokens. + void end_error (const char *type, token::end_tok_type ettype, int l, int c); + + // Check to see that end tokens are properly matched. + bool end_token_ok (token *tok, token::end_tok_type expected); + + // Maybe print a warning if an assignment expression is used as the + // test in a logical expression. + void maybe_warn_assign_as_truth_value (tree_expression *expr); + + // Maybe print a warning about switch labels that aren't constants. + void maybe_warn_variable_switch_label (tree_expression *expr); + + // Finish building a range. + tree_expression *finish_colon_expression (tree_colon_expression *e); + + // Build a constant. + tree_constant *make_constant (int op, token *tok_val); + + // Build a function handle. + tree_fcn_handle *make_fcn_handle (token *tok_val); + + // Build an anonymous function handle. + tree_anon_fcn_handle * + make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt); + + // Build a binary expression. + tree_expression * + make_binary_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2); + + // Build a boolean expression. + tree_expression * + make_boolean_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2); + + // Build a prefix expression. + tree_expression * + make_prefix_op (int op, tree_expression *op1, token *tok_val); + + // Build a postfix expression. + tree_expression * + make_postfix_op (int op, tree_expression *op1, token *tok_val); + + // Build an unwind-protect command. + tree_command * + make_unwind_command (token *unwind_tok, tree_statement_list *body, + tree_statement_list *cleanup, token *end_tok, + octave_comment_list *lc, octave_comment_list *mc); + + // Build a try-catch command. + tree_command * + make_try_command (token *try_tok, tree_statement_list *body, + tree_statement_list *cleanup, token *end_tok, + octave_comment_list *lc, octave_comment_list *mc); + + // Build a while command. + tree_command * + make_while_command (token *while_tok, tree_expression *expr, + tree_statement_list *body, token *end_tok, + octave_comment_list *lc); + + // Build a do-until command. + tree_command * + make_do_until_command (token *until_tok, tree_statement_list *body, + tree_expression *expr, octave_comment_list *lc); + + // Build a for command. + tree_command * + make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs, + tree_expression *expr, tree_expression *maxproc, + tree_statement_list *body, token *end_tok, + octave_comment_list *lc); + + // Build a break command. + tree_command *make_break_command (token *break_tok); + + // Build a continue command. + tree_command *make_continue_command (token *continue_tok); + + // Build a return command. + tree_command *make_return_command (token *return_tok); + + // Start an if command. + tree_if_command_list * + start_if_command (tree_expression *expr, tree_statement_list *list); + + // Finish an if command. + tree_if_command * + finish_if_command (token *if_tok, tree_if_command_list *list, + token *end_tok, octave_comment_list *lc); + + // Build an elseif clause. + tree_if_clause * + make_elseif_clause (token *elseif_tok, tree_expression *expr, + tree_statement_list *list, octave_comment_list *lc); + + // Finish a switch command. + tree_switch_command * + finish_switch_command (token *switch_tok, tree_expression *expr, + tree_switch_case_list *list, token *end_tok, + octave_comment_list *lc); + + // Build a switch case. + tree_switch_case * + make_switch_case (token *case_tok, tree_expression *expr, + tree_statement_list *list, octave_comment_list *lc); + + // Build an assignment to a variable. + tree_expression * + make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, + tree_expression *rhs); + + // Define a script. + void make_script (tree_statement_list *cmds, tree_statement *end_script); + + // Begin defining a function. + octave_user_function * + start_function (tree_parameter_list *param_list, tree_statement_list *body, + tree_statement *end_function); + + // Create a no-op statement for end_function. + tree_statement *make_end (const std::string& type, int l, int c); + + // Do most of the work for defining a function. + octave_user_function * + frob_function (const std::string& fname, octave_user_function *fcn); + + // Finish defining a function. + tree_function_def * + finish_function (tree_parameter_list *ret_list, + octave_user_function *fcn, octave_comment_list *lc); + + // Reset state after parsing function. + void + recover_from_parsing_function (void); + + tree_funcall * + make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c); + + tree_funcall * + make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c); + + tree_classdef * + make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc); + + tree_classdef_properties_block * + make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_methods_block * + make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_events_block * + make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_enum_block * + make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, octave_comment_list *lc); + + // Make an index expression. + tree_index_expression * + make_index_expression (tree_expression *expr, + tree_argument_list *args, char type); + + // Make an indirect reference expression. + tree_index_expression * + make_indirect_ref (tree_expression *expr, const std::string&); + + // Make an indirect reference expression with dynamic field name. + tree_index_expression * + make_indirect_ref (tree_expression *expr, tree_expression *field); + + // Make a declaration command. + tree_decl_command * + make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst); + + // Validate argument list forming a matrix or cell row. + tree_argument_list *validate_matrix_row (tree_argument_list *row); + + // Finish building a matrix list. + tree_expression *finish_matrix (tree_matrix *m); + + // Finish building a cell list. + tree_expression *finish_cell (tree_cell *c); + + // Maybe print a warning. Duh. + void maybe_warn_missing_semi (tree_statement_list *); + + // Set the print flag for a statement based on the separator type. + tree_statement_list * + set_stmt_print_flag (tree_statement_list *, char, bool); + + // Create a statement list. + tree_statement_list *make_statement_list (tree_statement *stmt); + + // Append a statement to an existing statement list. + tree_statement_list * + append_statement_list (tree_statement_list *list, char sep, + tree_statement *stmt, bool warn_missing_semi); + + // Generic error messages. + void bison_error (const char *s); + + // TRUE means that we have encountered EOF on the input stream. + bool end_of_input; + + // Have we found an explicit end to a function? + bool endfunction_found; + + // TRUE means we are in the process of autoloading a function. + bool autoloading; + + // TRUE means the current function file was found in a relative path + // element. + bool fcn_file_from_relative_lookup; + + // FALSE if we are still at the primary function. Subfunctions can + // only be declared inside function files. + bool parsing_subfunctions; + + // Maximum function depth detected. Used to determine whether + // we have nested functions or just implicitly ended subfunctions. + int max_fcn_depth; + + // = 0 currently outside any function. + // = 1 inside the primary function or a subfunction. + // > 1 means we are looking at a function definition that seems to be + // inside a function. Note that the function still might not be a + // nested function. + int curr_fcn_depth; + + // Scope where we install all subfunctions and nested functions. Only + // used while reading function files. + symbol_table::scope_id primary_fcn_scope; + + // Name of the current class when we are parsing class methods or + // constructors. + std::string curr_class_name; + + // A stack holding the nested function scopes being parsed. + // We don't use std::stack, because we want the clear method. Also, we + // must access one from the top + std::vector<symbol_table::scope_id> function_scopes; + + // Pointer to the primary user function or user script function. + octave_function *primary_fcn_ptr; + + // Pointer to the classdef object we just parsed, if any. + tree_classdef *classdef_object; + + // State of the lexer. + lexical_feedback *curr_lexer; + + // For unwind protect. + static void cleanup (octave_parser *parser) { delete parser; } + +private: + + // No copying! + + octave_parser (const octave_parser&); + + octave_parser& operator = (const octave_parser&); +}; + #endif
--- a/libinterp/parse-tree/pt-id.cc +++ b/libinterp/parse-tree/pt-id.cc @@ -59,7 +59,8 @@ } octave_value_list -tree_identifier::rvalue (int nargout) +tree_identifier::rvalue (int nargout, + const std::list<octave_lvalue> *lvalue_list) { octave_value_list retval; @@ -91,7 +92,9 @@ { octave_value_list tmp_args; - retval = val.do_multi_index_op (nargout, tmp_args); + retval = (lvalue_list + ? val.do_multi_index_op (nargout, tmp_args, lvalue_list) + : val.do_multi_index_op (nargout, tmp_args)); } else {
--- a/libinterp/parse-tree/pt-id.h +++ b/libinterp/parse-tree/pt-id.h @@ -104,7 +104,13 @@ octave_value rvalue1 (int nargout = 1); - octave_value_list rvalue (int nargout); + octave_value_list rvalue (int nargout) + { + return rvalue (nargout, 0); + } + + octave_value_list rvalue (int nargout, + const std::list<octave_lvalue> *lvalue_list); octave_lvalue lvalue (void);
--- a/libinterp/parse-tree/pt-mat.cc +++ b/libinterp/parse-tree/pt-mat.cc @@ -402,7 +402,7 @@ first_elem = false; dv = this_elt_dv; } - else if (! dv.hvcat (this_elt_dv, 1)) + else if ((! any_class) && (! dv.hvcat (this_elt_dv, 1))) { eval_error ("horizontal dimensions mismatch", dv, this_elt_dv); break; @@ -644,7 +644,7 @@ dv(1) = this_elt_nc; dv(0) += this_elt_nr; } - else if (! dv.hvcat (this_elt_dv, 0)) + else if ((!any_class) && (!dv.hvcat (this_elt_dv, 0))) { eval_error ("vertical dimensions mismatch", dv, this_elt_dv); return;
--- a/libinterp/parse-tree/token.h +++ b/libinterp/parse-tree/token.h @@ -25,6 +25,8 @@ #include <string> +#include "symtab.h" + class token {
--- a/liboctave/Makefile.am +++ b/liboctave/Makefile.am @@ -135,5 +135,7 @@ nobase_liboctavetests_DATA = $(TST_FILES) -DISTCLEANFILES += $(BUILT_INCS) +DISTCLEANFILES += \ + $(BUILT_INCS) \ + $(TST_FILES)
--- a/liboctave/cruft/mkf77def.in +++ b/liboctave/cruft/mkf77def.in @@ -25,19 +25,19 @@ F77_APPEND_UNDERSCORE="@F77_APPEND_UNDERSCORE@" F77_APPEND_EXTRA_UNDERSCORE="@F77_APPEND_EXTRA_UNDERSCORE@" -if $F77_TOLOWER; then +if test x$F77_TOLOWER = xyes; then case_cmd="tolower"; else case_cmd="toupper"; fi -if $F77_APPEND_UNDERSCORE; then +if test x$F77_APPEND_UNDERSCORE = xyes; then uscore="_"; else uscore=""; fi -if $F77_APPEND_EXTRA_UNDERSCORE; then +if test x$F77_APPEND_EXTRA_UNDERSCORE = xyes; then awkcmd="$AWK '{ if (\$0 ~ /_/) extra = \"_\"; else extra = \"\"; printf (\"%s%s%s\n\", $case_cmd (\$0), \"$uscore\", extra); }'" else awkcmd="$AWK '{ printf (\"%s%s\n\", tolower (\$0), \"$uscore\"); }'"
--- a/liboctave/util/data-conv.cc +++ b/liboctave/util/data-conv.cc @@ -487,7 +487,8 @@ if (len > 0) \ { \ OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \ - stream.read (reinterpret_cast<char *> (ptr), size * len); \ + std::streamsize n_bytes = size * len; \ + stream.read (reinterpret_cast<char *> (ptr), n_bytes); \ if (swap) \ swap_bytes< size > (ptr, len); \ for (octave_idx_type i = 0; i < len; i++) \ @@ -509,7 +510,8 @@ OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \ for (octave_idx_type i = 0; i < len; i++) \ ptr[i] = static_cast <TYPE> (data[i]); \ - stream.write (reinterpret_cast<char *> (ptr), size * len); \ + std::streamsize n_bytes = size * len; \ + stream.write (reinterpret_cast<char *> (ptr), n_bytes); \ } \ } \ while (0) @@ -1008,7 +1010,6 @@ } } - void read_doubles (std::istream& is, double *data, save_type type, octave_idx_type len, bool swap, @@ -1043,7 +1044,8 @@ case LS_FLOAT: { OCTAVE_LOCAL_BUFFER (float, ptr, len); - is.read (reinterpret_cast<char *> (ptr), 4 * len); + std::streamsize n_bytes = 4 * len; + is.read (reinterpret_cast<char *> (ptr), n_bytes); do_float_format_conversion (ptr, len, fmt); for (octave_idx_type i = 0; i < len; i++) data[i] = ptr[i]; @@ -1052,7 +1054,8 @@ case LS_DOUBLE: // No conversion necessary. { - is.read (reinterpret_cast<char *> (data), 8 * len); + std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len); + is.read (reinterpret_cast<char *> (data), n_bytes); do_double_format_conversion (data, len, fmt); for (int i = 0; i < len; i++) @@ -1098,14 +1101,18 @@ break; case LS_FLOAT: // No conversion necessary. - is.read (reinterpret_cast<char *> (data), 4 * len); - do_float_format_conversion (data, len, fmt); + { + std::streamsize n_bytes = 4 * len; + is.read (reinterpret_cast<char *> (data), n_bytes); + do_float_format_conversion (data, len, fmt); + } break; case LS_DOUBLE: { OCTAVE_LOCAL_BUFFER (double, ptr, len); - is.read (reinterpret_cast<char *> (ptr), 8 * len); + std::streamsize n_bytes = 8 * len; + is.read (reinterpret_cast<char *> (ptr), n_bytes); do_double_format_conversion (ptr, len, fmt); for (octave_idx_type i = 0; i < len; i++) data[i] = ptr[i]; @@ -1156,7 +1163,8 @@ { char tmp_type = static_cast<char> (type); os.write (&tmp_type, 1); - os.write (reinterpret_cast <const char *> (data), 8 * len); + std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len); + os.write (reinterpret_cast <const char *> (data), n_bytes); } break; @@ -1201,7 +1209,8 @@ { char tmp_type = static_cast<char> (type); os.write (&tmp_type, 1); - os.write (reinterpret_cast <const char *> (data), 4 * len); + std::streamsize n_bytes = 4 * len; + os.write (reinterpret_cast <const char *> (data), n_bytes); } break;
--- a/m4/acinclude.m4 +++ b/m4/acinclude.m4 @@ -370,10 +370,10 @@ LDFLAGS="$m4_toupper([$1])_LDFLAGS $LDFLAGS" LIBS="$m4_toupper([$1])_LIBS $LIBS" m4_ifnblank([$6], [AC_LANG_PUSH($6)]) - ac_octave_$1_check_for_lib=false - m4_ifblank([$4], [ac_octave_$1_check_for_lib=true], - [AC_CHECK_HEADERS([$4], [ac_octave_$1_check_for_lib=true; break])]) - if $ac_octave_$1_check_for_lib; then + ac_octave_$1_check_for_lib=no + m4_ifblank([$4], [ac_octave_$1_check_for_lib=yes], + [AC_CHECK_HEADERS([$4], [ac_octave_$1_check_for_lib=yes; break])]) + if test $ac_octave_$1_check_for_lib = yes; then AC_CACHE_CHECK([for $5 in $m4_toupper([$1])_LIBS], [octave_cv_lib_$1], [AC_LINK_IFELSE([AC_LANG_CALL([], [$5])], @@ -1159,16 +1159,16 @@ dnl readline. dnl AC_DEFUN([OCTAVE_ENABLE_READLINE], [ - USE_READLINE=true + USE_READLINE=yes READLINE_LIBS= AC_ARG_ENABLE([readline], [AS_HELP_STRING([--disable-readline], [use readline library])], [if test "$enableval" = no; then - USE_READLINE=false + USE_READLINE=no warn_readline="command editing and history features require GNU Readline" fi]) - if $USE_READLINE; then + if test $USE_READLINE = yes; then dnl RHEL 5 and older systems require termlib set before enabling readline AC_REQUIRE([OCTAVE_CHECK_LIB_TERMLIB]) ac_octave_save_LIBS="$LIBS" @@ -1672,15 +1672,15 @@ AC_REQUIRE([OCTAVE_PROG_TEXI2DVI]) AC_CHECK_PROG(TEXI2PDF, texi2pdf, texi2pdf, []) if test -z "$TEXI2PDF"; then - ac_octave_missing=true; + ac_octave_texi2pdf_missing=yes; if test -n "$TEXI2DVI"; then TEXI2PDF="$TEXI2DVI --pdf" - ac_octave_missing=false; + ac_octave_texi2pdf_missing=no; fi else - ac_octave_missing=false; + ac_octave_texi2pdf_missing=no; fi - if $ac_octave_missing; then + if test $ac_octave_texi2pdf_missing = yes; then TEXI2PDF='$(top_srcdir)/build-aux/missing texi2pdf' warn_texi2pdf="
--- a/scripts/io/strread.m +++ b/scripts/io/strread.m @@ -39,7 +39,7 @@ ## @item %s ## The word is parsed as a string. ## -## @itemx %f +## @item %f ## @itemx %n ## The word is parsed as a number and converted to double. ##
--- a/scripts/io/textread.m +++ b/scripts/io/textread.m @@ -1,4 +1,4 @@ -## Copyright (C) 2009-2012 Eric Chassande-Mottin, CNRS (France) +## Copyright (C) 2009-2013 Eric Chassande-Mottin, CNRS (France) ## ## This file is part of Octave. ## @@ -79,10 +79,22 @@ ## Skip header lines if requested headerlines = find (strcmpi (varargin, "headerlines"), 1); - ## Beware of zero valued headerline, fskipl would skip to EOF - if (! isempty (headerlines) && (varargin{headerlines + 1} > 0)) - fskipl (fid, varargin{headerlines + 1}); - varargin(headerlines:headerlines+1) = []; + if (! isempty (headerlines)) + ## Beware of missing or wrong headerline value + if (headerlines == numel (varargin) + || ! isnumeric (varargin{headerlines + 1})) + error ("missing or illegal value for 'headerlines'" ); + endif + ## Avoid conveying floats to fskipl + varargin{headerlines + 1} = round (varargin{headerlines + 1}); + ## Beware of zero valued headerline, fskipl would skip to EOF + if (varargin{headerlines + 1} > 0) + fskipl (fid, varargin{headerlines + 1}); + varargin(headerlines:headerlines+1) = []; + nargin = nargin - 2; + elseif (varargin{headerlines + 1} < 0) + warning ("textread: negative headerline value ignored"); + endif endif st_pos = ftell (fid); @@ -98,7 +110,7 @@ if (! isempty (endofline)) ## 'endofline' option set by user. if (! ischar (varargin{endofline + 1})); - error ("textread: character value required for EndOfLine"); + error ("character value required for EndOfLine"); endif else ## Determine EOL from file. Search for EOL candidates in first BUFLENGTH chars @@ -188,4 +200,6 @@ %!error textread (1) %!error <arguments must be strings> textread (1, "%f") %!error <arguments must be strings> textread ("fname", 1) - +%!error <missing or illegal value for> textread (file_in_loadpath ("textread.m"), "", "headerlines") +%!error <missing or illegal value for> textread (file_in_loadpath ("textread.m"), "", "headerlines", 'hh') +%!error <character value required for> textread (file_in_loadpath ("textread.m"), "%s", "endofline", true)
--- a/scripts/io/textscan.m +++ b/scripts/io/textscan.m @@ -1,4 +1,4 @@ -## Copyright (C) 2010-2012 Ben Abbott <bpabbott@mac.com> +## Copyright (C) 2010-2013 Ben Abbott <bpabbott@mac.com> ## ## This file is part of Octave. ## @@ -167,14 +167,23 @@ st_pos = ftell (fid); ## Skip header lines if requested headerlines = find (strcmpi (args, "headerlines"), 1); - ## Beware of zero valued headerline, fskipl would skip to EOF - if (! isempty (headerlines) && (args{headerlines + 1} > 0)) - fskipl (fid, args{headerlines + 1}); - args(headerlines:headerlines+1) = []; - st_pos = ftell (fid); + if (! isempty (headerlines)) + ## Beware of missing or wrong headerline value + if (headerlines == numel (args) + || ! isnumeric (args{headerlines + 1})) + error ("Missing or illegal value for 'headerlines'" ); + endif + ## Avoid conveying floats to fskipl + args{headerlines + 1} = round (args{headerlines + 1}); + if (args{headerlines + 1} > 0) + ## Beware of zero valued headerline, fskipl would skip to EOF + fskipl (fid, args{headerlines + 1}); + args(headerlines:headerlines+1) = []; + st_pos = ftell (fid); + elseif (args{headerlines + 1} < 0) + warning ("textscan.m: negative headerline value ignored"); + endif endif - ## Read a first file chunk. Rest follows after endofline processing - [str, count] = fscanf (fid, "%c", BUFLENGTH); endif ## Check for empty result @@ -497,3 +506,7 @@ %! rh = strtrim (rh); %! assert (strcmp (lh, rh)); %! end + +%!error <missing or illegal value for> textread (file_in_loadpath ("textscan.m"), "", "headerlines") +%!error <missing or illegal value for> textread (file_in_loadpath ("textscan.m"), "", "headerlines", 'hh') +%!error <character value required for> textread (file_in_loadpath ("textscan.m"), "", "endofline", true)
--- a/scripts/plot/__gnuplot_drawnow__.m +++ b/scripts/plot/__gnuplot_drawnow__.m @@ -23,10 +23,10 @@ ## Author: jwe -function __gnuplot_drawnow__ (h, term, file, mono, debug_file) +function __gnuplot_drawnow__ (h, term, file, mono = false, debug_file) - if (nargin < 4) - mono = false; + if (nargin < 1 || nargin > 5 || nargin == 2) + print_usage (); endif if (nargin >= 3 && nargin <= 5) @@ -39,7 +39,7 @@ plot_stream = __gnuplot_open_stream__ (2, h); gnuplot_supports_term = __gnuplot_has_terminal__ (term, plot_stream); if (gnuplot_supports_term) - enhanced = gnuplot_set_term (plot_stream (1), true, h, term, file); + enhanced = gnuplot_set_term (plot_stream(1), true, h, term, file); __go_draw_figure__ (h, plot_stream(1), enhanced, mono); if (nargin == 5) fid = fopen (debug_file, "wb"); @@ -47,7 +47,7 @@ __go_draw_figure__ (h, fid, enhanced, mono); endif else - error ("__gnuplot_drawnow__: the gnuplot terminal, \"%s\", is not available", + error ('__gnuplot_drawnow__: the gnuplot terminal, "%s", is not available', gnuplot_trim_term (term)); endif unwind_protect_cleanup @@ -65,7 +65,7 @@ fclose (fid); endif end_unwind_protect - elseif (nargin == 1) + else # nargin == 1 ## Graphics terminal for display. plot_stream = get (h, "__plot_stream__"); if (isempty (plot_stream)) @@ -78,13 +78,13 @@ if (strcmp (term, "dumb")) ## popen2 eats stdout of gnuplot, use temporary file instead dumb_tmp_file = tmpnam (); - enhanced = gnuplot_set_term (plot_stream (1), new_stream, h, ... + enhanced = gnuplot_set_term (plot_stream(1), new_stream, h, term, dumb_tmp_file); else - enhanced = gnuplot_set_term (plot_stream (1), new_stream, h, term); + enhanced = gnuplot_set_term (plot_stream(1), new_stream, h, term); endif - __go_draw_figure__ (h, plot_stream (1), enhanced, mono); - fflush (plot_stream (1)); + __go_draw_figure__ (h, plot_stream(1), enhanced, mono); + fflush (plot_stream(1)); if (strcmp (term, "dumb")) fid = -1; while (fid < 0) @@ -94,17 +94,14 @@ ## reprint the plot on screen [a, count] = fscanf (fid, '%c', Inf); fclose (fid); - if (count>0) - if (a(1)==12) - ## avoid ^L at the beginning - a = a(2:end); + if (count > 0) + if (a(1) == 12) + a = a(2:end); # avoid ^L at the beginning endif puts (a); endif unlink (dumb_tmp_file); endif - else - print_usage (); endif endfunction @@ -117,9 +114,8 @@ term = gnuplot_default_term (plot_stream); opts_str = ""; else - ## Get the one word terminal id and save the remaining as options to - ## be passed on to gnuplot. The terminal may respect the graphics - ## toolkit. + ## Get the one word terminal id and save the remaining as options to be + ## passed on to gnuplot. The terminal may respect the graphics toolkit. [term, opts_str] = gnuplot_trim_term (term); term = lower (term); if (strcmp (term, "lua")) @@ -149,7 +145,7 @@ ## Generate gnuplot title string for plot windows. if (output_to_screen (term) && ! strcmp (term, "dumb")) fig.numbertitle = get (h, "numbertitle"); - fig.name = strrep (get (h, "name"), "\"", "\\\""); + fig.name = strrep (get (h, "name"), '"', '\"'); if (strcmp (get (h, "numbertitle"), "on")) title_str = sprintf ("Figure %d", h); else @@ -161,11 +157,11 @@ title_str = fig.name; endif if (! isempty (title_str)) - title_str = sprintf ("title \"%s\"", title_str); + title_str = sprintf ('title "%s"', title_str); endif if (strcmp (term, "aqua")) ## Adjust axes-label and tick-label spacing. - opts_str = sprintf ("%s font \"%s,%d\"", opts_str, + opts_str = sprintf ('%s font "%s,%d"', opts_str, get (0, "defaultaxesfontname"), get (0, "defaultaxesfontsize") / 1.5); endif @@ -195,8 +191,8 @@ if (all (gnuplot_size > 0)) terminals_with_size = {"canvas", "emf", "epslatex", "fig", ... "gif", "jpeg", "latex", "pbm", "pdf", ... - "pdfcairo", "postscript", "png", "pngcairo", ... - "pstex", "pslatex", "svg", "tikz"}; + "pdfcairo", "postscript", "png", ... + "pngcairo", "pstex", "pslatex", "svg", "tikz"}; if (__gnuplot_has_feature__ ("windows_figure_position")) terminals_with_size{end+1} = "windows"; endif @@ -207,27 +203,27 @@ terminals_with_size{end+1} = "wxt"; endif switch (term) - case terminals_with_size - size_str = sprintf ("size %.12g,%.12g", gnuplot_size); - case "tikz" - size_str = sprintf ("size %gin,%gin", gnuplot_size); - case "dumb" - new_stream = 1; - if (! isempty (getenv ("COLUMNS")) && ! isempty (getenv ("LINES"))) - ## Let dumb use full text screen size (minus prompt lines). - n = sprintf ("%i", -2 - length (find (sprintf ("%s", PS1) == "\n"))); - ## n = the number of times \n appears in PS1 - size_str = ["size ", getenv("COLUMNS"), ",", getenv("LINES"), n]; - else - ## Use the gnuplot default. + case terminals_with_size + size_str = sprintf ("size %.12g,%.12g", gnuplot_size); + case "tikz" + size_str = sprintf ("size %gin,%gin", gnuplot_size); + case "dumb" + new_stream = 1; + if (! isempty (getenv ("COLUMNS")) && ! isempty (getenv ("LINES"))) + ## Let dumb use full text screen size (minus prompt lines). + n = sprintf ("%i", -2 - length (find (sprintf ("%s", PS1) == "\n"))); + ## n = the number of times \n appears in PS1 + size_str = ["size ", getenv("COLUMNS"), ",", getenv("LINES"), n]; + else + ## Use the gnuplot default. + size_str = ""; + endif + case {"aqua", "fig", "corel"} + size_str = sprintf ("size %g %g", gnuplot_size); + case "dxf" size_str = ""; - endif - case {"aqua", "fig", "corel"} - size_str = sprintf ("size %g %g", gnuplot_size); - case "dxf" - size_str = ""; - otherwise - size_str = ""; + otherwise + size_str = ""; endswitch if ((strncmpi (term, "x11", 3) && __gnuplot_has_feature__ ("x11_figure_position")) @@ -269,34 +265,44 @@ endif ## Set the gnuplot terminal (type, enhanced, title, options & size). - term_str = sprintf ("set terminal %s", term); + term_str = ["set terminal " term]; if (! isempty (enh_str)) - term_str = sprintf ("%s %s", term_str, enh_str); + term_str = [term_str " " enh_str]; endif if (! isempty (title_str)) - term_str = sprintf ("%s %s", term_str, title_str); + term_str = [term_str " " title_str]; endif if (isempty (strfind (term, "corel"))) if (! isempty (size_str) && new_stream) ## size_str comes after other options to permit specification of ## the canvas size for terminals cdr/corel. - term_str = sprintf ("%s %s", term_str, size_str); + term_str = [term_str " " size_str]; endif if (nargin > 3 && ischar (opts_str)) ## Options must go last. - term_str = sprintf ("%s %s", term_str, opts_str); + term_str = [term_str " " opts_str]; endif else if (nargin > 3 && ischar (opts_str)) ## Options must go last. - term_str = sprintf ("%s %s", term_str, opts_str); + term_str = [term_str " " opts_str]; endif if (! isempty (size_str) && new_stream) ## size_str comes after other options to permit specification of ## the canvas size for terminals cdr/corel. - term_str = sprintf ("%s %s", term_str, size_str); + term_str = [term_str " " size_str]; endif endif + if (! __gnuplot_has_feature__ ("has_termoption_dashed")) + ## If "set termoption dashed" isn't available add "dashed" option + ## to the "set terminal ..." command, if it is supported. + if (any (strcmpi (term, {"aqua", "cgm", "eepic", "emf", "epslatex", \ + "fig", "pcl5", "mp", "next", "openstep", "pdf", \ + "pdfcairo", "pngcairo", "postscript", \ + "pslatex", "pstext", "svg", "tgif", "x11"}))) + term_str = [term_str " dashed"]; + endif + end ## Work around the gnuplot feature of growing the x11 window and ## flickering window (x11, windows, & wxt) when the mouse and @@ -321,7 +327,9 @@ endif endif endif - fprintf (plot_stream, "set termoption dashed\n") + if (__gnuplot_has_feature__ ("has_termoption_dashed")) + fprintf (plot_stream, "set termoption dashed\n") + endif else ## gnuplot will pick up the GNUTERM environment variable itself ## so no need to set the terminal type if not also setting the @@ -331,7 +339,7 @@ endfunction function term = gnuplot_default_term (plot_stream) - term = getenv ("GNUTERM"); + term = lower (getenv ("GNUTERM")); ## If not specified, guess the terminal type. if (isempty (term) || ! __gnuplot_has_terminal__ (term, plot_stream)) if (isguirunning () && __gnuplot_has_terminal__ ("qt", plot_stream)) @@ -350,35 +358,31 @@ function [term, opts] = gnuplot_trim_term (string) ## Extract the terminal type and terminal options (from print.m) - string = deblank (string); - n = strfind (string, ' '); - if (isempty (n)) - term = string; - opts = ""; - else - term = string(1:(n-1)); - opts = string((n+1):end); + string = strtrim (string); + [term, opts] = strtok (string, ' '); + if (! isempty (opts)) + opts(1) = ""; # trim extra space from strtok endif endfunction function have_enhanced = gnuplot_is_enhanced_term (plot_stream, term) - persistent enhanced_terminals; - if (isempty (enhanced_terminals)) - ## Don't include pstex, pslatex or epslatex here as the TeX commands - ## should not be interpreted in that case. - enhanced_terminals = {"aqua", "canvas", "dumb", "emf", "gif", "jpeg", ... - "pdf", "pdfcairo", "pm", "png", "pngcairo", ... - "postscript", "qt", "svg", "windows", "wxt", "x11"}; - endif + ## Don't include pstex, pslatex or epslatex here as the TeX commands + ## should not be interpreted in that case. + persistent enhanced_terminals = {"aqua", "canvas", "dumb", "emf", "gif", ... + "jpeg", "pdf", "pdfcairo", "pm", "png", ... + "pngcairo", "postscript", "qt", "svg", ... + "windows", "wxt", "x11"}; + if (nargin < 2) ## Determine the default gnuplot terminal. term = gnuplot_default_term (plot_stream); endif - have_enhanced = any (strncmp (enhanced_terminals, term, min (numel (term), 3))); + have_enhanced = any (strcmp (term, enhanced_terminals)); endfunction function ret = output_to_screen (term) - ret = any (strcmpi ({"aqua", "dumb", "pm", "qt", "windows", "wxt", "x11"}, term)); + ret = any (strcmpi (term, + {"aqua", "dumb", "pm", "qt", "windows", "wxt", "x11"})); endfunction function retval = have_non_legend_axes (h)
--- a/scripts/plot/gnuplot_binary.in +++ b/scripts/plot/gnuplot_binary.in @@ -22,8 +22,9 @@ ## Query or set the name of the program invoked by the plot command ## when the graphics toolkit is set to "gnuplot". Additional arguments to ## pass to the external plotting program may also be given. -## The default value is @code{"gnuplot"} without additional arguments. +## The default value is @code{"gnuplot"} with no additional arguments. ## @xref{Installation}. +## @seealso{graphics_toolkit} ## @end deftypefn ## Author: jwe @@ -39,23 +40,26 @@ endif if (nargin == 1) - if (ischar (new_prog)) - if (! isempty (new_prog)) - gp_binary = new_prog; - else - error ("gnuplot_binary: value must not be empty"); - endif - else - error ("gnuplot_binary: expecting program to be a character string"); + if (! ischar (new_prog) || isempty (new_prog)) + error ("gnuplot_binary: NEW_PROG must be a non-empty string"); endif + gp_binary = new_prog; endif if (nargin > 1) - if (iscellstr (varargin)) - gp_args = varargin; - else - error ("gnuplot_binary: expecting arguments to be character strings"); + if (! iscellstr (varargin)) + error ("gnuplot_binary: arguments must be character strings"); endif + gp_args = varargin; endif endfunction + + +%!test +%! orig_val = gnuplot_binary (); +%! old_val = gnuplot_binary ("X"); +%! assert (orig_val, old_val); +%! assert (gnuplot_binary (), "X"); +%! gnuplot_binary (orig_val); +%! assert (gnuplot_binary (), orig_val);
--- a/scripts/plot/legend.m +++ b/scripts/plot/legend.m @@ -87,7 +87,7 @@ ## @item "hide" ## Hide legend on the plot ## -## @itemx "toggle" +## @item "toggle" ## Toggles between "hide" and "show" ## ## @item "boxon" @@ -102,7 +102,7 @@ ## @item "right" ## Place label text to the right of the keys ## -## @itemx "off" +## @item "off" ## Delete the legend object ## @end table ##
--- a/scripts/plot/newplot.m +++ b/scripts/plot/newplot.m @@ -17,13 +17,17 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} newplot () +## @deftypefn {Function File} {} newplot () +## @deftypefnx {Function File} {@var{h} =} newplot () ## Prepare graphics engine to produce a new plot. This function is ## called at the beginning of all high-level plotting functions. ## It is not normally required in user programs. +## +## The optional return value @var{h} is a graphics handle to the created +## axes (not figure). ## @end deftypefn -function newplot () +function h = newplot () if (nargin == 0) cf = gcf (); @@ -59,6 +63,9 @@ otherwise error ("newplot: unrecognized nextplot property for current axes"); endswitch + if (nargout > 0) + h = ca; + endif else print_usage (); endif @@ -70,7 +77,8 @@ %! hf = figure ("visible", "off"); %! unwind_protect %! p = plot ([0, 1]); -%! newplot; +%! ha = newplot (); +%! assert (ha, gca); %! assert (isempty (get (gca, "children"))); %! unwind_protect_cleanup %! close (hf);
--- a/scripts/plot/plotmatrix.m +++ b/scripts/plot/plotmatrix.m @@ -164,9 +164,9 @@ border = [0.130, 0.110, 0.225, 0.185] .* [xsize, ysize, xsize, ysize]; border(3:4) = - border(3:4) - border(1:2); - for i = 1 : n - for j = 1 : m - pos = [xsize * (j - 1) + xoff, ysize * (n - i) + yoff, xsize, ysize]; + for i = 1 : m + for j = 1 : n + pos = [xsize * (i - 1) + xoff, ysize * (n - j) + yoff, xsize, ysize]; tmp = axes ("outerposition", pos, "position", pos + border, "parent", parent); if (i == j && have_hist)
--- a/scripts/plot/print.m +++ b/scripts/plot/print.m @@ -207,11 +207,10 @@ ## is sent to a file the size is determined by the plot box defined by ## the figure's "paperposition" property. ## -## @itemx -append -## Append Postscript or PDF output to a pre-existing file of the -## same type. +## @item -append +## Append Postscript or PDF output to a pre-existing file of the same type. ## -## @itemx -r@var{NUM} +## @item -r@var{NUM} ## Resolution of bitmaps in pixels per inch. For both metafiles and ## SVG the default is the screen resolution; for other formats it is 150 dpi. ## To specify screen resolution, use "-r0".
--- a/scripts/plot/private/__gnuplot_get_var__.m +++ b/scripts/plot/private/__gnuplot_get_var__.m @@ -24,17 +24,11 @@ ## Author: Ben Abbott <bpabbott@mac.com> ## Created: 2009-02-07 -function gp_var_value = __gnuplot_get_var__ (h, gp_var_name, fmt) +function gp_var_value = __gnuplot_get_var__ (h, gp_var_name, fmt = "") - if (nargin == 0) - h = gcf (); - endif if (nargin < 2) print_usage (); endif - if (nargin < 3) - fmt = ''; - endif if (numel (h) == 1 && isfigure (h)) if (isempty (get (gcf, "__plot_stream__"))) @@ -65,8 +59,8 @@ ## Mode: 6*8*8 == 0600 [err, msg] = mkfifo (gpin_name, 6*8*8); - if (err != 0) - error ("__gnuplot_get_var__: Can not make fifo (%s)", msg); + if (err) + error ("__gnuplot_get_var__: Can not make FIFO (%s)", msg); endif endif @@ -79,18 +73,18 @@ unwind_protect ## Notes: Variables may be undefined if user closes gnuplot by "q" - ## or Alt-F4. Further, this abrupt close also requires the leading + ## or Alt-F4. Further, this abrupt close also requires the leading ## "\n" on the next line. if (use_mkfifo) fprintf (ostream, "\nset print \"%s\";\n", gpin_name); fflush (ostream); [gpin, err] = fopen (gpin_name, "r"); - if (err != 0) + if (err) ## Try a second time, and then give an error. [gpin, err] = fopen (gpin_name, "r"); endif - if (err != 0) - error ("__gnuplot_get_var__: can not open fifo"); + if (err) + error ("__gnuplot_get_var__: can not open FIFO"); endif gp_cmd = sprintf ("\nif (exists(\"%s\")) print %s; else print NaN\n", gp_var_name(1:n), gp_var_name); @@ -126,7 +120,7 @@ str = {}; while (isempty (str)) - str = char (fread (istream)'); + str = fread (istream, "*char")'; if (isempty (str)) sleep (0.05); else @@ -138,8 +132,7 @@ endif ## Strip out EOLs and the continuation character "|" - str(str=="\n") = ""; - str(str=="\r") = ""; + str(str=="\n" | str=="\r") = ""; n_continue = strfind (str, " \\ "); if (! isempty (n_continue)) str(n_continue+1) = "";
--- a/scripts/plot/private/__gnuplot_ginput__.m +++ b/scripts/plot/private/__gnuplot_ginput__.m @@ -31,6 +31,10 @@ function [x, y, button] = __gnuplot_ginput__ (f, n) + if (compare_versions (__gnuplot_version__ (), "4.0", "<=")) + error ("ginput: version %s of gnuplot not supported", gnuplot_version ()); + endif + ostream = get (f, "__plot_stream__"); if (numel (ostream) < 1) error ("ginput: stream to gnuplot not open"); @@ -46,10 +50,6 @@ ostream = ostream(1); endif - if (compare_versions (__gnuplot_version__ (), "4.0", "<=")) - error ("ginput: version %s of gnuplot not supported", gnuplot_version ()); - endif - if (nargin == 1) x = zeros (100, 1); y = zeros (100, 1); @@ -66,7 +66,7 @@ ##Mode: 6*8*8 == 0600 [err, msg] = mkfifo (gpin_name, 6*8*8); - if (err != 0) + if (err) error ("ginput: Can not open fifo (%s)", msg); endif endif @@ -84,8 +84,8 @@ fprintf (ostream, "set print \"%s\";\n", gpin_name); fflush (ostream); [gpin, err] = fopen (gpin_name, "r"); - if (err != 0) - error ("ginput: Can not open fifo (%s)", msg); + if (err) + error ("ginput: Can not open FIFO (%s)", msg); endif fputs (ostream, "pause mouse any;\n\n"); fputs (ostream, "\nif (exists(\"MOUSE_KEY\") && exists(\"MOUSE_X\")) print MOUSE_X, MOUSE_Y, MOUSE_KEY; else print \"0 0 -1\"\n"); @@ -98,7 +98,7 @@ [x(k), y(k), button(k), count] = fscanf (gpin, "%f %f %d", "C"); fclose (gpin); else - fprintf (ostream, "set print \"-\";\n"); + fputs (ostream, "set print \"-\";\n"); fflush (ostream); fputs (ostream, "pause mouse any;\n\n"); fputs (ostream, "\nif (exists(\"MOUSE_KEY\") && exists(\"MOUSE_X\")) print \"OCTAVE: \", MOUSE_X, MOUSE_Y, MOUSE_KEY; else print \"0 0 -1\"\n"); @@ -109,7 +109,7 @@ str = {}; while (isempty (str)) - str = char (fread (istream)'); + str = fread (istream, "*char")'; if (isempty (str)) sleep (0.05); else
--- a/scripts/plot/private/__gnuplot_has_feature__.m +++ b/scripts/plot/private/__gnuplot_has_feature__.m @@ -25,17 +25,18 @@ ## Created: 2009-01-27 function res = __gnuplot_has_feature__ (feature) - persistent features has_features - features = {"x11_figure_position", - "wxt_figure_size", - "transparent_patches", - "transparent_surface", - "epslatex_implies_eps_filesuffix", - "epslatexstandalone_terminal", - "screen_coordinates_for_{lrtb}margin", - "variable_GPVAL_TERMINALS", - "key_has_font_properties", - "windows_figure_position"}; + persistent features = {"x11_figure_position", + "wxt_figure_size", + "transparent_patches", + "transparent_surface", + "epslatex_implies_eps_filesuffix", + "epslatexstandalone_terminal", + "screen_coordinates_for_{lrtb}margin", + "variable_GPVAL_TERMINALS", + "key_has_font_properties", + "windows_figure_position", + "has_termoption_dashed"}; + persistent has_features; if (isempty (has_features)) try @@ -44,9 +45,9 @@ ## Don't throw an error if gnuplot isn't installed gnuplot_version = "0.0.0"; end_try_catch - versions = {"4.2.5", "4.4", "4.4", "4.4", "4.2", "4.2", "4.4", "4.4", "4.4", "4.4"}; - operators = {">=", ">=", ">=", ">=", ">=", ">=", ">=", ">=", ">=", ">="}; - have_features = logical (zeros (size (features))); + versions = {"4.2.5", "4.4", "4.4", "4.4", "4.2", "4.2", "4.4", "4.4", "4.4", "4.4", "4.3"}; + operators = {">=", ">=", ">=", ">=", ">=", ">=", ">=", ">=", ">=", ">=", ">="}; + have_features = false (size (features)); for n = 1 : numel (have_features) has_features(n) = compare_versions (gnuplot_version, versions{n}, operators{n}); endfor @@ -58,5 +59,6 @@ else res = has_features(n); endif + endfunction
--- a/scripts/plot/private/__gnuplot_has_terminal__.m +++ b/scripts/plot/private/__gnuplot_has_terminal__.m @@ -25,11 +25,10 @@ ## Created: 2010-09-13 function gnuplot_supports_term = __gnuplot_has_terminal__ (term, plot_stream) - term = deblank (term); - n = find (term == " ", 1); - if (! isempty (n)) - term = term(1:n-1); - endif + + term = strtrim (term); + term = lower (strtok (term, " ")); + if (__gnuplot_has_feature__ ("variable_GPVAL_TERMINALS")) if (nargin < 2) plot_stream = __gnuplot_open_stream__ (2); @@ -59,6 +58,8 @@ "svg", "texdraw", "tgif", "tkcanvas", ... "tpic", "windows", "x11", "xlib", "xterm"}; endif - gnuplot_supports_term = any (strcmpi (available_terminals, term)); + + gnuplot_supports_term = any (strcmp (term, available_terminals)); + endfunction
--- a/scripts/plot/private/__gnuplot_print__.m +++ b/scripts/plot/private/__gnuplot_print__.m @@ -51,15 +51,15 @@ switch (lower (opts.devopt)) case {"eps", "eps2", "epsc", "epsc2"} if (any (strcmp (opts.devopt, {"eps", "epsc"}))) - gp_opts = sprintf ("%s level1", gp_opts); + gp_opts = [gp_opts " level1"]; endif if (opts.tight_flag || ! isempty (opts.preview)) tmp_file = strcat (tmpnam (), ".eps"); eps_drawnow (opts, tmp_file, gp_opts); if (dos_shell) - cleanup = sprintf (" & del %s", strrep (tmp_file, '/', '\')); + cleanup = [" & del " strrep(tmp_file, '/', '\')]; else - cleanup = sprintf (" ; rm %s", tmp_file); + cleanup = [" ; rm " tmp_file]; endif pipeline = {sprintf("%s %s", opts.epstool_cmd (opts, tmp_file, opts.name), @@ -89,33 +89,33 @@ if (__gnuplot_has_feature__ ("epslatex_implies_eps_filesuffix")) suffix = "tex"; else - %% Gnuplot 4.0 wants a ".eps" suffix. + ## Gnuplot 4.0 wants a ".eps" suffix. suffix = "eps"; endif - local_drawnow (sprintf ("%s %s", term, gp_opts), + local_drawnow ([term " " gp_opts], strcat (name, ".", suffix), opts); case "tikz" if (__gnuplot_has_terminal__ ("tikz")) - local_drawnow (sprintf ("lua tikz %s", gp_opts), opts.name, opts); + local_drawnow (["lua tikz " gp_opts], opts.name, opts); else error (sprintf ("print:no%soutput", opts.devopt), "print.m: '%s' output is not available for gnuplot-%s", upper (opts.devopt), __gnuplot_version__ ()); endif case "svg" - local_drawnow (sprintf ("svg dynamic %s", gp_opts), opts.name, opts); + local_drawnow (["svg dynamic " gp_opts], opts.name, opts); case {"aifm", "corel", "eepic", "emf", "fig"} - local_drawnow (sprintf ("%s %s", opts.devopt, gp_opts), opts.name, opts); + local_drawnow ([opts.devopt " " gp_opts], opts.name, opts); case {"pdfcairo", "pngcairo"} if (__gnuplot_has_terminal__ (opts.devopt)) - local_drawnow (sprintf ("%s %s", opts.devopt, gp_opts), opts.name, opts); + local_drawnow ([opts.devopt " " gp_opts], opts.name, opts); else error (sprintf ("print:no%soutput", opts.devopt), "print.m: '%s' output is not available for gnuplot-%s", upper (opts.devopt), __gnuplot_version__ ()); endif case {"canvas", "dxf", "hpgl", "mf", "gif", "pstricks", "texdraw"} - local_drawnow (sprintf ("%s %s", opts.devopt, gp_opts), opts.name, opts); + local_drawnow ([opts.devopt " " gp_opts], opts.name, opts); case opts.ghostscript.device gp_opts = font_spec (opts, "devopt", "eps"); opts.ghostscript.output = opts.name; @@ -124,9 +124,9 @@ [cmd_gs, cmd_cleanup] = __ghostscript__ (opts.ghostscript); if (opts.send_to_printer || isempty (opts.name)) cmd_lpr = opts.lpr_cmd (opts); - cmd = sprintf ("%s | %s", cmd_gs, cmd_lpr); + cmd = [cmd_gs " | " cmd_lpr]; else - cmd = sprintf ("%s", cmd_gs); + cmd = cmd_gs; endif if (dos_shell) cmd = sprintf ("%s & del %s", cmd, strrep (opts.ghostscript.source, '/', '\')); @@ -135,9 +135,9 @@ endif if (! isempty (cmd_cleanup)) if (dos_shell) - pipeline = {sprintf("%s & %s", cmd, cmd_cleanup)}; + pipeline = {[cmd " & " cmd_cleanup]}; else - pipeline = {sprintf("%s ; %s", cmd, cmd_cleanup)}; + pipeline = {[cmd " ; " cmd_cleanup]}; endif else pipeline = {cmd}; @@ -170,14 +170,11 @@ function eps_drawnow (opts, epsfile, gp_opts) [h, fontsize] = get_figure_text_objs (opts); unwind_protect - for n = 1:numel (h) - set (h(n), "fontsize", 2 * fontsize{n}); - endfor - local_drawnow (sprintf ("postscript eps %s", gp_opts), epsfile, opts); + fontsize_2x = cellfun (@(x) 2*x, fontsize, "uniformoutput", false); + set (h, {"fontsize"}, fontsize_2x); + local_drawnow (["postscript eps " gp_opts], epsfile, opts); unwind_protect_cleanup - for n = 1:numel (h) - set (h(n), "fontsize", fontsize{n}); - endfor + set (h, {"fontsize"}, fontsize); end_unwind_protect endfunction @@ -203,9 +200,9 @@ switch (opts.devopt) case "cgm" if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("font ""%s,%d""", opts.font, opts.fontsize); + f = sprintf ('font "%s,%d"', opts.font, opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); elseif (! isempty (opts.fontsize)) f = sprintf ("%d", opts.fontsize); endif @@ -215,39 +212,39 @@ ## Compensate for the half scale. This will produce the proper ## spacing for the requested fontsize. if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("font ""%s,%d""", opts.font, 2 * opts.fontsize); + f = sprintf ('font "%s,%d"', opts.font, 2 * opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); elseif (! isempty (opts.fontsize)) f = sprintf ("%d", 2 * opts.fontsize); endif case "svg" if (! isempty (opts.font) && ! isempty (opts.fontsize)) fontsize = round (opts.fontsize * 0.75); - f = sprintf ("fname ""%s"" fsize %d", opts.font, fontsize); + f = sprintf ('fname "%s" fsize %d', opts.font, fontsize); elseif (! isempty (opts.font)) - f = sprintf ("fname ""%s""", opts.font); + f = sprintf ('fname "%s"', opts.font); elseif (! isempty (opts.fontsize)) fontsize = round (opts.fontsize * 0.75); f = sprintf ("%s fsize %d", f, fontsize); endif case "pdf" if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("font ""%s,%d""", opts.font, opts.fontsize); + f = sprintf ('font "%s,%d"', opts.font, opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); elseif (! isempty (opts.fontsize)) f = sprintf ("fsize %d", f, opts.fontsize); endif case {"pdfcairo", "pngcairo"} if (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); endif case {"epslatex", "epslatexstandalone"} if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("font ""%s,%d""", opts.font, opts.fontsize); + f = sprintf ('font "%s,%d"', opts.font, opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); elseif (! isempty (opts.fontsize)) f = sprintf ("%d", opts.fontsize); endif @@ -257,17 +254,17 @@ endif case {"gif", "jpeg", "png"} if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("font ""%s ,%d""", opts.font, opts.fontsize); + f = sprintf ('font "%s ,%d"', opts.font, opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("font ""%s""", opts.font); + f = sprintf ('font "%s"', opts.font); elseif (! isempty (opts.fontsize)) - f = sprintf ("font ""%d""", opts.fontsize); + f = sprintf ('font "%d"', opts.fontsize); endif case "emf" if (! isempty (opts.font) && ! isempty (opts.fontsize)) - f = sprintf ("""%s"" %d", opts.font, opts.fontsize); + f = sprintf ('"%s" %d', opts.font, opts.fontsize); elseif (! isempty (opts.font)) - f = sprintf ("""%s""", opts.font); + f = sprintf ('"%s"', opts.font); elseif (! isempty (opts.fontsize)) f = sprintf ("%d", opts.fontsize); endif
--- a/scripts/plot/private/__gnuplot_version__.m +++ b/scripts/plot/private/__gnuplot_version__.m @@ -30,12 +30,12 @@ persistent __version__ = ""; if (isempty (__version__)) - [status, output] = system (sprintf ("\"%s\" --version", gnuplot_binary ())); + [status, output] = system (sprintf ('"%s" --version', gnuplot_binary ())); if (status != 0) ## This message ends in a newline so that the traceback messages ## are skipped and people might actually see the message, read it, - ## comprehend it, actually take the advice it gives, and stop - ## asking us why plotting fails when gnuplot is not found. + ## comprehend it, take the advice it gives, and stop asking us + ## why plotting fails when gnuplot is not found. error ("you must have gnuplot installed to display graphics; if you have gnuplot installed in a non-standard location, see the 'gnuplot_binary' function\n"); endif output = strrep (output, "gnuplot", "");
--- a/scripts/plot/stemleaf.m +++ b/scripts/plot/stemleaf.m @@ -203,7 +203,7 @@ ## stems -+ 0 have to be handled as special cases. for xi = 1:nx - if(signbit(stems(kx)) == 1) + if(signbit(stems(kx)) != 0) t1 = ((x(xi) <= stems(kx)*10) && (x(xi) > (stems(kx-1)*10))); else t1 = ((x(xi) < stems(kx)*10) && (x(xi) >= (stems(kx-1)*10)));
--- a/scripts/statistics/distributions/binopdf.m +++ b/scripts/statistics/distributions/binopdf.m @@ -64,6 +64,12 @@ + x(k).*log (p(k)) + (n(k)-x(k)).*log (1-p(k))); endif + ## Special case inputs + ksp = k & (p == 0) & (x == 0); + pdf(ksp) = 1; + ksp = k & (p == 1) & (x == n); + pdf(ksp) = 1; + endfunction @@ -82,6 +88,11 @@ %!assert (binopdf (x, 2, 0.5*[0 -1 NaN 3 1]), [0 NaN NaN NaN 0]) %!assert (binopdf ([x, NaN], 2, 0.5), [y, NaN], tol) +## Test Special input values +%!assert (binopdf (0, 3, 0), 1); +%!assert (binopdf (2, 2, 1), 1); +%!assert (binopdf (1, 2, 1), 0); + %% Test class of input preserved %!assert (binopdf (single ([x, NaN]), 2, 0.5), single ([y, NaN])) %!assert (binopdf ([x, NaN], single (2), 0.5), single ([y, NaN]))
--- a/scripts/time/datetick.m +++ b/scripts/time/datetick.m @@ -22,13 +22,12 @@ ## @deftypefnx {Function File} {} datetick (@var{axis}, @var{form}) ## @deftypefnx {Function File} {} datetick (@dots{}, "keeplimits") ## @deftypefnx {Function File} {} datetick (@dots{}, "keepticks") -## @deftypefnx {Function File} {} datetick (@dots{ax}, @dots{}) -## Add date formatted tick labels to an axis. The axis the apply the -## ticks to is determined by @var{axis} that can take the values "x", -## "y" or "z". The default value is "x". The formatting of the labels is -## determined by the variable @var{form}, that can either be a string in -## the format needed by @code{dateform}, or a positive integer that can -## be accepted by @code{datestr}. +## @deftypefnx {Function File} {} datetick (@var{hax}, @dots{}) +## Add date formatted tick labels to an axis. The axis to apply the +## ticks to is determined by @var{axis} which can take the values "x", +## "y", or "z". The default value is "x". The formatting of the labels is +## determined by the variable @var{form}, which can either be a string or +## positive integer that @code{datestr} accepts. ## @seealso{datenum, datestr} ## @end deftypefn
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester1/CPrecedenceTester1.m @@ -0,0 +1,8 @@ +function x = CPrecedenceTester1() + + x = struct('useless_data', pi); + x = class(x, 'CPrecedenceTester1'); + + % don't change anything as far as precedence is concerned + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester1/tattack.m @@ -0,0 +1,5 @@ +function s = tattack(x, y) + + s = 'CPrecedenceTester1'; + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester2/CPrecedenceTester2.m @@ -0,0 +1,15 @@ +function x = CPrecedenceTester2(flag) + + x = struct('useless_data', pi^2); + x = class(x, 'CPrecedenceTester2'); + + switch flag, + case 1, % CPrecedencetester2 > Snork + superiorto('Snork'); + case 2, % CPrecedencetester2 < Snork + inferiorto('Snork'); + otherwise, + error('Incorrect value for argument flag: %d', flag); + end + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester2/tattack.m @@ -0,0 +1,5 @@ +function s = tattack(x, y) + + s = 'CPrecedenceTester2'; + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester3/CPrecedenceTester3.m @@ -0,0 +1,15 @@ +function x = CPrecedenceTester3(flag) + + x = struct('useless_data', pi^3); + x = class(x, 'CPrecedenceTester3'); + + switch flag, + case 1, % CPrecedencetester3 > Snork + superiorto('Snork'); + case 2, % CPrecedencetester3 < Snork + inferiorto('Snork'); + otherwise, + error('Incorrect value for argument flag: %d', flag); + end + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@CPrecedenceTester3/tattack.m @@ -0,0 +1,5 @@ +function s = tattack(x, y) + + s = 'CPrecedenceTester3'; + +end
new file mode 100644 --- /dev/null +++ b/test/classes/@Snork/tattack.m @@ -0,0 +1,5 @@ +function s = tattack(x, y) + + s = 'Snork'; + +end
--- a/test/classes/classes.tst +++ b/test/classes/classes.tst @@ -304,6 +304,10 @@ %!assert (s1 >= (x1 - 1)) %!assert (x1 >= (s1 - 1)) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Testing horizontal & vertical concatenation %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Test overloaded vertcat() for the Snork class %% See bug #38170 (http://savannah.gnu.org/bugs/?38170) %!test s = [s1; s2]; assert (isa (s, 'Snork') && isequal (s.gick, [x1; x2])); @@ -316,3 +320,43 @@ %!xtest s = [s1 x2]; assert (isa (s, 'Snork') && isequal (s.gick, [x1 x2])); %!xtest s = [x1 s2]; assert (isa (s, 'Snork') && isequal (s.gick, [x1 x2])); +%% Test with the Blork class, where neither vertcat() nor horzcat() is overloaded +%!shared x1, x2, x3 +%!test x1 = Blork(); +%!test x2 = [x1 x1]; +%!assert (isa (x2, 'Blork') && isequal (size (x2), [1 2])); +%!test x2 = [x1 51]; +%!assert (isa (x2, 'Blork') && isequal (size (x2), [1 2])); +%!test x3 = [x2; x2]; +%!assert (isa (x3, 'Blork') && isequal (size (x3), [2 2])); +%!test x3 = [x2; [51 x1]]; +%!assert (isa (x3, 'Blork') && isequal (size (x3), [2 2])); +%!error <dimension mismatch> x4 = [x1 x3]; +%!error <dimension mismatch> x4 = [x1; x3]; + +%%%%%%%%%%%%%%%%%%%%%%%% +%% Testing precedence %% +%%%%%%%%%%%%%%%%%%%%%%%% + +%% default: leftmost object wins +%!shared A, B +%!test A = Snork(rand(2)); +%!test B = CPrecedenceTester1(); % no call to inferiorto/superiorto +%!assert (isequal (tattack (A, B), 'Snork')) +%!assert (isequal (tattack (B, A), 'CPrecedenceTester1')) % idem + +%!shared A, B +%!test A = Snork(rand(2)); +%!test B = CPrecedenceTester2(1); % CPrecedenceTester2 > Snork +%!assert (isequal (tattack (A, B), 'CPrecedenceTester2')) +%!assert (isequal (tattack (B, A), 'CPrecedenceTester2')) +%% Trying to change to CPrecendenceTester < Snork +%!error D = CPrecedenceTester2(2); + +%!shared A, B +%!test A = Snork(rand(2)); +%!test B = CPrecedenceTester3(2); % CPrecedenceTester3 < Snork +%!assert (isequal (tattack (A, B), 'Snork')) +%!assert (isequal (tattack (B, A), 'Snork')) +%% Trying to change to CPrecendenceTester3 > Snork +%!error D = CPrecedenceTester3(1);
--- a/test/classes/module.mk +++ b/test/classes/module.mk @@ -1,14 +1,18 @@ -classes_FCN_FILES = \ +class_Blork_FCN_FILES = \ classes/@Blork/Blork.m \ classes/@Blork/bleek.m \ classes/@Blork/display.m \ classes/@Blork/get.m \ - classes/@Blork/set.m \ + classes/@Blork/set.m + +class_Cork_FCN_FILES = \ classes/@Cork/Cork.m \ classes/@Cork/click.m \ classes/@Cork/display.m \ classes/@Cork/get.m \ - classes/@Cork/set.m \ + classes/@Cork/set.m + +class_Dork_FCN_FILES = \ classes/@Dork/Dork.m \ classes/@Dork/bling.m \ classes/@Dork/display.m \ @@ -16,7 +20,9 @@ classes/@Dork/get.m \ classes/@Dork/getStash.m \ classes/@Dork/private/myStash.m \ - classes/@Dork/set.m \ + classes/@Dork/set.m + +class_Gork_FCN_FILES = \ classes/@Gork/Gork.m \ classes/@Gork/cork.m \ classes/@Gork/display.m \ @@ -24,16 +30,22 @@ classes/@Gork/get.m \ classes/@Gork/set.m \ classes/@Gork/subsasgn.m \ - classes/@Gork/subsref.m \ + classes/@Gork/subsref.m + +class_Pork_FCN_FILES = \ classes/@Pork/Pork.m \ classes/@Pork/bling.m \ classes/@Pork/display.m \ classes/@Pork/get.m \ classes/@Pork/gurk.m \ classes/@Pork/private/myStash.m \ - classes/@Pork/set.m \ + classes/@Pork/set.m + +class_Sneetch_FCN_FILES = \ classes/@Sneetch/Sneetch.m \ - classes/@Sneetch/display.m \ + classes/@Sneetch/display.m + +class_Snork_FCN_FILES = \ classes/@Snork/Snork.m \ classes/@Snork/cack.m \ classes/@Snork/display.m \ @@ -68,7 +80,9 @@ classes/@Snork/times.m \ classes/@Snork/uminus.m \ classes/@Snork/uplus.m \ - classes/@Snork/vertcat.m \ + classes/@Snork/vertcat.m + +class_Spork_FCN_FILES = \ classes/@Spork/Spork.m \ classes/@Spork/cack.m \ classes/@Spork/display.m \ @@ -78,7 +92,32 @@ classes/@Spork/loadobj.m \ classes/@Spork/private/myStash.m \ classes/@Spork/saveobj.m \ - classes/@Spork/set.m \ + classes/@Spork/set.m + +class_CPrecedenceTester1_FCN_FILES = \ + classes/@CPrecedenceTester1/CPrecedenceTester1.m \ + classes/@CPrecedenceTester1/tattack.m + +class_CPrecedenceTester2_FCN_FILES = \ + classes/@CPrecedenceTester2/CPrecedenceTester2.m \ + classes/@CPrecedenceTester2/tattack.m + +class_CPrecedenceTester3_FCN_FILES = \ + classes/@CPrecedenceTester3/CPrecedenceTester3.m \ + classes/@CPrecedenceTester3/tattack.m + +classes_FCN_FILES = \ + $(class_Blork_FCN_FILES) \ + $(class_Cork_FCN_FILES) \ + $(class_Dork_FCN_FILES) \ + $(class_Gork_FCN_FILES) \ + $(class_Pork_FCN_FILES) \ + $(class_Sneetch_FCN_FILES) \ + $(class_Snork_FCN_FILES) \ + $(class_Spork_FCN_FILES) \ + $(class_CPrecedenceTester1_FCN_FILES) \ + $(class_CPrecedenceTester2_FCN_FILES) \ + $(class_CPrecedenceTester3_FCN_FILES) \ classes/classes.tst FCN_FILES += $(classes_FCN_FILES)
--- a/test/index.tst +++ b/test/index.tst @@ -210,3 +210,20 @@ %!error <attempted to use a complex scalar as an index> x(i) %!error <attempted to use a complex scalar as an index> x(j) %!error <attempted to use a complex scalar as an index> x(1+i) + +## bug #38357 +%!shared d, dd +%! d = diag ([1, 2, 3]); +%! dd = diag ([1, 2, 3], 6, 3); +%!assert (d(1), 1); +%!assert (dd(1), 1); +%!assert (d(3, 3), 3); +%!assert (dd(3, 3), 3); +%!assert (d(2), 0); +%!assert (dd(2), 0); +%!assert (dd(6,1), 0); +%!error d(6,6); +%!error dd(6,6); +%!error d(3,6); +%!error dd(3,6); +