octave-maintainers
[Top][All Lists]
Advanced

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

[changeset] parsing nested functions


From: David Grundberg
Subject: [changeset] parsing nested functions
Date: Wed, 29 Jul 2009 21:31:46 +0200
User-agent: Thunderbird 2.0.0.22 (Windows/20090605)

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.

Best regards,
David
# HG changeset patch
# User David Grundberg <address@hidden>
# Date 1248893278 -7200
# Node ID d573340664366341bf5d1ba24018dc1bdbd6291a
# Parent  bcdf878e268649026f0776fed221e5c19d1ee92c
Parse nested functions more accurately.

diff -r bcdf878e2686 -r d57334066436 src/ChangeLog
--- a/src/ChangeLog     Wed Jul 29 13:40:42 2009 -0400
+++ b/src/ChangeLog     Wed Jul 29 20:47:58 2009 +0200
@@ -1,3 +1,48 @@
+2009-07-29  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>
 
        * ov-float.cc, ov-flt-re-mat.cc, ov-re-mat.cc, ov-re-sparse.cc,
diff -r bcdf878e2686 -r d57334066436 src/lex.h
--- a/src/lex.h Wed Jul 29 13:40:42 2009 -0400
+++ b/src/lex.h Wed Jul 29 20:47:58 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 bcdf878e2686 -r d57334066436 src/lex.l
--- a/src/lex.l Wed Jul 29 13:40:42 2009 -0400
+++ b/src/lex.l Wed Jul 29 20:47:58 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 bcdf878e2686 -r d57334066436 src/parse.h
--- a/src/parse.h       Wed Jul 29 13:40:42 2009 -0400
+++ b/src/parse.h       Wed Jul 29 20:47:58 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 bcdf878e2686 -r d57334066436 src/parse.y
--- a/src/parse.y       Wed Jul 29 13:40:42 2009 -0400
+++ b/src/parse.y       Wed Jul 29 20:47:58 2009 +0200
@@ -100,15 +100,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 +132,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 +438,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 +463,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 +507,10 @@
                  {
                    global_command = $1;
                    promptflag = 1;
+                   YYACCEPT;
+                 }
+               | function_file
+                 {
                    YYACCEPT;
                  }
                | simple_list parse_error
@@ -903,7 +922,7 @@
                  { $$ = $1; }
                | function
                  { $$ = $1; }
-               | script
+               | script_file
                  { $$ = $1; }
                ;
 
@@ -1112,11 +1131,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");
                  }
                ;
 
@@ -1215,7 +1244,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,
@@ -1227,6 +1256,23 @@
                  }
                ;
 
+// =============
+// Function file
+// =============
+
+function_file   : FUNCTION_FILE function_list opt_sep END_OF_INPUT
+                 {
+                 }
+               ;
+
+function_list   : function
+                 {
+                 }
+               | function_list sep function
+                 {
+                 }
+               ;
+
 // ===================
 // Function definition
 // ===================
@@ -1251,12 +1297,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;
                  }
@@ -1281,6 +1323,7 @@
 
 function_end   : END
                  {
+                   seen_endfunction = true;
                    if (end_token_ok ($1, token::function_end))
                      $$ = make_end ("endfunction", $1->line (), $1->column ());
                    else
@@ -1288,15 +1331,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);
                  }
                ;
 
@@ -2238,7 +2295,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);
@@ -2291,7 +2348,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
@@ -2526,7 +2583,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).
@@ -2578,35 +2635,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);
@@ -2616,11 +2674,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)
        {
@@ -2657,11 +2715,11 @@
       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;
 }
 
@@ -2690,23 +2748,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);
        }
@@ -2730,7 +2785,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;
@@ -2832,7 +2893,7 @@
       break;
 
     case STATIC:
-      if (lexer_flags.defining_func)
+      if (current_function_depth > 0)
        retval = new tree_static_command (lst, l, c);
       else
        {
@@ -2909,7 +2970,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();
 
@@ -3150,8 +3211,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,
@@ -3161,19 +3220,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);
@@ -3201,10 +3264,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;
@@ -3214,7 +3277,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;
@@ -3223,17 +3285,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);
 
@@ -3242,8 +3298,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 ();
 
@@ -3256,14 +3312,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",
@@ -3876,6 +3939,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;
@@ -3883,6 +3950,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 bcdf878e2686 -r d57334066436 src/symtab.cc
--- a/src/symtab.cc     Wed Jul 29 13:40:42 2009 -0400
+++ b/src/symtab.cc     Wed Jul 29 20:47:58 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 bcdf878e2686 -r d57334066436 src/symtab.h
--- a/src/symtab.h      Wed Jul 29 13:40:42 2009 -0400
+++ b/src/symtab.h      Wed Jul 29 20:47:58 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]