changeset 24037:21915520ac7b

use more direct method for non-local symbol access (bug #38236) * pt-id.h, pd-id.cc (tree_evaluator::get_current_scope): New function. * symtab.h, symtab.cc (symbol_table::symbol_reference): Delete class. (symbol_table::dummy_symbol_record): Delete static data member. * oct-lvalue.h, oct-lvalue.cc (octave_lvalue::sym): Use symbol_record, not symbol_reference. Change all uses. (octave_lvalue::black_hole): New data member. (octave_lvalue:is_black_hole): Use it. (octave_lvalue::mark_black_hole): New function. * pt-eval.cc (tree_identifier::sym): Use symbol_record, not symbol_reference. Change all uses. (tree_black_hole::lvalue): Explicitly mark retval as black_hole. (tree_evaluator::visit_tree_identifier): Adapt to tree_identifier::symbol returning symbol_record, not symbol_reference. * oct-parse.in.yy (push_script_symtab, begin_file): New non-terminals. (file): Use begin_file to start script and classdef files. Use separate symbol table scope when parsing scripts. * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_code::m_scope): Move here from octave_user_fcn. (octave_user_code::scope): Likewise. (octave_user_script::octave_user_script): New argument scope. (octave_user_script::call): Add symbol_table::scope::unbind_script_symbols to unwind_protect frame. Call scope::bind_script_symbols to access evaluation scope. (octave_user_function::octave_user_function): Pass scope argument to octave_user_code base class. * symtab.h, symtab.cc (symbol_record_rep::m_fwd_rep): New data member. Change member functions to forward to secondary rep if it is defined. (symbol_record::bind_fwd_rep, symbol_record_rep::bind_fwd_rep, symbol_record::unbind_fwd_rep, symbol_record_rep::unbind_fwd_rep): New functions. (scope::bind_script_symbols, scope::unbind_script_symbols): New functions. (scope::varval, scope::global_varval, scope::top_level_varval): Now const. (scope::update_nest): Set forwarding rep for nonlocal symbol. (scope::look_nonlocal): Likewise.
author John W. Eaton <jwe@octave.org>
date Wed, 13 Sep 2017 17:10:51 -0400
parents 2932a325930c
children bb5c1e767039
files libinterp/corefcn/oct-lvalue.cc libinterp/corefcn/oct-lvalue.h libinterp/corefcn/symtab.cc libinterp/corefcn/symtab.h libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h
diffstat 11 files changed, 499 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/oct-lvalue.cc	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/corefcn/oct-lvalue.cc	Wed Sep 13 17:10:51 2017 -0400
@@ -35,9 +35,9 @@
   if (! is_black_hole ())
     {
       if (idx.empty ())
-        sym->assign (op, rhs);
+        sym.assign (op, rhs);
       else
-        sym->assign (op, type, idx, rhs);
+        sym.assign (op, type, idx, rhs);
     }
 }
 
@@ -73,9 +73,9 @@
   if (! is_black_hole ())
     {
       if (idx.empty ())
-        sym->do_non_const_unary_op (op);
+        sym.do_non_const_unary_op (op);
       else
-        sym->do_non_const_unary_op (op, type, idx);
+        sym.do_non_const_unary_op (op, type, idx);
     }
 }
 
@@ -86,7 +86,7 @@
 
   if (! is_black_hole ())
     {
-      octave_value val = sym->varval ();
+      octave_value val = sym.varval ();
 
       if (idx.empty ())
         retval = val;
--- a/libinterp/corefcn/oct-lvalue.h	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/corefcn/oct-lvalue.h	Wed Sep 13 17:10:51 2017 -0400
@@ -38,13 +38,13 @@
 {
 public:
 
-  octave_lvalue (const octave::symbol_table::symbol_reference& s
-                   = octave::symbol_table::symbol_reference ())
-    : sym (s), type (), idx (), nel (1)
+  octave_lvalue (const octave::symbol_table::symbol_record& s
+                   = octave::symbol_table::symbol_record ())
+    : sym (s), black_hole (false), type (), idx (), nel (1)
   { }
 
   octave_lvalue (const octave_lvalue& vr)
-    : sym (vr.sym), type (vr.type), idx (vr.idx), nel (vr.nel)
+    : sym (vr.sym), black_hole (vr.black_hole), type (vr.type), idx (vr.idx), nel (vr.nel)
   { }
 
   octave_lvalue& operator = (const octave_lvalue& vr)
@@ -52,6 +52,7 @@
     if (this != &vr)
       {
         sym = vr.sym;
+        black_hole = vr.black_hole;
         type = vr.type;
         idx = vr.idx;
         nel = vr.nel;
@@ -62,21 +63,23 @@
 
   ~octave_lvalue (void) = default;
 
-  bool is_black_hole (void) const { return sym.is_black_hole (); }
+  bool is_black_hole (void) const { return black_hole; }
+
+  void mark_black_hole (void) { black_hole = true; }
 
   bool is_defined (void) const
   {
-    return ! is_black_hole () && sym->is_defined ();
+    return ! is_black_hole () && sym.is_defined ();
   }
 
   bool is_undefined (void) const
   {
-    return is_black_hole () || sym->is_undefined ();
+    return is_black_hole () || sym.is_undefined ();
   }
 
   bool isstruct (void) const { return value().isstruct (); }
 
-  void define (const octave_value& v) { sym->assign (v); }
+  void define (const octave_value& v) { sym.assign (v); }
 
   void assign (octave_value::assign_op, const octave_value&);
 
@@ -98,7 +101,9 @@
 
 private:
 
-  octave::symbol_table::symbol_reference sym;
+  octave::symbol_table::symbol_record sym;
+
+  bool black_hole;
 
   std::string type;
 
--- a/libinterp/corefcn/symtab.cc	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/corefcn/symtab.cc	Wed Sep 13 17:10:51 2017 -0400
@@ -60,6 +60,12 @@
   void
   symbol_table::symbol_record::symbol_record_rep::clear (scope *sid)
   {
+    if (m_fwd_rep)
+      {
+        m_fwd_rep->clear (sid);
+        return;
+      }
+
     if (! (is_hidden () || is_inherited ())
         && sid == decl_scope ())
       {
@@ -80,6 +86,12 @@
   void
   symbol_table::symbol_record::symbol_record_rep::init_persistent (void)
   {
+    if (m_fwd_rep)
+      {
+        m_fwd_rep->init_persistent ();
+        return;
+      }
+
     symbol_table::scope *scope
       = __require_current_scope__ ("symbol_table::symbol_record::symbol_record_rep::init_persistent");
 
@@ -97,6 +109,12 @@
   void
   symbol_table::symbol_record::symbol_record_rep::erase_persistent (void)
   {
+    if (m_fwd_rep)
+      {
+        m_fwd_rep->erase_persistent ();
+        return;
+      }
+
     unmark_persistent ();
 
     symbol_table::scope *scope
@@ -108,12 +126,19 @@
   symbol_table::symbol_record::symbol_record_rep *
   symbol_table::symbol_record::symbol_record_rep::dup (scope *new_scope) const
   {
+    // FIXME: is this the right thing do to?
+    if (m_fwd_rep)
+      return m_fwd_rep->dup (new_scope);
+
     return new symbol_record_rep (new_scope, name, varval (), storage_class);
   }
 
   octave_value
   symbol_table::symbol_record::symbol_record_rep::dump (void) const
   {
+    if (m_fwd_rep)
+      return m_fwd_rep->dump ();
+
     std::map<std::string, octave_value> m
       = {{ "name", name },
          { "local", is_local () },
@@ -135,6 +160,9 @@
   octave_value&
   symbol_table::symbol_record::symbol_record_rep::xglobal_varref (void)
   {
+    if (m_fwd_rep)
+      return m_fwd_rep->xglobal_varref ();
+
     symbol_table& symtab
       = __get_symbol_table__ ("symbol_table::symbol_record::symbol_record_rep::xglobal_varref");
 
@@ -148,6 +176,9 @@
   octave_value&
   symbol_table::symbol_record::symbol_record_rep::xpersistent_varref (void)
   {
+    if (m_fwd_rep)
+      return m_fwd_rep->xpersistent_varref ();
+
     symbol_table::scope *scope
       = __get_current_scope__ ("symbol_table::symbol_record::symbol_record_rep::xpersistent_varref");
 
@@ -157,6 +188,9 @@
   octave_value
   symbol_table::symbol_record::symbol_record_rep::xglobal_varval (void) const
   {
+    if (m_fwd_rep)
+      return m_fwd_rep->xglobal_varval ();
+
     symbol_table& symtab
       = __get_symbol_table__ ("symbol_table::symbol_record::symbol_record_rep::xglobal_varval");
 
@@ -166,6 +200,9 @@
   octave_value
   symbol_table::symbol_record::symbol_record_rep::xpersistent_varval (void) const
   {
+    if (m_fwd_rep)
+      return m_fwd_rep->xpersistent_varval ();
+
     symbol_table::scope *scope
       = __get_current_scope__ ("symbol_table::symbol_record::symbol_record_rep::xpersistent_varval");
 
@@ -216,30 +253,6 @@
 
     return retval;
   }
-
-  symbol_table::symbol_record
-  symbol_table::dummy_symbol_record (static_cast<symbol_table::scope*> (nullptr));
-
-  symbol_table::symbol_reference::symbol_reference (const symbol_record& record)
-    : m_scope (nullptr), m_context (0), m_sym (record)
-  {
-    m_scope = __get_current_scope__ ("symbol_reference");
-  }
-
-  void
-  symbol_table::symbol_reference::update (void) const
-  {
-    symbol_table::scope *curr_scope
-      = __get_current_scope__ ("symbol_reference::update");
-
-    if (curr_scope && (m_scope != curr_scope || ! m_sym.is_valid ()))
-      {
-        m_scope = curr_scope;
-        m_sym = m_scope->insert (m_sym.name ());  // ???
-      }
-
-    m_context = m_scope ? m_scope->current_context () : 0;
-  }
 }
 
 static void
@@ -1828,19 +1841,12 @@
         for (auto& nm_sr : m_symbols)
           {
             symbol_record& ours = nm_sr.second;
-            symbol_record parents;
 
             if (! ours.is_formal ()
-                && m_is_nested && m_parent->look_nonlocal (nm_sr.first, parents))
+                && m_is_nested && m_parent->look_nonlocal (nm_sr.first, ours))
               {
                 if (ours.is_global () || ours.is_persistent ())
                   error ("global and persistent may only be used in the topmost level in which a nested variable is used");
-
-                if (! ours.is_formal ())
-                  {
-                    ours.invalidate ();
-                    nm_sr.second = parents;
-                  }
               }
             else
               ours.set_curr_fcn (m_fcn);
@@ -1874,12 +1880,26 @@
       }
     else if (! p->second.is_automatic ())
       {
-        result = p->second;
+        result.bind_fwd_rep (p->second);
         return true;
       }
 
     return false;
   }
+
+  void
+  symbol_table::scope::bind_script_symbols (scope *curr_scope)
+  {
+    for (auto& nm_sr : m_symbols)
+      nm_sr.second.bind_fwd_rep (curr_scope->find_symbol (nm_sr.first));
+  }
+
+  void
+  symbol_table::scope::unbind_script_symbols (void)
+  {
+    for (auto& nm_sr : m_symbols)
+      nm_sr.second.unbind_fwd_rep ();
+  }
 }
 
 DEFUN (ignore_function_time_stamp, args, nargout,
--- a/libinterp/corefcn/symtab.h	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/corefcn/symtab.h	Wed Sep 13 17:10:51 2017 -0400
@@ -96,7 +96,8 @@
 
         symbol_record_rep (scope *s, const std::string& nm,
                            const octave_value& v, unsigned int sc)
-          : m_decl_scope (s), curr_fcn (nullptr), name (nm), value_stack (),
+          : m_decl_scope (s), curr_fcn (nullptr), name (nm),
+            m_fwd_rep (nullptr), value_stack (),
             storage_class (sc), /* finfo (), */ valid (true), count (1)
         {
           value_stack.push_back (v);
@@ -112,6 +113,12 @@
 
         void assign (const octave_value& value)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->assign (value);
+              return;
+            }
+
           varref () = value;
         }
 
@@ -120,16 +127,34 @@
                      const std::list<octave_value_list>& idx,
                      const octave_value& value)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->assign (op, type, idx, value);
+              return;
+            }
+
           varref().assign (op, type, idx, value);
         }
 
         void assign (octave_value::assign_op op, const octave_value& value)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->assign (op, value);
+              return;
+            }
+
           varref().assign (op, value);
         }
 
         void do_non_const_unary_op (octave_value::unary_op op)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->do_non_const_unary_op (op);
+              return;
+            }
+
           varref().do_non_const_unary_op (op);
         }
 
@@ -137,11 +162,20 @@
                                     const std::string& type,
                                     const std::list<octave_value_list>& idx)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->do_non_const_unary_op (op, type, idx);
+              return;
+            }
+
           varref().do_non_const_unary_op (op, type, idx);
         }
 
         octave_value& varref (void)
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->varref ();
+
           context_id context
             = m_decl_scope ? m_decl_scope->current_context () : 0;
 
@@ -161,6 +195,9 @@
 
         octave_value varval (void) const
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->varval ();
+
           context_id context
             = m_decl_scope ? m_decl_scope->current_context () : 0;
 
@@ -179,6 +216,12 @@
 
         void push_context (scope *sid)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->push_context (sid);
+              return;
+            }
+
           if (! (is_persistent () || is_global ())
               && sid == decl_scope ())
             value_stack.push_back (octave_value ());
@@ -200,6 +243,9 @@
 
         size_t pop_context (scope *sid)
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->pop_context (sid);
+
           size_t retval = 1;
 
           if (! (is_persistent () || is_global ())
@@ -212,80 +258,330 @@
           return retval;
         }
 
-        void clear (void) { clear (decl_scope ()); }
+        void clear (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->clear ();
+              return;
+            }
+
+          clear (decl_scope ());
+        }
 
         void clear (scope *sid);
 
         bool is_defined (void) const
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_defined ();
+
           return varval ().is_defined ();
         }
 
         bool is_valid (void) const
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_valid ();
+
           return valid;
         }
 
         bool is_variable (void) const
         {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_variable ();
+
           return (! is_local () || is_defined ());
         }
 
-        bool is_local (void) const { return storage_class & local; }
-        bool is_automatic (void) const { return storage_class & automatic; }
-        bool is_formal (void) const { return storage_class & formal; }
-        bool is_hidden (void) const { return storage_class & hidden; }
-        bool is_inherited (void) const { return storage_class & inherited; }
-        bool is_global (void) const { return storage_class & global; }
-        bool is_persistent (void) const { return storage_class & persistent; }
-        bool is_added_static (void) const {return storage_class & added_static; }
-
-        void mark_local (void) { storage_class |= local; }
-        void mark_automatic (void) { storage_class |= automatic; }
-        void mark_formal (void) { storage_class |= formal; }
-        void mark_hidden (void) { storage_class |= hidden; }
-        void mark_inherited (void) { storage_class |= inherited; }
+        bool is_local (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_local ();
+
+          return storage_class & local;
+        }
+
+        bool is_automatic (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_automatic ();
+
+          return storage_class & automatic;
+        }
+
+        bool is_formal (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_formal ();
+
+          return storage_class & formal;
+        }
+
+        bool is_hidden (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_hidden ();
+
+          return storage_class & hidden;
+        }
+
+        bool is_inherited (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_inherited ();
+
+          return storage_class & inherited;
+        }
+
+        bool is_global (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_global ();
+
+          return storage_class & global;
+        }
+
+        bool is_persistent (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_persistent ();
+
+          return storage_class & persistent;
+        }
+
+        bool is_added_static (void) const
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->is_added_static ();
+
+          return storage_class & added_static;
+        }
+
+        void mark_local (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_local ();
+              return;
+            }
+
+          storage_class |= local;
+        }
+
+        void mark_automatic (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_automatic ();
+              return;
+            }
+
+          storage_class |= automatic;
+        }
+
+        void mark_formal (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_formal ();
+              return;
+            }
+
+          storage_class |= formal;
+        }
+
+        void mark_hidden (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_hidden ();
+              return;
+            }
+
+          storage_class |= hidden;
+        }
+
+        void mark_inherited (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_inherited ();
+              return;
+            }
+
+          storage_class |= inherited;
+        }
+
         void mark_global (void)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_global ();
+              return;
+            }
+
           if (is_persistent ())
             error ("can't make persistent variable %s global", name.c_str ());
 
           storage_class |= global;
         }
+
         void mark_persistent (void)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_persistent ();
+              return;
+            }
+
           if (is_global ())
             error ("can't make global variable %s persistent", name.c_str ());
 
           storage_class |= persistent;
         }
-        void mark_added_static (void) { storage_class |= added_static; }
-
-        void unmark_local (void) { storage_class &= ~local; }
-        void unmark_automatic (void) { storage_class &= ~automatic; }
-        void unmark_formal (void) { storage_class &= ~formal; }
-        void unmark_hidden (void) { storage_class &= ~hidden; }
-        void unmark_inherited (void) { storage_class &= ~inherited; }
-        void unmark_global (void) { storage_class &= ~global; }
-        void unmark_persistent (void) { storage_class &= ~persistent; }
-        void unmark_added_static (void) { storage_class &= ~added_static; }
+
+        void mark_added_static (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->mark_added_static ();
+              return;
+            }
+
+          storage_class |= added_static;
+        }
+
+        void unmark_local (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_local ();
+              return;
+            }
+
+          storage_class &= ~local;
+        }
+
+        void unmark_automatic (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_automatic ();
+              return;
+            }
+
+          storage_class &= ~automatic;
+        }
+
+        void unmark_formal (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_formal ();
+              return;
+            }
+
+          storage_class &= ~formal;
+        }
+
+        void unmark_hidden (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_hidden ();
+              return;
+            }
+
+          storage_class &= ~hidden;
+        }
+
+        void unmark_inherited (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_inherited ();
+              return;
+            }
+
+          storage_class &= ~inherited;
+        }
+
+        void unmark_global (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_global ();
+              return;
+            }
+
+          storage_class &= ~global;
+        }
+
+        void unmark_persistent (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_persistent ();
+              return;
+            }
+
+          storage_class &= ~persistent;
+        }
+
+        void unmark_added_static (void)
+        {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->unmark_added_static ();
+              return;
+            }
+
+          storage_class &= ~added_static;
+        }
 
         void init_persistent (void);
 
         void invalidate (void)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->invalidate ();
+              return;
+            }
+
           valid = false;
         }
 
         void erase_persistent (void);
 
-        scope *decl_scope (void) { return m_decl_scope; }
+        scope *decl_scope (void)
+        {
+          if (m_fwd_rep)
+            return m_fwd_rep->decl_scope ();
+
+          return m_decl_scope;
+        }
 
         void set_curr_fcn (octave_user_function *fcn)
         {
+          if (m_fwd_rep)
+            {
+              m_fwd_rep->set_curr_fcn (fcn);
+              return;
+            }
+
           curr_fcn = fcn;
         }
 
+        // We don't forward more than once, so no need to forward the
+        // next two.
+
+        void bind_fwd_rep (symbol_record_rep *rep) { m_fwd_rep = rep; }
+
+        void unbind_fwd_rep (void) { m_fwd_rep = nullptr; }
+
         symbol_record_rep * dup (scope *new_scope) const;
 
         octave_value dump (void) const;
@@ -296,6 +592,8 @@
 
         std::string name;
 
+        symbol_record_rep *m_fwd_rep;
+
         std::deque<octave_value> value_stack;
 
         unsigned int storage_class;
@@ -470,7 +768,17 @@
 
       unsigned int xstorage_class (void) const { return rep->storage_class; }
 
-      void set_curr_fcn (octave_user_function *fcn) { rep->set_curr_fcn (fcn); }
+      void set_curr_fcn (octave_user_function *fcn)
+      {
+        rep->set_curr_fcn (fcn);
+      }
+
+      void bind_fwd_rep (const symbol_record& sr)
+      {
+        rep->bind_fwd_rep (sr.rep);
+      }
+
+      void unbind_fwd_rep (void) { rep->unbind_fwd_rep (); }
 
       octave_value dump (void) const { return rep->dump (); }
 
@@ -483,76 +791,6 @@
       symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { }
     };
 
-    static symbol_record dummy_symbol_record;
-
-    // Always access a symbol from the current scope.
-    // Useful for scripts, as they may be executed in more than one scope.
-    class
-      symbol_reference
-    {
-    public:
-
-      symbol_reference (void) : m_scope (nullptr), m_context (0) { }
-
-      symbol_reference (const symbol_record& record);
-
-      symbol_reference (const symbol_record& record, scope *curr_scope,
-                        context_id context)
-        : m_scope (curr_scope), m_context (context), m_sym (record)
-      { }
-
-      symbol_reference (const symbol_reference& ref) = default;
-
-      symbol_reference& operator = (const symbol_reference& ref) = default;
-
-      bool is_black_hole (void) const { return ! m_scope; }
-
-      symbol_table::scope * scope (void) const
-      {
-        update ();
-        return m_scope;
-      }
-
-      context_id context (void) const
-      {
-        update ();
-        return m_context;
-      }
-
-      // The name is the same regardless of scope.
-      const std::string& name (void) const { return m_sym.name (); }
-
-      symbol_record *operator-> (void)
-      {
-        update ();
-        return &m_sym;
-      }
-
-      symbol_record *operator-> (void) const
-      {
-        update ();
-        return &m_sym;
-      }
-
-      // can be used to place symbol_reference in maps, we don't overload < as
-      // it doesn't make any sense for symbol_reference
-      struct comparator
-      {
-        bool operator ()(const symbol_reference& lhs,
-                         const symbol_reference& rhs) const
-        {
-          return lhs.name () < rhs.name ();
-        }
-      };
-    private:
-
-      void update (void) const;
-
-      mutable symbol_table::scope *m_scope;
-      mutable context_id m_context;
-      mutable symbol_record m_sym;
-    };
-
     class fcn_info
     {
     public:
@@ -969,7 +1207,7 @@
         m_current_scope->assign (name, value);
     }
 
-    octave_value varval (const std::string& name)
+    octave_value varval (const std::string& name) const
     {
       return (m_current_scope
               ? m_current_scope->varval (name) : octave_value ());
@@ -987,8 +1225,7 @@
         p->second = value;
     }
 
-    octave_value
-      global_varval (const std::string& name)
+    octave_value global_varval (const std::string& name) const
     {
       global_symbols_const_iterator p = m_global_symbols.find (name);
 
@@ -1002,8 +1239,7 @@
       m_top_scope->assign (name, value);
     }
 
-    octave_value
-      top_level_varval (const std::string& name)
+    octave_value top_level_varval (const std::string& name) const
     {
       return m_top_scope->varval (name);
     }
@@ -1765,7 +2001,7 @@
                 ? m_persistent_symbols[name] : p->second);
       }
 
-      octave_value persistent_varval (const std::string& name)
+      octave_value persistent_varval (const std::string& name) const
       {
         m_persistent_symbols_const_iterator p = m_persistent_symbols.find (name);
 
@@ -2043,6 +2279,10 @@
       bool look_nonlocal (const std::string& name,
                           symbol_table::symbol_record& result);
 
+      void bind_script_symbols (scope *curr_scope);
+
+      void unbind_script_symbols (void);
+
     private:
 
       // Name for this scope (usually the corresponding filename of the
--- a/libinterp/octave-value/ov-usr-fcn.cc	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Wed Sep 13 17:10:51 2017 -0400
@@ -64,6 +64,7 @@
 
 octave_user_code::~octave_user_code (void)
 {
+  delete m_scope;
   delete m_file_info;
 }
 
@@ -131,11 +132,11 @@
     call_depth (-1)
 { }
 
-octave_user_script::octave_user_script (const std::string& fnm,
-                                        const std::string& nm,
-                                        octave::tree_statement_list *cmds,
-                                        const std::string& ds)
-  : octave_user_code (nm, ds), cmd_list (cmds), file_name (fnm),
+octave_user_script::octave_user_script
+  (const std::string& fnm, const std::string& nm,
+   octave::symbol_table::scope *scope, octave::tree_statement_list *cmds,
+   const std::string& ds)
+  : octave_user_code (nm, scope, ds), cmd_list (cmds), file_name (fnm),
     t_parsed (static_cast<time_t> (0)),
     t_checked (static_cast<time_t> (0)),
     call_depth (-1)
@@ -144,10 +145,10 @@
     cmd_list->mark_as_script_body ();
 }
 
-octave_user_script::octave_user_script (const std::string& fnm,
-                                        const std::string& nm,
-                                        const std::string& ds)
-  : octave_user_code (nm, ds), cmd_list (nullptr), file_name (fnm),
+octave_user_script::octave_user_script
+  (const std::string& fnm, const std::string& nm,
+   octave::symbol_table::scope *scope, const std::string& ds)
+  : octave_user_code (nm, scope, ds), cmd_list (nullptr), file_name (fnm),
     t_parsed (static_cast<time_t> (0)),
     t_checked (static_cast<time_t> (0)),
     call_depth (-1)
@@ -204,6 +205,10 @@
 
       octave::profiler::enter<octave_user_script> block (profiler, *this);
 
+      frame.add_method (m_scope,
+                        &octave::symbol_table::scope::unbind_script_symbols);
+      m_scope->bind_script_symbols (tw.get_current_scope ());
+
       if (tw.echo ())
         tw.push_echo_state (frame, octave::tree_evaluator::ECHO_SCRIPTS,
                             file_name);
@@ -238,7 +243,7 @@
 octave_user_function::octave_user_function
   (octave::symbol_table::scope *scope, octave::tree_parameter_list *pl,
    octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
-  : octave_user_code ("", ""), m_scope (scope),
+  : octave_user_code ("", scope, ""),
     param_list (pl), ret_list (rl), cmd_list (cl),
     lead_comm (), trail_comm (), file_name (),
     location_line (0), location_column (0),
@@ -267,8 +272,6 @@
   if (cmd_list)
     cmd_list->remove_all_breakpoints (file_name);
 
-  delete m_scope;
-
   delete param_list;
   delete ret_list;
   delete cmd_list;
--- a/libinterp/octave-value/ov-usr-fcn.h	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/octave-value/ov-usr-fcn.h	Wed Sep 13 17:10:51 2017 -0400
@@ -61,15 +61,18 @@
 protected:
 
   octave_user_code (const std::string& nm,
+                    octave::symbol_table::scope *scope = nullptr,
                     const std::string& ds = "")
-    : octave_function (nm, ds), curr_unwind_protect_frame (nullptr),
-      m_file_info (nullptr)
+    : octave_function (nm, ds), m_scope (scope), m_file_info (nullptr),
+      curr_unwind_protect_frame (nullptr)
   { }
 
 public:
 
   octave_user_code (void)
-    : octave_function () { }
+    : octave_function (), m_scope (nullptr), m_file_info (nullptr),
+      curr_unwind_protect_frame (nullptr)
+  { }
 
   // No copying!
 
@@ -94,6 +97,8 @@
   void cache_function_text (const std::string& text,
                             const octave::sys::time& timestamp);
 
+  octave::symbol_table::scope *scope (void) { return m_scope; }
+
   virtual std::map<std::string, octave_value> subfunctions (void) const;
 
   virtual octave::tree_statement_list * body (void) = 0;
@@ -102,12 +107,15 @@
 
   void get_file_info (void);
 
-  // pointer to the current unwind_protect frame of this function.
-  octave::unwind_protect *curr_unwind_protect_frame;
+  // Our symbol table scope.
+  octave::symbol_table::scope *m_scope;
 
   // Cached text of function or script code with line offsets
   // calculated.
   octave::file_info *m_file_info;
+
+  // pointer to the current unwind_protect frame of this function.
+  octave::unwind_protect *curr_unwind_protect_frame;
 };
 
 // Scripts.
@@ -120,10 +128,12 @@
   octave_user_script (void);
 
   octave_user_script (const std::string& fnm, const std::string& nm,
-                      octave::tree_statement_list *cmds,
+                      octave::symbol_table::scope *scope = nullptr,
+                      octave::tree_statement_list *cmds = nullptr,
                       const std::string& ds = "");
 
   octave_user_script (const std::string& fnm, const std::string& nm,
+                      octave::symbol_table::scope *scope = nullptr,
                       const std::string& ds = "");
 
   // No copying!
@@ -273,8 +283,6 @@
   octave::symbol_table::scope *
   parent_fcn_scope (void) const { return parent_scope; }
 
-  octave::symbol_table::scope *scope (void) { return m_scope; }
-
   octave::sys::time time_parsed (void) const { return t_parsed; }
 
   octave::sys::time time_checked (void) const { return t_checked; }
@@ -411,9 +419,6 @@
 
   std::string ctor_type_str (void) const;
 
-  // Our symbol table scope.
-  octave::symbol_table::scope *m_scope;
-
   // List of arguments for this function.  These are local variables.
   octave::tree_parameter_list *param_list;
 
--- a/libinterp/parse-tree/oct-parse.in.yy	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/parse-tree/oct-parse.in.yy	Wed Sep 13 17:10:51 2017 -0400
@@ -230,7 +230,8 @@
 %token<dummy_type> '(' ')' '[' ']' '{' '}' '.' ',' ';' '@' '\n'
 
 // Nonterminals we construct.
-%type <dummy_type> indirect_ref_op decl_param_init push_fcn_symtab
+%type <dummy_type> indirect_ref_op decl_param_init
+%type <dummy_type> push_fcn_symtab push_script_symtab begin_file
 %type <dummy_type> param_list_beg param_list_end stmt_begin parse_error
 %type <dummy_type> parsing_local_fcns
 %type <comment_type> stash_comment
@@ -1438,7 +1439,19 @@
                   { parser.m_parsing_local_functions = true; }
                 ;
 
-file            : INPUT_FILE opt_nl opt_list END_OF_INPUT
+push_script_symtab : // empty
+                  {
+                    $$ = 0;
+
+                    lexer.symtab_context.push (new octave::symbol_table::scope ());
+                  }
+                ;
+
+begin_file      : push_script_symtab INPUT_FILE
+                  { $$ = 0; }
+                ;
+
+file            : begin_file opt_nl opt_list END_OF_INPUT
                   {
                     YYUSE ($2);
 
@@ -1450,6 +1463,9 @@
                         // been stored in the symbol table or in
                         // base_parser::m_primary_fcn_ptr.
 
+                        // Unused symbol table context.
+                        lexer.symtab_context.pop ();
+
                         delete $3;
                       }
                     else
@@ -1464,12 +1480,15 @@
 
                     $$ = nullptr;
                   }
-                | INPUT_FILE opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT
+                | begin_file opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT
                   {
                     YYUSE ($2);
                     YYUSE ($5);
                     YYUSE ($6);
 
+                    // Unused symbol table context.
+                    lexer.symtab_context.pop ();
+
                     if (lexer.reading_classdef_file)
                       parser.m_classdef_object = $3;
 
@@ -3216,8 +3235,10 @@
     octave_user_script *script
       = new octave_user_script (m_lexer.fcn_file_full_name,
                                 m_lexer.fcn_file_name,
+                                m_lexer.symtab_context.curr_scope (),
                                 cmds, m_lexer.help_text);
 
+    m_lexer.symtab_context.pop ();
     m_lexer.help_text = "";
 
     sys::time now;
--- a/libinterp/parse-tree/pt-eval.cc	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Sep 13 17:10:51 2017 -0400
@@ -618,6 +618,14 @@
     return false;
   }
 
+  symbol_table::scope *
+  tree_evaluator::get_current_scope (void)
+  {
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    return symtab.current_scope ();
+  }
+
   void
   tree_evaluator::visit_decl_command (tree_decl_command& cmd)
   {
@@ -972,9 +980,9 @@
   {
     octave_value_list retval;
 
-    symbol_table::symbol_reference sym = expr.symbol ();
-
-    octave_value val = sym->find ();
+    symbol_table::symbol_record sym = expr.symbol ();
+
+    octave_value val = sym.find ();
 
     if (val.is_defined ())
       {
@@ -1014,7 +1022,7 @@
             retval = val;
           }
       }
-    else if (sym->is_added_static ())
+    else if (sym.is_added_static ())
       expr.static_workspace_error ();
     else
       expr.eval_undefined_error ();
--- a/libinterp/parse-tree/pt-eval.h	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/parse-tree/pt-eval.h	Wed Sep 13 17:10:51 2017 -0400
@@ -35,6 +35,7 @@
 #include "profiler.h"
 #include "pt-exp.h"
 #include "pt-walk.h"
+#include "symtab.h"
 
 namespace octave
 {
@@ -307,6 +308,8 @@
 
     profiler& get_profiler (void) { return m_profiler; }
 
+    symbol_table::scope *get_current_scope (void);
+
     int max_recursion_depth (void) const { return m_max_recursion_depth; }
 
     int max_recursion_depth (int n)
--- a/libinterp/parse-tree/pt-id.cc	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/parse-tree/pt-id.cc	Wed Sep 13 17:10:51 2017 -0400
@@ -60,7 +60,7 @@
   octave_lvalue
   tree_identifier::lvalue (tree_evaluator *)
   {
-    if (sym->is_added_static ())
+    if (sym.is_added_static ())
       static_workspace_error ();
 
     return octave_lvalue (sym);
--- a/libinterp/parse-tree/pt-id.h	Wed Sep 13 16:42:14 2017 -0700
+++ b/libinterp/parse-tree/pt-id.h	Wed Sep 13 17:10:51 2017 -0400
@@ -73,9 +73,9 @@
     // accessing it through sym so that this function may remain const.
     std::string name (void) const { return sym.name (); }
 
-    bool is_defined (void) { return sym->is_defined (); }
+    bool is_defined (void) { return sym.is_defined (); }
 
-    virtual bool is_variable (void) const { return sym->is_variable (); }
+    virtual bool is_variable (void) const { return sym.is_variable (); }
 
     virtual bool is_black_hole (void) { return false; }
 
@@ -97,14 +97,14 @@
     octave_value
     do_lookup (const octave_value_list& args = octave_value_list ())
     {
-      return sym->find (args);
+      return sym.find (args);
     }
 
-    void mark_global (void) { sym->mark_global (); }
+    void mark_global (void) { sym.mark_global (); }
 
-    void mark_persistent (void) { sym->init_persistent (); }
+    void mark_persistent (void) { sym.init_persistent (); }
 
-    void mark_as_formal_parameter (void) { sym->mark_formal (); }
+    void mark_as_formal_parameter (void) { sym.mark_formal (); }
 
     // We really need to know whether this symbol referst to a variable
     // or a function, but we may not know that yet.
@@ -128,14 +128,15 @@
       tw.visit_identifier (*this);
     }
 
-    symbol_table::symbol_reference symbol (void) const
+    symbol_table::symbol_record symbol (void) const
     {
       return sym;
     }
+
   private:
 
     // The symbol record that this identifier references.
-    symbol_table::symbol_reference sym;
+    symbol_table::symbol_record sym;
   };
 
   class tree_black_hole : public tree_identifier
@@ -158,7 +159,9 @@
 
     octave_lvalue lvalue (tree_evaluator *)
     {
-      return octave_lvalue (); // black hole lvalue
+      octave_lvalue retval;
+      retval.mark_black_hole ();
+      return retval;
     }
   };
 }