Mercurial > octave
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"); |