octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [changeset] parsing nested functions


From: David Grundberg
Subject: Re: [changeset] parsing nested functions
Date: Thu, 30 Jul 2009 11:56:37 +0200
User-agent: Thunderbird 2.0.0.22 (Windows/20090605)

John W. Eaton skrev:
On 29-Jul-2009, David Grundberg wrote:

| Hi all,
| | I've modified the parser to be able to properly parse nested functions. | So now a function body can contain nested functions anywhere, and not | just in the beginning. The nested function still work like subfunctions | to the primary function though, regardless where they are declared (or | in which depth). This changeset adds a warning message if any nested | function has been declared. Since they work as subfunctions, I thought | it reasonable. | | An error is raised if the functionends are incorrectly balanced. If one | function is explicitly ended, so must all the others. | | One mayor syntax change is that eval_string will require all function to | be explicitly ended. I removed the condition in the action of | function_end that allowed implicit ends (at END_OF_INPUT). Since Matlab | do not allow function declarations in eval strings, I think Octave could | be stricter. | | The parser now have a special way of parsing function files, and | statements are not allowed outside first-level functions. | | As I worked on this, I removed some intelligence from the lexer and | moved them into the parser. I also removed the parent_scope property | from the symbol table, since I couldn't find it used anywhere else than | in the parser.

Thanks for looking at this.  I'd like to apply it, but before I do,
can you look at the following problem?

If I have a file containing

  # This is a doc string

  function fcn ()
    if (nargin == 0)
      sub ();
    else
      print_usage ();
    endif

  function sub ()
    printf ("foobar:sub!\n");

and call it with

  fcn ()

it works, but if I call it with

  fcn (1)

I see

  error: print_usage: `fcn' is not documented

Instead of this message, I expect to get the usual print_usage help
text and the doc string for fcn.  If I change the function file to be


  # This is a doc string

  function fcn ()
    if (nargin == 0)
      sub ();
    else
      print_usage ();
    endif
  end

  function sub ()
    printf ("foobar:sub!\n");
  end

then it works as expected, but I think these two cases should be
equivalent (and need to be, for compatibility with Matlab).

I haven't tried to debug this yet, but it seems that the doc string is
somehow not attached to the main function when the structure is
rearranged when no endfunction tokens are found.  Can you take a look
and see if this is easy to fix?

Thanks,

jwe
The current diff is getting quite large so I'd rather work on the help bug in a separate changeset. All code involving help_buf was malfunctioning, and I think the changes needed would be rather involved.

I modified my previous changeset to make it store help text for the primary function. The examples you provided then works identically and the tests in strfind also passes. I also added a shameless copyright statement in parse.y. The new changeset is attached to this mail.

Regards,
David
# HG changeset patch
# User David Grundberg <address@hidden>
# Date 1248946383 -7200
# Node ID dc63b0e47a656c20ed55c9e367397b9cd996e720
# Parent  303f862a896de094060df5a90f3e57ec5cff798c
Parse nested functions more accurately.

diff -r 303f862a896d -r dc63b0e47a65 src/ChangeLog
--- a/src/ChangeLog     Wed Jul 29 19:36:22 2009 -0400
+++ b/src/ChangeLog     Thu Jul 30 11:33:03 2009 +0200
@@ -1,3 +1,48 @@
+2009-07-30  David Grundberg  <address@hidden>
+
+       * symtab.h (symbol_table::parent_scope): Remove.
+       (symbol_table::set_parent_scope): Remove.
+       (symbol_table::reset_parent_scope): Remove.
+       (symbol_table::install_subfunction): Require scope parameter
+       instead of xparent_scope default.
+       * symtab.cc: Remove symbol_table::xparent_scope
+       * lex.h (lexical_feedback::parsing_nested_function): Remove.
+       * lex.l (is_keyword_token): Don't ignore endfunctions.
+       (prep_lexer_for_script_file): Renamed from prep_lexer_for_script.
+       (prep_lexer_for_function_file): New function.
+       (display_token): Display SCRIPT_FILE and FUNCTION_FILE.
+       (display_state): Display FUNCTION_FILE_BEGIN
+       (FUNCTION_FILE_BEGIN): New state.
+       (NESTED_FUNCTION_END, NESTED_FUNCTION_BEGIN): Remove states.
+       (prep_for_function, prep_for_nested_function): Remove functions.
+       * parse.h: Remove extern declaration parent_function_name,
+       end_tokens_expected.
+       * parse.y: Add variables current_function_depth,
+       max_function_depth, parsing_subfunctions, seen_endfunction. Remove
+       parent_function_name. Rename curr_fcn_ptr to primary_fcn_ptr. Add
+       token FUNCTION_FILE. Rename token SCRIPT to SCRIPT_FILE.
+       (function_file): New rule.
+       (input): Accept function_file.
+       (script_file): Rule renamed from script.
+       (function_file): New rule.
+       (function_list): New rule.
+       (push_fcn_symtab): Parse nested functions.
+       (fcn_name): Remove parent_function_name.
+       (function_end): Use seen_endfunction. New error messages.
+       (make_script): Use primary_fcn_ptr.
+       (frob_function): Simplify control structures. Don't use
+       symbol_table::parent_scope.
+       (push_fcn_symtab, function_end, frob_function, finish_function):
+       Use current_function_depth instead of
+       lexical_feedback::parsing_nested_function.
+       (make_return_command): Use current_function_depth instead of
+       lexical_feedback::defining_func.
+       (make_break_command, make_decl_command, maybe_warn_missing_semi):
+       Ditto
+       (parse_fcn_file): Warn when nested functions have been
+       declared. Remove superfluous local variables. Parse function files
+       using function_file rule.
+
 2009-07-29  John W. Eaton  <address@hidden>
 
        * parse.y (param_list_end): Also set
diff -r 303f862a896d -r dc63b0e47a65 src/lex.h
--- a/src/lex.h Wed Jul 29 19:36:22 2009 -0400
+++ b/src/lex.h Thu Jul 30 11:33:03 2009 +0200
@@ -46,7 +46,8 @@
 // Is the given string a keyword?
 extern bool is_keyword (const std::string& s);
 
-extern void prep_lexer_for_script (void);
+extern void prep_lexer_for_script_file (void);
+extern void prep_lexer_for_function_file (void);
 
 // For communication between the lexer and parser.
 
@@ -117,14 +118,8 @@
   bool looking_at_indirect_ref;
 
   // TRUE means that we've already seen the name of this function.
-  // Should only matter if defining_func is also TRUE.
+  // Should only matter if current_function_level > 0
   bool parsed_function_name;
-
-  // Are we parsing a nested function?
-  //   1 ==> Yes.
-  //   0 ==> No.
-  //  -1 ==> Yes, but it is the last one because we have seen EOF.
-  int parsing_nested_function;
 
   // TRUE means we are parsing a class method.
   bool parsing_class_method;
diff -r 303f862a896d -r dc63b0e47a65 src/lex.l
--- a/src/lex.l Wed Jul 29 19:36:22 2009 -0400
+++ b/src/lex.l Thu Jul 30 11:33:03 2009 +0200
@@ -28,9 +28,7 @@
 %s MATRIX_START
 
 %x SCRIPT_FILE_BEGIN
-
-%x NESTED_FUNCTION_END
-%x NESTED_FUNCTION_BEGIN
+%x FUNCTION_FILE_BEGIN
 
 %{
 #ifdef HAVE_CONFIG_H
@@ -282,8 +280,6 @@
 static void fixup_column_count (char *s);
 static void do_comma_insert_check (void);
 static int is_keyword_token (const std::string& s);
-static void prep_for_function (void);
-static void prep_for_nested_function (void);
 static int process_comment (bool start_in_block, bool& eof);
 static bool match_any (char c, const char *s);
 static bool next_token_is_sep_op (void);
@@ -329,34 +325,25 @@
 NUMBER (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+))
 %%
 
+%{
+// Make script and function files start with a bogus token. This makes
+// the parser go down a special path.
+%}
+
 <SCRIPT_FILE_BEGIN>. {
     LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>.");
 
     BEGIN (INITIAL);
     xunput (yytext[0], yytext);
-    COUNT_TOK_AND_RETURN (SCRIPT);
+    COUNT_TOK_AND_RETURN (SCRIPT_FILE);
   }
 
-<NESTED_FUNCTION_END>. {
-    LEXER_DEBUG ("<NESTED_FUNCTION_END>.");
-
-    BEGIN (NESTED_FUNCTION_BEGIN);
-    xunput (yytext[0], yytext);
-
-    lexer_flags.at_beginning_of_statement = true;
-
-    COUNT_TOK_AND_RETURN (';');
-  }
-
-<NESTED_FUNCTION_BEGIN>. {
-    LEXER_DEBUG ("<NESTED_FUNCTION_BEGIN>.");
+<FUNCTION_FILE_BEGIN>. {
+    LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>.");
 
     BEGIN (INITIAL);
     xunput (yytext[0], yytext);
-
-    prep_for_nested_function ();
-
-    COUNT_TOK_AND_RETURN (FCN);
+    COUNT_TOK_AND_RETURN (FUNCTION_FILE);
   }
 
 %{
@@ -1004,8 +991,6 @@
 . {
     LEXER_DEBUG (".");
 
-    // EOF happens here if we are parsing nested functions.
-
     xunput (yytext[0], yytext);
 
     int c = text_yyinput ();
@@ -1058,12 +1043,9 @@
   BEGIN (INITIAL);
 
   parser_end_of_input = false;
-  end_tokens_expected = 0;
 
   while (! symtab_context.empty ())
     symtab_context.pop ();
-
-  symbol_table::reset_parent_scope ();
 
   // We do want a prompt by default.
   promptflag = 1;
@@ -1381,32 +1363,6 @@
   delete_buffer (static_cast<YY_BUFFER_STATE> (buf));
 }
 
-static void
-prep_for_function (void)
-{
-  end_tokens_expected++;
-
-  promptflag--;
-
-  lexer_flags.defining_func = true;
-  lexer_flags.parsed_function_name = false;
-
-  if (! (reading_fcn_file || reading_script_file))
-    input_line_number = 1;
-}
-
-static void
-prep_for_nested_function (void)
-{
-  lexer_flags.parsing_nested_function = 1;
-  help_buf.push (std::string ());
-  prep_for_function ();
-  // We're still only expecting one end token for this set of functions.
-  end_tokens_expected--;
-  yylval.tok_val = new token (input_line_number, current_input_column);
-  token_stack.push (yylval.tok_val);
-}
-
 static bool
 inside_any_object_index (void)
 {
@@ -1466,71 +1422,48 @@
                  && ! (lexer_flags.looking_at_return_list
                        || lexer_flags.parsed_function_name)))
            return 0;
-         else
-           {
-             if (reading_fcn_file && end_tokens_expected == 1)
-               return -1;
-             else
-               {
-                 yylval.tok_val = new token (token::simple_end, l, c);
-                 lexer_flags.at_beginning_of_statement = true;
-                 end_tokens_expected--;
-               }
-           }
+
+         yylval.tok_val = new token (token::simple_end, l, c);
+         lexer_flags.at_beginning_of_statement = true;
          break;
 
        case end_try_catch_kw:
          yylval.tok_val = new token (token::try_catch_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case end_unwind_protect_kw:
          yylval.tok_val = new token (token::unwind_protect_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case endfor_kw:
          yylval.tok_val = new token (token::for_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case endfunction_kw:
-         {
-           if (reading_fcn_file && end_tokens_expected == 1)
-             return -1;
-           else
-             {
-               yylval.tok_val = new token (token::function_end, l, c);
-               lexer_flags.at_beginning_of_statement = true;
-               end_tokens_expected--;
-             }
-         }
+         yylval.tok_val = new token (token::function_end, l, c);
+         lexer_flags.at_beginning_of_statement = true;
          break;
 
        case endif_kw:
          yylval.tok_val = new token (token::if_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case endswitch_kw:
          yylval.tok_val = new token (token::switch_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case endwhile_kw:
          yylval.tok_val = new token (token::while_end, l, c);
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected--;
          break;
 
        case for_kw:
        case while_kw:
-         end_tokens_expected++;
          promptflag--;
          lexer_flags.looping++;
          break;
@@ -1544,57 +1477,22 @@
        case try_kw:
        case unwind_protect_kw:
          lexer_flags.at_beginning_of_statement = true;
-         end_tokens_expected++;
          promptflag--;
          break;
 
        case if_kw:
        case switch_kw:
-         end_tokens_expected++;
          promptflag--;
          break;
 
        case function_kw:
-         {
-           if (lexer_flags.defining_func)
-             {
-               if (reading_fcn_file)
-                 {
-                   if (lexer_flags.parsing_nested_function)
-                     {
-                       BEGIN (NESTED_FUNCTION_END);
+         promptflag--;
 
-                       yylval.tok_val = new token (token::function_end, l, c);
-                       token_stack.push (yylval.tok_val);
+         lexer_flags.defining_func = true;
+         lexer_flags.parsed_function_name = false;
 
-                       lexer_flags.at_beginning_of_statement = true;
-
-                       return END;
-                     }
-                   else
-                     {
-                       prep_for_nested_function ();
-
-                       return FCN;
-                     }
-                 }
-               else
-                 {
-                   error ("nested functions not implemented in this context");
-
-                   if ((reading_fcn_file || reading_script_file)
-                       && ! curr_fcn_file_name.empty ())
-                     error ("near line %d of file `%s.m'",
-                            input_line_number, curr_fcn_file_name.c_str ());
-                   else
-                     error ("near line %d", input_line_number);
-
-                   return LEXICAL_ERROR;
-                 }
-             }
-           else
-             prep_for_function ();
-         }
+         if (! (reading_fcn_file || reading_script_file))
+           input_line_number = 1;
          break;
 
         case magic_file_kw:
@@ -3254,7 +3152,6 @@
   // Not initially defining a function.
   defining_func = false;
   parsed_function_name = false;
-  parsing_nested_function = 0;
   parsing_class_method = false;
 
   // Not initiallly looking at a function handle.
@@ -3341,9 +3238,15 @@
 }
 
 void
-prep_lexer_for_script (void)
+prep_lexer_for_script_file (void)
 {
   BEGIN (SCRIPT_FILE_BEGIN);
+}
+
+void
+prep_lexer_for_function_file (void)
+{
+  BEGIN (FUNCTION_FILE_BEGIN);
 }
 
 static void
@@ -3495,6 +3398,8 @@
     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 '\n': std::cerr << "\\n\n"; break;
     case '\r': std::cerr << "\\r\n"; break;
     case '\t': std::cerr << "TAB\n"; break;
@@ -3532,12 +3437,8 @@
       std::cerr << "SCRIPT_FILE_BEGIN" << std::endl;
       break;
 
-    case NESTED_FUNCTION_END:
-      std::cerr << "NESTED_FUNCTION_END" << std::endl;
-      break;
-
-    case NESTED_FUNCTION_BEGIN:
-      std::cerr << "NESTED_FUNCTION_BEGIN" << std::endl;
+    case FUNCTION_FILE_BEGIN:
+      std::cerr << "FUNCTION_FILE_BEGIN" << std::endl;
       break;
 
     default:
diff -r 303f862a896d -r dc63b0e47a65 src/parse.h
--- a/src/parse.h       Wed Jul 29 19:36:22 2009 -0400
+++ b/src/parse.h       Thu Jul 30 11:33:03 2009 +0200
@@ -65,16 +65,9 @@
 // Keep track of symbol table information when parsing functions.
 extern std::stack<symbol_table::scope_id> symtab_context;
 
-// Name of parent function when parsing function files that might
-// contain nested functions.
-extern std::string parent_function_name;
-
 // Name of the current class when we are parsing class methods or
 // constructors.
 extern std::string current_class_name;
-
-// Keep a count of how many END tokens we expect.
-extern int end_tokens_expected;
 
 extern OCTINTERP_API std::string
 get_help_from_file (const std::string& nm, bool& symbol_found,
diff -r 303f862a896d -r dc63b0e47a65 src/parse.y
--- a/src/parse.y       Wed Jul 29 19:36:22 2009 -0400
+++ b/src/parse.y       Thu Jul 30 11:33:03 2009 +0200
@@ -2,6 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
               2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009  John W. Eaton
+Copyright (C) 2009 David Grundberg
 
 This file is part of Octave.
 
@@ -100,15 +101,26 @@
 // TRUE means input is coming from startup file.
 bool input_from_startup_file = false;
 
-// Keep a count of how many END tokens we expect.
-int end_tokens_expected = 0;
+// = 0 currently outside any function.
+// = 1 inside the primary function or a subfunction.
+// > 1 means we are looking at a function definition that seems to be
+//     inside a function. Note that the function still might not be a
+//     nested function.
+int current_function_depth = 0;
+
+// Maximum function depth detected. Just here to determine whether
+// we have nested functions or just implicitly ended subfunctions.
+int max_function_depth = 0;
+
+// FALSE if we are still at the primary function. Subfunctions can
+// only be declared inside function files.
+int parsing_subfunctions = false;
+
+// Have we found an explicit end to a function?
+bool seen_endfunction = false;
 
 // Keep track of symbol table information when parsing functions.
 std::stack<symbol_table::scope_id> symtab_context;
-
-// Name of parent function when parsing function files that might
-// contain nested functions.
-std::string parent_function_name;
 
 // Name of the current class when we are parsing class methods or
 // constructors.
@@ -121,9 +133,12 @@
 // element.
 static bool fcn_file_from_relative_lookup = false;
 
-// If nonzero, this is a pointer to the function we just finished
-// parsing.
-static octave_function *curr_fcn_ptr = 0;
+// Pointer to the primary user function or user script function.
+static octave_function *primary_fcn_ptr = 0;
+
+// Scope where we install all subfunctions and nested functions. Only
+// used while reading function files.
+static symbol_table::scope_id primary_fcn_scope;
 
 // List of autoloads (function -> file mapping).
 static std::map<std::string, std::string> autoload_map;
@@ -424,7 +439,7 @@
 
 // Other tokens.
 %token END_OF_INPUT LEXICAL_ERROR
-%token FCN SCRIPT
+%token FCN SCRIPT_FILE FUNCTION_FILE
 // %token VARARGIN VARARGOUT
 %token CLOSE_BRACE
 
@@ -449,7 +464,8 @@
 %type <tree_parameter_list_type> param_list param_list1 param_list2
 %type <tree_parameter_list_type> return_list return_list1
 %type <tree_command_type> command select_command loop_command
-%type <tree_command_type> jump_command except_command function script
+%type <tree_command_type> jump_command except_command function script_file
+%type <tree_command_type> function_file function_list
 %type <tree_if_command_type> if_command
 %type <tree_if_clause_type> elseif_clause else_clause
 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
@@ -492,6 +508,10 @@
                  {
                    global_command = $1;
                    promptflag = 1;
+                   YYACCEPT;
+                 }
+               | function_file
+                 {
                    YYACCEPT;
                  }
                | simple_list parse_error
@@ -903,7 +923,7 @@
                  { $$ = $1; }
                | function
                  { $$ = $1; }
-               | script
+               | script_file
                  { $$ = $1; }
                ;
 
@@ -1112,11 +1132,21 @@
 
 push_fcn_symtab        : // empty
                  {
+                   current_function_depth++;
+
+                   if (max_function_depth < current_function_depth)
+                     max_function_depth = current_function_depth;
+
                    symtab_context.push (symbol_table::current_scope ());
                    symbol_table::set_scope (symbol_table::alloc_scope ());
 
-                   if (! lexer_flags.parsing_nested_function)
-                     symbol_table::set_parent_scope 
(symbol_table::current_scope ());
+                   if (! reading_script_file
+                       && current_function_depth == 1
+                       && ! parsing_subfunctions)
+                     primary_fcn_scope = symbol_table::current_scope ();
+
+                   if (reading_script_file && current_function_depth > 1)
+                     yyerror ("nested functions not implemented in this 
context");
                  }
                ;
 
@@ -1218,7 +1248,7 @@
 // Script file
 // ===========
 
-script         : SCRIPT opt_list END_OF_INPUT
+script_file    : SCRIPT_FILE opt_list END_OF_INPUT
                  {
                    tree_statement *end_of_script
                      = make_end ("endscript", input_line_number,
@@ -1230,6 +1260,23 @@
                  }
                ;
 
+// =============
+// Function file
+// =============
+
+function_file   : FUNCTION_FILE function_list opt_sep END_OF_INPUT
+                 {
+                 }
+               ;
+
+function_list   : function
+                 {
+                 }
+               | function_list sep function
+                 {
+                 }
+               ;
+
 // ===================
 // Function definition
 // ===================
@@ -1254,12 +1301,8 @@
                  {
                    std::string id_name = $1->name ();
 
-                   if (reading_fcn_file
-                       && ! lexer_flags.parsing_nested_function)
-                     parent_function_name = (curr_fcn_file_name == id_name)
-                       ? id_name : curr_fcn_file_name;
-
                    lexer_flags.parsed_function_name = true;
+                   lexer_flags.defining_func = false;
 
                    $$ = $1;
                  }
@@ -1284,6 +1327,7 @@
 
 function_end   : END
                  {
+                   seen_endfunction = true;
                    if (end_token_ok ($1, token::function_end))
                      $$ = make_end ("endfunction", $1->line (), $1->column ());
                    else
@@ -1291,15 +1335,29 @@
                  }
                | END_OF_INPUT
                  {
-                   if (lexer_flags.parsing_nested_function)
-                     lexer_flags.parsing_nested_function = -1;
-
-                   if (reading_fcn_file || reading_script_file
-                       || get_input_from_eval_string)
-                     $$ = make_end ("endfunction", input_line_number,
-                                    current_input_column);
-                   else
-                     YYABORT;
+// A lot of tests are based on the assumption that this is OK
+//                 if (reading_script_file)
+//                   {
+//                     yyerror ("function body open at end of script");
+//                     YYABORT;
+//                   }
+
+                   if (seen_endfunction)
+                     {
+                       yyerror ("inconsistent functionends. if one function "
+                                "is explicitly ended, so must all the "
+                                "others.");
+                       YYABORT;
+                     }
+
+                   if (! reading_fcn_file && ! reading_script_file)
+                     {
+                       yyerror ("function body open at end of input");
+                       YYABORT;
+                     }
+
+                   $$ = make_end ("endfunction", input_line_number,
+                                  current_input_column);
                  }
                ;
 
@@ -2241,7 +2299,7 @@
   // so that we don't turn eval ("break;") inside a function, script,
   // or loop into a no-op command.
 
-  if (lexer_flags.looping || lexer_flags.defining_func
+  if (lexer_flags.looping || current_function_depth > 0
       || reading_script_file || tree_evaluator::in_fcn_or_script_body
       || tree_evaluator::in_loop_command)
     retval = new tree_break_command (l, c);
@@ -2294,7 +2352,7 @@
       // that we don't turn eval ("return;") inside a function, script,
       // or loop into a no-op command.
 
-      if (lexer_flags.defining_func || reading_script_file
+      if (current_function_depth > 0 || reading_script_file
           || tree_evaluator::in_fcn_or_script_body)
         retval = new tree_return_command (l, c);
       else
@@ -2503,7 +2561,7 @@
   return retval;
 }
 
-// Define a function.
+// Define a script.
 
 static void
 make_script (tree_statement_list *cmds, tree_statement *end_script)
@@ -2529,7 +2587,7 @@
 
   script->stash_fcn_file_time (now);
 
-  curr_fcn_ptr = script;
+  primary_fcn_ptr = script;
 
   // Unmark any symbols that may have been tagged as local variables
   // while parsing (for example, by force_local_variable in lex.l).
@@ -2581,35 +2639,36 @@
   // the file does not match the name of the function stated in the
   // file.  Matlab doesn't provide a diagnostic (it ignores the stated
   // name).
+  if (! autoloading &&
+      reading_fcn_file &&
+      (current_function_depth == 1 &&
+       ! parsing_subfunctions &&
+       ! lexer_flags.parsing_class_method))
+  {
+    // FIXME -- should curr_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;
+
+    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);
+
+    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 = nm;
+      }
+  }
 
   if (reading_fcn_file || autoloading)
     {
-      if (! (autoloading
-            || lexer_flags.parsing_nested_function
-            || lexer_flags.parsing_class_method))
-       {
-         // FIXME -- should curr_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;
-
-         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);
-
-         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 = nm;
-           }
-       }
-
       octave_time now;
 
       fcn->stash_fcn_file_name (curr_fcn_file_full_name);
@@ -2619,11 +2678,11 @@
       if (fcn_file_from_relative_lookup)
        fcn->mark_relative ();
 
-      if (lexer_flags.parsing_nested_function)
-        {
-          fcn->stash_parent_fcn_name (parent_function_name);
-          fcn->stash_parent_fcn_scope (symbol_table::parent_scope ());
-       }
+      if (current_function_depth > 1 || parsing_subfunctions)
+        {
+         fcn->stash_parent_fcn_name (curr_fcn_file_name);
+         fcn->stash_parent_fcn_scope (primary_fcn_scope);
+        }
 
       if (lexer_flags.parsing_class_method)
        {
@@ -2653,18 +2712,20 @@
 
   fcn->stash_function_name (id_name);
 
-  if (! help_buf.empty ())
+  if (! help_buf.empty ()
+      && current_function_depth == 1
+      && ! parsing_subfunctions)
     {
       fcn->document (help_buf.top ());
 
       help_buf.pop ();
     }
 
-  if (reading_fcn_file && ! lexer_flags.parsing_nested_function)
-    curr_fcn_ptr = fcn;
-  else
-    curr_fcn_ptr = 0;
-
+  if (reading_fcn_file
+      && current_function_depth == 1
+      && ! parsing_subfunctions)
+    primary_fcn_ptr = fcn;
+  
   return fcn;
 }
 
@@ -2693,23 +2754,20 @@
 
       fcn->define_ret_list (ret_list);
 
-      if (lexer_flags.parsing_nested_function)
-       {
+      if (current_function_depth > 1 || parsing_subfunctions)
+        {
+          // TODO: is this flag used to determine if the function is a
+          // _subfunction_ somewhere?
          fcn->mark_as_nested_function ();
 
-         symbol_table::install_subfunction (nm, octave_value (fcn));
-
-         if (lexer_flags.parsing_nested_function < 0)
-           {
-             lexer_flags.parsing_nested_function = 0;
-             symbol_table::reset_parent_scope ();
-           }
-       }
-      else if (! curr_fcn_ptr)
+         symbol_table::install_subfunction (nm, octave_value (fcn), 
primary_fcn_scope);
+       }
+
+      if (! primary_fcn_ptr)
        {
          // FIXME -- there should be a better way to indicate that we
          // should create a tree_function_def object other than
-         // looking at curr_fcn_ptr...
+         // looking at primary_fcn_ptr...
 
          retval = new tree_function_def (fcn);
        }
@@ -2733,7 +2791,13 @@
   symbol_table::set_scope (symtab_context.top ());
   symtab_context.pop ();
 
-  lexer_flags.defining_func = false;
+  if (reading_fcn_file
+      && current_function_depth == 1
+      && ! parsing_subfunctions)
+    parsing_subfunctions = true;
+
+  current_function_depth--;
+
   lexer_flags.parsed_function_name = false;
   lexer_flags.looking_at_return_list = false;
   lexer_flags.looking_at_parameter_list = false;
@@ -2835,7 +2899,7 @@
       break;
 
     case STATIC:
-      if (lexer_flags.defining_func)
+      if (current_function_depth > 0)
        retval = new tree_static_command (lst, l, c);
       else
        {
@@ -2912,7 +2976,7 @@
 static void
 maybe_warn_missing_semi (tree_statement_list *t)
 {
-  if (lexer_flags.defining_func)
+  if (current_function_depth > 0)
     {
       tree_statement *tmp = t->back();
 
@@ -3153,8 +3217,6 @@
 
   // Open function file and parse.
 
-  bool old_reading_fcn_file_state = reading_fcn_file;
-
   FILE *in_stream = command_editor::get_input_stream ();
 
   unwind_protect::add_fcn (command_editor::set_input_stream,
@@ -3164,19 +3226,23 @@
 
   unwind_protect::protect_var (input_line_number);
   unwind_protect::protect_var (current_input_column);
-  unwind_protect::protect_var (end_tokens_expected);
   unwind_protect::protect_var (reading_fcn_file);
   unwind_protect::protect_var (line_editing);
-  unwind_protect::protect_var (parent_function_name);
   unwind_protect::protect_var (current_class_name);
+  unwind_protect::protect_var (current_function_depth);
+  unwind_protect::protect_var (max_function_depth);
+  unwind_protect::protect_var (parsing_subfunctions);
+  unwind_protect::protect_var (seen_endfunction);
 
   input_line_number = 1;
   current_input_column = 1;
-  end_tokens_expected = 0;
   reading_fcn_file = true;
   line_editing = false;
-  parent_function_name = "";
   current_class_name = dispatch_type;
+  current_function_depth = 0;
+  max_function_depth = 0;
+  parsing_subfunctions = false;
+  seen_endfunction = false;
 
   // The next four lines must be in this order.
   unwind_protect::add_fcn (command_history::ignore_entries, ! Vsaving_history);
@@ -3204,10 +3270,10 @@
        {
          std::string file_type;
 
-         bool parsing_script = false;
-
          unwind_protect::protect_var (get_input_from_eval_string);
          unwind_protect::protect_var (parser_end_of_input);
+         unwind_protect::protect_var (reading_fcn_file);
+         unwind_protect::protect_var (reading_script_file);
 
          get_input_from_eval_string = false;
          parser_end_of_input = false;
@@ -3217,7 +3283,6 @@
              file_type = "function";
 
              unwind_protect::protect_var (Vecho_executing_commands);
-             unwind_protect::protect_var (reading_fcn_file);
 
              Vecho_executing_commands = ECHO_OFF;
              reading_fcn_file = true;
@@ -3226,17 +3291,11 @@
            {
              file_type = "script";
 
-             // The value of `reading_fcn_file' will be restored to the
-             // proper value when we unwind from this frame.
-             reading_fcn_file = old_reading_fcn_file_state;
-
-             unwind_protect::protect_var (reading_script_file);
-
-             reading_script_file = true;
-
-             parsing_script = true;
-           }
-
+             reading_fcn_file = false;
+           }
+
+         reading_script_file = ! reading_fcn_file;
+         
          YY_BUFFER_STATE old_buf = current_buffer ();
          YY_BUFFER_STATE new_buf = create_buffer (ffile);
 
@@ -3245,8 +3304,8 @@
 
          switch_to_buffer (new_buf);
 
-         unwind_protect::protect_var (curr_fcn_ptr);
-         curr_fcn_ptr = 0;
+         unwind_protect::protect_var (primary_fcn_ptr);
+         primary_fcn_ptr = 0;
 
          reset_parser ();
 
@@ -3259,14 +3318,21 @@
          if (! help_txt.empty ())
            help_buf.push (help_txt);
 
-         if (parsing_script)
-           prep_lexer_for_script ();
+         if (reading_script_file)
+           prep_lexer_for_script_file ();
+         else
+           prep_lexer_for_function_file ();
 
          lexer_flags.parsing_class_method = ! dispatch_type.empty ();
 
          int status = yyparse ();
 
-         fcn_ptr = curr_fcn_ptr;
+         fcn_ptr = primary_fcn_ptr;
+
+         if (reading_fcn_file && seen_endfunction && max_function_depth > 1)
+           warning_with_id ("Octave:nested-functions-coerced",
+                            "nested functions are coerced into subfunctions "
+                            "in file %s", ff.c_str ());
 
          if (status != 0)
            error ("parse error while reading %s file %s",
@@ -3879,6 +3945,10 @@
   unwind_protect::protect_var (parser_end_of_input);
   unwind_protect::protect_var (line_editing);
   unwind_protect::protect_var (current_eval_string);
+  unwind_protect::protect_var (current_function_depth);
+  unwind_protect::protect_var (max_function_depth);
+  unwind_protect::protect_var (parsing_subfunctions);
+  unwind_protect::protect_var (seen_endfunction);
 
   input_line_number = 1;
   current_input_column = 1;
@@ -3886,6 +3956,10 @@
   input_from_eval_string_pending = true;
   parser_end_of_input = false;
   line_editing = false;
+  current_function_depth = 0;
+  max_function_depth = 0;
+  parsing_subfunctions = false;
+  seen_endfunction = false;
 
   current_eval_string = s;
 
diff -r 303f862a896d -r dc63b0e47a65 src/symtab.cc
--- a/src/symtab.cc     Wed Jul 29 19:36:22 2009 -0400
+++ b/src/symtab.cc     Thu Jul 30 11:33:03 2009 +0200
@@ -61,8 +61,6 @@
 const symbol_table::scope_id symbol_table::xtop_scope = 1;
 
 symbol_table::scope_id symbol_table::xcurrent_scope = 1;
-
-symbol_table::scope_id symbol_table::xparent_scope = -1;
 
 symbol_table::context_id symbol_table::xcurrent_context = 0;
 
diff -r 303f862a896d -r dc63b0e47a65 src/symtab.h
--- a/src/symtab.h      Wed Jul 29 19:36:22 2009 -0400
+++ b/src/symtab.h      Thu Jul 30 11:33:03 2009 +0200
@@ -888,9 +888,6 @@
 
   static context_id current_context (void) { return xcurrent_context; }
 
-  // We use parent_scope to handle parsing subfunctions.
-  static scope_id parent_scope (void) { return xparent_scope; }
-
   static scope_id alloc_scope (void) { return scope_id_cache::alloc (); }
 
   static void set_scope (scope_id scope)
@@ -940,16 +937,6 @@
         else
           xcurrent_context = context;
       }
-  }
-
-  static void set_parent_scope (scope_id scope)
-  {
-    xparent_scope = scope;
-  }
-
-  static void reset_parent_scope (void)
-  {
-    set_parent_scope (-1);
   }
 
   static void erase_scope (scope_id scope)
@@ -1207,7 +1194,7 @@
 
   static void install_subfunction (const std::string& name,
                                   const octave_value& fcn,
-                                  scope_id scope = xparent_scope)
+                                  scope_id scope)
   {
     fcn_table_iterator p = fcn_table.find (name);
 
@@ -1852,9 +1839,6 @@
 
   static scope_id xcurrent_scope;
 
-  // We use parent_scope to handle parsing subfunctions.
-  static scope_id xparent_scope;
-
   static context_id xcurrent_context;
 
   symbol_table (void)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]