# HG changeset patch # User John W. Eaton # Date 1362598579 18000 # Node ID 127cccb037bf2dcf138442050bfab41da0e33656 # Parent 7ce484126bb2ca93d944ad8600a9e63923107f90 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 diff -r 7ce484126bb2 -r 127cccb037bf libinterp/interpfcn/input.cc --- a/libinterp/interpfcn/input.cc Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/interpfcn/input.cc Wed Mar 06 14:36:19 2013 -0500 @@ -94,19 +94,9 @@ // Character to append after successful command-line completion attempts. static char Vcompletion_append_char = ' '; -// TRUE means that input is coming from a file that was named on -// the command line. -bool input_from_command_line_file = false; - // TRUE means that stdin is a terminal, not a pipe or redirected file. bool stdin_is_tty = false; -// Simple name of function file we are reading. -std::string curr_fcn_file_name; - -// Full name of file we are reading. -std::string curr_fcn_file_full_name; - // TRUE means this is an interactive shell. bool interactive = false; @@ -518,21 +508,13 @@ VPS1 = prompt; if (! (interactive || forced_interactive) - || (CURR_LEXER->reading_fcn_file - || CURR_LEXER->reading_classdef_file - || CURR_LEXER->reading_script_file - || CURR_LEXER->input_from_eval_string () - || input_from_startup_file - || input_from_command_line_file)) + || CURR_LEXER->reading_fcn_file + || CURR_LEXER->reading_classdef_file + || CURR_LEXER->reading_script_file + || CURR_LEXER->input_from_eval_string ()) { frame.protect_var (forced_interactive); forced_interactive = true; - - frame.protect_var (input_from_startup_file); - input_from_startup_file = false; - - frame.protect_var (input_from_command_line_file); - input_from_command_line_file = false; } // octave_parser constructor sets this for us. @@ -661,9 +643,6 @@ if (! (error_state || input_buf.empty ())) { - if (! input_from_startup_file) - command_history::add (input_buf); - size_t len = input_buf.length (); octave_diary << input_buf; diff -r 7ce484126bb2 -r 127cccb037bf libinterp/interpfcn/input.h --- a/libinterp/interpfcn/input.h Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/interpfcn/input.h Wed Mar 06 14:36:19 2013 -0500 @@ -37,19 +37,9 @@ extern OCTINTERP_API FILE *get_input_from_stdin (void); -// TRUE means that input is coming from a file that was named on -// the command line. -extern bool input_from_command_line_file; - // TRUE means that stdin is a terminal, not a pipe or redirected file. extern bool stdin_is_tty; -// Simple name of function file we are reading. -extern std::string curr_fcn_file_name; - -// Full name of file we are reading. -extern std::string curr_fcn_file_full_name; - // TRUE means this is an interactive shell. extern bool interactive; diff -r 7ce484126bb2 -r 127cccb037bf libinterp/interpfcn/load-path.cc --- a/libinterp/interpfcn/load-path.cc Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/interpfcn/load-path.cc Wed Mar 06 14:36:19 2013 -0500 @@ -1956,10 +1956,6 @@ unwind_protect frame; - frame.protect_var (input_from_startup_file); - - input_from_startup_file = true; - std::string file = file_ops::concat (dir, script_file); file_stat fs (file); diff -r 7ce484126bb2 -r 127cccb037bf libinterp/octave.cc --- a/libinterp/octave.cc Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/octave.cc Wed Mar 06 14:36:19 2013 -0500 @@ -355,10 +355,6 @@ { unwind_protect frame; - frame.protect_var (input_from_startup_file); - - input_from_startup_file = true; - std::string context; bool verbose = (verbose_flag && ! inhibit_startup_message); @@ -488,28 +484,18 @@ octave_initialized = true; frame.protect_var (interactive); - frame.protect_var (input_from_command_line_file); - - frame.protect_var (curr_fcn_file_name); - frame.protect_var (curr_fcn_file_full_name); frame.protect_var (octave_program_invocation_name); frame.protect_var (octave_program_name); interactive = false; - input_from_command_line_file = true; - curr_fcn_file_name = fname; - curr_fcn_file_full_name = curr_fcn_file_name; - - octave_program_invocation_name = curr_fcn_file_name; + octave_program_invocation_name = fname; - size_t pos = curr_fcn_file_name.find_last_of (file_ops::dir_sep_chars ()); + size_t pos = fname.find_last_of (file_ops::dir_sep_chars ()); - std::string tmp = (pos != std::string::npos) - ? curr_fcn_file_name.substr (pos+1) : curr_fcn_file_name; - - octave_program_name = tmp; + octave_program_name + = (pos != std::string::npos) ? fname.substr (pos+1) : fname; std::string context; bool verbose = false; diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/lex.h Wed Mar 06 14:36:19 2013 -0500 @@ -170,12 +170,14 @@ looking_for_object_index (false), looking_at_indirect_ref (false), parsing_class_method (false), maybe_classdef_get_set_method (false), parsing_classdef (false), - quote_is_transpose (false), reading_fcn_file (false), - reading_script_file (false), reading_classdef_file (false), + quote_is_transpose (false), force_script (false), + reading_fcn_file (false), reading_script_file (false), + reading_classdef_file (false), input_line_number (1), current_input_column (1), bracketflag (0), braceflag (0), looping (0), defining_func (0), looking_at_function_handle (0), - block_comment_nesting_level (0), + block_comment_nesting_level (0), token_count (0), + help_text (), fcn_file_name (), fcn_file_full_name (), looking_at_object_index (), parsed_function_name (), pending_local_variables (), nesting_level (), token_stack () { @@ -244,6 +246,10 @@ // return transpose or start a string? bool quote_is_transpose; + // TRUE means treat the current file as a script even if the first + // token is "function" or "classdef". + bool force_script; + // TRUE means we're parsing a function file. bool reading_fcn_file; @@ -277,6 +283,19 @@ // nestng level for blcok comments. int block_comment_nesting_level; + // Count of tokens recognized by this lexer since initialized or + // since the last reset. + size_t token_count; + + // The current help text. + std::string help_text; + + // Simple name of function file we are reading. + std::string fcn_file_name; + + // Full name of file we are reading. + std::string fcn_file_full_name; + // if the front of the list is true, the closest paren, brace, or // bracket nesting is an index for an object. std::list looking_at_object_index; @@ -372,9 +391,7 @@ void reset (void); - void prep_for_script_file (void); - - void prep_for_function_file (void); + void prep_for_file (void); int read (char *buf, unsigned int max_size); @@ -480,6 +497,16 @@ return input_reader.input_source (); } + bool input_from_terminal (void) const + { + return input_source () == "terminal"; + } + + bool input_from_file (void) const + { + return input_source () == "file"; + } + bool input_from_eval_string (void) const { return input_source () == "eval_string"; diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/lex.ll Wed Mar 06 14:36:19 2013 -0500 @@ -46,8 +46,7 @@ %s COMMAND_START %s MATRIX_START -%x SCRIPT_FILE_BEGIN -%x FUNCTION_FILE_BEGIN +%x INPUT_FILE_BEGIN %{ @@ -147,7 +146,11 @@ #define COUNT_TOK_AND_RETURN(tok) \ do \ { \ - Vtoken_count++; \ + if (tok != '\n') \ + { \ + Vtoken_count++; \ + curr_lexer->token_count++; \ + } \ DISPLAY_TOK_AND_RETURN (tok); \ } \ while (0) @@ -256,20 +259,17 @@ // the parser go down a special path. %} -. { - LEXER_DEBUG ("."); +. { + LEXER_DEBUG ("."); BEGIN (INITIAL); curr_lexer->xunput (yytext[0]); - COUNT_TOK_AND_RETURN (SCRIPT_FILE); - } - -. { - LEXER_DEBUG ("."); - - BEGIN (INITIAL); - curr_lexer->xunput (yytext[0]); - COUNT_TOK_AND_RETURN (FUNCTION_FILE); + + // May be reset later if we see "function" or "classdef" appears + // as the first token. + curr_lexer->reading_script_file = true; + + DISPLAY_TOK_AND_RETURN (INPUT_FILE); } %{ @@ -1324,6 +1324,7 @@ maybe_classdef_get_set_method = false; parsing_classdef = false; quote_is_transpose = false; + force_script = false; reading_fcn_file = false; reading_script_file = false; reading_classdef_file = false; @@ -1335,7 +1336,10 @@ defining_func = 0; looking_at_function_handle = 0; block_comment_nesting_level = 0; - + token_count = 0; + help_text = ""; + fcn_file_name = ""; + fcn_file_full_name = ""; looking_at_object_index.clear (); looking_at_object_index.push_front (false); @@ -1451,31 +1455,20 @@ && ! (reading_fcn_file || reading_classdef_file || reading_script_file - || input_from_eval_string () - || input_from_startup_file)) + || input_from_eval_string ())) yyrestart (stdin, scanner); - // Clear the buffer for help text. - while (! help_buf.empty ()) - help_buf.pop (); - lexical_feedback::reset (); } void -octave_lexer::prep_for_script_file (void) +octave_lexer::prep_for_file (void) { OCTAVE_YYG; - BEGIN (SCRIPT_FILE_BEGIN); -} - -void -octave_lexer::prep_for_function_file (void) -{ - OCTAVE_YYG; - - BEGIN (FUNCTION_FILE_BEGIN); + reading_script_file = true; + + BEGIN (INPUT_FILE_BEGIN); } int @@ -1517,9 +1510,9 @@ warning ("block comment open at end of input"); if ((reading_fcn_file || reading_script_file || reading_classdef_file) - && ! curr_fcn_file_name.empty ()) + && ! fcn_file_name.empty ()) warning ("near line %d of file '%s.m'", - input_line_number, curr_fcn_file_name.c_str ()); + input_line_number, fcn_file_name.c_str ()); } TOK_RETURN (END_OF_INPUT); @@ -1691,11 +1684,11 @@ case static_kw: if ((reading_fcn_file || reading_script_file || reading_classdef_file) - && ! curr_fcn_file_full_name.empty ()) + && ! fcn_file_full_name.empty ()) warning_with_id ("Octave:deprecated-keyword", "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d of file '%s'", input_line_number, - curr_fcn_file_full_name.c_str ()); + fcn_file_full_name.c_str ()); else warning_with_id ("Octave:deprecated-keyword", "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d", @@ -1834,6 +1827,12 @@ case classdef_kw: // 'classdef' is always a keyword. promptflag--; + + if (! force_script && token_count == 0 && input_from_file ()) + { + reading_classdef_file = true; + reading_script_file = false; + } break; case function_kw: @@ -1842,6 +1841,12 @@ defining_func++; parsed_function_name.push (false); + if (! force_script && token_count == 0 && input_from_file ()) + { + reading_fcn_file = true; + reading_script_file = false; + } + if (! (reading_fcn_file || reading_script_file || reading_classdef_file)) input_line_number = 1; @@ -1851,8 +1856,8 @@ { if ((reading_fcn_file || reading_script_file || reading_classdef_file) - && ! curr_fcn_file_full_name.empty ()) - tok_val = new token (curr_fcn_file_full_name, l, c); + && ! fcn_file_full_name.empty ()) + tok_val = new token (fcn_file_full_name, l, c); else tok_val = new token ("stdin", l, c); } @@ -2131,6 +2136,21 @@ return buf; } +static bool +looks_like_copyright (const std::string& s) +{ + bool retval = false; + + if (! s.empty ()) + { + size_t offset = s.find_first_not_of (" \t"); + + retval = (s.substr (offset, 9) == "Copyright" || s.substr (offset, 6) == "Author"); + } + + return retval; +} + int octave_lexer::process_comment (bool start_in_block, bool& eof) { @@ -2138,11 +2158,6 @@ eof = false; - std::string help_txt; - - if (! help_buf.empty ()) - help_txt = help_buf.top (); - char *yytxt = flex_yytext (); flex_stream_reader flex_reader (this, yytxt); @@ -2156,13 +2171,9 @@ if (lexer_debug_flag) std::cerr << "C: " << txt << std::endl; - if (help_txt.empty () && nesting_level.none ()) - { - if (! help_buf.empty ()) - help_buf.pop (); - - help_buf.push (txt); - } + if (nesting_level.none () && help_text.empty () && ! txt.empty () + && ! looks_like_copyright (txt)) + help_text = txt; octave_comment_buffer::append (txt); @@ -3513,7 +3524,7 @@ void octave_lexer::maybe_warn_separator_insert (char sep) { - std::string nm = curr_fcn_file_full_name; + std::string nm = fcn_file_full_name; if (nm.empty ()) warning_with_id ("Octave:separator-insert", @@ -3528,7 +3539,7 @@ void octave_lexer::gripe_single_quote_string (void) { - std::string nm = curr_fcn_file_full_name; + std::string nm = fcn_file_full_name; if (nm.empty ()) warning_with_id ("Octave:single-quote-string", @@ -3543,7 +3554,7 @@ void octave_lexer::gripe_matlab_incompatible (const std::string& msg) { - std::string nm = curr_fcn_file_full_name; + std::string nm = fcn_file_full_name; if (nm.empty ()) warning_with_id ("Octave:matlab-incompatible", @@ -3707,8 +3718,7 @@ case LEXICAL_ERROR: std::cerr << "LEXICAL_ERROR\n\n"; break; case FCN: std::cerr << "FCN\n"; break; case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break; - case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break; - case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break; + case INPUT_FILE: std::cerr << "INPUT_FILE\n"; break; case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break; case METAQUERY: std::cerr << "METAQUERY\n"; break; case GET: std::cerr << "GET\n"; break; @@ -3750,12 +3760,8 @@ std::cerr << "MATRIX_START" << std::endl; break; - case SCRIPT_FILE_BEGIN: - std::cerr << "SCRIPT_FILE_BEGIN" << std::endl; - break; - - case FUNCTION_FILE_BEGIN: - std::cerr << "FUNCTION_FILE_BEGIN" << std::endl; + case INPUT_FILE_BEGIN: + std::cerr << "INPUT_FILE_BEGIN" << std::endl; break; default: diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/oct-parse.in.yy Wed Mar 06 14:36:19 2013 -0500 @@ -95,9 +95,6 @@ #define malloc GNULIB_NAMESPACE::malloc #endif -// Buffer for help text snagged from function files. -std::stack help_buf; - // TRUE means we are using readline. // (--no-line-editing) bool line_editing = true; @@ -105,9 +102,6 @@ // TRUE means we printed messages about reading startup files. bool reading_startup_message_printed = false; -// TRUE means input is coming from startup file. -bool input_from_startup_file = false; - // Keep track of symbol table information when parsing functions. symtab_context parser_symtab_context; @@ -238,14 +232,14 @@ // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token FCN SCRIPT_FILE FUNCTION_FILE CLASSDEF +%token FCN INPUT_FILE CLASSDEF // %token VARARGIN VARARGOUT %token CLOSE_BRACE // Nonterminals we construct. %type stash_comment function_beg classdef_beg %type properties_beg methods_beg events_beg enum_beg -%type sep_no_nl opt_sep_no_nl sep opt_sep opt_comma +%type sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep opt_comma %type input %type string constant magic_colon %type anon_fcn_handle @@ -267,8 +261,7 @@ %type superclasses opt_superclasses %type command select_command loop_command %type jump_command except_command function -%type script_file classdef -%type function_file function_list +%type file classdef %type if_command %type elseif_clause else_clause %type if_cmd_list1 if_cmd_list @@ -329,8 +322,6 @@ promptflag = 1; YYACCEPT; } - | function_file - { YYACCEPT; } | simple_list parse_error { ABORT_PARSE; } | parse_error @@ -761,7 +752,7 @@ { $$ = $1; } | function { $$ = $1; } - | script_file + | file { $$ = $1; } | classdef { $$ = $1; } @@ -844,7 +835,7 @@ if_cmd_list1 : expression opt_sep opt_list { - $1->mark_braindead_shortcircuit (curr_fcn_file_full_name); + $1->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name); $$ = curr_parser.start_if_command ($1, $3); } @@ -857,7 +848,7 @@ elseif_clause : ELSEIF stash_comment opt_sep expression opt_sep opt_list { - $4->mark_braindead_shortcircuit (curr_fcn_file_full_name); + $4->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name); $$ = curr_parser.make_elseif_clause ($1, $4, $6, $2); } @@ -916,7 +907,7 @@ loop_command : WHILE stash_comment expression opt_sep opt_list END { - $3->mark_braindead_shortcircuit (curr_fcn_file_full_name); + $3->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name); if (! ($$ = curr_parser.make_while_command ($1, $3, $5, $6, $2))) ABORT_PARSE; @@ -1013,11 +1004,13 @@ curr_parser.function_scopes.push_back (symbol_table::current_scope ()); - if (! curr_lexer->reading_script_file && curr_parser.curr_fcn_depth == 1 + if (! curr_lexer->reading_script_file + && curr_parser.curr_fcn_depth == 1 && ! curr_parser.parsing_subfunctions) curr_parser.primary_fcn_scope = symbol_table::current_scope (); - if (curr_lexer->reading_script_file && curr_parser.curr_fcn_depth > 1) + if (curr_lexer->reading_script_file + && curr_parser.curr_fcn_depth > 1) curr_parser.bison_error ("nested functions not implemented in this context"); } ; @@ -1117,35 +1110,26 @@ } ; -// =========== -// Script file -// =========== - -script_file : SCRIPT_FILE opt_list END_OF_INPUT +// ======================= +// Script or function file +// ======================= + +file : INPUT_FILE opt_nl opt_list END_OF_INPUT { - tree_statement *end_of_script - = curr_parser.make_end ("endscript", - curr_lexer->input_line_number, - curr_lexer->current_input_column); - - curr_parser.make_script ($2, end_of_script); + if (! curr_lexer->reading_fcn_file) + { + tree_statement *end_of_script + = curr_parser.make_end ("endscript", + curr_lexer->input_line_number, + curr_lexer->current_input_column); + + curr_parser.make_script ($3, end_of_script); + } $$ = 0; } ; -// ============= -// Function file -// ============= - -function_file : FUNCTION_FILE function_list opt_sep END_OF_INPUT - { $$ = 0; } - ; - -function_list : function - | function_list sep function - ; - // =================== // Function definition // =================== @@ -1153,8 +1137,8 @@ function_beg : push_fcn_symtab FCN stash_comment { $$ = $3; - - if (curr_lexer->reading_classdef_file || curr_lexer->parsing_classdef) + if (curr_lexer->reading_classdef_file + || curr_lexer->parsing_classdef) curr_lexer->maybe_classdef_get_set_method = true; } ; @@ -1441,6 +1425,18 @@ { $$ = $1; } ; +opt_nl : // empty + { $$ = 0; } + | nl + { $$ = $1; } + ; + +nl : '\n' + { $$ = '\n'; } + | nl '\n' + { $$ = $1; } + ; + sep : ',' { $$ = ','; } | ';' @@ -1667,7 +1663,7 @@ if (expr->is_assignment_expression () && expr->paren_count () < 2) { - if (curr_fcn_file_full_name.empty ()) + if (curr_lexer->fcn_file_full_name.empty ()) warning_with_id ("Octave:assign-as-truth-value", "suggest parenthesis around assignment used as truth value"); @@ -1675,7 +1671,7 @@ warning_with_id ("Octave:assign-as-truth-value", "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'", - expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); + expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ()); } } @@ -1686,14 +1682,14 @@ { if (! expr->is_constant ()) { - if (curr_fcn_file_full_name.empty ()) + if (curr_lexer->fcn_file_full_name.empty ()) warning_with_id ("Octave:variable-switch-label", "variable switch label"); else warning_with_id ("Octave:variable-switch-label", "variable switch label near line %d, column %d in file '%s'", - expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); + expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ()); } } @@ -1955,7 +1951,7 @@ = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); // FIXME: Stash the filename. This does not work and produces // errors when executed. - //retval->stash_file_name (curr_fcn_file_name); + //retval->stash_file_name (curr_lexer->fcn_file_name); return retval; } @@ -2579,22 +2575,17 @@ octave_parser::make_script (tree_statement_list *cmds, tree_statement *end_script) { - std::string doc_string; - - if (! help_buf.empty ()) - { - doc_string = help_buf.top (); - help_buf.pop (); - } - if (! cmds) cmds = new tree_statement_list (); cmds->append (end_script); octave_user_script *script - = new octave_user_script (curr_fcn_file_full_name, curr_fcn_file_name, - cmds, doc_string); + = new octave_user_script (curr_lexer->fcn_file_full_name, + curr_lexer->fcn_file_name, + cmds, curr_lexer->help_text); + + curr_lexer->help_text = ""; octave_time now; @@ -2657,23 +2648,23 @@ if (! autoloading && curr_lexer->reading_fcn_file && curr_fcn_depth == 1 && ! parsing_subfunctions) { - // FIXME -- should curr_fcn_file_name already be + // FIXME -- should curr_lexer->fcn_file_name already be // preprocessed when we get here? It seems to only be a // problem with relative file names. - std::string nm = curr_fcn_file_name; + std::string nm = curr_lexer->fcn_file_name; size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); if (pos != std::string::npos) - nm = curr_fcn_file_name.substr (pos+1); + nm = curr_lexer->fcn_file_name.substr (pos+1); if (nm != id_name) { warning_with_id ("Octave:function-name-clash", "function name '%s' does not agree with function file name '%s'", - id_name.c_str (), curr_fcn_file_full_name.c_str ()); + id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ()); id_name = nm; } @@ -2683,7 +2674,7 @@ { octave_time now; - fcn->stash_fcn_file_name (curr_fcn_file_full_name); + fcn->stash_fcn_file_name (curr_lexer->fcn_file_full_name); fcn->stash_fcn_file_time (now); fcn->mark_as_system_fcn_file (); @@ -2692,7 +2683,7 @@ if (curr_fcn_depth > 1 || parsing_subfunctions) { - fcn->stash_parent_fcn_name (curr_fcn_file_name); + fcn->stash_parent_fcn_name (curr_lexer->fcn_file_name); if (curr_fcn_depth > 1) fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]); @@ -2718,24 +2709,25 @@ warning_with_id ("Octave:future-time-stamp", "time stamp for '%s' is in the future", nm.c_str ()); } - else if (! (input_from_tmp_history_file || input_from_startup_file) + else if (! input_from_tmp_history_file + && ! curr_lexer->force_script && curr_lexer->reading_script_file - && curr_fcn_file_name == id_name) + && curr_lexer->fcn_file_name == id_name) { warning ("function '%s' defined within script file '%s'", - id_name.c_str (), curr_fcn_file_full_name.c_str ()); + id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ()); } fcn->stash_function_name (id_name); fcn->stash_fcn_location (curr_lexer->input_line_number, curr_lexer->current_input_column); - if (! help_buf.empty () && curr_fcn_depth == 1 + if (! curr_lexer->help_text.empty () && curr_fcn_depth == 1 && ! parsing_subfunctions) { - fcn->document (help_buf.top ()); - - help_buf.pop (); + fcn->document (curr_lexer->help_text); + + curr_lexer->help_text = ""; } if (curr_lexer->reading_fcn_file && curr_fcn_depth == 1 @@ -2947,7 +2939,7 @@ { if (curr_lexer->reading_script_file) warning ("ignoring persistent declaration near line %d of file '%s'", - l, curr_fcn_file_full_name.c_str ()); + l, curr_lexer->fcn_file_full_name.c_str ()); else warning ("ignoring persistent declaration near line %d", l); } @@ -3032,7 +3024,7 @@ warning_with_id ("Octave:missing-semicolon", "missing semicolon near line %d, column %d in file '%s'", - tmp->line (), tmp->column (), curr_fcn_file_full_name.c_str ()); + tmp->line (), tmp->column (), curr_lexer->fcn_file_full_name.c_str ()); } } @@ -3100,7 +3092,7 @@ if (curr_lexer->reading_fcn_file || curr_lexer->reading_script_file || curr_lexer->reading_classdef_file) output_buf << "parse error near line " << curr_lexer->input_line_number - << " of file " << curr_fcn_file_full_name; + << " of file " << curr_lexer->fcn_file_full_name; else output_buf << "parse error:"; @@ -3152,216 +3144,9 @@ fclose (static_cast (f)); } -static bool -looks_like_copyright (const std::string& s) -{ - bool retval = false; - - if (! s.empty ()) - { - size_t offset = s.find_first_not_of (" \t"); - - retval = (s.substr (offset, 9) == "Copyright" || s.substr (offset, 6) == "Author"); - } - - return retval; -} - -static int -text_getc (FILE *f) -{ - int c = gnulib::getc (f); - - // Convert CRLF into just LF and single CR into LF. - - if (c == '\r') - { - c = gnulib::getc (f); - - if (c != '\n') - { - ungetc (c, f); - c = '\n'; - } - } - - return c; -} - -class -stdio_stream_reader : public stream_reader -{ -public: - - stdio_stream_reader (FILE *f_arg, int& l, int& c) - : stream_reader (), f (f_arg), line_num (l), column_num (c) - { } - - int getc (void) - { - char c = ::text_getc (f); - - if (c == '\n') - { - line_num++; - column_num = 0; - } - else - { - // FIXME -- try to be smarter about tabs? - column_num++; - } - - return c; - } - - int ungetc (int c) - { - if (c == '\n') - { - line_num--; - column_num = 0; - } - else - { - // FIXME -- try to be smarter about tabs? - column_num--; - } - - return ::ungetc (c, f); - } - -private: - - FILE *f; - - int& line_num; - - int& column_num; - - // No copying! - - stdio_stream_reader (const stdio_stream_reader&); - - stdio_stream_reader & operator = (const stdio_stream_reader&); -}; - -static bool -skip_white_space (stream_reader& reader) -{ - int c = 0; - - while ((c = reader.getc ()) != EOF) - { - switch (c) - { - case ' ': - case '\t': - case '\n': - break; - - default: - reader.ungetc (c); - goto done; - } - } - - done: - - return (c == EOF); -} - -static bool -looking_at_classdef_keyword (FILE *ffile) -{ - bool status = false; - - long pos = gnulib::ftell (ffile); - - char buf [10]; - gnulib::fgets (buf, 10, ffile); - size_t len = strlen (buf); - if (len > 8 && strncmp (buf, "classdef", 8) == 0 - && ! (isalnum (buf[8]) || buf[8] == '_')) - status = true; - - gnulib::fseek (ffile, pos, SEEK_SET); - - return status; - } - -static std::string -gobble_leading_white_space (FILE *ffile, bool& eof, int& line_num, - int& column_num) -{ - std::string help_txt; - - eof = false; - - // TRUE means we have already cached the help text. - bool have_help_text = false; - - std::string txt; - - stdio_stream_reader stdio_reader (ffile, line_num, column_num); - - while (true) - { - eof = skip_white_space (stdio_reader); - - if (eof) - break; - - txt = CURR_LEXER->grab_comment_block (stdio_reader, true, eof); - - if (txt.empty ()) - break; - - if (! (have_help_text || looks_like_copyright (txt))) - { - help_txt = txt; - have_help_text = true; - } - - octave_comment_buffer::append (txt); - - if (eof) - break; - } - - return help_txt; -} - -static std::string -gobble_leading_white_space (FILE *ffile, bool& eof) -{ - int line_num = 1; - int column_num = 1; - - return gobble_leading_white_space (ffile, eof, line_num, column_num); -} - -static bool -looking_at_function_keyword (FILE *ffile) -{ - bool status = false; - - long pos = gnulib::ftell (ffile); - - char buf [10]; - gnulib::fgets (buf, 10, ffile); - size_t len = strlen (buf); - if (len > 8 && strncmp (buf, "function", 8) == 0 - && ! (isalnum (buf[8]) || buf[8] == '_')) - status = true; - - gnulib::fseek (ffile, pos, SEEK_SET); - - return status; -} - static octave_function * -parse_fcn_file (const std::string& ff, const std::string& dispatch_type, +parse_fcn_file (const std::string& full_file, const std::string& file, + const std::string& dispatch_type, bool require_file, bool force_script, bool autoload, bool relative_lookup, const std::string& warn_for) { @@ -3386,8 +3171,8 @@ FILE *ffile = 0; - if (! ff.empty ()) - ffile = gnulib::fopen (ff.c_str (), "rb"); + if (! full_file.empty ()) + ffile = gnulib::fopen (full_file.c_str (), "rb"); frame.add_fcn (safe_fclose, ffile); @@ -3400,137 +3185,75 @@ octave_parser curr_parser (ffile); - curr_parser.curr_lexer->reading_fcn_file = true; - curr_parser.curr_class_name = dispatch_type; curr_parser.autoloading = autoload; curr_parser.fcn_file_from_relative_lookup = relative_lookup; - std::string help_txt - = gobble_leading_white_space - (ffile, eof, - curr_parser.curr_lexer->input_line_number, - curr_parser.curr_lexer->current_input_column); - - if (! help_txt.empty ()) - help_buf.push (help_txt); - - if (! eof) - { - std::string file_type; - - frame.protect_var (Vecho_executing_commands); - - Vecho_executing_commands = ECHO_OFF; - - if (! force_script && looking_at_function_keyword (ffile)) - { - file_type = "function"; - } - else - { - curr_parser.curr_lexer->reading_fcn_file = false; - - if (! force_script && looking_at_classdef_keyword (ffile)) - { - file_type = "classdef"; - - curr_parser.curr_lexer->reading_classdef_file = true; - - // FIXME -- Should classdef files be handled as - // scripts or separately? Currently, without - // setting up for reading script files, parsing - // classdef files fails. - curr_parser.curr_lexer->reading_script_file = true; - } - else - { - file_type = "script"; - - curr_parser.curr_lexer->reading_script_file = true; - } - } - - // Do this with an unwind-protect cleanup function so that - // the forced variables will be unmarked in the event of an - // interrupt. - symbol_table::scope_id scope = symbol_table::top_scope (); - frame.add_fcn (symbol_table::unmark_forced_variables, scope); - - if (! help_txt.empty ()) - help_buf.push (help_txt); - - if (curr_parser.curr_lexer->reading_script_file) - curr_parser.curr_lexer->prep_for_script_file (); - else - curr_parser.curr_lexer->prep_for_function_file (); - - curr_parser.curr_lexer->parsing_class_method = ! dispatch_type.empty (); - - int status = curr_parser.run (); - - fcn_ptr = curr_parser.primary_fcn_ptr; - - if (status != 0) - error ("parse error while reading %s file %s", - file_type.c_str (), ff.c_str ()); - } - else - { - int l = curr_parser.curr_lexer->input_line_number; - int c = curr_parser.curr_lexer->current_input_column; - - tree_statement *end_of_script - = curr_parser.make_end ("endscript", l, c); - - curr_parser.make_script (0, end_of_script); - - fcn_ptr = curr_parser.primary_fcn_ptr; - } + // Do this with an unwind-protect cleanup function so that + // the forced variables will be unmarked in the event of an + // interrupt. + symbol_table::scope_id scope = symbol_table::top_scope (); + frame.add_fcn (symbol_table::unmark_forced_variables, scope); + + curr_parser.curr_lexer->force_script = force_script; + curr_parser.curr_lexer->prep_for_file (); + curr_parser.curr_lexer->parsing_class_method = ! dispatch_type.empty (); + + curr_parser.curr_lexer->fcn_file_name = file; + curr_parser.curr_lexer->fcn_file_full_name = full_file; + + int status = curr_parser.run (); + + fcn_ptr = curr_parser.primary_fcn_ptr; + + if (status != 0) + error ("parse error while reading file %s", full_file.c_str ()); } else if (require_file) - error ("no such file, '%s'", ff.c_str ()); + error ("no such file, '%s'", full_file.c_str ()); else if (! warn_for.empty ()) - error ("%s: unable to open file '%s'", warn_for.c_str (), ff.c_str ()); + error ("%s: unable to open file '%s'", warn_for.c_str (), + full_file.c_str ()); return fcn_ptr; } std::string get_help_from_file (const std::string& nm, bool& symbol_found, - std::string& file) + std::string& full_file) { std::string retval; - file = fcn_file_in_path (nm); + full_file = fcn_file_in_path (nm); + + std::string file = full_file; + + size_t file_len = file.length (); + + if ((file_len > 4 && file.substr (file_len-4) == ".oct") + || (file_len > 4 && file.substr (file_len-4) == ".mex") + || (file_len > 2 && file.substr (file_len-2) == ".m")) + { + file = octave_env::base_pathname (file); + file = file.substr (0, file.find_last_of ('.')); + + size_t pos = file.find_last_of (file_ops::dir_sep_str ()); + if (pos != std::string::npos) + file = file.substr (pos+1); + } if (! file.empty ()) { symbol_found = true; - FILE *fptr = gnulib::fopen (file.c_str (), "r"); - - if (fptr) + octave_function *fcn + = parse_fcn_file (full_file, file, "", true, false, false, false, ""); + + if (fcn) { - unwind_protect frame; - frame.add_fcn (safe_fclose, fptr); - - bool eof; - retval = gobble_leading_white_space (fptr, eof); - - if (retval.empty ()) - { - octave_function *fcn = parse_fcn_file (file, "", true, - false, false, - false, ""); - - if (fcn) - { - retval = fcn->doc_string (); - - delete fcn; - } - } + retval = fcn->doc_string (); + + delete fcn; } } @@ -3633,14 +3356,9 @@ { // Temporarily load m-file version of mex-file, if it exists, // to get the help-string to use. - frame.protect_var (curr_fcn_file_name); - frame.protect_var (curr_fcn_file_full_name); - - curr_fcn_file_name = nm; - curr_fcn_file_full_name = file.substr (0, len - 2); octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2), - dispatch_type, false, + nm, dispatch_type, false, autoload, autoload, relative_lookup, ""); @@ -3652,15 +3370,7 @@ } else if (len > 2) { - // These are needed by yyparse. - - frame.protect_var (curr_fcn_file_name); - frame.protect_var (curr_fcn_file_full_name); - - curr_fcn_file_name = nm; - curr_fcn_file_full_name = file; - - retval = parse_fcn_file (file, dispatch_type, true, autoload, + retval = parse_fcn_file (file, nm, dispatch_type, true, autoload, autoload, relative_lookup, ""); } @@ -3830,12 +3540,6 @@ unwind_protect frame; - frame.protect_var (curr_fcn_file_name); - frame.protect_var (curr_fcn_file_full_name); - - curr_fcn_file_name = file_name; - curr_fcn_file_full_name = file_full_name; - if (source_call_depth.find (file_full_name) == source_call_depth.end ()) source_call_depth[file_full_name] = -1; @@ -3864,9 +3568,9 @@ if (! error_state) { - octave_function *fcn = parse_fcn_file (file_full_name, "", - require_file, true, false, - false, warn_for); + octave_function *fcn = parse_fcn_file (file_full_name, file_name, + "", require_file, true, + false, false, warn_for); if (! error_state) { diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/parse.h Wed Mar 06 14:36:19 2013 -0500 @@ -70,18 +70,12 @@ // Nonzero means print parser debugging info (-d). extern int octave_debug; -// Buffer for help text snagged from function files. -extern std::stack help_buf; - // TRUE means we are using readline. extern bool line_editing; // TRUE means we printed messages about reading startup files. extern bool reading_startup_message_printed; -// TRUE means input is coming from startup file. -extern bool input_from_startup_file; - extern OCTINTERP_API std::string get_help_from_file (const std::string& nm, bool& symbol_found, std::string& file); diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/pt-check.cc --- a/libinterp/parse-tree/pt-check.cc Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/pt-check.cc Wed Mar 06 14:36:19 2013 -0500 @@ -554,8 +554,8 @@ void tree_checker::gripe (const std::string& msg, int line) { - if (curr_fcn_file_name.empty ()) + if (file_name.empty ()) error ("%s", msg.c_str ()); else - error ("%s: %d: %s", curr_fcn_file_name.c_str (), line, msg.c_str ()); + error ("%s: %d: %s", file_name.c_str (), line, msg.c_str ()); } diff -r 7ce484126bb2 -r 127cccb037bf libinterp/parse-tree/pt-check.h --- a/libinterp/parse-tree/pt-check.h Wed Mar 06 11:29:44 2013 -0800 +++ b/libinterp/parse-tree/pt-check.h Wed Mar 06 14:36:19 2013 -0500 @@ -35,7 +35,7 @@ public: tree_checker (void) - : do_lvalue_check (false) { } + : do_lvalue_check (false), file_name () { } ~tree_checker (void) { } @@ -125,6 +125,8 @@ bool do_lvalue_check; + std::string file_name; + void do_decl_command (tree_decl_command&); void gripe (const std::string& msg, int line);