# HG changeset patch # User jwe # Date 752580851 0 # Node ID 13c6086c325c2583cb848f26eca50afd41614f84 # Parent 4f3364dcf450b97b77dfd60f04e0a6c31dd9ab7a [project @ 1993-11-06 10:12:29 by jwe] diff -r 4f3364dcf450 -r 13c6086c325c src/builtins.cc --- a/src/builtins.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/builtins.cc Sat Nov 06 10:14:11 1993 +0000 @@ -31,7 +31,6 @@ #include #include "tree-const.h" -#include "symtab.h" #include "t-builtins.h" #include "g-builtins.h" #include "builtins.h" @@ -396,6 +395,9 @@ { "inverse", 2, 1, builtin_inv, "inverse (X): inverse of a square matrix", }, + { "is_global", 2, 1, builtin_is_global, + "is_global (X): return 1 if the string X names a global variable", }, + { "isstr", 2, 1, builtin_isstr, "isstr (X): return 1 if X is a string", }, @@ -573,6 +575,9 @@ static builtin_string_variables string_variables[] = { + { "EDITOR", "??", sv_editor, + "name of the editor to be invoked by the edit_history command", }, + { "I", "??", NULL, "sqrt (-1)", }, @@ -629,6 +634,10 @@ { "i", "??", NULL, "sqrt (-1)", }, + { "ignore_function_time_stamp", "system", ignore_function_time_stamp, + "don't check to see if M-files have changed since they were last\n\ +compiled. Possible values are \"system\" and \"all\"", }, + { "implicit_str_to_num_ok", "false", implicit_str_to_num_ok, "allow implicit string to number conversion", }, @@ -710,75 +719,30 @@ { NULL, NULL, NULL, NULL, }, }; -static void -make_eternal (const char *s) -{ - symbol_record *sym_rec = curr_sym_tab->lookup (s, 0, 0); - if (sym_rec != (symbol_record *) NULL) - sym_rec->make_eternal (); -} - void install_builtins (void) { - symbol_record *sym_rec; - - tree_builtin *tb_tmp; - // So that the clear function can't delete other builtin variables and // functions, they are given eternal life. builtin_mapper_functions *mfptr = mapper_functions; while (mfptr->name != (char *) NULL) { - sym_rec = curr_sym_tab->lookup (mfptr->name, 1); - sym_rec->unprotect (); - - Mapper_fcn mfcn; - mfcn.neg_arg_complex = mfptr->neg_arg_complex; - mfcn.d_d_mapper = mfptr->d_d_mapper; - mfcn.d_c_mapper = mfptr->d_c_mapper; - mfcn.c_c_mapper = mfptr->c_c_mapper; - - tb_tmp = new tree_builtin (mfptr->nargin_max, mfptr->nargout_max, - mfcn, sym_rec); - - sym_rec->define (tb_tmp); - sym_rec->document (mfptr->help_string); - sym_rec->make_eternal (); - sym_rec->protect (); + install_builtin_mapper_function (mfptr); mfptr++; } builtin_text_functions *tfptr = text_functions; while (tfptr->name != (char *) NULL) { - sym_rec = curr_sym_tab->lookup (tfptr->name, 1); - sym_rec->unprotect (); - - tb_tmp = new tree_builtin (tfptr->nargin_max, 1, - tfptr->text_fcn, sym_rec); - - sym_rec->define (tb_tmp); - sym_rec->document (tfptr->help_string); - sym_rec->make_eternal (); - sym_rec->protect (); + install_builtin_text_function (tfptr); tfptr++; } builtin_general_functions *gfptr = general_functions; while (gfptr->name != (char *) NULL) { - sym_rec = curr_sym_tab->lookup (gfptr->name, 1); - sym_rec->unprotect (); - - tb_tmp = new tree_builtin (gfptr->nargin_max, gfptr->nargout_max, - gfptr->general_fcn, sym_rec); - - sym_rec->define (tb_tmp); - sym_rec->document (gfptr->help_string); - sym_rec->make_eternal (); - sym_rec->protect (); + install_builtin_general_function (gfptr); gfptr++; } @@ -788,110 +752,75 @@ builtin_string_variables *svptr = string_variables; while (svptr->name != (char *) NULL) { - sym_rec = curr_sym_tab->lookup (svptr->name, 1); - sym_rec->unprotect (); - - tree_constant *tmp = new tree_constant (svptr->value); - - sym_rec->set_sv_function (svptr->sv_function); - sym_rec->define (tmp); - sym_rec->document (svptr->help_string); - sym_rec->make_eternal (); + install_builtin_variable (svptr); svptr++; } -// XXX FIXME XXX -- Need a convenient way to document these variables. - // IMPORTANT: Always create a new tree_constant for each variable. tree_constant *tmp = NULL_TREE_CONST; - bind_variable ("ans", tmp); + bind_builtin_variable ("ans", tmp); Complex ctmp (0.0, 1.0); tmp = new tree_constant (ctmp); - bind_protected_variable ("I", tmp); - make_eternal ("I"); + bind_builtin_variable ("I", tmp, 1, 1); tmp = new tree_constant (ctmp); - bind_protected_variable ("J", tmp); - make_eternal ("J"); + bind_builtin_variable ("J", tmp, 1, 1); // Let i and j be functions so they can be redefined without being // wiped out. - char *tmp_help; - tmp = new tree_constant (ctmp); - sym_rec = curr_sym_tab->lookup ("i", 1); - tmp_help = sym_rec->help (); - sym_rec->define_as_fcn (tmp); - sym_rec->document (tmp_help); - sym_rec->protect (); - sym_rec->make_eternal (); + install_builtin_variable_as_function ("i", tmp, 1, 1); tmp = new tree_constant (ctmp); - sym_rec = curr_sym_tab->lookup ("j", 1); - tmp_help = sym_rec->help (); - sym_rec->define_as_fcn (tmp); - sym_rec->document (tmp_help); - sym_rec->protect (); - sym_rec->make_eternal (); + install_builtin_variable_as_function ("j", tmp, 1, 1); tmp = new tree_constant (get_working_directory ("initialize_globals")); - bind_protected_variable ("PWD", tmp); - make_eternal ("PWD"); + bind_builtin_variable ("PWD", tmp, 1, 1); tmp = new tree_constant (load_path); - bind_variable ("LOADPATH", tmp); - make_eternal ("LOADPATH"); + bind_builtin_variable ("LOADPATH", tmp, 0, 1); tmp = new tree_constant (info_file); - bind_variable ("INFO_FILE", tmp); - make_eternal ("INFO_FILE"); + bind_builtin_variable ("INFO_FILE", tmp, 0, 1); + + tmp = new tree_constant (editor); + bind_builtin_variable ("EDITOR", tmp, 0, 1); tmp = new tree_constant (default_pager ()); - bind_variable ("PAGER", tmp); - make_eternal ("PAGER"); + bind_builtin_variable ("PAGER", tmp, 0, 1); tmp = new tree_constant (0.0); - bind_variable ("SEEK_SET", tmp); - make_eternal ("SEEK_SET"); + bind_builtin_variable ("SEEK_SET", tmp, 0, 1); tmp = new tree_constant (1.0); - bind_variable ("SEEK_CUR", tmp); - make_eternal ("SEEK_CUR"); + bind_builtin_variable ("SEEK_CUR", tmp, 0, 1); tmp = new tree_constant (2.0); - bind_variable ("SEEK_END", tmp); - make_eternal ("SEEK_END"); + bind_builtin_variable ("SEEK_END", tmp, 0, 1); tmp = new tree_constant (DBL_EPSILON); - bind_protected_variable ("eps", tmp); - make_eternal ("eps"); + bind_builtin_variable ("eps", tmp, 1, 1); tmp = new tree_constant (10.0); - bind_variable ("output_max_field_width", tmp); - make_eternal ("output_max_field_width"); + bind_builtin_variable ("output_max_field_width", tmp, 0, 1); tmp = new tree_constant (5.0); - bind_variable ("output_precision", tmp); - make_eternal ("output_precision"); + bind_builtin_variable ("output_precision", tmp, 0, 1); tmp = new tree_constant (4.0 * atan (1.0)); - bind_protected_variable ("pi", tmp); - make_eternal ("pi"); + bind_builtin_variable ("pi", tmp, 1, 1); tmp = new tree_constant (0.0); - bind_protected_variable ("stdin", tmp); - make_eternal ("stdin"); + bind_builtin_variable ("stdin", tmp, 1, 1); tmp = new tree_constant (1.0); - bind_protected_variable ("stdout", tmp); - make_eternal ("stdout"); + bind_builtin_variable ("stdout", tmp, 1, 1); tmp = new tree_constant (2.0); - bind_protected_variable ("stderr", tmp); - make_eternal ("stderr"); + bind_builtin_variable ("stderr", tmp, 1, 1); // If using 1.0 / 0.0 doesn't work, you might also try using a very // large constant like 1.0e100000. @@ -904,12 +833,10 @@ #endif tmp = new tree_constant (tmp_inf); - bind_protected_variable ("Inf", tmp); - make_eternal ("Inf"); + bind_builtin_variable ("Inf", tmp, 1, 1); tmp = new tree_constant (tmp_inf); - bind_protected_variable ("inf", tmp); - make_eternal ("inf"); + bind_builtin_variable ("inf", tmp, 1, 1); #else @@ -917,31 +844,27 @@ // off completely, or writing an entire IEEE emulation package? tmp = new tree_constant (DBL_MAX); - bind_protected_variable ("Inf", tmp); - make_eternal ("Inf"); + bind_builtin_variable ("Inf", tmp, 1, 1); tmp = new tree_constant (DBL_MAX); - bind_protected_variable ("inf", tmp); - make_eternal ("inf"); + bind_builtin_variable ("inf", tmp, 1, 1); #endif -// If tmp_inf / tmp_inf fails to produce a NaN, you might also try -// something like 0.0 / 0.0. +// If 0.0 / 0.0 fails to produce a NaN, you might also try +// something like Inf / Inf. #if defined (HAVE_ISNAN) #ifdef linux double tmp_nan = NAN; #else - double tmp_nan = tmp_inf / tmp_inf; + double tmp_nan = 0.0 / 0.0; #endif tmp = new tree_constant (tmp_nan); - bind_protected_variable ("NaN", tmp); - make_eternal ("NaN"); + bind_builtin_variable ("NaN", tmp, 1, 1); tmp = new tree_constant (tmp_nan); - bind_protected_variable ("nan", tmp); - make_eternal ("nan"); + bind_builtin_variable ("nan", tmp, 1, 1); #endif } diff -r 4f3364dcf450 -r 13c6086c325c src/defaults.h.in --- a/src/defaults.h.in Wed Nov 03 21:38:05 1993 +0000 +++ b/src/defaults.h.in Sat Nov 06 10:14:11 1993 +0000 @@ -28,14 +28,6 @@ #define DEFAULT_PAGER %DEFAULT_PAGER% #endif -#ifndef DEFAULT_INFO_PROG -#define DEFAULT_INFO_PROG %DEFAULT_INFO_PROG% -#endif - -#ifndef DEFAULT_INFO_FILE -#define DEFAULT_INFO_FILE %DEFAULT_INFO_FILE% -#endif - #ifndef OCTAVE_HOME #define OCTAVE_HOME %OCTAVE_HOME% #endif diff -r 4f3364dcf450 -r 13c6086c325c src/g-builtins.cc --- a/src/g-builtins.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/g-builtins.cc Sat Nov 06 10:14:11 1993 +0000 @@ -900,6 +900,27 @@ } /* + * Does the given string name a global variable? + */ +tree_constant * +builtin_is_global (const tree_constant *args, int nargin, int nargout) +{ + tree_constant *retval = new tree_constant [2]; + retval[0] = tree_constant (0.0); + + if (nargin == 2 && args[1].is_string_type ()) + { + char *name = args[1].string_value (); + if (is_globally_visible (name)) + retval[0] = tree_constant (1.0); + } + else + print_usage ("is_global"); + + return retval; +} + +/* * Is the argument a string? */ tree_constant * diff -r 4f3364dcf450 -r 13c6086c325c src/g-builtins.h --- a/src/g-builtins.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/g-builtins.h Sat Nov 06 10:14:11 1993 +0000 @@ -82,6 +82,7 @@ extern tree_constant *builtin_input (const tree_constant *, int, int); extern tree_constant *builtin_ifft (const tree_constant *, int, int); extern tree_constant *builtin_inv (const tree_constant *, int, int); +extern tree_constant *builtin_is_global (const tree_constant *, int, int); extern tree_constant *builtin_isstr (const tree_constant *, int, int); extern tree_constant *builtin_keyboard (const tree_constant *, int, int); extern tree_constant *builtin_logm (const tree_constant *, int, int); diff -r 4f3364dcf450 -r 13c6086c325c src/input.cc --- a/src/input.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/input.cc Sat Nov 06 10:14:11 1993 +0000 @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -75,7 +76,6 @@ #include "input.h" #include "pager.h" #include "help.h" -#include "symtab.h" #include "octave-hist.h" #include "sighandlers.h" #include "parse.h" diff -r 4f3364dcf450 -r 13c6086c325c src/lex.l --- a/src/lex.l Wed Nov 03 21:38:05 1993 +0000 +++ b/src/lex.l Sat Nov 06 10:14:11 1993 +0000 @@ -1037,24 +1037,12 @@ } /* - * Try to find an identifier in one symbol table or another. + * Try to find an identifier. All binding to global or builtin + * variables occurs when expressions are evaluated. */ static symbol_record * lookup_identifier (char *name) { - if (curr_sym_tab == top_level_sym_tab) - { - symbol_record *lsr = curr_sym_tab->lookup (name, 0, 0); - if (lsr != (symbol_record *) NULL && lsr->is_defined ()) - return lsr; - - symbol_record *gsr = global_sym_tab->lookup (name, 0, 0); - if (gsr != (symbol_record *) NULL - && ! (looping || iffing) - && (gsr->is_defined () || gsr->is_forced_global ())) - return gsr; - } - return curr_sym_tab->lookup (name, 1, 0); } diff -r 4f3364dcf450 -r 13c6086c325c src/oct-hist.cc --- a/src/oct-hist.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/oct-hist.cc Sat Nov 06 10:14:11 1993 +0000 @@ -49,6 +49,7 @@ #include "error.h" #include "input.h" #include "octave.h" +#include "user-prefs.h" #include "unwind-prot.h" #include "octave-hist.h" #include "sighandlers.h" @@ -415,8 +416,6 @@ #define histline(i) (hlist[(i)]->line) -#define EDIT_COMMAND "${EDITOR:-vi}" - static char * mk_tmp_hist_file (int argc, char **argv, int insert_curr, char *warn_for) { @@ -529,7 +528,7 @@ // Call up our favorite editor on the file of commands. ostrstream buf; - buf << EDIT_COMMAND << " " << name << ends; + buf << user_pref.editor << " " << name << ends; char *cmd = buf.str (); // Ignore interrupts while we are off editing commands. Should we diff -r 4f3364dcf450 -r 13c6086c325c src/octave.cc --- a/src/octave.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/octave.cc Sat Nov 06 10:14:11 1993 +0000 @@ -48,7 +48,6 @@ #include "variables.h" #include "error.h" #include "tree-const.h" -#include "symtab.h" #include "utils.h" #include "builtins.h" #include "input.h" @@ -101,6 +100,9 @@ // Name of the info file specified on command line. char *info_file = (char *) NULL; +// Name of the editor to be invoked by the edit_history command. +char *editor = (char *) NULL; + // If nonzero, don't do fancy line editing. int no_line_editing = 0; @@ -116,6 +118,17 @@ // Top level context (?) jmp_buf toplevel; +// This is not really the right place to do this... +typedef void (*one_arg_error_handler_t) (const char*); +extern one_arg_error_handler_t set_Complex_error_handler + (one_arg_error_handler_t f); + +static void +octave_Complex_error_handler (const char* msg) +{ + warning (msg); +} + // Nonzero means we read ~/.octaverc and ./.octaverc. static int read_init_files = 1; @@ -179,6 +192,8 @@ load_path = default_path (); info_file = default_info_file (); + + editor = default_editor (); } void @@ -320,7 +335,7 @@ /* * Fix up things before exiting. */ -volatile void +void clean_up_and_exit (int retval) { raw_mode (0); @@ -338,6 +353,11 @@ retval = 0; exit (retval); + +// This is bogus but should prevent g++ from giving a warning saying +// that this volatile function does return. + + panic_impossible (); } static void @@ -357,6 +377,9 @@ // details. sysdep_init (); +// This is not really the right place to do this... + set_Complex_error_handler (octave_Complex_error_handler); + // Do this first, since some command line arguments may override the // defaults. initialize_globals (argv[0]); @@ -409,14 +432,10 @@ initialize_file_io (); - global_sym_tab = new symbol_table (); - curr_sym_tab = global_sym_tab; + initialize_symbol_tables (); install_builtins (); - top_level_sym_tab = new symbol_table (); - curr_sym_tab = top_level_sym_tab; - if (read_init_files) { saving_history = 0; diff -r 4f3364dcf450 -r 13c6086c325c src/parse.h --- a/src/parse.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/parse.h Sat Nov 06 10:14:11 1993 +0000 @@ -36,9 +36,6 @@ class tree_identifier; class symbol_table; -// Identifier to define if we are reading an M-fie. -extern tree_identifier *id_to_define; - // Nonzero means we're in the middle of defining a function. extern int defining_func; diff -r 4f3364dcf450 -r 13c6086c325c src/parse.y --- a/src/parse.y Wed Nov 03 21:38:05 1993 +0000 +++ b/src/parse.y Sat Nov 06 10:14:11 1993 +0000 @@ -46,9 +46,6 @@ #include "lex.h" #include "token.h" -// Identifier to define if we are reading an M-fie. -tree_identifier *id_to_define; - // Nonzero means we're in the middle of defining a function. int defining_func = 0; @@ -151,6 +148,7 @@ tree_word_list *tree_word_list_type; tree_command *tree_command_type; tree_if_command *tree_if_command_type; + tree_global_command *tree_global_command_type; tree_command_list *tree_command_list_type; tree_word_list_command *tree_word_list_command_type; tree_plot_command *tree_plot_command_type; @@ -193,8 +191,8 @@ %type word_list word_list1 %type statement %type elseif +%type global_decl global_decl1 %type simple_list simple_list1 list list1 opt_list -%type global_decl global_decl1 %type word_list_cmd %type plot_command %type plot_command1 plot_command2 plot_options @@ -478,37 +476,29 @@ global_decl : GLOBAL global_decl1 { $$ = $2->reverse (); } + | GLOBAL global_decl1 ',' + { $$ = $2->reverse (); } ; global_decl1 : NAME { - force_global ($1->sym_rec()->name ()); - $$ = new tree_command_list (); + $$ = new tree_global_command + ($1->sym_rec (), $1->line (), $1->column ()); } | NAME '=' expression { - symbol_record *sr = force_global ($1->sym_rec()->name ()); - tree_identifier *id = new tree_identifier - (sr, $1->line (), $1->column ()); - tree_simple_assignment_expression *expr = - new tree_simple_assignment_expression - (id, $3, $2->line (), $2->column ()); - $$ = new tree_command_list (expr); + $$ = new tree_global_command + ($1->sym_rec (), $3, $1->line (), $1->column ()); } | global_decl1 optcomma NAME { - force_global ($3->sym_rec()->name ()); - $$ = $1; + $$ = $1->chain ($3->sym_rec (), $3->line (), + $3->column ()); } | global_decl1 optcomma NAME '=' expression { - symbol_record *sr = force_global ($3->sym_rec()->name ()); - tree_identifier *id = new tree_identifier - (sr, $3->line (), $3->column ()); - tree_simple_assignment_expression *expr = - new tree_simple_assignment_expression - (id, $5, $4->line (), $4->column ()); - $$ = $1->chain (expr); + $$ = $1->chain ($3->sym_rec (), $5, $3->line (), + $3->column ()); } ; @@ -891,26 +881,30 @@ if (reading_m_file) { if (strcmp (curr_m_file_name, id_name) != 0) - warning ("function name `%s' does not agree\ + { + warning ("function name `%s' does not agree\ with M-file name `%s.m'", id_name, curr_m_file_name); - id_to_define->define ($4); - id_to_define->document (help_buf); + $1->rename (curr_m_file_name); + } + + $4->stash_m_file_name (curr_m_file_name); + $4->stash_m_file_time (time ((time_t *) NULL)); + $4->mark_as_system_m_file (); } - else + else if (! input_from_tmp_history_file + && reading_script_file + && strcmp (curr_m_file_name, id_name) == 0) { - if (! input_from_tmp_history_file - && reading_script_file - && strcmp (curr_m_file_name, id_name) == 0) - warning ("function `%s' defined within\ + warning ("function `%s' defined within\ script file `%s.m'", id_name, curr_m_file_name); - - $1->define ($4); - $1->document (help_buf); - top_level_sym_tab->clear (id_name); } $4->stash_function_name (id_name); + + $1->define ($4); + $1->document (help_buf); + $$ = $4; } ; @@ -1182,40 +1176,32 @@ * * XXX FIXME XXX. This isn't quite sufficient. For example, try the * command `x = 4, x' for `x' previously undefined. + * + * XXX FIXME XXX -- we should probably delay doing this until eval-time. */ tree * maybe_convert_to_ans_assign (tree *expr) { - tree *retval = expr; - - symbol_record *sr = global_sym_tab->lookup ("ans", 1, 0); - - assert (sr != (symbol_record *) NULL); - if (expr->is_index_expression ()) { - tree_index_expression *idx_expr = (tree_index_expression *) expr; - tree_argument_list *args = idx_expr->arg_list (); + expr->mark_for_possible_ans_assign (); + return expr; + } + else if (expr->is_assignment_expression () + || expr->is_prefix_expression ()) + { + return expr; + } + else + { + symbol_record *sr = global_sym_tab->lookup ("ans", 1, 0); - if (args == (tree_argument_list *) NULL) - { - tree_identifier *tmp = idx_expr->ident (); - tree *defn = tmp->def (); - if (defn != NULL_TREE && ! defn->is_builtin ()) - { - return retval; - } - } + assert (sr != (symbol_record *) NULL); + + tree_identifier *ans = new tree_identifier (sr); + + return new tree_simple_assignment_expression (ans, expr); } - else if (expr->is_assignment_expression ()) - { - return retval; - } - - tree_identifier *ans = new tree_identifier (sr); - retval = new tree_simple_assignment_expression (ans, expr); - - return retval; } void diff -r 4f3364dcf450 -r 13c6086c325c src/pr-output.cc --- a/src/pr-output.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/pr-output.cc Sat Nov 06 10:14:11 1993 +0000 @@ -1145,10 +1145,10 @@ tree_constant *tmp = NULL_TREE_CONST; tmp = new tree_constant ((double) prec); - bind_variable ("output_precision", tmp); + bind_builtin_variable ("output_precision", tmp); tmp = new tree_constant ((double) fw); - bind_variable ("output_max_field_width", tmp); + bind_builtin_variable ("output_max_field_width", tmp); } void diff -r 4f3364dcf450 -r 13c6086c325c src/pt-base.h --- a/src/pt-base.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/pt-base.h Sat Nov 06 10:14:11 1993 +0000 @@ -111,9 +111,9 @@ virtual int is_assignment_expression (void) const { return 0; } - virtual tree *def (void) - { assert (0); return (tree *) NULL; } - + virtual int is_prefix_expression (void) const + { return 0; } + virtual char *name (void) { assert (0); return (char *) NULL; } @@ -123,24 +123,24 @@ virtual void set_print_flag (int print) { assert (0); } + virtual void mark_for_possible_ans_assign (void) + { assert (0); } + virtual tree_constant assign (tree_constant& t, tree_constant *args, int nargs); virtual void bump_value (tree::expression_type) { assert (0); } - virtual void stash_m_file_name (char *s) - { assert (0); } - - virtual void stash_m_file_time (time_t t) - { assert (0); } - virtual char *m_file_name (void) { return (char *) NULL; } virtual time_t time_parsed (void) { assert (0); return 0; } + virtual int is_system_m_file (void) const + { return 0; } + virtual tree_constant eval (int print) = 0; virtual tree_constant *eval (int print, int nargout); diff -r 4f3364dcf450 -r 13c6086c325c src/symtab.cc --- a/src/symtab.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/symtab.cc Sat Nov 06 10:14:11 1993 +0000 @@ -39,38 +39,41 @@ */ symbol_def::symbol_def (void) { - help_string = (char *) NULL; - type = unknown_type; - lifespan = temporary; - sym_class = read_write; - definition = (tree *) NULL; + init_state (); } symbol_def::symbol_def (tree_constant *t) { - help_string = (char *) NULL; - type = variable; - lifespan = temporary; - sym_class = read_write; + init_state (); definition = t; + type = USER_VARIABLE; } symbol_def::symbol_def (tree_builtin *t) { - help_string = (char *) NULL; - type = builtin_function; - lifespan = temporary; - sym_class = read_write; + init_state (); definition = t; + type = BUILTIN_FUNCTION; } symbol_def::symbol_def (tree_function *t) { + init_state (); + definition = t; + type = USER_FUNCTION; +} + +void +symbol_def::init_state (void) +{ + type = UNKNOWN; + eternal = 0; + read_only = 0; + help_string = (char *) NULL; - type = user_function; - lifespan = temporary; - sym_class = read_write; - definition = t; + definition = NULL_TREE; + next_elem = (symbol_def *) NULL; + count = 0; } symbol_def::~symbol_def (void) @@ -79,25 +82,81 @@ delete definition; } +int +symbol_def::is_variable (void) const +{ + return (type == USER_VARIABLE || type == BUILTIN_VARIABLE); +} + +int +symbol_def::is_function (void) const +{ + return (type == USER_FUNCTION || type == BUILTIN_FUNCTION); +} + +int +symbol_def::is_user_variable (void) const +{ + return (type == USER_VARIABLE); +} + +int +symbol_def::is_user_function (void) const +{ + return (type == USER_FUNCTION); +} + +int +symbol_def::is_builtin_variable (void) const +{ + return (type == BUILTIN_VARIABLE); +} + +int +symbol_def::is_builtin_function (void) const +{ + return (type == BUILTIN_FUNCTION); +} + void symbol_def::define (tree_constant *t) { definition = t; - type = variable; + if (! is_builtin_variable ()) + type = USER_VARIABLE; } void symbol_def::define (tree_builtin *t) { definition = t; - type = builtin_function; + type = BUILTIN_FUNCTION; } void symbol_def::define (tree_function *t) { definition = t; - type = user_function; + type = USER_FUNCTION; +} + +void +symbol_def::protect (void) +{ + read_only = 1; +} + +void +symbol_def::unprotect (void) +{ + read_only = 0; + +} + +void +symbol_def::make_eternal (void) +{ + eternal = 1; } tree * @@ -125,51 +184,53 @@ return definition->save (os, mark_as_global); } +int +maybe_delete (symbol_def *def) +{ + int count = 0; + if (def != (symbol_def *) NULL) + { + if (def->count > 0) + { + def->count--; + count = def->count; + if (def->count == 0) + delete def; + } + } + return count; +} + /* * Individual records in a symbol table. */ symbol_record::symbol_record (void) { - nm = (char *) NULL; - formal_param = 0; - forced_global = 0; - var = (symbol_def *) NULL; - fcn = (symbol_def *) NULL; - sv_fcn = (sv_Function) NULL; - next_elem = (symbol_record *) NULL; + init_state (); } -symbol_record::symbol_record (const char *n) +symbol_record::symbol_record (const char *n, + symbol_record *nxt = (symbol_record *) NULL) { + init_state (); nm = strsave (n); - formal_param = 0; - forced_global = 0; - var = (symbol_def *) NULL; - fcn = (symbol_def *) NULL; - sv_fcn = (sv_Function) NULL; - next_elem = (symbol_record *) NULL; + next_elem = nxt; } -symbol_record::symbol_record (const char *n, symbol_record *nxt) +void +symbol_record::init_state (void) { - nm = strsave (n); formal_param = 0; - forced_global = 0; - var = (symbol_def *) NULL; - fcn = (symbol_def *) NULL; + linked_to_global = 0; + nm = (char *) NULL; sv_fcn = (sv_Function) NULL; - next_elem = nxt; + definition = (symbol_def *) NULL; + next_elem = (symbol_record *) NULL; } symbol_record::~symbol_record (void) { delete [] nm; - - if (var != (symbol_def *) NULL && --var->count <= 0) - delete var; - - if (fcn != (symbol_def *) NULL && --fcn->count <= 0) - delete fcn; } char * @@ -181,41 +242,147 @@ char * symbol_record::help (void) const { - if (var != (symbol_def *) NULL) - return var->help (); - else if (fcn != (symbol_def *) NULL) - return fcn->help (); + if (definition != (symbol_def *) NULL) + return definition->help (); else return (char *) NULL; } +void +symbol_record::rename (const char *n) +{ + delete [] nm; + nm = strsave (n); +} + tree * symbol_record::def (void) const { - if (var != (symbol_def *) NULL) - return var->def (); - else if (fcn != (symbol_def *) NULL) - return fcn->def (); + if (definition != (symbol_def *) NULL) + return definition->def (); else - return (tree *) NULL; + return NULL_TREE; } int symbol_record::is_function (void) const { - return (var == (symbol_def *) NULL && fcn != (symbol_def *) NULL); + if (definition != (symbol_def *) NULL) + return definition->is_function (); + else + return 0; +} + +int +symbol_record::is_user_function (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->is_user_function (); + else + return 0; +} + +int +symbol_record::is_builtin_function (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->is_builtin_function (); + else + return 0; } int symbol_record::is_variable (void) const { - return (var != (symbol_def *) NULL); + if (definition != (symbol_def *) NULL) + return definition->is_variable (); + else + return 0; +} + +int +symbol_record::is_user_variable (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->is_user_variable (); + else + return 0; +} + +int +symbol_record::is_builtin_variable (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->is_builtin_variable (); + else + return 0; +} + +unsigned +symbol_record::type (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->type; + else + return 0; } int symbol_record::is_defined (void) const { - return (var != (symbol_def *) NULL || fcn != (symbol_def *) NULL); + if (definition != (symbol_def *) NULL) + return (definition->def () != NULL_TREE); + else + return 0; +} + +int +symbol_record::is_read_only (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->read_only; + else + return 0; +} + +int +symbol_record::is_eternal (void) const +{ + if (definition != (symbol_def *) NULL) + return definition->eternal; + else + return 0; +} + +void +symbol_record::protect (void) +{ + if (definition != (symbol_def *) NULL) + { + definition->protect (); + + if (! is_defined ()) + warning ("protecting undefined variable `%s'", nm); + } +} + +void +symbol_record::unprotect (void) +{ + if (definition != (symbol_def *) NULL) + definition->unprotect (); +} + +void +symbol_record::make_eternal (void) +{ + if (definition != (symbol_def *) NULL) + { + definition->make_eternal (); + + if (! is_defined ()) + warning ("giving eternal life to undefined variable `%s'", nm); + } } void @@ -225,55 +392,34 @@ } int -symbol_record::var_read_only (void) -{ - if (var != (symbol_def *) NULL - && var->sym_class == symbol_def::read_only) - { - error ("can't assign to read only symbol `%s'", nm); - return 1; - } - else - return 0; -} - -int -symbol_record::read_only (void) -{ - if ((var != (symbol_def *) NULL - && var->sym_class == symbol_def::read_only) - || (fcn != (symbol_def *) NULL - && fcn->sym_class == symbol_def::read_only)) - { - error ("can't assign to read only symbol `%s'", nm); - return 1; - } - else - return 0; -} - -int symbol_record::define (tree_constant *t) { - if (var_read_only ()) + if (is_variable () && read_only_error ()) return 0; - tree_constant *saved_def = NULL_TREE_CONST; - - if (var != (symbol_def *) NULL) + tree *saved_def = NULL_TREE; + if (definition == (symbol_def *) NULL) + { + definition = new symbol_def (); + definition->count = 1; + } + else if (is_function ()) { - saved_def = (tree_constant *) var->def (); // XXX FIXME XXX - var->define (t); + symbol_def *new_def = new symbol_def (); + push_def (new_def); + definition->count = 1; } - else + else if (is_variable ()) { - var = new symbol_def (t); - var->count = 1; + saved_def = definition->def (); } + definition->define (t); + if (sv_fcn != (sv_Function) NULL && sv_fcn () < 0) { - var->define (saved_def); +// Would be nice to be able to avoid this cast. XXX FIXME XXX + definition->define ((tree_constant *) saved_def); delete t; return 0; } @@ -286,115 +432,97 @@ int symbol_record::define (tree_builtin *t) { - if (read_only ()) + if (read_only_error ()) return 0; - if (var != (symbol_def *) NULL) + if (is_variable ()) { - if (--var->count <= 0) - delete var; - var = (symbol_def *) NULL; + symbol_def *old_def = pop_def (); + maybe_delete (old_def); } - if (fcn != (symbol_def *) NULL) - fcn->define (t); - else + if (is_function ()) { - fcn = new symbol_def (t); - fcn->count = 1; + symbol_def *old_def = pop_def (); + maybe_delete (old_def); } + symbol_def *new_def = new symbol_def (t); + push_def (new_def); + definition->count = 1; + return 1; } int symbol_record::define (tree_function *t) { - if (read_only ()) + if (read_only_error ()) return 0; - if (var != (symbol_def *) NULL) + if (is_variable ()) { - if (--var->count <= 0) - delete var; - var = (symbol_def *) NULL; + symbol_def *old_def = pop_def (); + maybe_delete (old_def); } - if (fcn != (symbol_def *) NULL) - fcn->define (t); - else + if (is_function ()) { - fcn = new symbol_def (t); - fcn->count = 1; + symbol_def *old_def = pop_def (); + maybe_delete (old_def); } + symbol_def *new_def = new symbol_def (t); + push_def (new_def); + definition->count = 1; + return 1; } int symbol_record::define_as_fcn (tree_constant *t) { - if (read_only ()) + if (is_variable () && read_only_error ()) return 0; - if (var != (symbol_def *) NULL) + if (is_variable ()) { - if (--var->count <= 0) - delete var; - var = (symbol_def *) NULL; + symbol_def *old_def = pop_def (); + maybe_delete (old_def); + } + + if (is_function ()) + { + symbol_def *old_def = pop_def (); + maybe_delete (old_def); } - if (fcn != (symbol_def *) NULL) - fcn->define (t); - else - { - fcn = new symbol_def (t); - fcn->count = 1; - } + symbol_def *new_def = new symbol_def (t); + push_def (new_def); + definition->count = 1; + definition->type = symbol_def::BUILTIN_FUNCTION; return 1; } +int +symbol_record::define_builtin_var (tree_constant *t) +{ + define (t); + if (is_variable ()) + definition->type = symbol_def::BUILTIN_VARIABLE; +} + void symbol_record::document (const char *h) { - if (var != (symbol_def *) NULL) - var->document (h); - else if (fcn != (symbol_def *) NULL) - fcn->document (h); - else - warning ("couldn't document undefined variable `%s'", nm); -} - -void -symbol_record::protect (void) -{ - if (var != (symbol_def *) NULL) - var->sym_class = symbol_def::read_only; - else if (fcn != (symbol_def *) NULL) - fcn->sym_class = symbol_def::read_only; - else - warning ("couldn't protect undefined variable `%s'", nm); -} + if (definition != (symbol_def *) NULL) + { + definition->document (h); -void -symbol_record::unprotect (void) -{ - if (var != (symbol_def *) NULL) - var->sym_class = symbol_def::read_write; - else if (fcn != (symbol_def *) NULL) - fcn->sym_class = symbol_def::read_write; -} - -void -symbol_record::make_eternal (void) -{ - if (var != (symbol_def *) NULL) - var->lifespan = symbol_def::eternal; - else if (fcn != (symbol_def *) NULL) - fcn->lifespan = symbol_def::eternal; - else - warning ("couldn't give eternal life to the variable `%s'", nm); + if (! is_defined ()) + warning ("documenting undefined variable `%s'", nm); + } } int @@ -402,74 +530,65 @@ { int status = 0; - if (var != (symbol_def *) NULL && var->def () != (tree *) NULL) +// This is a kludge, but hey, it doesn't make sense to save them +// anyway, does it? Even if it did, we would just have trouble trying +// to read NaN and Inf on lots of systems anyway... + + if (is_read_only ()) { -// For now, eternal implies builtin. - if (var->lifespan != symbol_def::eternal) - { -// Should we also save the help string? Maybe someday. - os << "# name: " << nm << "\n"; - status = var->save (os, mark_as_global); - } + warning ("save: sorry, can't save read-only variable `%s'", nm); + status = -1; } - else if (fcn != (symbol_def *) NULL) - message ("save", "sorry, can't save functions yet"); + else if (is_function ()) + { + warning ("save: sorry, can't save function `%s'", nm); + status = -1; + } else { -// Kludge! We probably don't want to print warnings for ans, but it -// does seem reasonable to print them for other undefined variables. - if (strcmp (nm, "ans") != 0) - warning ("not saving undefined symbol `%s'", nm); +// Should we also save the help string? Maybe someday. + + os << "# name: " << nm << "\n"; + + status = definition->save (os, mark_as_global); } return status; } int -symbol_record::clear_visible (void) +symbol_record::clear (void) { - int status = 0; - - if (is_defined ()) + int count = 0; + if (linked_to_global) { - if (var != (symbol_def *) NULL - && var->lifespan != symbol_def::eternal) - { - if (--var->count <= 0) - delete var; - var = (symbol_def *) NULL; - forced_global = 0; - status = 1; - } - else if (fcn != (symbol_def *) NULL - && fcn->lifespan != symbol_def::eternal) - { - if (--fcn->count <= 0) - delete fcn; - fcn = (symbol_def *) NULL; - status = 1; - } + count = maybe_delete (definition); + definition = (symbol_def *) NULL; + linked_to_global = 0; } - - return status; + else + { + symbol_def *old_def = pop_def (); + count = maybe_delete (old_def); + } + return count; } void -symbol_record::clear_all (void) +symbol_record::alias (symbol_record *s, int force = 0) { - if (var != (symbol_def *) NULL && var->lifespan != symbol_def::eternal) + sv_fcn = s->sv_fcn; + + if (force && s->definition == (symbol_def *) NULL) { - if (--var->count <= 0) - delete var; - var = (symbol_def *) NULL; - forced_global = 0; + s->definition = new symbol_def (); + definition = s->definition; + definition->count = 2; // Yes, this is correct. } - - if (fcn != (symbol_def *) NULL && fcn->lifespan != symbol_def::eternal) + else if (s->definition != (symbol_def *) NULL) { - if (--fcn->count <= 0) - delete fcn; - fcn = (symbol_def *) NULL; + definition = s->definition; + definition->count++; } } @@ -486,44 +605,15 @@ } void -symbol_record::mark_as_forced_global (void) +symbol_record::mark_as_linked_to_global (void) { - forced_global = 1; + linked_to_global = 1; } int -symbol_record::is_forced_global (void) const -{ - return forced_global; -} - -void -symbol_record::alias (symbol_record *s, int force = 0) +symbol_record::is_linked_to_global (void) const { - sv_fcn = s->sv_fcn; // Maybe this should go in the var symbol_def? - -// formal_param = s->formal_param; // Hmm. -// forced_global = s->forced_global; // Hmm. - - if (force && s->var == (symbol_def *) NULL - && s->fcn == (symbol_def *) NULL) - { - s->var = new symbol_def (); - var = s->var; - var->count = 2; // Yes, this is correct. - return; - } - - if (s->var != (symbol_def *) NULL) - { - var = s->var; - var->count++; - } - else if (s->fcn != (symbol_def *) NULL) - { - fcn = s->fcn; - fcn->count++; - } + return linked_to_global; } symbol_record * @@ -532,6 +622,247 @@ return next_elem; } +void +symbol_record::chain (symbol_record *s) +{ + next_elem = s; +} + +int +symbol_record::read_only_error (void) +{ + if (is_read_only ()) + { + char *tag = "symbol"; + if (is_variable ()) + tag = "variable"; + else if (is_function ()) + tag = "function"; + + error ("can't redefined read-only %s `%s'", tag, nm); + + return 1; + } + else + return 0; +} + +void +symbol_record::push_def (symbol_def *sd) +{ + if (sd == (symbol_def *) NULL) + return; + + sd->next_elem = definition; + definition = sd; +} + +symbol_def * +symbol_record::pop_def (void) +{ + symbol_def *top = definition; + if (definition != (symbol_def *) NULL) + definition = definition->next_elem; + return top; +} + +/* + * A structure for handling verbose information about a symbol_record. + */ + +symbol_record_info::symbol_record_info (void) +{ + init_state (); +} + +symbol_record_info::symbol_record_info (const symbol_record& sr) +{ + init_state (); + + type = sr.type (); + + if (sr.is_variable () && sr.is_defined ()) + { +// Would be nice to avoid this cast. XXX FIXME XXX + tree_constant *tmp = (tree_constant *) sr.def (); + switch (tmp->const_type ()) + { + case tree_constant_rep::scalar_constant: + const_type = SR_INFO_SCALAR; + break; + case tree_constant_rep::complex_scalar_constant: + const_type = SR_INFO_COMPLEX_SCALAR; + break; + case tree_constant_rep::matrix_constant: + const_type = SR_INFO_MATRIX; + break; + case tree_constant_rep::complex_matrix_constant: + const_type = SR_INFO_COMPLEX_MATRIX; + break; + case tree_constant_rep::range_constant: + const_type = SR_INFO_RANGE; + break; + case tree_constant_rep::string_constant: + const_type = SR_INFO_STRING; + break; + default: + break; + } + + nr = tmp->rows (); + nc = tmp->columns (); + + symbol_def *sr_def = sr.definition; + symbol_def *hidden_def = sr_def->next_elem; + if (hidden_def != (symbol_def *) NULL) + { + if (hidden_def->is_user_function ()) + hides = SR_INFO_USER_FUNCTION; + else if (hidden_def->is_builtin_function ()) + hides = SR_INFO_BUILTIN_FUNCTION; + } + } + + eternal = sr.is_eternal (); + read_only = sr.is_read_only (); + + nm = strsave (sr.name ()); + + initialized = 1; +} + +symbol_record_info::symbol_record_info (const symbol_record_info& s) +{ + type = s.type; + const_type = s.const_type; + hides = s.hides; + eternal = s.eternal; + read_only = s.read_only; + nr = s.nr; + nc = s.nc; + nm = strsave (s.nm); + initialized = s.initialized; +} + +symbol_record_info::~symbol_record_info (void) +{ + delete nm; +} + +symbol_record_info& +symbol_record_info::operator = (const symbol_record_info& s) +{ + if (this != &s) + { + delete nm; + type = s.type; + const_type = s.const_type; + hides = s.hides; + eternal = s.eternal; + read_only = s.read_only; + nr = s.nr; + nc = s.nc; + nm = strsave (s.nm); + initialized = s.initialized; + } + return *this; +} + +int +symbol_record_info::is_defined (void) const +{ + return initialized; +} + +int +symbol_record_info::is_read_only (void) const +{ + return read_only; +} + +int +symbol_record_info::is_eternal (void) const +{ + return eternal; +} + +int +symbol_record_info::hides_fcn (void) const +{ + return (hides & SR_INFO_USER_FUNCTION); +} + +int +symbol_record_info::hides_builtin (void) const +{ + return (hides & SR_INFO_BUILTIN_FUNCTION); +} + +char * +symbol_record_info::type_as_string (void) const +{ + if (type == symbol_def::USER_FUNCTION) + return "user function"; + else if (type == symbol_def::BUILTIN_FUNCTION) + return "builtin function"; + else + { + if (const_type == SR_INFO_SCALAR) + return "real scalar"; + else if (const_type == SR_INFO_COMPLEX_SCALAR) + return "complex scalar"; + else if (const_type == SR_INFO_MATRIX) + return "real matrix"; + else if (const_type == SR_INFO_COMPLEX_MATRIX) + return "complex matrix"; + else if (const_type == SR_INFO_RANGE) + return "range"; + else if (const_type == SR_INFO_STRING) + return "string"; + else + return ""; + } +} + +int +symbol_record_info::is_function (void) const +{ + return (type == symbol_def::USER_FUNCTION + || type == symbol_def::BUILTIN_FUNCTION); +} + +int +symbol_record_info::rows (void) const +{ + return nr; +} + +int +symbol_record_info::columns (void) const +{ + return nc; +} + +char * +symbol_record_info::name (void) const +{ + return nm; +} + +void +symbol_record_info::init_state (void) +{ + initialized = 0; + type = symbol_def::UNKNOWN; + const_type = SR_INFO_UNKNOWN; + hides = SR_INFO_NONE; + eternal = 0; + read_only = 0; + nr = -1; + nc = -1; + nm = (char *) NULL; +} + /* * A symbol table. */ @@ -558,7 +889,7 @@ { symbol_record *new_sym; new_sym = new symbol_record (nm, table[index].next ()); - table[index].next_elem = new_sym; + table[index].chain (new_sym); return new_sym; } else if (warn) @@ -568,7 +899,7 @@ } void -symbol_table::clear (void) +symbol_table::clear (int clear_user_functions = 1) { for (int i = 0; i < HASH_TABLE_SIZE; i++) { @@ -576,61 +907,45 @@ while (ptr != (symbol_record *) NULL) { - ptr->clear_all (); + if (ptr->is_user_variable () + || (clear_user_functions && ptr->is_user_function ())) + { + ptr->clear (); + } + ptr = ptr->next (); } } } int -symbol_table::clear (const char *nm) +symbol_table::clear (const char *nm, int clear_user_functions = 1) { int index = hash (nm) & HASH_MASK; - symbol_record *prev = &table[index]; - symbol_record *curr = prev->next (); + symbol_record *ptr = table[index].next (); - while (curr != (symbol_record *) NULL) + while (ptr != (symbol_record *) NULL) { - if (strcmp (curr->name (), nm) == 0) + if (strcmp (ptr->name (), nm) == 0 + && (ptr->is_user_variable () + || (clear_user_functions && ptr->is_user_function ()))) { - if (curr->clear_visible ()) - return 1; + ptr->clear (); + return 1; } - prev = curr; - curr = curr->next (); + ptr = ptr->next (); } return 0; } -// Ugh. - -void -symbol_table::bind_globals (void) -{ - assert (this != global_sym_tab); - - for (int i = 0; i < HASH_TABLE_SIZE; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr != (symbol_record *) NULL && ! ptr->formal_param) - { - char *nm = ptr->name (); - symbol_record *sr = global_sym_tab->lookup (nm, 0, 0); - if (sr != (symbol_record *) NULL && sr->is_forced_global ()) - ptr->alias (sr, 1); - ptr = ptr->next (); - } - } -} - int symbol_table::save (ostream& os, int mark_as_global = 0) { int status = 0; - char **names = sorted_var_list (); + int count; + char **names = list (count, 1, symbol_def::USER_VARIABLE); if (names != (char **) NULL) { while (*names != (char *) NULL) @@ -670,52 +985,60 @@ return count; } -char ** -symbol_table::list (void) const +static inline int +pstrcmp (char **a, char **b) { - int count; - return list (count); + return strcmp (*a, *b); } -char ** -symbol_table::var_list (void) const +static inline int +symbol_record_info_cmp (symbol_record_info *a, symbol_record_info *b) { - int count; - return var_list (count); + return strcmp (a->name (), b->name ()); } -char ** -symbol_table::fcn_list (void) const -{ - int count; - return fcn_list (count); -} +// This function should probably share code with symbol_table::list. +// XXX FIXME XXX -char ** -symbol_table::list (int& count) const +symbol_record_info * +symbol_table::long_list (int& count, int sort = 0, + unsigned type = SYMTAB_ALL_TYPES, + unsigned scope = SYMTAB_ALL_SCOPES) const { count = 0; int n = size (); if (n == 0) - return (char **) NULL; + return (symbol_record_info *) NULL; - char **symbols = new char * [n+1]; + symbol_record_info *symbols = new symbol_record_info [n+1]; for (int i = 0; i < HASH_TABLE_SIZE; i++) { symbol_record *ptr = table[i].next (); while (ptr != (symbol_record *) NULL) { assert (count < n); - symbols[count++] = strsave (ptr->name ()); + unsigned my_scope = ptr->is_linked_to_global () + 1; // Tricky... + unsigned my_type = ptr->type (); + if ((type & my_type) && (scope & my_scope)) + { + symbols[count++] = symbol_record_info (*ptr); + } ptr = ptr->next (); } } - symbols[count] = (char *) NULL; + symbols[count] = symbol_record_info (); + + if (sort && symbols != (symbol_record_info *) NULL) + qsort ((void *) symbols, count, sizeof (symbol_record_info), + (int (*)(void*, void*)) symbol_record_info_cmp); + return symbols; } char ** -symbol_table::var_list (int& count) const +symbol_table::list (int& count, int sort = 0, + unsigned type = SYMTAB_ALL_TYPES, + unsigned scope = SYMTAB_ALL_SCOPES) const { count = 0; int n = size (); @@ -729,93 +1052,19 @@ while (ptr != (symbol_record *) NULL) { assert (count < n); - if (ptr->is_variable ()) - symbols[count++] = strsave (ptr->name ()); - ptr = ptr->next (); - } - } - symbols[count] = (char *) NULL; - return symbols; -} - -char ** -symbol_table::fcn_list (int& count) const -{ - count = 0; - int n = size (); - if (n == 0) - return (char **) NULL; - - char **symbols = new char * [n+1]; - for (int i = 0; i < HASH_TABLE_SIZE; i++) - { - symbol_record *ptr = table[i].next (); - while (ptr != (symbol_record *) NULL) - { - assert (count < n); - if (ptr->is_function ()) + unsigned my_scope = ptr->is_linked_to_global () + 1; // Tricky... + unsigned my_type = ptr->type (); + if ((type & my_type) && (scope & my_scope)) symbols[count++] = strsave (ptr->name ()); ptr = ptr->next (); } } symbols[count] = (char *) NULL; - return symbols; -} -static inline int -pstrcmp (char **a, char **b) -{ - return strcmp (*a, *b); -} - -char ** -symbol_table::sorted_list (void) const -{ - int count = 0; - return sorted_list (count); -} - -char ** -symbol_table::sorted_var_list (void) const -{ - int count = 0; - return sorted_var_list (count); -} - -char ** -symbol_table::sorted_fcn_list (void) const -{ - int count = 0; - return sorted_fcn_list (count); -} - -char ** -symbol_table::sorted_list (int& count) const -{ - char **symbols = list (count); - if (symbols != (char **) NULL) + if (sort && symbols != (char **) NULL) qsort ((void **) symbols, count, sizeof (char *), (int (*)(void*, void*)) pstrcmp); - return symbols; -} -char ** -symbol_table::sorted_var_list (int& count) const -{ - char **symbols = var_list (count); - if (symbols != (char **) NULL) - qsort ((void **) symbols, count, sizeof (char *), - (int (*)(void*, void*)) pstrcmp); - return symbols; -} - -char ** -symbol_table::sorted_fcn_list (int& count) const -{ - char **symbols = fcn_list (count); - if (symbols != (char **) NULL) - qsort ((void **) symbols, count, sizeof (char *), - (int (*)(void*, void*)) pstrcmp); return symbols; } diff -r 4f3364dcf450 -r 13c6086c325c src/symtab.h --- a/src/symtab.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/symtab.h Sat Nov 06 10:14:11 1993 +0000 @@ -50,6 +50,7 @@ class symbol_def; class symbol_record; +class symbol_record_info; class symbol_table; /* @@ -58,29 +59,10 @@ class symbol_def { friend class symbol_record; + friend class symbol_record_info; public: - enum symbol_type - { - unknown_type, - variable, - builtin_function, - user_function, - }; - - enum symbol_lifespan - { - temporary, - eternal, - }; - - enum symbol_class - { - read_write, - read_only, - }; - symbol_def (void); symbol_def (tree_constant *t); symbol_def (tree_builtin *t); @@ -88,25 +70,50 @@ ~symbol_def (void); + int is_variable (void) const; + int is_function (void) const; + int is_user_variable (void) const; + int is_user_function (void) const; + int is_builtin_variable (void) const; + int is_builtin_function (void) const; + void define (tree_constant *t); void define (tree_builtin *t); void define (tree_function *t); + void protect (void); + void unprotect (void); + void make_eternal (void); + tree *def (void) const; char *help (void) const; void document (const char *h); int save (ostream& os, int mark_as_global); + enum TYPE + { + UNKNOWN = 0, + USER_FUNCTION = 1, + USER_VARIABLE = 2, + BUILTIN_FUNCTION = 4, + BUILTIN_VARIABLE = 8 + }; + + friend maybe_delete (symbol_def *def); + private: + unsigned type : 4; + unsigned eternal : 1; + unsigned read_only : 1; + char *help_string; - symbol_lifespan lifespan; - symbol_class sym_class; - symbol_type type; tree *definition; + symbol_def *next_elem; int count; - int preserve; + + void init_state (void); symbol_def (const symbol_def& sd); symbol_def& operator = (const symbol_def& sd); @@ -118,12 +125,11 @@ class symbol_record { - friend class symbol_table; + friend class symbol_record_info; public: symbol_record (void); - symbol_record (const char *n); - symbol_record (const char *n, symbol_record *nxt); + symbol_record (const char *n, symbol_record *nxt = (symbol_record *) NULL); ~symbol_record (void); @@ -131,57 +137,135 @@ char *help (void) const; tree *def (void) const; + void rename (const char *n); + int is_function (void) const; + int is_user_function (void) const; + int is_builtin_function (void) const; int is_variable (void) const; + int is_user_variable (void) const; + int is_builtin_variable (void) const; + + unsigned type (void) const; int is_defined (void) const; - - void set_sv_function (sv_Function f); - - int var_read_only (void); - int read_only (void); - - int define (tree_constant *t); - int define (tree_builtin *t); - int define (tree_function *t); - int define_as_fcn (tree_constant *t); - - void document (const char *h); + int is_read_only (void) const; + int is_eternal (void) const; void protect (void); void unprotect (void); void make_eternal (void); + void set_sv_function (sv_Function f); + + int define (tree_constant *t); + int define (tree_builtin *t); + int define (tree_function *t); + int define_as_fcn (tree_constant *t); + int define_builtin_var (tree_constant *t); + + void document (const char *h); + int save (ostream& os, int mark_as_global = 0); - int clear_visible (void); - void clear_all (void); + int clear (void); + + void alias (symbol_record *s, int force = 0); void mark_as_formal_parameter (void); int is_formal_parameter (void) const; - void mark_as_forced_global (void); - int is_forced_global (void) const; - - void alias (symbol_record *s, int force = 0); + void mark_as_linked_to_global (void); + int is_linked_to_global (void) const; symbol_record *next (void) const; + void chain (symbol_record *s); + private: + unsigned formal_param : 1; + unsigned linked_to_global : 1; + char *nm; - int formal_param; - int forced_global; - symbol_def *var; - symbol_def *fcn; sv_Function sv_fcn; + symbol_def *definition; symbol_record *next_elem; - symbol_record (const symbol_record& s) { assert (0); } + void init_state (void); + + int read_only_error (void); + + void push_def (symbol_def *sd); + symbol_def *pop_def (void); + symbol_record& operator = (const symbol_record& s); }; /* + * A structure for handling verbose information about a symbol_record. + */ + +class +symbol_record_info +{ +public: + + symbol_record_info (void); + symbol_record_info (const symbol_record& s); + + symbol_record_info (const symbol_record_info& s); + + ~symbol_record_info (void); + + symbol_record_info& operator = (const symbol_record_info& s); + + int is_defined (void) const; + int is_read_only (void) const; + int is_eternal (void) const; + int hides_fcn (void) const; + int hides_builtin (void) const; + char *type_as_string (void) const; + int is_function (void) const; + int rows (void) const; + int columns (void) const; + char *name (void) const; + + enum HIDES + { + SR_INFO_NONE = 0, + SR_INFO_USER_FUNCTION = 1, + SR_INFO_BUILTIN_FUNCTION = 2 + }; + + enum CONST_TYPE + { + SR_INFO_UNKNOWN = 0, + SR_INFO_SCALAR = 1, + SR_INFO_COMPLEX_SCALAR = 2, + SR_INFO_MATRIX = 4, + SR_INFO_COMPLEX_MATRIX = 8, + SR_INFO_RANGE = 16, + SR_INFO_STRING = 32 + }; + +private: + + void init_state (void); + + unsigned type : 4; + unsigned const_type : 6; + unsigned hides : 2; + unsigned eternal : 1; + unsigned read_only : 1; + int nr; + int nc; + char *nm; + + int initialized; +}; + +/* * A symbol table. */ class @@ -193,31 +277,31 @@ symbol_record *lookup (const char *nm, int insert = 0, int warn = 0); - void clear (void); - int clear (const char *nm); - - void bind_globals (void); + void clear (int clear_user_functions = 1); + int clear (const char *nm, int clear_user_functions = 1); int save (ostream& os, int mark_as_global = 0); int save (ostream& os, const char *name, int mark_as_global = 0); int size (void) const; - char **list (void) const; - char **var_list (void) const; - char **fcn_list (void) const; +#define SYMTAB_LOCAL_SCOPE 1 +#define SYMTAB_GLOBAL_SCOPE 2 - char **list (int& count) const; - char **var_list (int& count) const; - char **fcn_list (int& count) const; +#define SYMTAB_ALL_SCOPES (SYMTAB_LOCAL_SCOPE | SYMTAB_GLOBAL_SCOPE) - char **sorted_list (void) const; - char **sorted_var_list (void) const; - char **sorted_fcn_list (void) const; +#define SYMTAB_ALL_TYPES (symbol_def::USER_FUNCTION \ + | symbol_def::USER_VARIABLE \ + | symbol_def::BUILTIN_FUNCTION \ + | symbol_def::BUILTIN_VARIABLE) - char **sorted_list (int& count) const; - char **sorted_var_list (int& count) const; - char **sorted_fcn_list (int& count) const; + symbol_record_info *long_list (int& count, int sort = 0, + unsigned type = SYMTAB_ALL_TYPES, + unsigned scope = SYMTAB_ALL_SCOPES) const; + + char **list (int& count, int sort = 0, + unsigned type = SYMTAB_ALL_TYPES, + unsigned scope = SYMTAB_ALL_SCOPES) const; private: diff -r 4f3364dcf450 -r 13c6086c325c src/t-builtins.cc --- a/src/t-builtins.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/t-builtins.cc Sat Nov 06 10:14:11 1993 +0000 @@ -92,8 +92,6 @@ extern char *replace_in_documentation (); } -extern int symbol_out_of_date (symbol_record *s); - // Is this a parametric plot? Makes a difference for 3D plotting. extern int parametric_plot; @@ -218,11 +216,12 @@ char *directory = get_working_directory ("cd"); tree_constant *dir = new tree_constant (directory); - bind_protected_variable ("PWD", dir); + bind_builtin_variable ("PWD", dir, 1); return retval; } +#if 0 static int in_list (char *s, char **list) { @@ -235,32 +234,44 @@ return 0; } +#endif /* * Wipe out user-defined variables and functions given a list of - * regular expressions. + * regular expressions. + * + * It's not likely that this works correctly now. XXX FIXME XXX */ tree_constant builtin_clear (int argc, char **argv) { tree_constant retval; + +// Always clear the local table, but don't clear currently compiled +// functions unless we are at the top level. (Allowing that to happen +// inside functions would result in pretty odd behavior...) + + int clear_user_functions = (curr_sym_tab == top_level_sym_tab); + if (argc == 1) { curr_sym_tab->clear (); - if (curr_sym_tab == top_level_sym_tab) - global_sym_tab->clear (); + global_sym_tab->clear (clear_user_functions); } else { - int count; - char **names = curr_sym_tab->list (count); - - int g_count; - char **g_names = global_sym_tab->list (g_count); - - int num_cleared = 0; - char **locals_cleared = new char * [count+1]; - locals_cleared[num_cleared] = (char *) NULL; + int lcount; + char **lvars = curr_sym_tab->list (lcount, 0, + symbol_def::USER_VARIABLE, + SYMTAB_LOCAL_SCOPE); + int gcount; + char **gvars = curr_sym_tab->list (gcount, 0, + symbol_def::USER_VARIABLE, + SYMTAB_GLOBAL_SCOPE); + int fcount; + char **fcns = curr_sym_tab->list (fcount, 0, + symbol_def::USER_FUNCTION, + SYMTAB_ALL_SCOPES); while (--argc > 0) { @@ -270,38 +281,41 @@ Regex rx (*argv); int i; - for (i = 0; i < count; i++) + for (i = 0; i < lcount; i++) { - String nm (names[i]); - if (nm.matches (rx) && curr_sym_tab->clear (names[i])) + String nm (lvars[i]); + if (nm.matches (rx)) + curr_sym_tab->clear (lvars[i]); + } + + int count; + for (i = 0; i < gcount; i++) + { + String nm (gvars[i]); + if (nm.matches (rx)) { - locals_cleared[num_cleared++] = strsave (names[i]); - locals_cleared[num_cleared] = (char *) NULL; + count = curr_sym_tab->clear (gvars[i]); + if (count > 0) + global_sym_tab->clear (gvars[i], clear_user_functions); } } - if (curr_sym_tab == top_level_sym_tab) + for (i = 0; i < fcount; i++) { - for (i = 0; i < g_count; i++) + String nm (fcns[i]); + if (nm.matches (rx)) { - String nm (g_names[i]); - if (nm.matches (rx) - && ! in_list (g_names[i], locals_cleared)) - { - global_sym_tab->clear (g_names[i]); - } + count = curr_sym_tab->clear (fcns[i]); + if (count > 0) + global_sym_tab->clear (fcns[i], clear_user_functions); } } } } - int i = 0; - while (locals_cleared[i] != (char *) NULL) - delete [] locals_cleared[i++]; - delete [] locals_cleared; - - delete [] names; - delete [] g_names; + delete [] lvars; + delete [] gvars; + delete [] fcns; } return retval; @@ -315,22 +329,9 @@ { tree_constant retval; if (argc == 3) - { - symbol_record *sym_rec = curr_sym_tab->lookup (argv[1], 0); - if (sym_rec == (symbol_record *) NULL) - { - sym_rec = global_sym_tab->lookup (argv[1], 0); - if (sym_rec == (symbol_record *) NULL) - { - error ("document: no such symbol `%s'", argv[1]); - return retval; - } - } - sym_rec->document (argv[2]); - } + document_symbol (argv[1], argv[2]); else print_usage ("document"); - return retval; } @@ -848,20 +849,54 @@ if (argc == 1) { - curr_sym_tab->save (stream); - global_sym_tab->save (stream, 1); + int count; + char **vars = curr_sym_tab->list (count, 0, + symbol_def::USER_VARIABLE, + SYMTAB_ALL_SCOPES); + + for (int i = 0; i < count; i++) + curr_sym_tab->save (stream, vars[i], + is_globally_visible (vars[i])); + + delete [] vars; } else { while (--argc > 0) { argv++; - if (! curr_sym_tab->save (stream, *argv)) - if (! global_sym_tab->save (stream, *argv, 1)) - { - warning ("save: no such variable `%s'", *argv); - continue; - } + + int count; + char **lvars = curr_sym_tab->list (count, 0, + symbol_def::USER_VARIABLE); + Regex rx (*argv); + + int saved_or_error = 0; + int i; + for (i = 0; i < count; i++) + { + String nm (lvars[i]); + if (nm.matches (rx) + && curr_sym_tab->save (stream, lvars[i]) != 0) + saved_or_error++; + } + + char **bvars = global_sym_tab->list (count, 0, + symbol_def::BUILTIN_VARIABLE); + + for (i = 0; i < count; i++) + { + String nm (bvars[i]); + if (nm.matches (rx) + && global_sym_tab->save (stream, bvars[i]) != 0) + saved_or_error++; + } + + delete [] lvars; + delete [] bvars; + + if (! saved_or_error) + warning ("save: no such variable `%s'", *argv); } } @@ -928,104 +963,160 @@ /* * List variable names. */ +static void +print_symbol_info_line (ostrstream& output_buf, const symbol_record_info& s) +{ + output_buf << (s.is_read_only () ? " -" : " w"); + output_buf << (s.is_eternal () ? "- " : "d "); +#if 0 + output_buf << (s.hides_fcn () ? "f" : (s.hides_builtin () ? "F" : "-")); +#endif + output_buf.form (" %-16s", s.type_as_string ()); + if (s.is_function ()) + output_buf << " - -"; + else + { + output_buf.form ("%7d", s.rows ()); + output_buf.form ("%7d", s.columns ()); + } + output_buf << " " << s.name () << "\n"; +} + +static void +print_long_listing (ostrstream& output_buf, symbol_record_info *s) +{ + if (s == (symbol_record_info *) NULL) + return; + + symbol_record_info *ptr = s; + while (ptr->is_defined ()) + { + print_symbol_info_line (output_buf, *ptr); + ptr++; + } +} + +static int +maybe_list (const char *header, ostrstream& output_buf, + int show_verbose, symbol_table *sym_tab, unsigned type, + unsigned scope) +{ + int count; + int status = 0; + if (show_verbose) + { + symbol_record_info *symbols; + symbols = sym_tab->long_list (count, 1, type, scope); + if (symbols != (symbol_record_info *) NULL && count > 0) + { + output_buf << "\n" << header << "\n\n" + << "prot type rows cols name\n" + << "==== ==== ==== ==== ====\n"; + + print_long_listing (output_buf, symbols); + status = 1; + } + delete [] symbols; + } + else + { + char **symbols = sym_tab->list (count, 1, type, scope); + if (symbols != (char **) NULL && count > 0) + { + output_buf << "\n" << header << "\n\n"; + list_in_columns (output_buf, symbols); + status = 1; + } + delete [] symbols; + } + return status; +} + tree_constant builtin_who (int argc, char **argv) { tree_constant retval; - int show_global = 0; - int show_local = 1; - int show_top = 0; - int show_fcns = 0; + + int show_builtins = 0; + int show_functions = (curr_sym_tab == top_level_sym_tab); + int show_variables = 1; + int show_verbose = 0; if (argc > 1) - show_local = 0; + { + show_functions = 0; + show_variables = 0; + } for (int i = 1; i < argc; i++) { argv++; - if (strcmp (*argv, "-all") == 0) + if (strcmp (*argv, "-all") == 0 || strcmp (*argv, "-a") == 0) { - show_global++; - show_local++; - show_top++; - show_fcns++; + show_builtins++; + show_functions++; + show_variables++; } - else if (strcmp (*argv, "-global") == 0) - show_global++; - else if (strcmp (*argv, "-local") == 0) - show_local++; - else if (strcmp (*argv, "-top") == 0) - show_top++; - else if (strcmp (*argv, "-fcn") == 0 - || strcmp (*argv, "-fcns") == 0 - || strcmp (*argv, "-functions") == 0) - show_fcns++; + else if (strcmp (*argv, "-builtins") == 0 + || strcmp (*argv, "-b") == 0) + show_builtins++; + else if (strcmp (*argv, "-functions") == 0 + || strcmp (*argv, "-f") == 0) + show_functions++; + else if (strcmp (*argv, "-long") == 0 + || strcmp (*argv, "-l") == 0) + show_verbose++; + else if (strcmp (*argv, "-variables") == 0 + || strcmp (*argv, "-v") == 0) + show_variables++; else - { - warning ("who: unrecognized option `%s'", *argv); - if (argc == 2) - show_local = 1; - } + warning ("who: unrecognized option `%s'", *argv); + } + +// If the user specified -l and nothing else, show variables. If +// evaluating this at the top level, also show functions. + + if (show_verbose && ! (show_builtins || show_functions || show_variables)) + { + show_functions = (curr_sym_tab == top_level_sym_tab); + show_variables = 1; } ostrstream output_buf; int pad_after = 0; - if (show_global) + + if (show_builtins) { - int count = 0; - char **symbols = global_sym_tab->sorted_var_list (count); - if (symbols != (char **) NULL && count > 0) - { - output_buf << "\n*** global symbols:\n\n"; - list_in_columns (output_buf, symbols); - delete [] symbols; - pad_after++; - } - } + pad_after += maybe_list ("*** built-in variables:", + output_buf, show_verbose, global_sym_tab, + symbol_def::BUILTIN_VARIABLE, + SYMTAB_ALL_SCOPES); - if (show_top) - { - int count = 0; - char **symbols = top_level_sym_tab->sorted_var_list (count); - if (symbols != (char **) NULL && count > 0) - { - output_buf << "\n*** top level symbols:\n\n"; - list_in_columns (output_buf, symbols); - delete [] symbols; - pad_after++; - } + pad_after += maybe_list ("*** built-in functions:", + output_buf, show_verbose, global_sym_tab, + symbol_def::BUILTIN_FUNCTION, + SYMTAB_ALL_SCOPES); } - if (show_local) + if (show_functions) { - if (show_top && curr_sym_tab == top_level_sym_tab) - output_buf << - "\ncurrent (local) symbol table == top level symbol table\n"; - else - { - int count = 0; - char **symbols = curr_sym_tab->sorted_var_list (count); - if (symbols != (char **) NULL && count > 0) - { - output_buf << "\n*** local symbols:\n\n"; - list_in_columns (output_buf, symbols); - delete [] symbols; - pad_after++; - } - } + pad_after += maybe_list ("*** currently compiled functions:", + output_buf, show_verbose, global_sym_tab, + symbol_def::USER_FUNCTION, + SYMTAB_ALL_SCOPES); } - if (show_fcns) + if (show_variables) { - int count = 0; - char **symbols = global_sym_tab->sorted_fcn_list (count); - if (symbols != (char **) NULL && count > 0) - { - output_buf << "\n*** functions builtin or currently compiled:\n\n"; - list_in_columns (output_buf, symbols); - delete [] symbols; - pad_after++; - } + pad_after += maybe_list ("*** local user variables:", + output_buf, show_verbose, curr_sym_tab, + symbol_def::USER_VARIABLE, + SYMTAB_LOCAL_SCOPE); + + pad_after += maybe_list ("*** globally visible user variables:", + output_buf, show_verbose, curr_sym_tab, + symbol_def::USER_VARIABLE, + SYMTAB_GLOBAL_SCOPE); } if (pad_after) diff -r 4f3364dcf450 -r 13c6086c325c src/toplev.h --- a/src/toplev.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/toplev.h Sat Nov 06 10:14:11 1993 +0000 @@ -28,7 +28,14 @@ class tree; -extern volatile void clean_up_and_exit (int); +// Tell g++ that clean_up_and_exit doesn't return; + +#ifdef __GNUG__ +typedef void v_fcn_i (int); +volatile v_fcn_i clean_up_and_exit; +#endif + +extern void clean_up_and_exit (int); extern void parse_and_execute (char*, int); extern void parse_and_execute (FILE*, int); @@ -56,6 +63,9 @@ // Name of the info file specified on command line. extern char *info_file; +// Name of the editor to be invoked by the edit_history command. +extern char *editor; + // If nonzero, don't do fancy line editing. extern int no_line_editing; diff -r 4f3364dcf450 -r 13c6086c325c src/tree.h.old --- a/src/tree.h.old Wed Nov 03 21:38:05 1993 +0000 +++ b/src/tree.h.old Sat Nov 06 10:14:11 1993 +0000 @@ -84,6 +84,7 @@ class tree_word_list; class tree_command; class tree_command_list; +class tree_global_command; class tree_while_command; class tree_for_command; class tree_if_command; @@ -133,10 +134,16 @@ tree_builtin : public tree { public: - tree_builtin (void); - tree_builtin (int i_max, int o_max, Mapper_fcn& m_fcn, symbol_record *s); - tree_builtin (int i_max, int o_max, Text_fcn t_fcn, symbol_record *s); - tree_builtin (int i_max, int o_max, General_fcn t_fcn, symbol_record *s); + tree_builtin (const char *nm = (char *) NULL); + + tree_builtin (int i_max, int o_max, Mapper_fcn& m_fcn, + const char *nm = (char *) NULL); + + tree_builtin (int i_max, int o_max, Text_fcn t_fcn, + const char *nm = (char *) NULL); + + tree_builtin (int i_max, int o_max, General_fcn t_fcn, + const char *nm = (char *) NULL); ~tree_builtin (void); @@ -151,7 +158,6 @@ tree_constant *eval (const tree_constant *args, int n_in, int n_out, int print); - tree *def (void); char *name (void); int max_expected_args (void); @@ -162,9 +168,7 @@ Mapper_fcn mapper_fcn; Text_fcn text_fcn; General_fcn general_fcn; - symbol_record *sym; // Is this really needed? It points back - // to the symbol record that contains this - // builtin function... + char *my_name; }; /* @@ -183,9 +187,8 @@ int is_identifier (void) const; - tree *def (void); char *name (void); - symbol_record *symrec (void); + void rename (const char *n); tree_identifier *define (tree_constant *t); tree_identifier *define (tree_function *t); @@ -205,6 +208,8 @@ void mark_as_formal_parameter (void); + void mark_for_possible_ans_assign (void); + tree_constant eval (int print); tree_constant *eval (int print, int nargout); @@ -218,6 +223,7 @@ private: symbol_record *sym; + int maybe_do_ans_assign; }; /* @@ -242,6 +248,9 @@ char *m_file_name (void); time_t time_parsed (void); + void mark_as_system_m_file (void); + int is_system_m_file (void) const; + void stash_function_name (char *s); char *function_name (void); @@ -267,6 +276,7 @@ char *file_name; char *fcn_name; time_t t_parsed; + int system_m_file; }; /* @@ -303,6 +313,8 @@ void eval_error (void); + int is_prefix_expression (void) const; + private: tree_identifier *id; }; @@ -482,6 +494,8 @@ tree_argument_list *arg_list (void); + void mark_for_possible_ans_assign (void); + tree_constant eval (int print); tree_constant *eval (int print, int nargout); @@ -644,6 +658,33 @@ }; /* + * Global. + */ +class +tree_global_command : public tree_command +{ + public: + tree_global_command (int l = -1, int c = -1); + tree_global_command (symbol_record *s, int l = -1, int c = -1); + tree_global_command (symbol_record *s, tree *e, int l = -1, int c = -1); + + ~tree_global_command (void); + + tree_global_command *chain (symbol_record *s, int l = -1, int c = -1); + tree_global_command *chain (symbol_record *s, tree *e, int l = -1, int c = -1); + tree_global_command *reverse (void); + + tree_constant eval (int print); + + void eval_error (void); + + private: + symbol_record *sr; // Symbol record from local symbol table. + tree *rhs; // RHS of assignment. + tree_global_command *next; // Next global command. +}; + +/* * While. */ class diff -r 4f3364dcf450 -r 13c6086c325c src/user-prefs.cc --- a/src/user-prefs.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/user-prefs.cc Sat Nov 06 10:14:11 1993 +0000 @@ -48,7 +48,7 @@ static int check_str_pref (char *var) { - char *val = octave_string_variable (var); + char *val = builtin_string_variable (var); int pref = -1; if (val != (char *) NULL) { @@ -237,6 +237,30 @@ } /* + * Should Octave always check to see if M-files have changed since + * they were last compiled? + */ +int +ignore_function_time_stamp (void) +{ + int pref = 0; + + char *val = builtin_string_variable ("ignore_function_time_stamp"); + + if (val != (char *) NULL) + { + if (strncmp (val, "all", 3) == 0) + pref = 2; + if (strncmp (val, "system", 6) == 0) + pref = 1; + } + + user_pref.ignore_function_time_stamp = pref; + + return 0; +} + +/* * Should should big matrices be split into smaller slices for output? */ int @@ -301,7 +325,7 @@ warn_assign_as_truth_value (void) { user_pref.warn_assign_as_truth_value = - check_str_pref ("user_pref.warn_assign_as_truth_value"); + check_str_pref ("warn_assign_as_truth_value"); return 0; } @@ -326,7 +350,7 @@ static int kludge = 0; double val; - if (octave_real_scalar_variable ("output_max_field_width", val) == 0) + if (builtin_real_scalar_variable ("output_max_field_width", val) == 0) { int ival = NINT (val); if (ival > 0 && (double) ival == val) @@ -355,7 +379,7 @@ static int kludge = 0; double val; - if (octave_real_scalar_variable ("output_precision", val) == 0) + if (builtin_real_scalar_variable ("output_precision", val) == 0) { int ival = NINT (val); if (ival >= 0 && (double) ival == val) @@ -381,7 +405,7 @@ { int status = 0; - char *s = octave_string_variable ("LOADPATH"); + char *s = builtin_string_variable ("LOADPATH"); if (s != (char *) NULL) { delete [] user_pref.loadpath; @@ -401,7 +425,7 @@ { int status = 0; - char *s = octave_string_variable ("INFO_FILE"); + char *s = builtin_string_variable ("INFO_FILE"); if (s != (char *) NULL) { delete [] user_pref.info_file; @@ -417,11 +441,31 @@ } int +sv_editor (void) +{ + int status = 0; + + char *s = builtin_string_variable ("EDITOR"); + if (s != (char *) NULL) + { + delete [] user_pref.editor; + user_pref.editor = s; + } + else + { + warning ("invalid value specified for EDITOR"); + status = -1; + } + + return status; +} + +int sv_ps1 (void) { int status = 0; - char *s = octave_string_variable ("PS1"); + char *s = builtin_string_variable ("PS1"); if (s != (char *) NULL) { delete [] user_pref.ps1; @@ -441,7 +485,7 @@ { int status = 0; - char *s = octave_string_variable ("PS2"); + char *s = builtin_string_variable ("PS2"); if (s != (char *) NULL) { delete [] user_pref.ps2; @@ -461,7 +505,7 @@ { int status = 0; - char *s = octave_string_variable ("PWD"); + char *s = builtin_string_variable ("PWD"); if (s != (char *) NULL) { delete [] user_pref.pwd; @@ -481,7 +525,7 @@ { int status = 0; - char *s = octave_string_variable ("gnuplot_binary"); + char *s = builtin_string_variable ("gnuplot_binary"); if (s != (char *) NULL) { delete [] user_pref.gnuplot_binary; @@ -501,7 +545,7 @@ { int status = 0; - char *s = octave_string_variable ("PAGER"); + char *s = builtin_string_variable ("PAGER"); if (s != (char *) NULL) { delete [] user_pref.pager_binary; diff -r 4f3364dcf450 -r 13c6086c325c src/user-prefs.h --- a/src/user-prefs.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/user-prefs.h Sat Nov 06 10:14:11 1993 +0000 @@ -42,6 +42,7 @@ int resize_on_range_error; int return_last_computed_value; int silent_functions; + int ignore_function_time_stamp; int split_long_rows; int treat_neg_dim_as_zero; int warn_comma_in_global_decl; @@ -53,6 +54,7 @@ char *loadpath; char *info_file; + char *editor; char *ps1; char *ps2; char *pwd; @@ -74,6 +76,7 @@ extern int resize_on_range_error (void); extern int return_last_computed_value (void); extern int silent_functions (void); +extern int ignore_function_time_stamp (void); extern int split_long_rows (void); extern int treat_neg_dim_as_zero (void); extern int warn_comma_in_global_decl (void); @@ -86,6 +89,7 @@ extern int sv_loadpath (void); extern int sv_info_file (void); +extern int sv_editor (void); extern int sv_pager_binary (void); extern int sv_ps1 (void); extern int sv_ps2 (void); diff -r 4f3364dcf450 -r 13c6086c325c src/utils.cc --- a/src/utils.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/utils.cc Sat Nov 06 10:14:11 1993 +0000 @@ -386,7 +386,7 @@ return path; } -static char * +char * octave_home (void) { static char *home = (char *) NULL; @@ -399,7 +399,7 @@ return home; } -static char * +char * octave_lib_dir (void) { static char *ol = (char *) NULL; @@ -410,7 +410,7 @@ return ol; } -static char * +char * octave_info_dir (void) { static char *oi = (char *) NULL; @@ -453,6 +453,19 @@ } char * +default_editor (void) +{ + static char *editor_string = (char *) NULL; + delete [] editor_string; + char *env_editor = getenv ("EDITOR"); + if (env_editor == (char *) NULL || *env_editor == '\0') + editor_string = strsave ("vi"); + else + editor_string = strsave (env_editor); + return editor_string; +} + +char * get_site_defaults (void) { static char *sd = (char *) NULL; diff -r 4f3364dcf450 -r 13c6086c325c src/utils.h --- a/src/utils.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/utils.h Sat Nov 06 10:14:11 1993 +0000 @@ -48,8 +48,12 @@ extern void raw_mode (int); extern int kbhit (void); extern char **pathstring_to_vector (char *); +extern char *octave_home (void); +extern char *octave_lib_dir (void); +extern char *octave_info_dir (void); extern char *default_path (void); extern char *default_info_file (void); +extern char *default_editor (void); extern char *get_site_defaults (void); extern char *default_pager (void); extern char *file_in_path (const char *, const char *); diff -r 4f3364dcf450 -r 13c6086c325c src/variables.cc --- a/src/variables.cc Wed Nov 03 21:38:05 1993 +0000 +++ b/src/variables.cc Sat Nov 06 10:14:11 1993 +0000 @@ -35,7 +35,11 @@ #include "statdefs.h" #include "tree-const.h" #include "variables.h" +#include "user-prefs.h" #include "symtab.h" +#include "builtins.h" +#include "g-builtins.h" +#include "t-builtins.h" #include "error.h" #include "utils.h" #include "tree.h" @@ -50,6 +54,16 @@ // Symbol table for global symbols. symbol_table *global_sym_tab; +void +initialize_symbol_tables (void) +{ + global_sym_tab = new symbol_table (); + + top_level_sym_tab = new symbol_table (); + + curr_sym_tab = top_level_sym_tab; +} + /* * Is there a corresponding M-file that is newer than the symbol * definition? @@ -57,141 +71,218 @@ int symbol_out_of_date (symbol_record *sr) { - int status = 0; + int ignore = user_pref.ignore_function_time_stamp; + + if (ignore == 2) + return 0; + if (sr != (symbol_record *) NULL) { tree *ans = sr->def (); if (ans != NULL_TREE) { char *mf = ans->m_file_name (); - if (mf != (char *) NULL) + if (! (mf == (char *) NULL + || (ignore && ans->is_system_m_file ()))) { time_t tp = ans->time_parsed (); - status = is_newer (mf, tp); + char *fname = m_file_in_path (mf); + int status = is_newer (fname, tp); + delete [] fname; + if (status > 0) + return 1; } } } - return status; + return 0; } -/* - * Force a symbol into the global symbol table. - */ -symbol_record * -force_global (char *name) +void +document_symbol (const char *name, const char *help) { - symbol_record *retval = (symbol_record *) NULL; - - if (valid_identifier (name)) + if (is_builtin_variable (name)) { - symbol_record *sr; - sr = curr_sym_tab->lookup (name, 0, 0); - if (sr == (symbol_record *) NULL) + error ("sorry, can't redefine help for builtin variables"); + } + else + { + symbol_record *sym_rec = curr_sym_tab->lookup (name, 0); + if (sym_rec == (symbol_record *) NULL) { - retval = global_sym_tab->lookup (name, 1, 0); - retval->mark_as_forced_global (); - } - else if (sr->is_formal_parameter ()) - { - error ("formal parameter `%s' can't be made global", name); + error ("document: no such symbol `%s'", name); } else { - retval = global_sym_tab->lookup (name, 1, 0); - retval->mark_as_forced_global (); - retval->alias (sr, 1); - curr_sym_tab->clear (name); - } - } - else - warning ("`%s' is invalid as an identifier", name); - - return retval; -} - -int -bind_variable (char *varname, tree_constant *val) -{ -// Look for the symbol in the current symbol table. If it's there, -// great. If not, don't insert it, but look for it in the global -// symbol table. If it's there, great. If not, insert it in the -// original current symbol table. - - symbol_record *sr; - sr = curr_sym_tab->lookup (varname, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = global_sym_tab->lookup (varname, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = curr_sym_tab->lookup (varname, 1); + sym_rec->document (help); } } +} - if (sr != (symbol_record *) NULL) - { - sr->define (val); - return 0; - } - else - return 1; +void +install_builtin_mapper_function (builtin_mapper_functions *mf) +{ + symbol_record *sym_rec = global_sym_tab->lookup (mf->name, 1); + sym_rec->unprotect (); + + Mapper_fcn mfcn; + mfcn.neg_arg_complex = mf->neg_arg_complex; + mfcn.d_d_mapper = mf->d_d_mapper; + mfcn.d_c_mapper = mf->d_c_mapper; + mfcn.c_c_mapper = mf->c_c_mapper; + + tree_builtin *def = new tree_builtin (mf->nargin_max, + mf->nargout_max, mfcn, + mf->name); + + sym_rec->define (def); + + sym_rec->document (mf->help_string); + sym_rec->make_eternal (); + sym_rec->protect (); +} + +void +install_builtin_text_function (builtin_text_functions *tf) +{ + symbol_record *sym_rec = global_sym_tab->lookup (tf->name, 1); + sym_rec->unprotect (); + + tree_builtin *def = new tree_builtin (tf->nargin_max, 1, + tf->text_fcn, tf->name); + + sym_rec->define (def); + + sym_rec->document (tf->help_string); + sym_rec->make_eternal (); + sym_rec->protect (); + } -int -bind_protected_variable (char *varname, tree_constant *val) +void +install_builtin_general_function (builtin_general_functions *gf) +{ + symbol_record *sym_rec = global_sym_tab->lookup (gf->name, 1); + sym_rec->unprotect (); + + tree_builtin *def = new tree_builtin (gf->nargin_max, + gf->nargout_max, + gf->general_fcn, gf->name); + + sym_rec->define (def); + + sym_rec->document (gf->help_string); + sym_rec->make_eternal (); + sym_rec->protect (); +} + +void +install_builtin_variable (builtin_string_variables *sv) { -// Look for the symbol in the current symbol table. If it's there, -// great. If not, don't insert it, but look for it in the global -// symbol table. If it's there, great. If not, insert it in the -// original current symbol table. + tree_constant *val = new tree_constant (sv->value); + + bind_builtin_variable (sv->name, val, 0, 1, sv->sv_function, + sv->help_string); +} + +void +install_builtin_variable_as_function (const char *name, tree_constant *val, + int protect = 0, int eternal = 0) +{ + symbol_record *sym_rec = global_sym_tab->lookup (name, 1); + sym_rec->unprotect (); + + char *tmp_help = sym_rec->help (); + sym_rec->define_as_fcn (val); + + sym_rec->document (tmp_help); + + if (protect) + sym_rec->protect (); + + if (eternal) + sym_rec->make_eternal (); +} + +void +bind_nargin_and_nargout (symbol_table *sym_tab, int nargin, int nargout) +{ + tree_constant *tmp; symbol_record *sr; - sr = curr_sym_tab->lookup (varname, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = global_sym_tab->lookup (varname, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = curr_sym_tab->lookup (varname, 1); - } - } - if (sr != (symbol_record *) NULL) - { - sr->unprotect (); - sr->define (val); - sr->protect (); - return 0; - } - else - return 1; + sr = sym_tab->lookup ("nargin", 1, 0); + sr->unprotect (); + tmp = new tree_constant (nargin-1); + sr->define (tmp); + sr->protect (); + + sr = sym_tab->lookup ("nargout", 1, 0); + sr->unprotect (); + tmp = new tree_constant (nargout); + sr->define (tmp); + sr->protect (); } /* - * Look for name first in current then in global symbol tables. If - * name is found and it refers to a string, return a new string - * containing its value. Otherwise, return NULL. + * Give a global variable a definition. This will insert the symbol + * in the global table if necessary. + */ +void +bind_builtin_variable (const char *varname, tree_constant *val, + int protect = 0, int eternal = 0, + sv_Function sv_fcn = (sv_Function) 0, + const char *help = (char *) 0) +{ + symbol_record *sr = global_sym_tab->lookup (varname, 1, 0); + +// It is a programming error for a builtin symbol to be missing. +// Besides, we just inserted it, so it must be there. + + assert (sr != (symbol_record *) NULL); + + sr->unprotect (); + +// Must do this before define, since define will call the special +// variable function only if it knows about it, and it needs to, so +// that user prefs can be properly initialized. + + if (sv_fcn) + sr->set_sv_function (sv_fcn); + + sr->define_builtin_var (val); + + if (protect) + sr->protect (); + + if (eternal) + sr->make_eternal (); + + if (help) + sr->document (help); +} + +/* + * Look for the given name in the global symbol table. If it refers + * to a string, return a new copy. If not, return NULL. */ char * -octave_string_variable (char *name) +builtin_string_variable (const char *name) { + symbol_record *sr = global_sym_tab->lookup (name, 0, 0); + +// It is a prorgramming error to look for builtins that aren't. + + assert (sr != (symbol_record *) NULL); + char *retval = (char *) NULL; - symbol_record *sr; - sr = curr_sym_tab->lookup (name, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = global_sym_tab->lookup (name, 0, 0); - if (sr == (symbol_record *) NULL) - return retval; - } tree *defn = sr->def (); + if (defn != NULL_TREE) { tree_constant val = defn->eval (0); - if (error_state) - return retval; - else if (val.is_string_type ()) + + if (! error_state && val.is_string_type ()) { char *s = val.string_value (); if (s != (char *) NULL) @@ -203,30 +294,28 @@ } /* - * Look for name first in current then in global symbol tables. If - * name is found and it refers to a real scalar, place the value in d - * and return 0. Otherwise, return -1. + * Look for the given name in the global symbol table. If it refers + * to a real scalar, place the value in d and return 0. Otherwise, + * return -1. */ int -octave_real_scalar_variable (char *name, double& d) +builtin_real_scalar_variable (const char *name, double& d) { int status = -1; - symbol_record *sr; - sr = curr_sym_tab->lookup (name, 0, 0); - if (sr == (symbol_record *) NULL) - { - sr = global_sym_tab->lookup (name, 0, 0); - if (sr == (symbol_record *) NULL) - return status; - } + symbol_record *sr = global_sym_tab->lookup (name, 0, 0); + +// It is a prorgramming error to look for builtins that aren't. + + assert (sr != (symbol_record *) NULL); tree *defn = sr->def (); + if (defn != NULL_TREE) { tree_constant val = defn->eval (0); - if (error_state) - return status; - else if (val.const_type () == tree_constant_rep::scalar_constant) + + if (! error_state + && val.const_type () == tree_constant_rep::scalar_constant) { d = val.double_value (); status = 0; @@ -237,6 +326,120 @@ } /* + * Make the definition of the symbol record sr be the same as the + * definition of the global variable of the same name, creating it if + * it doesn't already exist. + */ +void +link_to_global_variable (symbol_record *sr) +{ + if (sr->is_linked_to_global ()) + return; + + symbol_record *gsr = global_sym_tab->lookup (sr->name (), 1, 0); + + if (sr->is_formal_parameter ()) + { + error ("can't make function parameter `%s' global", sr->name ()); + return; + } + +// There must be a better way to do this. XXX FIXME XXX + + if (sr->is_variable ()) + { +// Would be nice not to have this cast. XXX FIXME XXX + tree_constant *tmp = (tree_constant *) sr->def (); + tmp = new tree_constant (*tmp); + gsr->define (tmp); + } + else + { + sr->clear (); + } + +// If the global symbol is currently defined as a function, we need to +// hide it with a variable. + + if (gsr->is_function ()) + gsr->define (NULL_TREE_CONST); + + sr->alias (gsr, 1); + sr->mark_as_linked_to_global (); +} + +/* + * Make the definition of the symbol record sr be the same as the + * definition of the builtin variable of the same name. + */ +void +link_to_builtin_variable (symbol_record *sr) +{ + symbol_record *tmp_sym = global_sym_tab->lookup (sr->name (), 0, 0); + + if (tmp_sym != (symbol_record *) NULL) + { + if (tmp_sym->is_builtin_variable ()) + { + sr->alias (tmp_sym); + } + } +} + +/* + * Make the definition of the symbol record sr be the same as the + * definition of the builtin variable or function, or user function of + * the same name, provided that the name has not been used as a formal + * parameter. + */ +void +link_to_builtin_or_function (symbol_record *sr) +{ + symbol_record *tmp_sym = global_sym_tab->lookup (sr->name (), 0, 0); + + if (tmp_sym != (symbol_record *) NULL) + { + if ((tmp_sym->is_builtin_variable () || tmp_sym->is_function ()) + && ! tmp_sym->is_formal_parameter ()) + { + sr->alias (tmp_sym); + } + } +} + +/* + * Force a link to a function in the current symbol table. This is + * used just after defining a function to avoid different behavior + * depending on whether or not the function has been evaluated after + * being defined. + * + * Return without doing anything if there isn't a function with the + * given name defined in the global symbol table. + */ +void +force_link_to_function (const char *id_name) +{ + symbol_record *gsr = global_sym_tab->lookup (id_name, 1, 0); + if (gsr->is_function ()) + { + curr_sym_tab->clear (id_name); + symbol_record *csr = curr_sym_tab->lookup (id_name, 1, 0); + csr->alias (gsr); + } +} + +/* + * Return 1 if the argument names a globally visible variable. + * Otherwise, return 0. + */ +int +is_globally_visible (const char *name) +{ + symbol_record *sr = curr_sym_tab->lookup (name, 0, 0); + return (sr != (symbol_record *) NULL && sr->is_linked_to_global ()); +} + +/* * Extract a keyword and its value from a file. Input should look * something like: * @@ -396,12 +599,21 @@ if (stat (name, &buf) == 0 && S_ISREG (buf.st_mode)) return 2; } - } return 0; } /* + * Is this variable a builtin? + */ +int +is_builtin_variable (const char *name) +{ + symbol_record *sr = global_sym_tab->lookup (name, 0, 0); + return (sr != (symbol_record *) NULL && sr->is_builtin_variable ()); +} + +/* * Is this tree_constant a valid function? */ tree * @@ -462,6 +674,8 @@ return 1; } +// It's not likely that this does the right thing now. XXX FIXME XXX + char ** make_name_list (void) { diff -r 4f3364dcf450 -r 13c6086c325c src/variables.h --- a/src/variables.h Wed Nov 03 21:38:05 1993 +0000 +++ b/src/variables.h Sat Nov 06 10:14:11 1993 +0000 @@ -34,17 +34,63 @@ class tree; class tree_constant; +struct builtin_mapper_functions; +struct builtin_text_functions; +struct builtin_general_functions; +struct builtin_string_variables; + +#ifndef SV_FUNCTION_TYPEDEFS +#define SV_FUNCTION_TYPEDEFS 1 + +typedef int (*sv_Function)(void); + +#endif + +extern void initialize_symbol_tables (void); + extern int symbol_out_of_date (symbol_record *sr); -extern symbol_record *force_global (char *name); -extern int bind_variable (char *, tree_constant *); -extern int bind_protected_variable (char *, tree_constant *); -extern char *octave_string_variable (char *); -extern int octave_real_scalar_variable (char *, double&); + +extern void document_symbol (const char *name, const char *help); + +extern void install_builtin_mapper_function (builtin_mapper_functions *mf); + +extern void install_builtin_text_function (builtin_text_functions *tf); + +extern void install_builtin_general_function (builtin_general_functions *gf); + +extern void install_builtin_variable (builtin_string_variables *sv); + +extern void install_builtin_variable_as_function (const char *name, + tree_constant *val, + int protect = 0, + int eternal = 0); + +extern void bind_nargin_and_nargout (symbol_table *sym_tab, + int nargin, int nargout); + +extern void bind_builtin_variable (const char *, tree_constant *, + int protect = 0, int eternal = 0, + sv_Function f = (sv_Function) 0, + const char *help = (char *) 0); + +extern char *builtin_string_variable (const char *); +extern int builtin_real_scalar_variable (const char *, double&); + +extern void link_to_global_variable (symbol_record *sr); +extern void link_to_builtin_variable (symbol_record *sr); +extern void link_to_builtin_or_function (symbol_record *sr); + +extern void force_link_to_function (const char *s); + +extern int is_globally_visible (const char *nm); + extern int extract_keyword (istream&, char *, char *); extern int extract_keyword (istream&, char *, int&); + extern void skip_comments (istream&); extern int valid_identifier (char *); extern int identifier_exists (char *); +extern int is_builtin_variable (const char *name); extern tree *is_valid_function (tree_constant&, char *, int warn = 0); extern int takes_correct_nargs (tree *, int, char *, int warn = 0); extern char **make_name_list (void);