comparison libinterp/parse-tree/oct-parse.in.yy @ 16203:127cccb037bf

move more global parser and lexer variables to classes * pt-check.h, pt-check.cc (tree_checker::file_name): New data member. (tree_checker::gripe): Use it instead of curr_fcn_file_name. * input.h, input.cc, octave.cc (input_from_command_line_file): Delete global variable and all uses. * parse.h, oct-parse.in.yy (input_from_startup_file): Delete global variable and all uses. * input.h, input.cc, lex.h, lex.ll (curr_fcn_file_name, curr_fcn_file_full_name): Declare as members of lexical_feedback class. Rename to fcn_file_name and fcn_file_full_name. Change all uses. * oct-parse.in.yy (parse_fcn_file): New arg, file. Set curr_lexer->fcn_file_name and curr_lexer->fcn_file_full_name here. (load_fcn_from_file): Pass short file name to parse_fcn_file. * octave.cc (execute_command_line_file): Not here. * lex.h, lex.ll (lexical_feedback::force_script): New data member. * oct-parse.in.yy (parse_fcn_file): Set it here. * lex.h, lex.ll (lexical_feedback::input_from_terminal, lexical_feedback::input_from_file): New functions. * lex.ll (octave_lexer::handle_keyword): Set reading_fcn_file, reading_classdef_file, and reading_script_file. * lex.h, lex.ll (lexical_feedback::token_count): New variable. (COUNT_TOK_AND_RETURN): Increment it here. Don't count '\n' as a token. * lex.h, lex.ll (lexical_feedback::help_text): New variable. * parse.h, parse.in.yy (help_buf): Delete global variable and all uses. (octave_parser::frob_function, octave_parser::make_script): Use help_text. * lex.ll (octave_lexer::process_comment): Cache doc string directly in help_text variable. (looks_like_copyright): Move here from parse.in.yy. * lex.h, lex.ll (octave_lexer::prep_for_file): New function. (octave_lexer::prep_for_function_file, octave_lexer::prep_for_script_file): Delete. * parse.in.yy (INPUT_FILE_BEGIN): New start state. Delete SCRIPT_FILE_BEGIN and FCN_FILE_BEGIN. Tentatively set curr_lexer->reading_script_file to true. (parse_fcn_file): Call curr_lexer->prep_for_file. Don't call gobble_leading_whitespace. Don't attempt to determine function script, or classdef file status here. * parse.in.yy (INPUT_FILE): New token. (SCRIPT_FILE, FUNCTION_FILE): Delete. * lex.ll (octave_lexer::display_token): Update. * parse.in.yy (nl, opt_nl): New non-terminals. (function_file): Delete rule. (file): Rename from script_file. Allow opt_nl before opt_list. Don't make script if reading fcn file. * parse.in.yy (text_getc, class stdio_stream_reader, skip_white_space, looking_at_classdef_keyword, gobble_leading_white_space, looking_at_function_keyword): Delete. (get_help_from_file): Parse file to get help instead of calling gobble_leading_white_space
author John W. Eaton <jwe@octave.org>
date Wed, 06 Mar 2013 14:36:19 -0500
parents 810a71122c25
children a8f9eb92fa6e 0467d68ca891
comparison
equal deleted inserted replaced
16202:7ce484126bb2 16203:127cccb037bf
93 #define fclose GNULIB_NAMESPACE::fclose 93 #define fclose GNULIB_NAMESPACE::fclose
94 #define fprintf GNULIB_NAMESPACE::fprintf 94 #define fprintf GNULIB_NAMESPACE::fprintf
95 #define malloc GNULIB_NAMESPACE::malloc 95 #define malloc GNULIB_NAMESPACE::malloc
96 #endif 96 #endif
97 97
98 // Buffer for help text snagged from function files.
99 std::stack<std::string> help_buf;
100
101 // TRUE means we are using readline. 98 // TRUE means we are using readline.
102 // (--no-line-editing) 99 // (--no-line-editing)
103 bool line_editing = true; 100 bool line_editing = true;
104 101
105 // TRUE means we printed messages about reading startup files. 102 // TRUE means we printed messages about reading startup files.
106 bool reading_startup_message_printed = false; 103 bool reading_startup_message_printed = false;
107
108 // TRUE means input is coming from startup file.
109 bool input_from_startup_file = false;
110 104
111 // Keep track of symbol table information when parsing functions. 105 // Keep track of symbol table information when parsing functions.
112 symtab_context parser_symtab_context; 106 symtab_context parser_symtab_context;
113 107
114 // List of autoloads (function -> file mapping). 108 // List of autoloads (function -> file mapping).
236 %token <tok_val> SUPERCLASSREF 230 %token <tok_val> SUPERCLASSREF
237 %token <tok_val> GET SET 231 %token <tok_val> GET SET
238 232
239 // Other tokens. 233 // Other tokens.
240 %token END_OF_INPUT LEXICAL_ERROR 234 %token END_OF_INPUT LEXICAL_ERROR
241 %token FCN SCRIPT_FILE FUNCTION_FILE CLASSDEF 235 %token FCN INPUT_FILE CLASSDEF
242 // %token VARARGIN VARARGOUT 236 // %token VARARGIN VARARGOUT
243 %token CLOSE_BRACE 237 %token CLOSE_BRACE
244 238
245 // Nonterminals we construct. 239 // Nonterminals we construct.
246 %type <comment_type> stash_comment function_beg classdef_beg 240 %type <comment_type> stash_comment function_beg classdef_beg
247 %type <comment_type> properties_beg methods_beg events_beg enum_beg 241 %type <comment_type> properties_beg methods_beg events_beg enum_beg
248 %type <sep_type> sep_no_nl opt_sep_no_nl sep opt_sep opt_comma 242 %type <sep_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep opt_comma
249 %type <tree_type> input 243 %type <tree_type> input
250 %type <tree_constant_type> string constant magic_colon 244 %type <tree_constant_type> string constant magic_colon
251 %type <tree_anon_fcn_handle_type> anon_fcn_handle 245 %type <tree_anon_fcn_handle_type> anon_fcn_handle
252 %type <tree_fcn_handle_type> fcn_handle 246 %type <tree_fcn_handle_type> fcn_handle
253 %type <tree_matrix_type> matrix_rows matrix_rows1 247 %type <tree_matrix_type> matrix_rows matrix_rows1
265 %type <tree_parameter_list_type> param_list param_list1 param_list2 259 %type <tree_parameter_list_type> param_list param_list1 param_list2
266 %type <tree_parameter_list_type> return_list return_list1 260 %type <tree_parameter_list_type> return_list return_list1
267 %type <tree_parameter_list_type> superclasses opt_superclasses 261 %type <tree_parameter_list_type> superclasses opt_superclasses
268 %type <tree_command_type> command select_command loop_command 262 %type <tree_command_type> command select_command loop_command
269 %type <tree_command_type> jump_command except_command function 263 %type <tree_command_type> jump_command except_command function
270 %type <tree_command_type> script_file classdef 264 %type <tree_command_type> file classdef
271 %type <tree_command_type> function_file function_list
272 %type <tree_if_command_type> if_command 265 %type <tree_if_command_type> if_command
273 %type <tree_if_clause_type> elseif_clause else_clause 266 %type <tree_if_clause_type> elseif_clause else_clause
274 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list 267 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
275 %type <tree_switch_command_type> switch_command 268 %type <tree_switch_command_type> switch_command
276 %type <tree_switch_case_type> switch_case default_case 269 %type <tree_switch_case_type> switch_case default_case
327 { 320 {
328 curr_parser.stmt_list = $1; 321 curr_parser.stmt_list = $1;
329 promptflag = 1; 322 promptflag = 1;
330 YYACCEPT; 323 YYACCEPT;
331 } 324 }
332 | function_file
333 { YYACCEPT; }
334 | simple_list parse_error 325 | simple_list parse_error
335 { ABORT_PARSE; } 326 { ABORT_PARSE; }
336 | parse_error 327 | parse_error
337 { ABORT_PARSE; } 328 { ABORT_PARSE; }
338 ; 329 ;
759 { $$ = $1; } 750 { $$ = $1; }
760 | except_command 751 | except_command
761 { $$ = $1; } 752 { $$ = $1; }
762 | function 753 | function
763 { $$ = $1; } 754 { $$ = $1; }
764 | script_file 755 | file
765 { $$ = $1; } 756 { $$ = $1; }
766 | classdef 757 | classdef
767 { $$ = $1; } 758 { $$ = $1; }
768 ; 759 ;
769 760
842 } 833 }
843 ; 834 ;
844 835
845 if_cmd_list1 : expression opt_sep opt_list 836 if_cmd_list1 : expression opt_sep opt_list
846 { 837 {
847 $1->mark_braindead_shortcircuit (curr_fcn_file_full_name); 838 $1->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
848 839
849 $$ = curr_parser.start_if_command ($1, $3); 840 $$ = curr_parser.start_if_command ($1, $3);
850 } 841 }
851 | if_cmd_list1 elseif_clause 842 | if_cmd_list1 elseif_clause
852 { 843 {
855 } 846 }
856 ; 847 ;
857 848
858 elseif_clause : ELSEIF stash_comment opt_sep expression opt_sep opt_list 849 elseif_clause : ELSEIF stash_comment opt_sep expression opt_sep opt_list
859 { 850 {
860 $4->mark_braindead_shortcircuit (curr_fcn_file_full_name); 851 $4->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
861 852
862 $$ = curr_parser.make_elseif_clause ($1, $4, $6, $2); 853 $$ = curr_parser.make_elseif_clause ($1, $4, $6, $2);
863 } 854 }
864 ; 855 ;
865 856
914 // Looping 905 // Looping
915 // ======= 906 // =======
916 907
917 loop_command : WHILE stash_comment expression opt_sep opt_list END 908 loop_command : WHILE stash_comment expression opt_sep opt_list END
918 { 909 {
919 $3->mark_braindead_shortcircuit (curr_fcn_file_full_name); 910 $3->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
920 911
921 if (! ($$ = curr_parser.make_while_command ($1, $3, $5, $6, $2))) 912 if (! ($$ = curr_parser.make_while_command ($1, $3, $5, $6, $2)))
922 ABORT_PARSE; 913 ABORT_PARSE;
923 } 914 }
924 | DO stash_comment opt_sep opt_list UNTIL expression 915 | DO stash_comment opt_sep opt_list UNTIL expression
1011 1002
1012 symbol_table::set_scope (symbol_table::alloc_scope ()); 1003 symbol_table::set_scope (symbol_table::alloc_scope ());
1013 1004
1014 curr_parser.function_scopes.push_back (symbol_table::current_scope ()); 1005 curr_parser.function_scopes.push_back (symbol_table::current_scope ());
1015 1006
1016 if (! curr_lexer->reading_script_file && curr_parser.curr_fcn_depth == 1 1007 if (! curr_lexer->reading_script_file
1008 && curr_parser.curr_fcn_depth == 1
1017 && ! curr_parser.parsing_subfunctions) 1009 && ! curr_parser.parsing_subfunctions)
1018 curr_parser.primary_fcn_scope = symbol_table::current_scope (); 1010 curr_parser.primary_fcn_scope = symbol_table::current_scope ();
1019 1011
1020 if (curr_lexer->reading_script_file && curr_parser.curr_fcn_depth > 1) 1012 if (curr_lexer->reading_script_file
1013 && curr_parser.curr_fcn_depth > 1)
1021 curr_parser.bison_error ("nested functions not implemented in this context"); 1014 curr_parser.bison_error ("nested functions not implemented in this context");
1022 } 1015 }
1023 ; 1016 ;
1024 1017
1025 // =========================== 1018 // ===========================
1115 $1->append (new tree_decl_elt ($3)); 1108 $1->append (new tree_decl_elt ($3));
1116 $$ = $1; 1109 $$ = $1;
1117 } 1110 }
1118 ; 1111 ;
1119 1112
1120 // =========== 1113 // =======================
1121 // Script file 1114 // Script or function file
1122 // =========== 1115 // =======================
1123 1116
1124 script_file : SCRIPT_FILE opt_list END_OF_INPUT 1117 file : INPUT_FILE opt_nl opt_list END_OF_INPUT
1125 { 1118 {
1126 tree_statement *end_of_script 1119 if (! curr_lexer->reading_fcn_file)
1127 = curr_parser.make_end ("endscript", 1120 {
1128 curr_lexer->input_line_number, 1121 tree_statement *end_of_script
1129 curr_lexer->current_input_column); 1122 = curr_parser.make_end ("endscript",
1130 1123 curr_lexer->input_line_number,
1131 curr_parser.make_script ($2, end_of_script); 1124 curr_lexer->current_input_column);
1125
1126 curr_parser.make_script ($3, end_of_script);
1127 }
1132 1128
1133 $$ = 0; 1129 $$ = 0;
1134 } 1130 }
1135 ;
1136
1137 // =============
1138 // Function file
1139 // =============
1140
1141 function_file : FUNCTION_FILE function_list opt_sep END_OF_INPUT
1142 { $$ = 0; }
1143 ;
1144
1145 function_list : function
1146 | function_list sep function
1147 ; 1131 ;
1148 1132
1149 // =================== 1133 // ===================
1150 // Function definition 1134 // Function definition
1151 // =================== 1135 // ===================
1152 1136
1153 function_beg : push_fcn_symtab FCN stash_comment 1137 function_beg : push_fcn_symtab FCN stash_comment
1154 { 1138 {
1155 $$ = $3; 1139 $$ = $3;
1156 1140 if (curr_lexer->reading_classdef_file
1157 if (curr_lexer->reading_classdef_file || curr_lexer->parsing_classdef) 1141 || curr_lexer->parsing_classdef)
1158 curr_lexer->maybe_classdef_get_set_method = true; 1142 curr_lexer->maybe_classdef_get_set_method = true;
1159 } 1143 }
1160 ; 1144 ;
1161 1145
1162 function : function_beg function1 1146 function : function_beg function1
1436 ; 1420 ;
1437 1421
1438 opt_sep_no_nl : // empty 1422 opt_sep_no_nl : // empty
1439 { $$ = 0; } 1423 { $$ = 0; }
1440 | sep_no_nl 1424 | sep_no_nl
1425 { $$ = $1; }
1426 ;
1427
1428 opt_nl : // empty
1429 { $$ = 0; }
1430 | nl
1431 { $$ = $1; }
1432 ;
1433
1434 nl : '\n'
1435 { $$ = '\n'; }
1436 | nl '\n'
1441 { $$ = $1; } 1437 { $$ = $1; }
1442 ; 1438 ;
1443 1439
1444 sep : ',' 1440 sep : ','
1445 { $$ = ','; } 1441 { $$ = ','; }
1665 octave_parser::maybe_warn_assign_as_truth_value (tree_expression *expr) 1661 octave_parser::maybe_warn_assign_as_truth_value (tree_expression *expr)
1666 { 1662 {
1667 if (expr->is_assignment_expression () 1663 if (expr->is_assignment_expression ()
1668 && expr->paren_count () < 2) 1664 && expr->paren_count () < 2)
1669 { 1665 {
1670 if (curr_fcn_file_full_name.empty ()) 1666 if (curr_lexer->fcn_file_full_name.empty ())
1671 warning_with_id 1667 warning_with_id
1672 ("Octave:assign-as-truth-value", 1668 ("Octave:assign-as-truth-value",
1673 "suggest parenthesis around assignment used as truth value"); 1669 "suggest parenthesis around assignment used as truth value");
1674 else 1670 else
1675 warning_with_id 1671 warning_with_id
1676 ("Octave:assign-as-truth-value", 1672 ("Octave:assign-as-truth-value",
1677 "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'", 1673 "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'",
1678 expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); 1674 expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ());
1679 } 1675 }
1680 } 1676 }
1681 1677
1682 // Maybe print a warning about switch labels that aren't constants. 1678 // Maybe print a warning about switch labels that aren't constants.
1683 1679
1684 void 1680 void
1685 octave_parser::maybe_warn_variable_switch_label (tree_expression *expr) 1681 octave_parser::maybe_warn_variable_switch_label (tree_expression *expr)
1686 { 1682 {
1687 if (! expr->is_constant ()) 1683 if (! expr->is_constant ())
1688 { 1684 {
1689 if (curr_fcn_file_full_name.empty ()) 1685 if (curr_lexer->fcn_file_full_name.empty ())
1690 warning_with_id ("Octave:variable-switch-label", 1686 warning_with_id ("Octave:variable-switch-label",
1691 "variable switch label"); 1687 "variable switch label");
1692 else 1688 else
1693 warning_with_id 1689 warning_with_id
1694 ("Octave:variable-switch-label", 1690 ("Octave:variable-switch-label",
1695 "variable switch label near line %d, column %d in file '%s'", 1691 "variable switch label near line %d, column %d in file '%s'",
1696 expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); 1692 expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ());
1697 } 1693 }
1698 } 1694 }
1699 1695
1700 static tree_expression * 1696 static tree_expression *
1701 fold (tree_binary_expression *e) 1697 fold (tree_binary_expression *e)
1953 1949
1954 tree_anon_fcn_handle *retval 1950 tree_anon_fcn_handle *retval
1955 = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); 1951 = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c);
1956 // FIXME: Stash the filename. This does not work and produces 1952 // FIXME: Stash the filename. This does not work and produces
1957 // errors when executed. 1953 // errors when executed.
1958 //retval->stash_file_name (curr_fcn_file_name); 1954 //retval->stash_file_name (curr_lexer->fcn_file_name);
1959 1955
1960 return retval; 1956 return retval;
1961 } 1957 }
1962 1958
1963 // Build a binary expression. 1959 // Build a binary expression.
2577 2573
2578 void 2574 void
2579 octave_parser::make_script (tree_statement_list *cmds, 2575 octave_parser::make_script (tree_statement_list *cmds,
2580 tree_statement *end_script) 2576 tree_statement *end_script)
2581 { 2577 {
2582 std::string doc_string;
2583
2584 if (! help_buf.empty ())
2585 {
2586 doc_string = help_buf.top ();
2587 help_buf.pop ();
2588 }
2589
2590 if (! cmds) 2578 if (! cmds)
2591 cmds = new tree_statement_list (); 2579 cmds = new tree_statement_list ();
2592 2580
2593 cmds->append (end_script); 2581 cmds->append (end_script);
2594 2582
2595 octave_user_script *script 2583 octave_user_script *script
2596 = new octave_user_script (curr_fcn_file_full_name, curr_fcn_file_name, 2584 = new octave_user_script (curr_lexer->fcn_file_full_name,
2597 cmds, doc_string); 2585 curr_lexer->fcn_file_name,
2586 cmds, curr_lexer->help_text);
2587
2588 curr_lexer->help_text = "";
2598 2589
2599 octave_time now; 2590 octave_time now;
2600 2591
2601 script->stash_fcn_file_time (now); 2592 script->stash_fcn_file_time (now);
2602 2593
2655 // file. Matlab doesn't provide a diagnostic (it ignores the stated 2646 // file. Matlab doesn't provide a diagnostic (it ignores the stated
2656 // name). 2647 // name).
2657 if (! autoloading && curr_lexer->reading_fcn_file 2648 if (! autoloading && curr_lexer->reading_fcn_file
2658 && curr_fcn_depth == 1 && ! parsing_subfunctions) 2649 && curr_fcn_depth == 1 && ! parsing_subfunctions)
2659 { 2650 {
2660 // FIXME -- should curr_fcn_file_name already be 2651 // FIXME -- should curr_lexer->fcn_file_name already be
2661 // preprocessed when we get here? It seems to only be a 2652 // preprocessed when we get here? It seems to only be a
2662 // problem with relative file names. 2653 // problem with relative file names.
2663 2654
2664 std::string nm = curr_fcn_file_name; 2655 std::string nm = curr_lexer->fcn_file_name;
2665 2656
2666 size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); 2657 size_t pos = nm.find_last_of (file_ops::dir_sep_chars ());
2667 2658
2668 if (pos != std::string::npos) 2659 if (pos != std::string::npos)
2669 nm = curr_fcn_file_name.substr (pos+1); 2660 nm = curr_lexer->fcn_file_name.substr (pos+1);
2670 2661
2671 if (nm != id_name) 2662 if (nm != id_name)
2672 { 2663 {
2673 warning_with_id 2664 warning_with_id
2674 ("Octave:function-name-clash", 2665 ("Octave:function-name-clash",
2675 "function name '%s' does not agree with function file name '%s'", 2666 "function name '%s' does not agree with function file name '%s'",
2676 id_name.c_str (), curr_fcn_file_full_name.c_str ()); 2667 id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ());
2677 2668
2678 id_name = nm; 2669 id_name = nm;
2679 } 2670 }
2680 } 2671 }
2681 2672
2682 if (curr_lexer->reading_fcn_file || curr_lexer->reading_classdef_file || autoloading) 2673 if (curr_lexer->reading_fcn_file || curr_lexer->reading_classdef_file || autoloading)
2683 { 2674 {
2684 octave_time now; 2675 octave_time now;
2685 2676
2686 fcn->stash_fcn_file_name (curr_fcn_file_full_name); 2677 fcn->stash_fcn_file_name (curr_lexer->fcn_file_full_name);
2687 fcn->stash_fcn_file_time (now); 2678 fcn->stash_fcn_file_time (now);
2688 fcn->mark_as_system_fcn_file (); 2679 fcn->mark_as_system_fcn_file ();
2689 2680
2690 if (fcn_file_from_relative_lookup) 2681 if (fcn_file_from_relative_lookup)
2691 fcn->mark_relative (); 2682 fcn->mark_relative ();
2692 2683
2693 if (curr_fcn_depth > 1 || parsing_subfunctions) 2684 if (curr_fcn_depth > 1 || parsing_subfunctions)
2694 { 2685 {
2695 fcn->stash_parent_fcn_name (curr_fcn_file_name); 2686 fcn->stash_parent_fcn_name (curr_lexer->fcn_file_name);
2696 2687
2697 if (curr_fcn_depth > 1) 2688 if (curr_fcn_depth > 1)
2698 fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]); 2689 fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]);
2699 else 2690 else
2700 fcn->stash_parent_fcn_scope (primary_fcn_scope); 2691 fcn->stash_parent_fcn_scope (primary_fcn_scope);
2716 2707
2717 if (fs && fs.is_newer (now)) 2708 if (fs && fs.is_newer (now))
2718 warning_with_id ("Octave:future-time-stamp", 2709 warning_with_id ("Octave:future-time-stamp",
2719 "time stamp for '%s' is in the future", nm.c_str ()); 2710 "time stamp for '%s' is in the future", nm.c_str ());
2720 } 2711 }
2721 else if (! (input_from_tmp_history_file || input_from_startup_file) 2712 else if (! input_from_tmp_history_file
2713 && ! curr_lexer->force_script
2722 && curr_lexer->reading_script_file 2714 && curr_lexer->reading_script_file
2723 && curr_fcn_file_name == id_name) 2715 && curr_lexer->fcn_file_name == id_name)
2724 { 2716 {
2725 warning ("function '%s' defined within script file '%s'", 2717 warning ("function '%s' defined within script file '%s'",
2726 id_name.c_str (), curr_fcn_file_full_name.c_str ()); 2718 id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ());
2727 } 2719 }
2728 2720
2729 fcn->stash_function_name (id_name); 2721 fcn->stash_function_name (id_name);
2730 fcn->stash_fcn_location (curr_lexer->input_line_number, 2722 fcn->stash_fcn_location (curr_lexer->input_line_number,
2731 curr_lexer->current_input_column); 2723 curr_lexer->current_input_column);
2732 2724
2733 if (! help_buf.empty () && curr_fcn_depth == 1 2725 if (! curr_lexer->help_text.empty () && curr_fcn_depth == 1
2734 && ! parsing_subfunctions) 2726 && ! parsing_subfunctions)
2735 { 2727 {
2736 fcn->document (help_buf.top ()); 2728 fcn->document (curr_lexer->help_text);
2737 2729
2738 help_buf.pop (); 2730 curr_lexer->help_text = "";
2739 } 2731 }
2740 2732
2741 if (curr_lexer->reading_fcn_file && curr_fcn_depth == 1 2733 if (curr_lexer->reading_fcn_file && curr_fcn_depth == 1
2742 && ! parsing_subfunctions) 2734 && ! parsing_subfunctions)
2743 primary_fcn_ptr = fcn; 2735 primary_fcn_ptr = fcn;
2945 retval = new tree_persistent_command (lst, l, c); 2937 retval = new tree_persistent_command (lst, l, c);
2946 else 2938 else
2947 { 2939 {
2948 if (curr_lexer->reading_script_file) 2940 if (curr_lexer->reading_script_file)
2949 warning ("ignoring persistent declaration near line %d of file '%s'", 2941 warning ("ignoring persistent declaration near line %d of file '%s'",
2950 l, curr_fcn_file_full_name.c_str ()); 2942 l, curr_lexer->fcn_file_full_name.c_str ());
2951 else 2943 else
2952 warning ("ignoring persistent declaration near line %d", l); 2944 warning ("ignoring persistent declaration near line %d", l);
2953 } 2945 }
2954 break; 2946 break;
2955 2947
3030 3022
3031 if (tmp->is_expression ()) 3023 if (tmp->is_expression ())
3032 warning_with_id 3024 warning_with_id
3033 ("Octave:missing-semicolon", 3025 ("Octave:missing-semicolon",
3034 "missing semicolon near line %d, column %d in file '%s'", 3026 "missing semicolon near line %d, column %d in file '%s'",
3035 tmp->line (), tmp->column (), curr_fcn_file_full_name.c_str ()); 3027 tmp->line (), tmp->column (), curr_lexer->fcn_file_full_name.c_str ());
3036 } 3028 }
3037 } 3029 }
3038 3030
3039 tree_statement_list * 3031 tree_statement_list *
3040 octave_parser::set_stmt_print_flag (tree_statement_list *list, char sep, 3032 octave_parser::set_stmt_print_flag (tree_statement_list *list, char sep,
3098 3090
3099 std::ostringstream output_buf; 3091 std::ostringstream output_buf;
3100 3092
3101 if (curr_lexer->reading_fcn_file || curr_lexer->reading_script_file || curr_lexer->reading_classdef_file) 3093 if (curr_lexer->reading_fcn_file || curr_lexer->reading_script_file || curr_lexer->reading_classdef_file)
3102 output_buf << "parse error near line " << curr_lexer->input_line_number 3094 output_buf << "parse error near line " << curr_lexer->input_line_number
3103 << " of file " << curr_fcn_file_full_name; 3095 << " of file " << curr_lexer->fcn_file_full_name;
3104 else 3096 else
3105 output_buf << "parse error:"; 3097 output_buf << "parse error:";
3106 3098
3107 if (s && strcmp (s, "parse error") != 0) 3099 if (s && strcmp (s, "parse error") != 0)
3108 output_buf << "\n\n " << s; 3100 output_buf << "\n\n " << s;
3150 3142
3151 if (f) 3143 if (f)
3152 fclose (static_cast<FILE *> (f)); 3144 fclose (static_cast<FILE *> (f));
3153 } 3145 }
3154 3146
3155 static bool
3156 looks_like_copyright (const std::string& s)
3157 {
3158 bool retval = false;
3159
3160 if (! s.empty ())
3161 {
3162 size_t offset = s.find_first_not_of (" \t");
3163
3164 retval = (s.substr (offset, 9) == "Copyright" || s.substr (offset, 6) == "Author");
3165 }
3166
3167 return retval;
3168 }
3169
3170 static int
3171 text_getc (FILE *f)
3172 {
3173 int c = gnulib::getc (f);
3174
3175 // Convert CRLF into just LF and single CR into LF.
3176
3177 if (c == '\r')
3178 {
3179 c = gnulib::getc (f);
3180
3181 if (c != '\n')
3182 {
3183 ungetc (c, f);
3184 c = '\n';
3185 }
3186 }
3187
3188 return c;
3189 }
3190
3191 class
3192 stdio_stream_reader : public stream_reader
3193 {
3194 public:
3195
3196 stdio_stream_reader (FILE *f_arg, int& l, int& c)
3197 : stream_reader (), f (f_arg), line_num (l), column_num (c)
3198 { }
3199
3200 int getc (void)
3201 {
3202 char c = ::text_getc (f);
3203
3204 if (c == '\n')
3205 {
3206 line_num++;
3207 column_num = 0;
3208 }
3209 else
3210 {
3211 // FIXME -- try to be smarter about tabs?
3212 column_num++;
3213 }
3214
3215 return c;
3216 }
3217
3218 int ungetc (int c)
3219 {
3220 if (c == '\n')
3221 {
3222 line_num--;
3223 column_num = 0;
3224 }
3225 else
3226 {
3227 // FIXME -- try to be smarter about tabs?
3228 column_num--;
3229 }
3230
3231 return ::ungetc (c, f);
3232 }
3233
3234 private:
3235
3236 FILE *f;
3237
3238 int& line_num;
3239
3240 int& column_num;
3241
3242 // No copying!
3243
3244 stdio_stream_reader (const stdio_stream_reader&);
3245
3246 stdio_stream_reader & operator = (const stdio_stream_reader&);
3247 };
3248
3249 static bool
3250 skip_white_space (stream_reader& reader)
3251 {
3252 int c = 0;
3253
3254 while ((c = reader.getc ()) != EOF)
3255 {
3256 switch (c)
3257 {
3258 case ' ':
3259 case '\t':
3260 case '\n':
3261 break;
3262
3263 default:
3264 reader.ungetc (c);
3265 goto done;
3266 }
3267 }
3268
3269 done:
3270
3271 return (c == EOF);
3272 }
3273
3274 static bool
3275 looking_at_classdef_keyword (FILE *ffile)
3276 {
3277 bool status = false;
3278
3279 long pos = gnulib::ftell (ffile);
3280
3281 char buf [10];
3282 gnulib::fgets (buf, 10, ffile);
3283 size_t len = strlen (buf);
3284 if (len > 8 && strncmp (buf, "classdef", 8) == 0
3285 && ! (isalnum (buf[8]) || buf[8] == '_'))
3286 status = true;
3287
3288 gnulib::fseek (ffile, pos, SEEK_SET);
3289
3290 return status;
3291 }
3292
3293 static std::string
3294 gobble_leading_white_space (FILE *ffile, bool& eof, int& line_num,
3295 int& column_num)
3296 {
3297 std::string help_txt;
3298
3299 eof = false;
3300
3301 // TRUE means we have already cached the help text.
3302 bool have_help_text = false;
3303
3304 std::string txt;
3305
3306 stdio_stream_reader stdio_reader (ffile, line_num, column_num);
3307
3308 while (true)
3309 {
3310 eof = skip_white_space (stdio_reader);
3311
3312 if (eof)
3313 break;
3314
3315 txt = CURR_LEXER->grab_comment_block (stdio_reader, true, eof);
3316
3317 if (txt.empty ())
3318 break;
3319
3320 if (! (have_help_text || looks_like_copyright (txt)))
3321 {
3322 help_txt = txt;
3323 have_help_text = true;
3324 }
3325
3326 octave_comment_buffer::append (txt);
3327
3328 if (eof)
3329 break;
3330 }
3331
3332 return help_txt;
3333 }
3334
3335 static std::string
3336 gobble_leading_white_space (FILE *ffile, bool& eof)
3337 {
3338 int line_num = 1;
3339 int column_num = 1;
3340
3341 return gobble_leading_white_space (ffile, eof, line_num, column_num);
3342 }
3343
3344 static bool
3345 looking_at_function_keyword (FILE *ffile)
3346 {
3347 bool status = false;
3348
3349 long pos = gnulib::ftell (ffile);
3350
3351 char buf [10];
3352 gnulib::fgets (buf, 10, ffile);
3353 size_t len = strlen (buf);
3354 if (len > 8 && strncmp (buf, "function", 8) == 0
3355 && ! (isalnum (buf[8]) || buf[8] == '_'))
3356 status = true;
3357
3358 gnulib::fseek (ffile, pos, SEEK_SET);
3359
3360 return status;
3361 }
3362
3363 static octave_function * 3147 static octave_function *
3364 parse_fcn_file (const std::string& ff, const std::string& dispatch_type, 3148 parse_fcn_file (const std::string& full_file, const std::string& file,
3149 const std::string& dispatch_type,
3365 bool require_file, bool force_script, bool autoload, 3150 bool require_file, bool force_script, bool autoload,
3366 bool relative_lookup, const std::string& warn_for) 3151 bool relative_lookup, const std::string& warn_for)
3367 { 3152 {
3368 unwind_protect frame; 3153 unwind_protect frame;
3369 3154
3384 3169
3385 command_history::ignore_entries (); 3170 command_history::ignore_entries ();
3386 3171
3387 FILE *ffile = 0; 3172 FILE *ffile = 0;
3388 3173
3389 if (! ff.empty ()) 3174 if (! full_file.empty ())
3390 ffile = gnulib::fopen (ff.c_str (), "rb"); 3175 ffile = gnulib::fopen (full_file.c_str (), "rb");
3391 3176
3392 frame.add_fcn (safe_fclose, ffile); 3177 frame.add_fcn (safe_fclose, ffile);
3393 3178
3394 if (ffile) 3179 if (ffile)
3395 { 3180 {
3397 3182
3398 // octave_parser constructor sets this for us. 3183 // octave_parser constructor sets this for us.
3399 frame.protect_var (CURR_LEXER); 3184 frame.protect_var (CURR_LEXER);
3400 3185
3401 octave_parser curr_parser (ffile); 3186 octave_parser curr_parser (ffile);
3402
3403 curr_parser.curr_lexer->reading_fcn_file = true;
3404 3187
3405 curr_parser.curr_class_name = dispatch_type; 3188 curr_parser.curr_class_name = dispatch_type;
3406 curr_parser.autoloading = autoload; 3189 curr_parser.autoloading = autoload;
3407 curr_parser.fcn_file_from_relative_lookup = relative_lookup; 3190 curr_parser.fcn_file_from_relative_lookup = relative_lookup;
3408 3191
3409 std::string help_txt 3192 // Do this with an unwind-protect cleanup function so that
3410 = gobble_leading_white_space 3193 // the forced variables will be unmarked in the event of an
3411 (ffile, eof, 3194 // interrupt.
3412 curr_parser.curr_lexer->input_line_number, 3195 symbol_table::scope_id scope = symbol_table::top_scope ();
3413 curr_parser.curr_lexer->current_input_column); 3196 frame.add_fcn (symbol_table::unmark_forced_variables, scope);
3414 3197
3415 if (! help_txt.empty ()) 3198 curr_parser.curr_lexer->force_script = force_script;
3416 help_buf.push (help_txt); 3199 curr_parser.curr_lexer->prep_for_file ();
3417 3200 curr_parser.curr_lexer->parsing_class_method = ! dispatch_type.empty ();
3418 if (! eof) 3201
3419 { 3202 curr_parser.curr_lexer->fcn_file_name = file;
3420 std::string file_type; 3203 curr_parser.curr_lexer->fcn_file_full_name = full_file;
3421 3204
3422 frame.protect_var (Vecho_executing_commands); 3205 int status = curr_parser.run ();
3423 3206
3424 Vecho_executing_commands = ECHO_OFF; 3207 fcn_ptr = curr_parser.primary_fcn_ptr;
3425 3208
3426 if (! force_script && looking_at_function_keyword (ffile)) 3209 if (status != 0)
3427 { 3210 error ("parse error while reading file %s", full_file.c_str ());
3428 file_type = "function";
3429 }
3430 else
3431 {
3432 curr_parser.curr_lexer->reading_fcn_file = false;
3433
3434 if (! force_script && looking_at_classdef_keyword (ffile))
3435 {
3436 file_type = "classdef";
3437
3438 curr_parser.curr_lexer->reading_classdef_file = true;
3439
3440 // FIXME -- Should classdef files be handled as
3441 // scripts or separately? Currently, without
3442 // setting up for reading script files, parsing
3443 // classdef files fails.
3444 curr_parser.curr_lexer->reading_script_file = true;
3445 }
3446 else
3447 {
3448 file_type = "script";
3449
3450 curr_parser.curr_lexer->reading_script_file = true;
3451 }
3452 }
3453
3454 // Do this with an unwind-protect cleanup function so that
3455 // the forced variables will be unmarked in the event of an
3456 // interrupt.
3457 symbol_table::scope_id scope = symbol_table::top_scope ();
3458 frame.add_fcn (symbol_table::unmark_forced_variables, scope);
3459
3460 if (! help_txt.empty ())
3461 help_buf.push (help_txt);
3462
3463 if (curr_parser.curr_lexer->reading_script_file)
3464 curr_parser.curr_lexer->prep_for_script_file ();
3465 else
3466 curr_parser.curr_lexer->prep_for_function_file ();
3467
3468 curr_parser.curr_lexer->parsing_class_method = ! dispatch_type.empty ();
3469
3470 int status = curr_parser.run ();
3471
3472 fcn_ptr = curr_parser.primary_fcn_ptr;
3473
3474 if (status != 0)
3475 error ("parse error while reading %s file %s",
3476 file_type.c_str (), ff.c_str ());
3477 }
3478 else
3479 {
3480 int l = curr_parser.curr_lexer->input_line_number;
3481 int c = curr_parser.curr_lexer->current_input_column;
3482
3483 tree_statement *end_of_script
3484 = curr_parser.make_end ("endscript", l, c);
3485
3486 curr_parser.make_script (0, end_of_script);
3487
3488 fcn_ptr = curr_parser.primary_fcn_ptr;
3489 }
3490 } 3211 }
3491 else if (require_file) 3212 else if (require_file)
3492 error ("no such file, '%s'", ff.c_str ()); 3213 error ("no such file, '%s'", full_file.c_str ());
3493 else if (! warn_for.empty ()) 3214 else if (! warn_for.empty ())
3494 error ("%s: unable to open file '%s'", warn_for.c_str (), ff.c_str ()); 3215 error ("%s: unable to open file '%s'", warn_for.c_str (),
3216 full_file.c_str ());
3495 3217
3496 return fcn_ptr; 3218 return fcn_ptr;
3497 } 3219 }
3498 3220
3499 std::string 3221 std::string
3500 get_help_from_file (const std::string& nm, bool& symbol_found, 3222 get_help_from_file (const std::string& nm, bool& symbol_found,
3501 std::string& file) 3223 std::string& full_file)
3502 { 3224 {
3503 std::string retval; 3225 std::string retval;
3504 3226
3505 file = fcn_file_in_path (nm); 3227 full_file = fcn_file_in_path (nm);
3228
3229 std::string file = full_file;
3230
3231 size_t file_len = file.length ();
3232
3233 if ((file_len > 4 && file.substr (file_len-4) == ".oct")
3234 || (file_len > 4 && file.substr (file_len-4) == ".mex")
3235 || (file_len > 2 && file.substr (file_len-2) == ".m"))
3236 {
3237 file = octave_env::base_pathname (file);
3238 file = file.substr (0, file.find_last_of ('.'));
3239
3240 size_t pos = file.find_last_of (file_ops::dir_sep_str ());
3241 if (pos != std::string::npos)
3242 file = file.substr (pos+1);
3243 }
3506 3244
3507 if (! file.empty ()) 3245 if (! file.empty ())
3508 { 3246 {
3509 symbol_found = true; 3247 symbol_found = true;
3510 3248
3511 FILE *fptr = gnulib::fopen (file.c_str (), "r"); 3249 octave_function *fcn
3512 3250 = parse_fcn_file (full_file, file, "", true, false, false, false, "");
3513 if (fptr) 3251
3252 if (fcn)
3514 { 3253 {
3515 unwind_protect frame; 3254 retval = fcn->doc_string ();
3516 frame.add_fcn (safe_fclose, fptr); 3255
3517 3256 delete fcn;
3518 bool eof;
3519 retval = gobble_leading_white_space (fptr, eof);
3520
3521 if (retval.empty ())
3522 {
3523 octave_function *fcn = parse_fcn_file (file, "", true,
3524 false, false,
3525 false, "");
3526
3527 if (fcn)
3528 {
3529 retval = fcn->doc_string ();
3530
3531 delete fcn;
3532 }
3533 }
3534 } 3257 }
3535 } 3258 }
3536 3259
3537 return retval; 3260 return retval;
3538 } 3261 }
3631 } 3354 }
3632 else if (len > 4 && file.substr (len-4, len-1) == ".mex") 3355 else if (len > 4 && file.substr (len-4, len-1) == ".mex")
3633 { 3356 {
3634 // Temporarily load m-file version of mex-file, if it exists, 3357 // Temporarily load m-file version of mex-file, if it exists,
3635 // to get the help-string to use. 3358 // to get the help-string to use.
3636 frame.protect_var (curr_fcn_file_name);
3637 frame.protect_var (curr_fcn_file_full_name);
3638
3639 curr_fcn_file_name = nm;
3640 curr_fcn_file_full_name = file.substr (0, len - 2);
3641 3359
3642 octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2), 3360 octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2),
3643 dispatch_type, false, 3361 nm, dispatch_type, false,
3644 autoload, autoload, 3362 autoload, autoload,
3645 relative_lookup, ""); 3363 relative_lookup, "");
3646 3364
3647 retval = octave_dynamic_loader::load_mex (nm, file, relative_lookup); 3365 retval = octave_dynamic_loader::load_mex (nm, file, relative_lookup);
3648 3366
3650 retval->document (tmpfcn->doc_string ()); 3368 retval->document (tmpfcn->doc_string ());
3651 delete tmpfcn; 3369 delete tmpfcn;
3652 } 3370 }
3653 else if (len > 2) 3371 else if (len > 2)
3654 { 3372 {
3655 // These are needed by yyparse. 3373 retval = parse_fcn_file (file, nm, dispatch_type, true, autoload,
3656
3657 frame.protect_var (curr_fcn_file_name);
3658 frame.protect_var (curr_fcn_file_full_name);
3659
3660 curr_fcn_file_name = nm;
3661 curr_fcn_file_full_name = file;
3662
3663 retval = parse_fcn_file (file, dispatch_type, true, autoload,
3664 autoload, relative_lookup, ""); 3374 autoload, relative_lookup, "");
3665 } 3375 }
3666 3376
3667 if (retval) 3377 if (retval)
3668 { 3378 {
3828 3538
3829 file_full_name = octave_env::make_absolute (file_full_name); 3539 file_full_name = octave_env::make_absolute (file_full_name);
3830 3540
3831 unwind_protect frame; 3541 unwind_protect frame;
3832 3542
3833 frame.protect_var (curr_fcn_file_name);
3834 frame.protect_var (curr_fcn_file_full_name);
3835
3836 curr_fcn_file_name = file_name;
3837 curr_fcn_file_full_name = file_full_name;
3838
3839 if (source_call_depth.find (file_full_name) == source_call_depth.end ()) 3543 if (source_call_depth.find (file_full_name) == source_call_depth.end ())
3840 source_call_depth[file_full_name] = -1; 3544 source_call_depth[file_full_name] = -1;
3841 3545
3842 frame.protect_var (source_call_depth[file_full_name]); 3546 frame.protect_var (source_call_depth[file_full_name]);
3843 3547
3862 frame.add_fcn (octave_call_stack::pop); 3566 frame.add_fcn (octave_call_stack::pop);
3863 } 3567 }
3864 3568
3865 if (! error_state) 3569 if (! error_state)
3866 { 3570 {
3867 octave_function *fcn = parse_fcn_file (file_full_name, "", 3571 octave_function *fcn = parse_fcn_file (file_full_name, file_name,
3868 require_file, true, false, 3572 "", require_file, true,
3869 false, warn_for); 3573 false, false, warn_for);
3870 3574
3871 if (! error_state) 3575 if (! error_state)
3872 { 3576 {
3873 if (fcn && fcn->is_user_script ()) 3577 if (fcn && fcn->is_user_script ())
3874 { 3578 {