comparison src/parse.y @ 7715:5b4d278ec828

parse scripts completely before executing
author John W. Eaton <jwe@octave.org>
date Wed, 16 Apr 2008 15:09:56 -0400
parents 27a5f578750c
children 87eda1f8faaa
comparison
equal deleted inserted replaced
7714:83ea845cda36 7715:5b4d278ec828
257 // Build an assignment to a variable. 257 // Build an assignment to a variable.
258 static tree_expression * 258 static tree_expression *
259 make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, 259 make_assign_op (int op, tree_argument_list *lhs, token *eq_tok,
260 tree_expression *rhs); 260 tree_expression *rhs);
261 261
262 // Define a script.
263 static void
264 make_script (tree_statement_list *cmds);
265
262 // Begin defining a function. 266 // Begin defining a function.
263 static octave_user_function * 267 static octave_user_function *
264 start_function (tree_parameter_list *param_list, tree_statement_list *body); 268 start_function (tree_parameter_list *param_list, tree_statement_list *body);
265 269
266 // Do most of the work for defining a function. 270 // Do most of the work for defining a function.
267 static octave_user_function * 271 static octave_user_function *
268 frob_function (const std::string& fname, octave_user_function *fcn); 272 frob_function (const std::string& fname, octave_user_function *fcn);
269 273
270 // Finish defining a function. 274 // Finish defining a function.
271 static void 275 static tree_function_def *
272 finish_function (tree_parameter_list *ret_list, 276 finish_function (tree_parameter_list *ret_list,
273 octave_user_function *fcn, octave_comment_list *lc); 277 octave_user_function *fcn, octave_comment_list *lc);
274 278
275 // Reset state after parsing function. 279 // Reset state after parsing function.
276 static void 280 static void
397 %token <tok_val> GLOBAL STATIC 401 %token <tok_val> GLOBAL STATIC
398 %token <tok_val> FCN_HANDLE 402 %token <tok_val> FCN_HANDLE
399 403
400 // Other tokens. 404 // Other tokens.
401 %token END_OF_INPUT LEXICAL_ERROR 405 %token END_OF_INPUT LEXICAL_ERROR
402 %token FCN 406 %token FCN SCRIPT
403 // %token VARARGIN VARARGOUT 407 // %token VARARGIN VARARGOUT
404 %token CLOSE_BRACE 408 %token CLOSE_BRACE
405 409
406 // Nonterminals we construct. 410 // Nonterminals we construct.
407 %type <comment_type> stash_comment function_beg 411 %type <comment_type> stash_comment function_beg
422 %type <tree_argument_list_type> arg_list word_list assign_lhs 426 %type <tree_argument_list_type> arg_list word_list assign_lhs
423 %type <tree_argument_list_type> cell_or_matrix_row 427 %type <tree_argument_list_type> cell_or_matrix_row
424 %type <tree_parameter_list_type> param_list param_list1 param_list2 428 %type <tree_parameter_list_type> param_list param_list1 param_list2
425 %type <tree_parameter_list_type> return_list return_list1 429 %type <tree_parameter_list_type> return_list return_list1
426 %type <tree_command_type> command select_command loop_command 430 %type <tree_command_type> command select_command loop_command
427 %type <tree_command_type> jump_command except_command function 431 %type <tree_command_type> jump_command except_command function script
428 %type <tree_if_command_type> if_command 432 %type <tree_if_command_type> if_command
429 %type <tree_if_clause_type> elseif_clause else_clause 433 %type <tree_if_clause_type> elseif_clause else_clause
430 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list 434 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
431 %type <tree_switch_command_type> switch_command 435 %type <tree_switch_command_type> switch_command
432 %type <tree_switch_case_type> switch_case default_case 436 %type <tree_switch_case_type> switch_case default_case
519 $$ = $1; 523 $$ = $1;
520 } 524 }
521 ; 525 ;
522 526
523 list1 : statement 527 list1 : statement
524 { 528 { $$ = new tree_statement_list ($1); }
525 lexer_flags.beginning_of_function = false;
526 $$ = new tree_statement_list ($1);
527 }
528 | list1 sep statement 529 | list1 sep statement
529 { 530 {
530 set_stmt_print_flag ($1, $2, true); 531 set_stmt_print_flag ($1, $2, true);
531 $1->append ($3); 532 $1->append ($3);
532 $$ = $1; 533 $$ = $1;
906 { $$ = $1; } 907 { $$ = $1; }
907 | except_command 908 | except_command
908 { $$ = $1; } 909 { $$ = $1; }
909 | function 910 | function
910 { $$ = $1; } 911 { $$ = $1; }
912 | script
913 { $$ = $1; }
911 ; 914 ;
912 915
913 // ===================== 916 // =====================
914 // Declaration statemnts 917 // Declaration statemnts
915 // ===================== 918 // =====================
1204 $1->append (new tree_decl_elt ($3)); 1207 $1->append (new tree_decl_elt ($3));
1205 $$ = $1; 1208 $$ = $1;
1206 } 1209 }
1207 ; 1210 ;
1208 1211
1212 // ===========
1213 // Script file
1214 // ===========
1215
1216 script : SCRIPT opt_list END_OF_INPUT
1217 {
1218 make_script ($2);
1219 $$ = 0;
1220 }
1221 ;
1222
1209 // =================== 1223 // ===================
1210 // Function definition 1224 // Function definition
1211 // =================== 1225 // ===================
1212 1226
1213 function_beg : push_fcn_symtab FCN stash_comment 1227 function_beg : push_fcn_symtab FCN stash_comment
1214 { $$ = $3; } 1228 { $$ = $3; }
1215 ; 1229 ;
1216 1230
1217 function : function_beg function1 1231 function : function_beg function1
1218 { 1232 {
1219 $2->stash_leading_comment ($1); 1233 $$ = finish_function (0, $2, $1);
1220 recover_from_parsing_function (); 1234 recover_from_parsing_function ();
1221 $$ = 0;
1222 } 1235 }
1223 | function_beg return_list '=' function1 1236 | function_beg return_list '=' function1
1224 { 1237 {
1225 finish_function ($2, $4, $1); 1238 $$ = finish_function ($2, $4, $1);
1226 recover_from_parsing_function (); 1239 recover_from_parsing_function ();
1227 $$ = 0;
1228 } 1240 }
1229 ; 1241 ;
1230 1242
1231 fcn_name : identifier 1243 fcn_name : identifier
1232 { 1244 {
2384 return new tree_multi_assignment (lhs, rhs, false, l, c, t); 2396 return new tree_multi_assignment (lhs, rhs, false, l, c, t);
2385 2397
2386 return retval; 2398 return retval;
2387 } 2399 }
2388 2400
2401 // Define a function.
2402
2403 static void
2404 make_script (tree_statement_list *cmds)
2405 {
2406 std::string doc_string;
2407
2408 if (! help_buf.empty ())
2409 {
2410 doc_string = help_buf.top ();
2411 help_buf.pop ();
2412 }
2413
2414 octave_user_script *script
2415 = new octave_user_script (curr_fcn_file_full_name, curr_fcn_file_name,
2416 cmds, doc_string);
2417
2418 octave_time now;
2419
2420 script->stash_fcn_file_time (now);
2421
2422 curr_fcn_ptr = script;
2423 }
2424
2389 // Begin defining a function. 2425 // Begin defining a function.
2390 2426
2391 static octave_user_function * 2427 static octave_user_function *
2392 start_function (tree_parameter_list *param_list, tree_statement_list *body) 2428 start_function (tree_parameter_list *param_list, tree_statement_list *body)
2393 { 2429 {
2509 { 2545 {
2510 lexer_flags.parsing_nested_function = 0; 2546 lexer_flags.parsing_nested_function = 0;
2511 symbol_table::reset_parent_scope (); 2547 symbol_table::reset_parent_scope ();
2512 } 2548 }
2513 } 2549 }
2514 else if (! reading_fcn_file) 2550 else if (reading_fcn_file)
2515 { 2551 curr_fcn_ptr = fcn;
2516 std::string nm = fcn->name ();
2517
2518 symbol_table::install_cmdline_function (nm, octave_value (fcn));
2519
2520 // Make sure that any variable with the same name as the new
2521 // function is cleared.
2522
2523 symbol_table::varref (nm) = octave_value ();
2524 }
2525 else 2552 else
2526 curr_fcn_ptr = fcn; 2553 curr_fcn_ptr = 0;
2527 2554
2528 return fcn; 2555 return fcn;
2529 } 2556 }
2530 2557
2531 // Finish defining a function. 2558 static tree_function_def *
2532
2533 static void
2534 finish_function (tree_parameter_list *ret_list, 2559 finish_function (tree_parameter_list *ret_list,
2535 octave_user_function *fcn, octave_comment_list *lc) 2560 octave_user_function *fcn, octave_comment_list *lc)
2536 { 2561 {
2537 ret_list->mark_as_formal_parameters (); 2562 tree_function_def *retval = 0;
2538 2563
2539 fcn->stash_leading_comment (lc); 2564 if (ret_list)
2540 2565 ret_list->mark_as_formal_parameters ();
2541 fcn->define_ret_list (ret_list); 2566
2567 if (fcn)
2568 {
2569 if (lc)
2570 fcn->stash_leading_comment (lc);
2571
2572 fcn->define_ret_list (ret_list);
2573 }
2574
2575 if (! curr_fcn_ptr)
2576 retval = new tree_function_def (fcn);
2577
2578 return retval;
2542 } 2579 }
2543 2580
2544 static void 2581 static void
2545 recover_from_parsing_function (void) 2582 recover_from_parsing_function (void)
2546 { 2583 {
2549 2586
2550 symbol_table::set_scope (symtab_context.top ()); 2587 symbol_table::set_scope (symtab_context.top ());
2551 symtab_context.pop (); 2588 symtab_context.pop ();
2552 2589
2553 lexer_flags.defining_func = false; 2590 lexer_flags.defining_func = false;
2554 lexer_flags.beginning_of_function = false;
2555 lexer_flags.parsed_function_name = false; 2591 lexer_flags.parsed_function_name = false;
2556 lexer_flags.looking_at_return_list = false; 2592 lexer_flags.looking_at_return_list = false;
2557 lexer_flags.looking_at_parameter_list = false; 2593 lexer_flags.looking_at_parameter_list = false;
2558 } 2594 }
2559 2595
2765 warning ("unrecognized separator type!"); 2801 warning ("unrecognized separator type!");
2766 break; 2802 break;
2767 } 2803 }
2768 } 2804 }
2769 2805
2770 void
2771 parse_and_execute (FILE *f)
2772 {
2773 unwind_protect::begin_frame ("parse_and_execute");
2774
2775 unwind_protect_ptr (global_command);
2776
2777 YY_BUFFER_STATE old_buf = current_buffer ();
2778 YY_BUFFER_STATE new_buf = create_buffer (f);
2779
2780 unwind_protect::add (restore_input_buffer, old_buf);
2781 unwind_protect::add (delete_input_buffer, new_buf);
2782
2783 switch_to_buffer (new_buf);
2784
2785 unwind_protect_bool (line_editing);
2786 unwind_protect_bool (get_input_from_eval_string);
2787 unwind_protect_bool (parser_end_of_input);
2788
2789 line_editing = false;
2790 get_input_from_eval_string = false;
2791 parser_end_of_input = false;
2792
2793 int retval;
2794 do
2795 {
2796 reset_parser ();
2797
2798 retval = yyparse ();
2799
2800 if (retval == 0)
2801 {
2802 if (global_command)
2803 {
2804 global_command->eval ();
2805
2806 delete global_command;
2807
2808 global_command = 0;
2809
2810 OCTAVE_QUIT;
2811
2812 bool quit = (tree_return_command::returning
2813 || tree_break_command::breaking);
2814
2815 if (tree_return_command::returning)
2816 tree_return_command::returning = 0;
2817
2818 if (tree_break_command::breaking)
2819 tree_break_command::breaking--;
2820
2821 if (error_state)
2822 {
2823 error ("near line %d of file `%s'", input_line_number,
2824 curr_fcn_file_full_name.c_str ());
2825
2826 break;
2827 }
2828
2829 if (quit)
2830 break;
2831 }
2832 else if (parser_end_of_input)
2833 break;
2834 }
2835 }
2836 while (retval == 0);
2837
2838 unwind_protect::run_frame ("parse_and_execute");
2839 }
2840
2841 static void 2806 static void
2842 safe_fclose (void *f) 2807 safe_fclose (void *f)
2843 { 2808 {
2844 // FIXME -- comments at the end of an input file are 2809 // FIXME -- comments at the end of an input file are
2845 // discarded (otherwise, they would be appended to the next 2810 // discarded (otherwise, they would be appended to the next
2850 2815
2851 delete tc; 2816 delete tc;
2852 2817
2853 if (f) 2818 if (f)
2854 fclose (static_cast<FILE *> (f)); 2819 fclose (static_cast<FILE *> (f));
2855 }
2856
2857 void
2858 parse_and_execute (const std::string& s, bool verbose, const char *warn_for)
2859 {
2860 unwind_protect::begin_frame ("parse_and_execute_2");
2861
2862 unwind_protect_bool (reading_script_file);
2863 unwind_protect_str (curr_fcn_file_full_name);
2864
2865 reading_script_file = true;
2866 curr_fcn_file_full_name = s;
2867
2868 FILE *f = get_input_from_file (s, 0);
2869
2870 if (f)
2871 {
2872 unwind_protect::add (safe_fclose, f);
2873
2874 octave_user_script *script = new octave_user_script (s, s, "");
2875 octave_call_stack::push (script);
2876 unwind_protect::add (octave_call_stack::unwind_pop_script, 0);
2877
2878 unwind_protect_int (input_line_number);
2879 unwind_protect_int (current_input_column);
2880
2881 input_line_number = 0;
2882 current_input_column = 1;
2883
2884 if (verbose)
2885 {
2886 std::cout << "reading commands from " << s << " ... ";
2887 reading_startup_message_printed = true;
2888 std::cout.flush ();
2889 }
2890
2891 parse_and_execute (f);
2892
2893 if (verbose)
2894 std::cout << "done." << std::endl;
2895 }
2896 else if (warn_for)
2897 error ("%s: unable to open file `%s'", warn_for, s.c_str ());
2898
2899 unwind_protect::run_frame ("parse_and_execute_2");
2900 } 2820 }
2901 2821
2902 static bool 2822 static bool
2903 looks_like_copyright (const std::string& s) 2823 looks_like_copyright (const std::string& s)
2904 { 2824 {
2928 2848
2929 return c; 2849 return c;
2930 } 2850 }
2931 2851
2932 // Eat whitespace and comments from FFILE, returning the text of the 2852 // Eat whitespace and comments from FFILE, returning the text of the
2933 // comments read if it doesn't look like a copyright notice. If 2853 // comments read if it doesn't look like a copyright notice. The
2934 // IN_PARTS, consider each block of comments separately; otherwise, 2854 // parser line and column number information is updated. Processing
2935 // grab them all at once. If UPDATE_POS is TRUE, line and column 2855 // stops at the first non-whitespace character that is not part of a
2936 // number information is updated. If SAVE_COPYRIGHT is TRUE, then
2937 // comments that are recognized as a copyright notice are saved in the
2938 // comment buffer. If SKIP_CODE is TRUE, then ignore code, otherwise
2939 // stop at the first non-whitespace character that is not part of a
2940 // comment. 2856 // comment.
2941 2857
2942 // FIXME -- skipping code will fail for something like this:
2943 //
2944 // function foo (x)
2945 // fprintf ('%d\n', x);
2946 //
2947 // % This is the help for foo.
2948 //
2949 // because we recognize the '%' in the fprintf format as a comment
2950 // character. Fixing this will probably require actually parsing the
2951 // file properly.
2952
2953 // FIXME -- grab_help_text() in lex.l duplicates some of this
2954 // code!
2955
2956 static std::string 2858 static std::string
2957 gobble_leading_white_space (FILE *ffile, bool in_parts, 2859 gobble_leading_white_space (FILE *ffile)
2958 bool update_pos, bool save_copyright,
2959 bool skip_code)
2960 { 2860 {
2961 std::string help_txt; 2861 std::string help_txt;
2962 2862
2963 // TRUE means we have already seen the first block of comments. 2863 // TRUE means we have already seen the first block of comments.
2964 bool first_comments_seen = false; 2864 bool first_comments_seen = false;
2978 2878
2979 int c; 2879 int c;
2980 2880
2981 while ((c = text_getc (ffile)) != EOF) 2881 while ((c = text_getc (ffile)) != EOF)
2982 { 2882 {
2983 if (update_pos) 2883 current_input_column++;
2984 current_input_column++;
2985 2884
2986 if (begin_comment) 2885 if (begin_comment)
2987 { 2886 {
2988 if (c == '%' || c == '#') 2887 if (c == '%' || c == '#')
2989 continue; 2888 continue;
3004 help_txt += static_cast<char> (c); 2903 help_txt += static_cast<char> (c);
3005 } 2904 }
3006 2905
3007 if (c == '\n') 2906 if (c == '\n')
3008 { 2907 {
3009 if (update_pos) 2908 input_line_number++;
3010 { 2909 current_input_column = 0;
3011 input_line_number++;
3012 current_input_column = 0;
3013 }
3014 2910
3015 in_comment = false; 2911 in_comment = false;
3016 discard_space = true; 2912 discard_space = true;
3017
3018 if (in_parts)
3019 {
3020 if ((c = text_getc (ffile)) != EOF)
3021 {
3022 if (update_pos)
3023 current_input_column--;
3024 ungetc (c, ffile);
3025 if (c == '\n')
3026 break;
3027 }
3028 else
3029 break;
3030 }
3031 } 2913 }
3032 } 2914 }
3033 else 2915 else
3034 { 2916 {
3035 switch (c) 2917 switch (c)
3036 { 2918 {
2919 case '\n':
2920 input_line_number++;
2921 current_input_column = 0;
2922 // fall through...
2923
3037 case ' ': 2924 case ' ':
3038 case '\t': 2925 case '\t':
3039 if (first_comments_seen) 2926 if (first_comments_seen && ! have_help_text)
3040 have_help_text = true; 2927 {
2928 if (looks_like_copyright (help_txt))
2929 help_txt.resize (0);
2930
2931 if (! help_txt.empty ())
2932 have_help_text = true;
2933 }
3041 break; 2934 break;
3042 2935
3043 case '%': 2936 case '%':
3044 case '#': 2937 case '#':
3045 begin_comment = true; 2938 begin_comment = true;
3046 in_comment = true; 2939 in_comment = true;
3047 break; 2940 break;
3048 2941
3049 case '\n':
3050 if (first_comments_seen)
3051 have_help_text = true;
3052 if (update_pos)
3053 {
3054 input_line_number++;
3055 current_input_column = 0;
3056 }
3057 continue;
3058
3059 default: 2942 default:
3060 if (skip_code) 2943 current_input_column--;
3061 continue; 2944 ungetc (c, ffile);
3062 else 2945 goto done;
3063 {
3064 if (update_pos)
3065 current_input_column--;
3066 ungetc (c, ffile);
3067 goto done;
3068 }
3069 } 2946 }
3070 } 2947 }
3071 } 2948 }
3072 2949
3073 done: 2950 done:
3074 2951
3075 if (! help_txt.empty ())
3076 {
3077 if (looks_like_copyright (help_txt))
3078 {
3079 if (save_copyright)
3080 octave_comment_buffer::append (help_txt);
3081
3082 help_txt.resize (0);
3083 }
3084
3085 if (in_parts && help_txt.empty ())
3086 help_txt = gobble_leading_white_space (ffile, in_parts, update_pos,
3087 false, skip_code);
3088 }
3089
3090 return help_txt; 2952 return help_txt;
3091 } 2953 }
3092 2954
3093 std::string 2955 static void
3094 get_help_from_file (const std::string& nm, bool& symbol_found, 2956 process_leading_comments (FILE *fptr)
3095 std::string& file) 2957 {
3096 { 2958 std::string txt = gobble_leading_white_space (fptr);
3097 std::string retval; 2959
3098 2960 help_buf.push (txt);
3099 file = fcn_file_in_path (nm); 2961
3100 2962 octave_comment_buffer::append (txt);
3101 if (! file.empty ()) 2963 }
3102 { 2964
3103 symbol_found = true; 2965 static bool
3104 2966 looking_at_function_keyword (FILE *ffile)
3105 FILE *fptr = fopen (file.c_str (), "r"); 2967 {
3106 2968 bool status = false;
3107 if (fptr)
3108 {
3109 unwind_protect::add (safe_fclose, fptr);
3110
3111 retval = gobble_leading_white_space (fptr, true, true, false, true);
3112
3113 unwind_protect::run ();
3114 }
3115 }
3116
3117 return retval;
3118 }
3119
3120 std::string
3121 get_help_from_file (const std::string& nm, bool& symbol_found)
3122 {
3123 std::string file;
3124 return get_help_from_file (nm, symbol_found, file);
3125 }
3126
3127 static int
3128 is_function_file (FILE *ffile)
3129 {
3130 int status = 0;
3131 2969
3132 long pos = ftell (ffile); 2970 long pos = ftell (ffile);
3133
3134 gobble_leading_white_space (ffile, false, false, false, false);
3135 2971
3136 char buf [10]; 2972 char buf [10];
3137 fgets (buf, 10, ffile); 2973 fgets (buf, 10, ffile);
3138 int len = strlen (buf); 2974 size_t len = strlen (buf);
3139 if (len > 8 && strncmp (buf, "function", 8) == 0 2975 if (len > 8 && strncmp (buf, "function", 8) == 0
3140 && ! (isalnum (buf[8]) || buf[8] == '_')) 2976 && ! (isalnum (buf[8]) || buf[8] == '_'))
3141 status = 1; 2977 status = true;
3142 2978
3143 fseek (ffile, pos, SEEK_SET); 2979 fseek (ffile, pos, SEEK_SET);
3144 2980
3145 return status; 2981 return status;
3146 }
3147
3148 static int
3149 is_function_file (const std::string& fname)
3150 {
3151 int retval = 0;
3152
3153 FILE *fid = fopen (fname.c_str (), "r");
3154
3155 if (fid)
3156 {
3157 retval = is_function_file (fid);
3158
3159 fclose (fid);
3160 }
3161
3162 return retval;
3163 } 2982 }
3164 2983
3165 static void 2984 static void
3166 restore_command_history (void *) 2985 restore_command_history (void *)
3167 { 2986 {
3172 restore_input_stream (void *f) 2991 restore_input_stream (void *f)
3173 { 2992 {
3174 command_editor::set_input_stream (static_cast<FILE *> (f)); 2993 command_editor::set_input_stream (static_cast<FILE *> (f));
3175 } 2994 }
3176 2995
3177 typedef octave_function * octave_function_ptr;
3178
3179 static octave_function * 2996 static octave_function *
3180 parse_fcn_file (const std::string& ff, const std::string& dispatch_type, 2997 parse_fcn_file (const std::string& ff, const std::string& dispatch_type,
3181 bool exec_script, bool force_script = false) 2998 bool force_script = false, bool require_file = true,
2999 const std::string& warn_for = std::string ())
3182 { 3000 {
3183 unwind_protect::begin_frame ("parse_fcn_file"); 3001 unwind_protect::begin_frame ("parse_fcn_file");
3184 3002
3185 octave_function *fcn_ptr = 0; 3003 octave_function *fcn_ptr = 0;
3186 3004
3208 reading_fcn_file = true; 3026 reading_fcn_file = true;
3209 line_editing = false; 3027 line_editing = false;
3210 parent_function_name = ""; 3028 parent_function_name = "";
3211 current_class_name = dispatch_type; 3029 current_class_name = dispatch_type;
3212 3030
3031 // The next four lines must be in this order.
3032 unwind_protect::add (restore_command_history, 0);
3033
3034 // FIXME -- we shouldn't need both the
3035 // command_history object and the
3036 // Vsaving_history variable...
3037 command_history::ignore_entries ();
3038
3039 unwind_protect_bool (Vsaving_history);
3040
3041 Vsaving_history = false;
3042
3213 FILE *ffile = get_input_from_file (ff, 0); 3043 FILE *ffile = get_input_from_file (ff, 0);
3214 3044
3215 unwind_protect::add (safe_fclose, ffile); 3045 unwind_protect::add (safe_fclose, ffile);
3216 3046
3217 if (ffile) 3047 if (ffile)
3218 { 3048 {
3219 // Check to see if this file defines a function or is just a 3049 process_leading_comments (ffile);
3220 // list of commands. 3050
3221 3051 std::string file_type;
3222 if (! force_script && is_function_file (ffile)) 3052
3053 bool parsing_script = false;
3054
3055 if (! force_script && looking_at_function_keyword (ffile))
3223 { 3056 {
3224 // FIXME -- we shouldn't need both the 3057 file_type = "function";
3225 // command_history object and the
3226 // Vsaving_history variable...
3227 command_history::ignore_entries ();
3228
3229 unwind_protect::add (restore_command_history, 0);
3230 3058
3231 unwind_protect_int (Vecho_executing_commands); 3059 unwind_protect_int (Vecho_executing_commands);
3232 unwind_protect_bool (Vsaving_history);
3233 unwind_protect_bool (reading_fcn_file); 3060 unwind_protect_bool (reading_fcn_file);
3234 unwind_protect_bool (get_input_from_eval_string); 3061 unwind_protect_bool (get_input_from_eval_string);
3235 unwind_protect_bool (parser_end_of_input); 3062 unwind_protect_bool (parser_end_of_input);
3236 3063
3237 Vecho_executing_commands = ECHO_OFF; 3064 Vecho_executing_commands = ECHO_OFF;
3238 Vsaving_history = false;
3239 reading_fcn_file = true; 3065 reading_fcn_file = true;
3240 get_input_from_eval_string = false; 3066 get_input_from_eval_string = false;
3241 parser_end_of_input = false; 3067 parser_end_of_input = false;
3242
3243 YY_BUFFER_STATE old_buf = current_buffer ();
3244 YY_BUFFER_STATE new_buf = create_buffer (ffile);
3245
3246 unwind_protect::add (restore_input_buffer, old_buf);
3247 unwind_protect::add (delete_input_buffer, new_buf);
3248
3249 switch_to_buffer (new_buf);
3250
3251 unwind_protect_ptr (curr_fcn_ptr);
3252 curr_fcn_ptr = 0;
3253
3254 reset_parser ();
3255
3256 std::string txt
3257 = gobble_leading_white_space (ffile, true, true, true, false);
3258
3259 help_buf.push (txt);
3260
3261 octave_comment_buffer::append (txt);
3262
3263 // FIXME -- this should not be necessary.
3264 gobble_leading_white_space (ffile, false, true, false, false);
3265
3266 lexer_flags.parsing_class_method = ! dispatch_type.empty ();
3267
3268 int status = yyparse ();
3269
3270 fcn_ptr = curr_fcn_ptr;
3271
3272 if (status != 0)
3273 error ("parse error while reading function file %s", ff.c_str ());
3274 } 3068 }
3275 else if (exec_script) 3069 else
3276 { 3070 {
3071 file_type = "script";
3072
3277 // The value of `reading_fcn_file' will be restored to the 3073 // The value of `reading_fcn_file' will be restored to the
3278 // proper value when we unwind from this frame. 3074 // proper value when we unwind from this frame.
3279 reading_fcn_file = old_reading_fcn_file_state; 3075 reading_fcn_file = old_reading_fcn_file_state;
3280 3076
3281 // FIXME -- we shouldn't need both the
3282 // command_history object and the
3283 // Vsaving_history variable...
3284 command_history::ignore_entries ();
3285
3286 unwind_protect::add (restore_command_history, 0);
3287
3288 unwind_protect_bool (Vsaving_history);
3289 unwind_protect_bool (reading_script_file); 3077 unwind_protect_bool (reading_script_file);
3290 3078
3291 Vsaving_history = false;
3292 reading_script_file = true; 3079 reading_script_file = true;
3293 3080
3294 octave_user_script *script = new octave_user_script (ff, ff, ""); 3081 parsing_script = true;
3295 octave_call_stack::push (script);
3296 unwind_protect::add (octave_call_stack::unwind_pop_script, 0);
3297
3298 parse_and_execute (ffile);
3299 } 3082 }
3300 } 3083
3301 else 3084 YY_BUFFER_STATE old_buf = current_buffer ();
3085 YY_BUFFER_STATE new_buf = create_buffer (ffile);
3086
3087 unwind_protect::add (restore_input_buffer, old_buf);
3088 unwind_protect::add (delete_input_buffer, new_buf);
3089
3090 switch_to_buffer (new_buf);
3091
3092 unwind_protect_ptr (curr_fcn_ptr);
3093 curr_fcn_ptr = 0;
3094
3095 reset_parser ();
3096
3097 if (parsing_script)
3098 prep_lexer_for_script ();
3099
3100 lexer_flags.parsing_class_method = ! dispatch_type.empty ();
3101
3102 int status = yyparse ();
3103
3104 fcn_ptr = curr_fcn_ptr;
3105
3106 if (status != 0)
3107 error ("parse error while reading %s file %s",
3108 file_type.c_str(), ff.c_str ());
3109 }
3110 else if (require_file)
3302 error ("no such file, `%s'", ff.c_str ()); 3111 error ("no such file, `%s'", ff.c_str ());
3112 else if (! warn_for.empty ())
3113 error ("%s: unable to open file `%s'", warn_for.c_str (), ff.c_str ());
3303 3114
3304 unwind_protect::run_frame ("parse_fcn_file"); 3115 unwind_protect::run_frame ("parse_fcn_file");
3305 3116
3306 return fcn_ptr; 3117 return fcn_ptr;
3118 }
3119
3120 std::string
3121 get_help_from_file (const std::string& nm, bool& symbol_found,
3122 std::string& file)
3123 {
3124 std::string retval;
3125
3126 file = fcn_file_in_path (nm);
3127
3128 if (! file.empty ())
3129 {
3130 symbol_found = true;
3131
3132 FILE *fptr = fopen (file.c_str (), "r");
3133
3134 if (fptr)
3135 {
3136 unwind_protect::add (safe_fclose, fptr);
3137
3138 retval = gobble_leading_white_space (fptr);
3139
3140 if (retval.empty ())
3141 {
3142 octave_function *fcn = parse_fcn_file (file, "");
3143
3144 if (fcn)
3145 {
3146 retval = fcn->doc_string ();
3147
3148 delete fcn;
3149 }
3150 }
3151
3152 unwind_protect::run ();
3153 }
3154 }
3155
3156 return retval;
3157 }
3158
3159 std::string
3160 get_help_from_file (const std::string& nm, bool& symbol_found)
3161 {
3162 std::string file;
3163 return get_help_from_file (nm, symbol_found, file);
3307 } 3164 }
3308 3165
3309 std::string 3166 std::string
3310 lookup_autoload (const std::string& nm) 3167 lookup_autoload (const std::string& nm)
3311 { 3168 {
3400 } 3257 }
3401 else if (len > 4 && file.substr (len-4, len-1) == ".mex") 3258 else if (len > 4 && file.substr (len-4, len-1) == ".mex")
3402 retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup); 3259 retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup);
3403 else if (len > 2) 3260 else if (len > 2)
3404 { 3261 {
3405 if (is_function_file (file)) 3262 // These are needed by yyparse.
3406 { 3263
3407 // These are needed by yyparse. 3264 unwind_protect_str (curr_fcn_file_name);
3408 3265 unwind_protect_str (curr_fcn_file_full_name);
3409 unwind_protect_str (curr_fcn_file_name); 3266
3410 unwind_protect_str (curr_fcn_file_full_name); 3267 curr_fcn_file_name = nm;
3411 3268 curr_fcn_file_full_name = file;
3412 curr_fcn_file_name = nm; 3269
3413 curr_fcn_file_full_name = file; 3270 retval = parse_fcn_file (file, dispatch_type, autoloading);
3414
3415 retval = parse_fcn_file (file, dispatch_type, false, autoloading);
3416 }
3417 else
3418 retval = new octave_user_script (file, fcn_name);
3419 } 3271 }
3420 3272
3421 if (retval) 3273 if (retval)
3422 retval->stash_dir_name (dir_name); 3274 retval->stash_dir_name (dir_name);
3423 3275
3528 3380
3529 return retval; 3381 return retval;
3530 } 3382 }
3531 3383
3532 void 3384 void
3533 source_file (const std::string& file_name, const std::string& context) 3385 source_file (const std::string& file_name, const std::string& context,
3386 bool verbose, bool require_file, const std::string& warn_for)
3534 { 3387 {
3535 std::string file_full_name = file_ops::tilde_expand (file_name); 3388 std::string file_full_name = file_ops::tilde_expand (file_name);
3536 3389
3537 unwind_protect::begin_frame ("source_file"); 3390 unwind_protect::begin_frame ("source_file");
3538 3391
3555 unwind_protect::add (symbol_table::pop_scope); 3408 unwind_protect::add (symbol_table::pop_scope);
3556 } 3409 }
3557 3410
3558 if (! error_state) 3411 if (! error_state)
3559 { 3412 {
3560 parse_fcn_file (file_full_name, "", true, true); 3413 octave_function *fcn = parse_fcn_file (file_full_name, "", true,
3561 3414 require_file, warn_for);
3562 if (error_state) 3415
3416 if (! error_state)
3417 {
3418 if (fcn && fcn->is_user_script ())
3419 {
3420 octave_value_list args;
3421
3422 if (verbose)
3423 {
3424 std::cout << "executing commands from " << file_full_name << " ... ";
3425 reading_startup_message_printed = true;
3426 std::cout.flush ();
3427 }
3428
3429 fcn->do_multi_index_op (0, args);
3430
3431 if (verbose)
3432 std::cout << "done." << std::endl;
3433
3434 delete fcn;
3435 }
3436 }
3437 else
3563 error ("source: error sourcing file `%s'", 3438 error ("source: error sourcing file `%s'",
3564 file_full_name.c_str ()); 3439 file_full_name.c_str ());
3565 } 3440 }
3566 3441
3567 unwind_protect::run_frame ("source_file"); 3442 unwind_protect::run_frame ("source_file");