changeset 33298:e3d55a08aff4 bytecode-interpreter

maint: merge default to bytecode-interpreter
author John W. Eaton <jwe@octave.org>
date Tue, 02 Apr 2024 16:11:12 -0400
parents 85f39533661d (current diff) 0376082b659f (diff)
children 95596df836a1
files libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/module.mk libinterp/parse-tree/pt-eval.cc
diffstat 42 files changed, 1468 insertions(+), 1793 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/cdef-class.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/octave-value/cdef-class.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -969,7 +969,7 @@
 
       // Method blocks
 
-      std::list<tree_classdef_methods_block *> mb_list = b->methods_list ();
+      std::list<tree_classdef_methods_block *> mb_list = b->method_list ();
 
       load_path& lp = interp.get_load_path ();
 
@@ -1083,7 +1083,7 @@
       //        evaluating default value expressions.
 
       std::list<tree_classdef_properties_block *> pb_list
-        = b->properties_list ();
+        = b->property_list ();
 
       for (auto& pb_p : pb_list)
         {
--- a/libinterp/octave-value/ov-usr-fcn.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -45,6 +45,7 @@
 #include "ov-usr-fcn.h"
 #include "ov.h"
 #include "pager.h"
+#include "pt-cmd.h"
 #include "pt-eval.h"
 #include "pt-jump.h"
 #include "pt-misc.h"
@@ -263,7 +264,6 @@
  octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
   : octave_user_code ("", "", scope, cl, ""),
     m_param_list (pl), m_ret_list (rl),
-    m_lead_comm (), m_trail_comm (),
     m_location_line (0), m_location_column (0),
     m_system_fcn_file (false),
     m_num_named_args (m_param_list ? m_param_list->size () : 0),
@@ -279,8 +279,6 @@
 {
   delete m_param_list;
   delete m_ret_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
 }
 
 std::string
@@ -314,6 +312,39 @@
   return this;
 }
 
+void
+octave_user_function::attach_trailing_comments (const octave::comment_list& lst)
+{
+  if (m_cmd_list && ! m_cmd_list->empty ())
+    {
+      octave::tree_statement *last_stmt = m_cmd_list->back ();
+
+      octave::tree_command *cmd = last_stmt->command ();
+
+      octave::tree_no_op_command *no_op_cmd = dynamic_cast <octave::tree_no_op_command *> (cmd);
+
+      if (no_op_cmd && (no_op_cmd->is_end_of_fcn_or_script () || no_op_cmd->is_end_of_file ()))
+        no_op_cmd->attach_trailing_comments (lst);
+    }
+}
+
+octave::comment_list octave_user_function::trailing_comments () const
+{
+  if (m_cmd_list && ! m_cmd_list->empty ())
+    {
+      octave::tree_statement *last_stmt = m_cmd_list->back ();
+
+      octave::tree_command *cmd = last_stmt->command ();
+
+      octave::tree_no_op_command *no_op_cmd = dynamic_cast <octave::tree_no_op_command *> (cmd);
+
+      if (no_op_cmd && (no_op_cmd->is_end_of_fcn_or_script () || no_op_cmd->is_end_of_file ()))
+        return no_op_cmd->trailing_comments ();
+    }
+
+  return octave::comment_list ();
+}
+
 // If there is no explicit end statement at the end of the function,
 // relocate the no_op that was generated for the end of file condition
 // to appear on the next line after the last statement in the file, or
--- a/libinterp/octave-value/ov-usr-fcn.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.h	Tue Apr 02 16:11:12 2024 -0400
@@ -35,6 +35,7 @@
 #include "ov-fcn.h"
 #include "ov-typeinfo.h"
 #include "symscope.h"
+#include "token.h"
 #include "unwind-prot.h"
 #if defined (OCTAVE_ENABLE_BYTECODE_EVALUATOR)
 #  include "pt-bytecode.h"
@@ -248,6 +249,11 @@
 
   octave_user_function * define_ret_list (octave::tree_parameter_list *t);
 
+  void set_fcn_tok (const octave::token& fcn_tok) { m_fcn_tok = fcn_tok; }
+  void set_eq_tok (const octave::token& eq_tok) { m_eq_tok = eq_tok; }
+
+  void attach_trailing_comments (const octave::comment_list& lst);
+
   void stash_fcn_location (int line, int col)
   {
     m_location_line = line;
@@ -270,10 +276,6 @@
 
   void stash_parent_fcn_scope (const octave::symbol_scope& ps);
 
-  void stash_leading_comment (octave::comment_list *lc) { m_lead_comm = lc; }
-
-  void stash_trailing_comment (octave::comment_list *tc) { m_trail_comm = tc; }
-
   std::string profiler_name () const;
 
   std::string parent_fcn_name () const
@@ -410,9 +412,8 @@
 
   octave::tree_parameter_list * return_list () { return m_ret_list; }
 
-  octave::comment_list * leading_comment () { return m_lead_comm; }
-
-  octave::comment_list * trailing_comment () { return m_trail_comm; }
+  octave::comment_list leading_comments () const { return m_fcn_tok.leading_comments (); }
+  octave::comment_list trailing_comments () const;
 
   // If is_special_expr is true, retrieve the sigular expression that forms the
   // body.  May be null (even if is_special_expr is true).
@@ -443,11 +444,10 @@
   // this function.
   octave::tree_parameter_list *m_ret_list;
 
-  // The comments preceding the FUNCTION token.
-  octave::comment_list *m_lead_comm;
-
-  // The comments preceding the ENDFUNCTION token.
-  octave::comment_list *m_trail_comm;
+  // FIXME: Should we also be caching the final token (END or EOF) as
+  // m_end_tok?
+  octave::token m_fcn_tok;
+  octave::token m_eq_tok;
 
   // Location where this function was defined.
   int m_location_line;
--- a/libinterp/parse-tree/comment-list.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/comment-list.h	Tue Apr 02 16:11:12 2024 -0400
@@ -29,6 +29,7 @@
 #include "octave-config.h"
 
 #include <list>
+#include <memory>
 #include <string>
 
 OCTAVE_BEGIN_NAMESPACE(octave)
@@ -105,31 +106,53 @@
   bool m_uses_hash_char;
 };
 
-class comment_list : public std::list<comment_elt>
+class comment_list
 {
 public:
 
   OCTAVE_DEFAULT_CONSTRUCT_COPY_MOVE_DELETE (comment_list)
 
+  typedef std::list<comment_elt>::reference reference;
+  typedef std::list<comment_elt>::const_reference const_reference;
+
+  typedef std::list<comment_elt>::iterator iterator;
+  typedef std::list<comment_elt>::const_iterator const_iterator;
+
   void append (const comment_elt& elt)
   {
-    push_back (elt);
+    m_list.push_back (elt);
   }
 
   void append (const std::string& s,
                comment_elt::comment_type t = comment_elt::unknown,
                bool uses_hash_char = false)
   {
-    push_back (comment_elt (s, t, uses_hash_char));
+    m_list.push_back (comment_elt (s, t, uses_hash_char));
   }
 
+  void clear () { m_list.clear (); }
+
+  bool empty () const { return m_list.empty (); }
+
+  reference front () { return m_list.front (); }
+  reference back () { return m_list.back (); }
+
+  const_reference front () const { return m_list.front (); }
+  const_reference back () const { return m_list.back (); }
+
+  iterator begin () { return m_list.begin (); }
+  iterator end () { return m_list.end (); }
+
+  const_iterator begin () const { return m_list.begin (); }
+  const_iterator end () const { return m_list.end (); }
+
   comment_list * dup () const;
 
   // Documentation for functions is typically the first block of
   // comments that doesn't look like a copyright statement.
   comment_elt find_doc_comment () const
   {
-    for (const auto& elt : *this)
+    for (const auto& elt : m_list)
       {
         // FIXME: should we also omit end-of-line comments?
         if (! elt.is_copyright ())
@@ -143,6 +166,10 @@
   {
     return find_doc_comment().text ();
   }
+
+private:
+
+  std::list<comment_elt> m_list;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/lex.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/lex.h	Tue Apr 02 16:11:12 2024 -0400
@@ -483,7 +483,7 @@
   std::string m_current_input_line;
 
   // The text of the current comment, used to gather comment lines
-  // before storing in m_comment_buf.
+  // before storing in m_comment_list.
   std::string m_comment_text;
 
   // The text of functions entered on the command line.
@@ -559,52 +559,8 @@
     bool m_eof;
   };
 
-  // Collect comment text.
-
-  class comment_buffer
-  {
-  public:
-
-    comment_buffer () : m_comment_list (nullptr) { }
-
-    OCTAVE_DISABLE_COPY_MOVE (comment_buffer)
-
-    ~comment_buffer () { delete m_comment_list; }
-
-    void append (const std::string& s, comment_elt::comment_type t, bool uses_hash_char)
-    {
-      if (! m_comment_list)
-        m_comment_list = new comment_list ();
-
-      m_comment_list->append (s, t, uses_hash_char);
-    }
-
-    // Caller is expected to delete the returned value.
-
-    comment_list * get_comment_list ()
-    {
-      comment_list *retval = m_comment_list;
-
-      m_comment_list = nullptr;
-
-      return retval;
-    }
-
-    void reset ()
-    {
-      delete m_comment_list;
-
-      m_comment_list = nullptr;
-    }
-
-  private:
-
-    comment_list *m_comment_list;
-  };
-
   base_lexer (interpreter& interp)
-    : lexical_feedback (interp), m_scanner (nullptr), m_input_buf (),
-      m_comment_buf ()
+    : lexical_feedback (interp), m_scanner (nullptr), m_input_buf ()
   {
     init ();
   }
@@ -661,7 +617,12 @@
 
   void finish_comment (comment_elt::comment_type typ);
 
-  comment_list * get_comment_list () { return m_comment_buf.get_comment_list (); }
+  comment_list get_comment_list ()
+  {
+    comment_list retval = m_comment_list;
+    m_comment_list.clear ();
+    return retval;
+  }
 
   int handle_close_bracket (int bracket_type);
 
@@ -717,8 +678,8 @@
   // Object that reads and buffers input.
   input_buffer m_input_buf;
 
-  // Object that collects comment text.
-  comment_buffer m_comment_buf;
+  // List of collected comments.
+  comment_list m_comment_list;
 
   virtual std::string input_source () const { return "unknown"; }
 
--- a/libinterp/parse-tree/lex.ll	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/lex.ll	Tue Apr 02 16:11:12 2024 -0400
@@ -991,7 +991,7 @@
         curr_lexer->m_looking_for_object_index = true;
         curr_lexer->m_at_beginning_of_statement = false;
 
-        octave::token *tok = new octave::token (DQ_STRING, curr_lexer->m_string_text, curr_lexer->m_tok_beg, curr_lexer->m_tok_end);
+        octave::token *tok = new octave::token (DQ_STRING, curr_lexer->m_string_text, curr_lexer->m_tok_beg, curr_lexer->m_tok_end, curr_lexer->get_comment_list ());
 
         curr_lexer->m_string_text = "";
 
@@ -1141,7 +1141,7 @@
         curr_lexer->m_looking_for_object_index = true;
         curr_lexer->m_at_beginning_of_statement = false;
 
-        octave::token *tok = new octave::token (SQ_STRING, curr_lexer->m_string_text, curr_lexer->m_tok_beg, curr_lexer->m_tok_end);
+        octave::token *tok = new octave::token (SQ_STRING, curr_lexer->m_string_text, curr_lexer->m_tok_beg, curr_lexer->m_tok_end, curr_lexer->get_comment_list ());
 
         curr_lexer->m_string_text = "";
 
@@ -1407,7 +1407,7 @@
 
                 curr_lexer->m_looking_for_object_index = true;
 
-                tok = new octave::token (FCN_HANDLE, ident, curr_lexer->m_tok_beg, curr_lexer->m_tok_end);
+                tok = new octave::token (FCN_HANDLE, ident, curr_lexer->m_tok_beg, curr_lexer->m_tok_end, curr_lexer->get_comment_list ());
 
                 return curr_lexer->handle_token (tok);
               }
@@ -2441,7 +2441,7 @@
 
     lexical_feedback::reset ();
 
-    m_comment_buf.reset ();
+    m_comment_list.clear ();
   }
 
   void
@@ -2479,7 +2479,7 @@
         syntax_error (msg);
       }
 
-    token *tok = new token (END_OF_INPUT, m_tok_beg, m_tok_end);
+    token *tok = new token (END_OF_INPUT, m_tok_beg, m_tok_end, get_comment_list ());
 
     return handle_token (tok);
   }
@@ -2644,47 +2644,47 @@
             return nullptr;
           }
 
-        tok = new token (kw->tok_id, token::simple_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::simple_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case end_try_catch_kw:
-        tok = new token (kw->tok_id, token::try_catch_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::try_catch_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case end_unwind_protect_kw:
-        tok = new token (kw->tok_id, token::unwind_protect_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::unwind_protect_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endfor_kw:
-        tok = new token (kw->tok_id, token::for_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::for_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endfunction_kw:
-        tok = new token (kw->tok_id, token::function_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::function_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endif_kw:
-        tok = new token (kw->tok_id, token::if_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::if_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endparfor_kw:
-        tok = new token (kw->tok_id, token::parfor_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::parfor_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endswitch_kw:
-        tok = new token (kw->tok_id, token::switch_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::switch_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endwhile_kw:
-        tok = new token (kw->tok_id, token::while_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::while_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
@@ -2692,33 +2692,33 @@
 #if defined (DISABLE_ARGUMENTS_VALIDATION_BLOCK)
         return nullptr;
 #else
-        tok = new token (kw->tok_id, token::arguments_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::arguments_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 #endif
 
       case endclassdef_kw:
-        tok = new token (kw->tok_id, token::classdef_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::classdef_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endenumeration_kw:
-        tok = new token (kw->tok_id, token::enumeration_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::enumeration_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endevents_kw:
-        tok = new token (kw->tok_id, token::events_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::events_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endmethods_kw:
-        tok = new token (kw->tok_id, token::methods_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::methods_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
       case endproperties_kw:
-        tok = new token (kw->tok_id, token::properties_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::properties_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
@@ -2821,7 +2821,7 @@
         break;
 
       case endspmd_kw:
-        tok = new token (kw->tok_id, token::spmd_end, m_tok_beg, m_tok_end);
+        tok = new token (kw->tok_id, token::spmd_end, m_tok_beg, m_tok_end, get_comment_list ());
         m_at_beginning_of_statement = true;
         break;
 
@@ -2830,9 +2830,9 @@
           if ((m_reading_fcn_file || m_reading_script_file
                || m_reading_classdef_file)
               && ! m_fcn_file_full_name.empty ())
-            tok = new token (kw->tok_id, m_fcn_file_full_name, m_tok_beg, m_tok_end);
+            tok = new token (kw->tok_id, m_fcn_file_full_name, m_tok_beg, m_tok_end, get_comment_list ());
           else
-            tok = new token (kw->tok_id, "stdin", m_tok_beg, m_tok_end);
+            tok = new token (kw->tok_id, "stdin", m_tok_beg, m_tok_end, get_comment_list ());
         }
         break;
 
@@ -2840,7 +2840,7 @@
         {
           int l = m_tok_beg.line ();
           octave_value ov_value (static_cast<double> (l));
-          tok = new token (kw->tok_id, ov_value, "", m_tok_beg, m_tok_end);
+          tok = new token (kw->tok_id, ov_value, "", m_tok_beg, m_tok_end, get_comment_list ());
         }
         break;
 
@@ -2849,7 +2849,7 @@
       }
 
     if (! tok)
-      tok = new token (kw->tok_id, true, m_tok_beg, m_tok_end);
+            tok = new token (kw->tok_id, true, m_tok_beg, m_tok_end, get_comment_list ());
 
     return tok;
   }
@@ -3036,7 +3036,7 @@
 
     update_token_positions (flex_yyleng ());
 
-    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end);
+    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end, get_comment_list ());
 
     return handle_token (tok);
   }
@@ -3158,7 +3158,7 @@
                   ? octave_value (Complex (0.0, value))
                   : octave_value (value));
 
-    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end);
+    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end, get_comment_list ());
 
     return handle_token (tok);
   }
@@ -3229,7 +3229,7 @@
 
     update_token_positions (flex_yyleng ());
 
-    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end);
+    token *tok = new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end, get_comment_list ());
 
     return handle_token (tok);
   }
@@ -3307,7 +3307,7 @@
     if (looks_like_copyright (m_comment_text))
       typ = comment_elt::copyright;
 
-    m_comment_buf.append (m_comment_text, typ, m_comment_uses_hash_char);
+    m_comment_list.append (m_comment_text, typ, m_comment_uses_hash_char);
 
     m_comment_text = "";
     m_comment_uses_hash_char = false;
@@ -3373,7 +3373,7 @@
         return syntax_error (msg);
       }
 
-    token *tok = new token (SUPERCLASSREF, meth, cls, m_tok_beg, m_tok_end);
+    token *tok = new token (SUPERCLASSREF, meth, cls, m_tok_beg, m_tok_end, get_comment_list ());
 
     m_filepos.increment_column (flex_yyleng ());
 
@@ -3388,7 +3388,7 @@
 
     m_looking_for_object_index = true;
 
-    token *tok = new token (METAQUERY, cls, m_tok_beg, m_tok_end);
+    token *tok = new token (METAQUERY, cls, m_tok_beg, m_tok_end, get_comment_list ());
 
     m_filepos.increment_column (flex_yyleng ());
 
@@ -3403,7 +3403,7 @@
 
     m_looking_for_object_index = true;
 
-    token *tok = new token (FQ_IDENT, ident, m_tok_beg, m_tok_end);
+    token *tok = new token (FQ_IDENT, ident, m_tok_beg, m_tok_end, get_comment_list ());
 
     m_filepos.increment_column (flex_yyleng ());
 
@@ -3427,7 +3427,7 @@
 
     if (m_looking_at_indirect_ref)
       {
-        token *tok = new token (STRUCT_ELT, ident, m_tok_beg, m_tok_end);
+        token *tok = new token (STRUCT_ELT, ident, m_tok_beg, m_tok_end, get_comment_list ());
 
         m_looking_for_object_index = true;
 
@@ -3452,7 +3452,7 @@
         return handle_token (tok);
       }
 
-    tok = new token (NAME, ident, m_tok_beg, m_tok_end);
+    tok = new token (NAME, ident, m_tok_beg, m_tok_end, get_comment_list ());
 
     // For compatibility with Matlab, the following symbols are
     // handled specially so that things like
@@ -3889,7 +3889,7 @@
 
     update_token_positions (flex_yyleng ());
 
-    token *tok = new token (tok_id, m_tok_beg, m_tok_end);
+    token *tok = new token (tok_id, m_tok_beg, m_tok_end, get_comment_list ());
 
     m_looking_for_object_index = false;
     m_at_beginning_of_statement = bos;
@@ -3923,7 +3923,7 @@
   int
   base_lexer::finish_command_arg ()
   {
-    token *tok = new token (SQ_STRING, m_string_text, m_tok_beg, m_tok_end);
+    token *tok = new token (SQ_STRING, m_string_text, m_tok_beg, m_tok_end, get_comment_list ());
 
     m_string_text = "";
     m_command_arg_paren_count = 0;
--- a/libinterp/parse-tree/module.mk	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/module.mk	Tue Apr 02 16:11:12 2024 -0400
@@ -27,6 +27,7 @@
   %reldir%/pt-colon.h \
   %reldir%/pt-const.h \
   %reldir%/pt-decl.h \
+  %reldir%/pt-delimiter-list.h \
   %reldir%/pt-eval.h \
   %reldir%/pt-except.h \
   %reldir%/pt-exp.h \
--- a/libinterp/parse-tree/oct-parse.yy	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/oct-parse.yy	Tue Apr 02 16:11:12 2024 -0400
@@ -141,9 +141,6 @@
   // The type of the basic tokens returned by the lexer.
   octave::token *tok;
 
-  // Comment strings that we need to deal with mid-rule.
-  octave::comment_list *comment_type;
-
   // Types for the nonterminals we generate.
   char punct_type;
   octave::tree *tree_type;
@@ -190,10 +187,10 @@
   octave::tree_classdef_property* tree_classdef_property_type;
   octave::tree_classdef_property_list* tree_classdef_property_list_type;
   octave::tree_classdef_properties_block* tree_classdef_properties_block_type;
-  octave::tree_classdef_methods_list* tree_classdef_methods_list_type;
+  octave::tree_classdef_method_list* tree_classdef_method_list_type;
   octave::tree_classdef_methods_block* tree_classdef_methods_block_type;
   octave::tree_classdef_event* tree_classdef_event_type;
-  octave::tree_classdef_events_list* tree_classdef_events_list_type;
+  octave::tree_classdef_event_list* tree_classdef_event_list_type;
   octave::tree_classdef_events_block* tree_classdef_events_block_type;
   octave::tree_classdef_enum* tree_classdef_enum_type;
   octave::tree_classdef_enum_list* tree_classdef_enum_list_type;
@@ -242,12 +239,11 @@
 // %token VARARGIN VARARGOUT
 
 // Nonterminals we construct.
-%type <dummy_type> indirect_ref_op
 %type <dummy_type> push_fcn_symtab push_script_symtab begin_file
-%type <dummy_type> param_list_beg param_list_end stmt_begin anon_fcn_begin
+%type <dummy_type> stmt_begin anon_fcn_begin
 %type <dummy_type> parsing_local_fcns parse_error at_first_executable_stmt
-%type <comment_type> stash_comment
-%type <tok> function_beg classdef_beg arguments_beg
+%type <tok> param_list_beg param_list_end
+%type <tok> function_beg classdef_beg arguments_beg indirect_ref_op
 %type <tok> properties_beg methods_beg events_beg enumeration_beg
 %type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep
 %type <tree_type> input
@@ -275,8 +271,8 @@
 %type <tree_classdef_type> classdef
 %type <tree_command_type> file
 %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
+%type <tree_if_command_list_type> if_clause_list
+%type <tree_if_clause_type> if_clause elseif_clause else_clause
 %type <tree_switch_command_type> switch_command
 %type <tree_switch_case_type> switch_case default_case
 %type <tree_switch_case_list_type> case_list1 case_list
@@ -295,10 +291,10 @@
 %type <tree_classdef_property_type> class_property
 %type <tree_classdef_property_list_type> property_list property_list1
 %type <tree_classdef_properties_block_type> properties_block
-%type <tree_classdef_methods_list_type> methods_list methods_list1
+%type <tree_classdef_method_list_type> method_list method_list1
 %type <tree_classdef_methods_block_type> methods_block
 %type <tree_classdef_event_type> class_event
-%type <tree_classdef_events_list_type> events_list events_list1
+%type <tree_classdef_event_list_type> event_list event_list1
 %type <tree_classdef_events_block_type> events_block
 %type <tree_classdef_enum_type> class_enum
 %type <tree_classdef_enum_list_type> enum_list enum_list1
@@ -311,7 +307,6 @@
 %type <tree_arg_size_spec_type> size_spec
 %type <tree_identifier_type> class_name
 %type <tree_arg_validation_fcns_type> validation_fcns
-%type <tree_expression_type> default_value
 %type <octave_user_function_type> method_decl1
 
 // Precedence and associativity.
@@ -338,7 +333,6 @@
 
 %destructor { } <tok>
 %destructor { } <punct_type>
-%destructor { } <comment_type>
 %destructor { } <>
 
 %destructor { delete $$; } <tree_type>
@@ -384,10 +378,10 @@
 %destructor { delete $$; } <tree_classdef_property_type>
 %destructor { delete $$; } <tree_classdef_property_list_type>
 %destructor { delete $$; } <tree_classdef_properties_block_type>
-%destructor { delete $$; } <tree_classdef_methods_list_type>
+%destructor { delete $$; } <tree_classdef_method_list_type>
 %destructor { delete $$; } <tree_classdef_methods_block_type>
 %destructor { delete $$; } <tree_classdef_event_type>
-%destructor { delete $$; } <tree_classdef_events_list_type>
+%destructor { delete $$; } <tree_classdef_event_list_type>
 %destructor { delete $$; } <tree_classdef_events_block_type>
 %destructor { delete $$; } <tree_classdef_enum_type>
 %destructor { delete $$; } <tree_classdef_enum_list_type>
@@ -523,7 +517,7 @@
 
 word_list_cmd   : identifier word_list
                   {
-                    $$ = parser.make_index_expression ($1, $2, '(');
+                    $$ = parser.make_index_expression ($1, nullptr, $2, nullptr, '(');
                     if (! $$)
                       {
                         // make_index_expression deleted $1 and $2.
@@ -536,7 +530,7 @@
 word_list       : string
                   { $$ = parser.make_argument_list ($1); }
                 | word_list string
-                  { $$ = parser.append_argument_list ($1, $2); }
+                  { $$ = parser.append_argument_list ($1, nullptr, $2); }
                 ;
 
 // ===========
@@ -569,30 +563,26 @@
                 ;
 
 matrix          : '[' matrix_rows ']'
-                  { $$ = parser.finish_matrix ($2, $1, $3); }
+                  { $$ = parser.finish_matrix ($1, $2, $3); }
                 ;
 
 matrix_rows     : cell_or_matrix_row
                   { $$ = parser.make_matrix ($1); }
                 | matrix_rows ';' cell_or_matrix_row
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_matrix_row ($1, $3);
+                    $$ = parser.append_matrix_row ($1, $2, $3);
                   }
                 ;
 
 cell            : '{' cell_rows '}'
-                  { $$ = parser.finish_cell ($2, $1, $3); }
+                  { $$ = parser.finish_cell ($1, $2, $3); }
                 ;
 
 cell_rows       : cell_or_matrix_row
                   { $$ = parser.make_cell ($1); }
                 | cell_rows ';' cell_or_matrix_row
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_cell_row ($1, $3);
+                    $$ = parser.append_cell_row ($1, $2, $3);
                   }
                 ;
 
@@ -685,9 +675,7 @@
                   { $$ = $1; }
                 | '(' expression ')'
                   {
-                    OCTAVE_YYUSE ($1, $3);
-
-                    $$ = $2->mark_in_parens ();
+                    $$ = $2->mark_in_delims (*($1), *($3));
                   }
                 ;
 
@@ -697,9 +685,7 @@
 
 magic_tilde     : '~'
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = parser.make_black_hole ();
+                    $$ = parser.make_black_hole ($1);
                   }
                 ;
 
@@ -711,44 +697,35 @@
                   { $$ = parser.make_argument_list ($1); }
                 | arg_list ',' magic_colon
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_argument_list ($1, $3);
+                    $$ = parser.append_argument_list ($1, $2, $3);
                   }
                 | arg_list ',' magic_tilde
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_argument_list ($1, $3);
+                    $$ = parser.append_argument_list ($1, $2, $3);
                   }
                 | arg_list ',' expression
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_argument_list ($1, $3);
+                    $$ = parser.append_argument_list ($1, $2, $3);
                   }
                 ;
 
 indirect_ref_op : '.'
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = 0;
                     lexer.m_looking_at_indirect_ref = true;
+                    $$ = $1;
                   }
                 ;
 
 oper_expr       : primary_expr
                   { $$ = $1; }
                 | oper_expr PLUS_PLUS
-                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | oper_expr MINUS_MINUS
-                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | oper_expr '(' ')'
                   {
-                    OCTAVE_YYUSE ($2, $3);
-
-                    $$ = parser.make_index_expression ($1, nullptr, '(');
+                    $$ = parser.make_index_expression ($1, $2, nullptr, $3, '(');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1.
@@ -757,9 +734,8 @@
                   }
                 | oper_expr '(' arg_list ')'
                   {
-                    OCTAVE_YYUSE ($2, $4);
-
-                    $$ = parser.make_index_expression ($1, $3, '(');
+                    $$ = parser.make_index_expression ($1, $2, $3, $4, '(');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1 and $3.
@@ -768,9 +744,8 @@
                   }
                 | oper_expr '{' '}'
                   {
-                    OCTAVE_YYUSE ($2, $3);
-
-                    $$ = parser.make_index_expression ($1, nullptr, '{');
+                    $$ = parser.make_index_expression ($1, $2, nullptr, $3, '{');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1.
@@ -779,9 +754,8 @@
                   }
                 | oper_expr '{' arg_list '}'
                   {
-                    OCTAVE_YYUSE ($2, $4);
-
-                    $$ = parser.make_index_expression ($1, $3, '{');
+                    $$ = parser.make_index_expression ($1, $2, $3, $4, '{');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1 and $3.
@@ -789,62 +763,57 @@
                       }
                   }
                 | oper_expr HERMITIAN
-                  { $$ = parser.make_postfix_op (HERMITIAN, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | oper_expr TRANSPOSE
-                  { $$ = parser.make_postfix_op (TRANSPOSE, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | oper_expr indirect_ref_op STRUCT_ELT
-                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
+                  { $$ = parser.make_indirect_ref ($1, $2, $3); }
                 | oper_expr indirect_ref_op '(' expression ')'
-                  {
-                    OCTAVE_YYUSE ($3, $5);
-
-                    $$ = parser.make_indirect_ref ($1, $4);
-                  }
+                  { $$ = parser.make_indirect_ref ($1, $2, $3, $4, $5); }
                 | PLUS_PLUS oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | MINUS_MINUS oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '~' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('~', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '!' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('!', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '+' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('+', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '-' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('-', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | oper_expr POW power_expr
-                  { $$ = parser.make_binary_op (POW, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr EPOW power_expr
-                  { $$ = parser.make_binary_op (EPOW, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr '+' oper_expr
-                  { $$ = parser.make_binary_op ('+', $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr '-' oper_expr
-                  { $$ = parser.make_binary_op ('-', $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr '*' oper_expr
-                  { $$ = parser.make_binary_op ('*', $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr '/' oper_expr
-                  { $$ = parser.make_binary_op ('/', $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr EMUL oper_expr
-                  { $$ = parser.make_binary_op (EMUL, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr EDIV oper_expr
-                  { $$ = parser.make_binary_op (EDIV, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr LEFTDIV oper_expr
-                  { $$ = parser.make_binary_op (LEFTDIV, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | oper_expr ELEFTDIV oper_expr
-                  { $$ = parser.make_binary_op (ELEFTDIV, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 ;
 
 power_expr      : primary_expr
                   { $$ = $1; }
                 | power_expr PLUS_PLUS
-                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | power_expr MINUS_MINUS
-                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
+                  { $$ = parser.make_postfix_op ($1, $2); }
                 | power_expr '(' ')'
                   {
-                    OCTAVE_YYUSE ($2, $3);
-
-                    $$ = parser.make_index_expression ($1, nullptr, '(');
+                    $$ = parser.make_index_expression ($1, $2, nullptr, $3, '(');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1.
@@ -853,9 +822,8 @@
                   }
                 | power_expr '(' arg_list ')'
                   {
-                    OCTAVE_YYUSE ($2, $4);
-
-                    $$ = parser.make_index_expression ($1, $3, '(');
+                    $$ = parser.make_index_expression ($1, $2, $3, $4, '(');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1 and $3.
@@ -864,9 +832,8 @@
                   }
                 | power_expr '{' '}'
                   {
-                    OCTAVE_YYUSE ($2, $3);
-
-                    $$ = parser.make_index_expression ($1, nullptr, '{');
+                    $$ = parser.make_index_expression ($1, $2, nullptr, $3, '{');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1.
@@ -875,9 +842,8 @@
                   }
                 | power_expr '{' arg_list '}'
                   {
-                    OCTAVE_YYUSE ($2, $4);
-
-                    $$ = parser.make_index_expression ($1, $3, '{');
+                    $$ = parser.make_index_expression ($1, $2, $3, $4, '{');
+
                     if (! $$)
                       {
                         // make_index_expression deleted $1 and $3.
@@ -885,32 +851,26 @@
                       }
                   }
                 | power_expr indirect_ref_op STRUCT_ELT
-                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
+                  { $$ = parser.make_indirect_ref ($1, $2, $3); }
                 | power_expr indirect_ref_op '(' expression ')'
-                  {
-                    OCTAVE_YYUSE ($3, $5);
-
-                    $$ = parser.make_indirect_ref ($1, $4);
-                  }
+                  { $$ = parser.make_indirect_ref ($1, $2, $3, $4, $5); }
                 | PLUS_PLUS power_expr %prec POW
-                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | MINUS_MINUS power_expr %prec POW
-                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '~' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('~', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '!' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('!', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '+' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('+', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 | '-' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('-', $2, $1); }
+                  { $$ = parser.make_prefix_op ($1, $2); }
                 ;
 
 colon_expr      : oper_expr ':' oper_expr
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.make_colon_expression ($1, $3);
+                    $$ = parser.make_colon_expression ($1, $2, $3);
 
                     if (! $$)
                       {
@@ -920,9 +880,7 @@
                   }
                 | oper_expr ':' oper_expr ':' oper_expr
                   {
-                    OCTAVE_YYUSE ($2, $4);
-
-                    $$ = parser.make_colon_expression ($1, $5, $3);
+                    $$ = parser.make_colon_expression ($1, $2, $3, $4, $5);
 
                     if (! $$)
                       {
@@ -937,25 +895,25 @@
                 | colon_expr
                   { $$ = $1; }
                 | simple_expr EXPR_LT simple_expr
-                  { $$ = parser.make_binary_op (EXPR_LT, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_LE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_LE, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_EQ simple_expr
-                  { $$ = parser.make_binary_op (EXPR_EQ, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_GE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_GE, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_GT simple_expr
-                  { $$ = parser.make_binary_op (EXPR_GT, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_NE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_NE, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_AND simple_expr
-                  { $$ = parser.make_binary_op (EXPR_AND, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_OR simple_expr
-                  { $$ = parser.make_binary_op (EXPR_OR, $1, $2, $3); }
+                  { $$ = parser.make_binary_op ($1, $2, $3); }
                 | simple_expr EXPR_AND_AND simple_expr
-                  { $$ = parser.make_boolean_op (EXPR_AND_AND, $1, $2, $3); }
+                  { $$ = parser.make_boolean_op ($1, $2, $3); }
                 | simple_expr EXPR_OR_OR simple_expr
-                  { $$ = parser.make_boolean_op (EXPR_OR_OR, $1, $2, $3); }
+                  { $$ = parser.make_boolean_op ($1, $2, $3); }
                 ;
 
 assign_lhs      : simple_expr
@@ -973,31 +931,31 @@
                 ;
 
 assign_expr     : assign_lhs '=' expression
-                  { $$ = parser.make_assign_op ('=', $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs ADD_EQ expression
-                  { $$ = parser.make_assign_op (ADD_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs SUB_EQ expression
-                  { $$ = parser.make_assign_op (SUB_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs MUL_EQ expression
-                  { $$ = parser.make_assign_op (MUL_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs DIV_EQ expression
-                  { $$ = parser.make_assign_op (DIV_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs LEFTDIV_EQ expression
-                  { $$ = parser.make_assign_op (LEFTDIV_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs POW_EQ expression
-                  { $$ = parser.make_assign_op (POW_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs EMUL_EQ expression
-                  { $$ = parser.make_assign_op (EMUL_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs EDIV_EQ expression
-                  { $$ = parser.make_assign_op (EDIV_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs ELEFTDIV_EQ expression
-                  { $$ = parser.make_assign_op (ELEFTDIV_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs EPOW_EQ expression
-                  { $$ = parser.make_assign_op (EPOW_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs AND_EQ expression
-                  { $$ = parser.make_assign_op (AND_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 | assign_lhs OR_EQ expression
-                  { $$ = parser.make_assign_op (OR_EQ, $1, $2, $3); }
+                  { $$ = parser.make_assign_op ($1, $2, $3); }
                 ;
 
 expression      : simple_expr
@@ -1052,12 +1010,12 @@
 
 declaration     : GLOBAL decl_init_list
                   {
-                    $$ = parser.make_decl_command (GLOBAL, $1, $2);
+                    $$ = parser.make_decl_command ($1, $2);
                     lexer.m_looking_at_decl_list = false;
                   }
                 | PERSISTENT decl_init_list
                   {
-                    $$ = parser.make_decl_command (PERSISTENT, $1, $2);
+                    $$ = parser.make_decl_command ($1, $2);
                     lexer.m_looking_at_decl_list = false;
                   }
                 ;
@@ -1088,49 +1046,45 @@
 // If statement
 // ============
 
-if_command      : IF stash_comment if_cmd_list END
+if_command      : if_clause_list else_clause END
                   {
-                    if (! ($$ = parser.finish_if_command ($1, $3, $4, $2)))
+                    if (! ($$ = parser.finish_if_command ($1, $2, $3)))
                       {
-                        // finish_if_command deleted $3.
+                        // finish_if_command deleted $1 and $2.
                         YYABORT;
                       }
                   }
                 ;
 
-if_cmd_list     : if_cmd_list1
-                  { $$ = $1; }
-                | if_cmd_list1 else_clause
-                  { $$ = parser.append_if_clause ($1, $2); }
-                ;
-
-if_cmd_list1    : expression stmt_begin opt_sep opt_list
-                  {
-                    OCTAVE_YYUSE ($3);
-
-                    parser.maybe_convert_to_braindead_shortcircuit ($1);
-
-                    $$ = parser.start_if_command ($1, $4);
-                  }
-                | if_cmd_list1 elseif_clause
+if_clause_list  : if_clause
+                  { $$ = parser.start_if_command ($1); }
+                | if_clause_list elseif_clause
                   { $$ = parser.append_if_clause ($1, $2); }
                 ;
 
-elseif_clause   : ELSEIF stash_comment opt_sep expression stmt_begin opt_sep opt_list
+if_clause       : IF opt_sep expression stmt_begin opt_sep opt_list
                   {
-                    OCTAVE_YYUSE ($3, $6);
-
-                    parser.maybe_convert_to_braindead_shortcircuit ($4);
-
-                    $$ = parser.make_elseif_clause ($1, $4, $7, $2);
+                    OCTAVE_YYUSE ($2, $5);
+
+                    $$ = parser.make_if_clause ($1, $3, $6);
                   }
                 ;
 
-else_clause     : ELSE stash_comment opt_sep opt_list
+elseif_clause   : ELSEIF opt_sep expression stmt_begin opt_sep opt_list
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    $$ = parser.make_else_clause ($1, $2, $4);
+                    OCTAVE_YYUSE ($2, $5);
+
+                    $$ = parser.make_if_clause ($1, $3, $6);
+                  }
+                ;
+
+else_clause     : // empty
+                  { $$ = nullptr; }
+                | ELSE opt_sep opt_list
+                  {
+                    OCTAVE_YYUSE ($2);
+
+                    $$ = parser.make_if_clause ($1, nullptr, $3);
                   }
                 ;
 
@@ -1138,13 +1092,13 @@
 // Switch statement
 // ================
 
-switch_command  : SWITCH stash_comment expression opt_sep case_list END
+switch_command  : SWITCH expression opt_sep case_list END
                   {
-                    OCTAVE_YYUSE ($4);
-
-                    if (! ($$ = parser.finish_switch_command ($1, $3, $5, $6, $2)))
+                    OCTAVE_YYUSE ($3);
+
+                    if (! ($$ = parser.finish_switch_command ($1, $2, $4, $5)))
                       {
-                        // finish_switch_command deleted $3 adn $5.
+                        // finish_switch_command deleted $2 and $4.
                         YYABORT;
                       }
                   }
@@ -1166,19 +1120,19 @@
                   { $$ = parser.append_switch_case ($1, $2); }
                 ;
 
-switch_case     : CASE stash_comment opt_sep expression stmt_begin opt_sep opt_list
+switch_case     : CASE opt_sep expression stmt_begin opt_sep opt_list
                   {
-                    OCTAVE_YYUSE ($3, $6);
-
-                    $$ = parser.make_switch_case ($1, $4, $7, $2);
+                    OCTAVE_YYUSE ($2, $5);
+
+                    $$ = parser.make_switch_case ($1, $3, $6);
                   }
                 ;
 
-default_case    : OTHERWISE stash_comment opt_sep opt_list
+default_case    : OTHERWISE opt_sep opt_list
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    $$ = parser.make_default_switch_case ($1, $2, $4);
+                    OCTAVE_YYUSE ($2);
+
+                    $$ = parser.make_default_switch_case ($1, $3);
                   }
                 ;
 
@@ -1186,65 +1140,61 @@
 // Looping
 // =======
 
-loop_command    : WHILE stash_comment expression stmt_begin opt_sep opt_list END
+loop_command    : WHILE expression stmt_begin opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($5);
-
-                    parser.maybe_convert_to_braindead_shortcircuit ($3);
-
-                    if (! ($$ = parser.make_while_command ($1, $3, $6, $7, $2)))
+                    OCTAVE_YYUSE ($4);
+
+                    parser.maybe_convert_to_braindead_shortcircuit ($2);
+
+                    if (! ($$ = parser.make_while_command ($1, $2, $5, $6)))
                       {
-                        // make_while_command deleted $3 and $6.
+                        // make_while_command deleted $2 and $5.
                         YYABORT;
                       }
                   }
-                | DO stash_comment opt_sep opt_list UNTIL expression
+                | DO opt_sep opt_list UNTIL expression
                   {
-                    OCTAVE_YYUSE ($1, $3);
-
-                    $$ = parser.make_do_until_command ($5, $4, $6, $2);
+                    OCTAVE_YYUSE ($2);
+
+                    $$ = parser.make_do_until_command ($1, $3, $4, $5);
                   }
-                | FOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
+                | FOR assign_lhs '=' expression stmt_begin opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($4, $7);
-
-                    if (! ($$ = parser.make_for_command (FOR, $1, $3, $5,
-                                                         nullptr, $8, $9, $2)))
+                    OCTAVE_YYUSE ($6);
+
+                    if (! ($$ = parser.make_for_command ($1, nullptr, $2, $3, $4, nullptr, nullptr, nullptr, $7, $8)))
+                      {
+                        // make_for_command deleted $2, $4, and $7.
+                        YYABORT;
+                      }
+                  }
+                | FOR '(' assign_lhs '=' expression ')' opt_sep opt_list END
+                  {
+                    OCTAVE_YYUSE ($2, $4, $6, $7);
+
+                    if (! ($$ = parser.make_for_command ($1, $2, $3, $4, $5, nullptr, nullptr, $6, $8, $9)))
                       {
                         // make_for_command deleted $3, $5, and $8.
                         YYABORT;
                       }
                   }
-                | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END
+                | PARFOR assign_lhs '=' expression stmt_begin opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($3, $5, $7, $8);
-
-                    if (! ($$ = parser.make_for_command (FOR, $1, $4, $6,
-                                                         nullptr, $9, $10, $2)))
+                    OCTAVE_YYUSE ($3, $6);
+
+                    if (! ($$ = parser.make_for_command ($1, nullptr, $2, $3, $4, nullptr, nullptr, nullptr, $7, $8)))
                       {
-                        // make_for_command deleted $4, $6, and $9.
+                        // make_for_command deleted $2, $4, and $7.
                         YYABORT;
                       }
                   }
-                | PARFOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
+                | PARFOR '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($4, $7);
-
-                    if (! ($$ = parser.make_for_command (PARFOR, $1, $3, $5,
-                                                         nullptr, $8, $9, $2)))
+                    OCTAVE_YYUSE ($2, $4, $6, $8, $9);
+
+                    if (! ($$ = parser.make_for_command ($1, $2, $3, $4, $5, $6, $7, $8, $10, $11)))
                       {
-                        // make_for_command deleted $3, $5, and $8.
-                        YYABORT;
-                      }
-                  }
-                | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END
-                  {
-                    OCTAVE_YYUSE ($3, $5, $7, $9, $10);
-
-                    if (! ($$ = parser.make_for_command (PARFOR, $1, $4, $6,
-                                                         $8, $11, $12, $2)))
-                      {
-                        // make_for_command deleted $4, $6, $8, and $11.
+                        // make_for_command deleted $3, $5, $7, and $10.
                         YYABORT;
                       }
                   }
@@ -1272,16 +1222,13 @@
 // Parallel execution pool
 // =======================
 
-spmd_command    : SPMD stash_comment opt_sep opt_list END
+spmd_command    : SPMD opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_spmd_command ($1, $4, $5, lc, tc)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_spmd_command ($1, $3, $4)))
                       {
-                        // make_spmd_command deleted $4, LC, and TC.
+                        // make_spmd_command deleted $3.
                         YYABORT;
                       }
                   }
@@ -1291,36 +1238,33 @@
 // Exceptions
 // ==========
 
-except_command  : UNWIND stash_comment opt_sep opt_list CLEANUP
-                  stash_comment opt_sep opt_list END
+except_command  : UNWIND opt_sep opt_list CLEANUP opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($3, $5, $7);
-
-                    if (! ($$ = parser.make_unwind_command ($1, $4, $8, $9, $2, $6)))
+                    OCTAVE_YYUSE ($2, $5);
+
+                    if (! ($$ = parser.make_unwind_command ($1, $3, $4, $6, $7)))
                       {
-                        // make_unwind_command deleted $4 and $8.
+                        // make_unwind_command deleted $3 and $6.
                         YYABORT;
                       }
                   }
-                | TRY stash_comment opt_sep opt_list CATCH stash_comment
-                  opt_sep opt_list END
+                | TRY opt_sep opt_list CATCH opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($3, $5, $7);
-
-                    if (! ($$ = parser.make_try_command ($1, $4, $7, $8, $9, $2, $6)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_try_command ($1, $3, $4, $5, $6, $7)))
                       {
-                        // make_try_command deleted $4 and $8.
+                        // make_try_command deleted $3 and $6.
                         YYABORT;
                       }
                   }
-                | TRY stash_comment opt_sep opt_list END
+                | TRY opt_sep opt_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    if (! ($$ = parser.make_try_command ($1, $4, 0, nullptr,
-                                                         $5, $2, nullptr)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_try_command ($1, $3, nullptr, 0, nullptr, $4)))
                       {
-                        // make_try_command deleted $4.
+                        // make_try_command deleted $3.
                         YYABORT;
                       }
                   }
@@ -1345,9 +1289,6 @@
 
 param_list_beg  : '('
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = 0;
                     lexer.m_looking_at_parameter_list = true;
                     lexer.m_arguments_is_keyword = false;
 
@@ -1358,17 +1299,18 @@
                         lexer.m_looking_at_function_handle--;
                         lexer.m_looking_at_anon_fcn_args = true;
                       }
+
+                    $$ = $1;
                   }
                 ;
 
 param_list_end  : ')'
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = 0;
                     lexer.m_looking_at_parameter_list = false;
                     lexer.m_arguments_is_keyword = true;
                     lexer.m_looking_for_object_index = false;
+
+                    $$ = $1;
                   }
                 ;
 
@@ -1383,11 +1325,14 @@
                     if ($2)
                       lexer.mark_as_variables ($2->variable_names ());
 
-                    $$ = $2;
+                    $$ = $2->mark_in_delims (*($1), *($3));
                   }
                 | param_list_beg error
                   {
+                    OCTAVE_YYUSE ($1);
+
                     $$ = nullptr;
+
                     parser.bison_error ("invalid parameter list");
                     YYABORT;
                   }
@@ -1416,9 +1361,7 @@
                   { $$ = parser.make_parameter_list (octave::tree_parameter_list::in, $1); }
                 | param_list2 ',' param_list_elt
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_parameter_list ($1, $3);
+                    $$ = parser.append_parameter_list ($1, $2, $3);
                   }
                 ;
 
@@ -1434,18 +1377,17 @@
 
 return_list     : '[' ']'
                   {
-                    OCTAVE_YYUSE ($1, $2);
-
                     lexer.m_looking_at_return_list = false;
 
-                    $$ = parser.make_parameter_list (octave::tree_parameter_list::out);
+                    octave::tree_parameter_list *tmp = parser.make_parameter_list (octave::tree_parameter_list::out);
+
+                    $$ = tmp->mark_in_delims (*($1), *($2));
                   }
                 | identifier
                   {
                     lexer.m_looking_at_return_list = false;
 
-                    octave::tree_parameter_list *tmp
-                      = parser.make_parameter_list (octave::tree_parameter_list::out, $1);
+                    octave::tree_parameter_list *tmp = parser.make_parameter_list (octave::tree_parameter_list::out, $1);
 
                     // Even though this parameter list can contain only
                     // a single identifier, we still need to validate it
@@ -1461,15 +1403,13 @@
                   }
                 | '[' return_list1 ']'
                   {
-                    OCTAVE_YYUSE ($1, $3);
-
                     lexer.m_looking_at_return_list = false;
 
                     // Check for duplicate parameter names, varargin,
                     // or varargout.
 
                     if (parser.validate_param_list ($2, octave::tree_parameter_list::out))
-                      $$ = $2;
+                      $$ = $2->mark_in_delims (*($1), *($3));
                     else
                       {
                         delete $2;
@@ -1484,9 +1424,7 @@
                   }
                 | return_list1 ',' identifier
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_parameter_list ($1, $3);
+                    $$ = parser.append_parameter_list ($1, $2, $3);
                   }
                 ;
 
@@ -1533,8 +1471,7 @@
                     else
                       {
                         octave::tree_statement *end_of_script
-                          = parser.make_end ("endscript", true,
-                                             $4->beg_pos (), $4->end_pos ());
+                          = parser.make_end ("endscript", true, $4, $4->beg_pos (), $4->end_pos ());
 
                         parser.make_script ($3, end_of_script);
                       }
@@ -1546,12 +1483,12 @@
                   }
                 | begin_file opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT
                   {
-                    OCTAVE_YYUSE ($2, $5, $7);
+                    OCTAVE_YYUSE ($2, $5);
 
                     // Unused symbol table context.
                     lexer.m_symtab_context.pop ();
 
-                    if (! parser.finish_classdef_file ($3, $6))
+                    if (! parser.finish_classdef_file ($3, $6, $7))
                       YYABORT;
 
                     $$ = nullptr;
@@ -1583,9 +1520,7 @@
                   }
                 | GET '.' identifier
                   {
-                    OCTAVE_YYUSE ($1, $2);
-
-                    $$ = $3;
+                    $$ = $3->mark_get_set (*($1), *($2));
 
                     lexer.m_parsed_function_name.top () = true;
                     lexer.m_maybe_classdef_get_set_method = false;
@@ -1594,9 +1529,7 @@
                   }
                 | SET '.' identifier
                   {
-                    OCTAVE_YYUSE ($1, $2);
-
-                    $$ = $3;
+                    $$ = $3->mark_get_set (*($1), *($2));
 
                     lexer.m_parsed_function_name.top () = true;
                     lexer.m_maybe_classdef_get_set_method = false;
@@ -1610,8 +1543,7 @@
                     parser.endfunction_found (true);
 
                     if (parser.end_token_ok ($1, octave::token::function_end))
-                      $$ = parser.make_end ("endfunction", false,
-                                            $1->beg_pos (), $1->end_pos ());
+                      $$ = parser.make_end ("endfunction", false, $1, $1->beg_pos (), $1->end_pos ());
                     else
                       {
                         parser.end_token_error ($1, octave::token::function_end);
@@ -1648,29 +1580,26 @@
                         YYABORT;
                       }
 
-                    $$ = parser.make_end ("endfunction", true,
-                                          $1->beg_pos (), $1->end_pos ());
+                    $$ = parser.make_end ("endfunction", true, $1, $1->beg_pos (), $1->end_pos ());
                   }
                 ;
 
-function        : function_beg stash_comment fcn_name opt_param_list opt_sep stash_comment function_body function_end
+function        : function_beg fcn_name opt_param_list opt_sep function_body function_end
                   {
-                    OCTAVE_YYUSE ($5);
-
-                    $$ = parser.make_function ($1, nullptr, $3, $4, $7, $8, $2, $6);
+                    OCTAVE_YYUSE ($4);
+
+                    $$ = parser.make_function ($1, nullptr, nullptr, $2, $3, $5, $6);
                   }
-                | function_beg stash_comment return_list '=' fcn_name opt_param_list opt_sep stash_comment function_body function_end
+                | function_beg return_list '=' fcn_name opt_param_list opt_sep function_body function_end
                   {
-                    OCTAVE_YYUSE ($4, $7);
-
-                    $$ = parser.make_function ($1, $3, $5, $6, $9, $10, $2, $8);
+                    OCTAVE_YYUSE ($6);
+
+                    $$ = parser.make_function ($1, $2, $3, $4, $5, $7, $8);
                   }
                 ;
 
 function_body   : at_first_executable_stmt opt_list
                   {
-                    OCTAVE_YYUSE ($1);
-
                     $$ = $2;
                   }
                 | function_body1 opt_sep at_first_executable_stmt opt_list
@@ -1684,7 +1613,6 @@
 at_first_executable_stmt
                 : // empty
                   {
-                    $$ = 0;
                     lexer.m_arguments_is_keyword = false;
                   }
                 ;
@@ -1703,17 +1631,13 @@
                   }
                 ;
 
-arguments_block : arguments_beg stash_comment opt_sep args_attr_list
-                  args_validation_list opt_sep END
+arguments_block : arguments_beg opt_sep args_attr_list args_validation_list opt_sep END
                   {
-                    OCTAVE_YYUSE ($3, $6);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_arguments_block ($1, $4, $5, $7, lc, tc)))
+                    OCTAVE_YYUSE ($2, $5);
+
+                    if (! ($$ = parser.make_arguments_block ($1, $3, $4, $6)))
                       {
-                        // make_arguments_block deleted $4, $5, LC, and TC.
+                        // make_arguments_block deleted $3, and $4.
                         YYABORT;
                       }
 
@@ -1732,7 +1656,7 @@
                   { $$ = nullptr; }
                 | '(' identifier ')'
                   {
-                    OCTAVE_YYUSE ($1, $3);
+                    $2->mark_in_delims (*($1), *($3));
 
                     // Error if $$ is nullptr.
                     if  (! ($$ = parser.make_args_attribute_list ($2)))
@@ -1766,21 +1690,29 @@
                     { $$ = $1; }
                   ;
 
-arg_validation    : size_spec class_name validation_fcns default_value
-                  {
-                    if (! ($$ = parser.make_arg_validation ($1, $2, $3, $4)))
-                      {
-                        // make_arg_validation deleted ...
-                        YYABORT;
-                      }
-                  }
+arg_validation    : size_spec class_name validation_fcns
+                    {
+                      if (! ($$ = parser.make_arg_validation ($1, $2, $3)))
+                        {
+                          // make_arg_validation deleted ...
+                          YYABORT;
+                        }
+                    }
+                  | size_spec class_name validation_fcns '=' expression
+                    {
+                      if (! ($$ = parser.make_arg_validation ($1, $2, $3, $4, $5)))
+                        {
+                          // make_arg_validation deleted ...
+                          YYABORT;
+                        }
+                    }
                 ;
 
 size_spec       : // empty
                   { $$ = nullptr; }
                 | '(' arg_list ')'
                   {
-                    OCTAVE_YYUSE ($1, $3);
+                    $2->mark_in_delims (*($1), *($3));
 
                     if (! ($$ = parser.make_arg_size_spec ($2)))
                       {
@@ -1801,7 +1733,7 @@
                   { $$ = nullptr; }
                 | '{' arg_list '}'
                   {
-                    OCTAVE_YYUSE ($1, $3);
+                    $2->mark_in_delims (*($1), *($3));
 
                     if (! ($$ = parser.make_arg_validation_fcns ($2)))
                       {
@@ -1811,16 +1743,6 @@
                   }
                 ;
 
-default_value   : // empty
-                  { $$ = nullptr; }
-                | '=' expression
-                  {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = $2;
-                  }
-                ;
-
 // ========
 // Classdef
 // ========
@@ -1843,15 +1765,15 @@
                   }
                 ;
 
-classdef        : classdef_beg stash_comment attr_list identifier opt_sep superclass_list stash_comment class_body stash_comment END
+classdef        : classdef_beg attr_list identifier opt_sep superclass_list class_body END
                   {
-                    OCTAVE_YYUSE ($5);
+                    OCTAVE_YYUSE ($4);
 
                     lexer.m_parsing_classdef = false;
 
-                    if (! ($$ = parser.make_classdef ($1, $3, $4, $6, $8, $10, $2, $7, $9)))
+                    if (! ($$ = parser.make_classdef ($1, $2, $3, $5, $6, $7)))
                       {
-                        // make_classdef deleted $2, $3, $4, $6, $7, $8, $9
+                        // make_classdef deleted $2, $3, $5, $6
                         YYABORT;
                       }
                   }
@@ -1861,9 +1783,9 @@
                   { $$ = nullptr; }
                 | '(' attr_list1 ')' opt_sep
                   {
-                    OCTAVE_YYUSE ($1, $3, $4);
-
-                    $$ = $2;
+                    OCTAVE_YYUSE ($4);
+
+                    $$ = $2->mark_in_delims (*($1), *($3));
                   }
                 ;
 
@@ -1871,9 +1793,7 @@
                   { $$ = parser.make_classdef_attribute_list ($1); }
                 | attr_list1 ',' attr
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_classdef_attribute ($1, $3);
+                    $$ = parser.append_classdef_attribute ($1, $2, $3);
                   }
                 ;
 
@@ -1881,21 +1801,15 @@
                   { $$ = parser.make_classdef_attribute ($1); }
                 | identifier '=' expression
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.make_classdef_attribute ($1, $3);
+                    $$ = parser.make_classdef_attribute ($1, $2, $3);
                   }
                 | '~' identifier
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = parser.make_not_classdef_attribute ($2);
+                    $$ = parser.make_not_classdef_attribute ($1, $2);
                   }
                 | '!' identifier
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = parser.make_not_classdef_attribute ($2);
+                    $$ = parser.make_not_classdef_attribute ($1, $2);
                   }
                 ;
 
@@ -1920,15 +1834,11 @@
 superclass_list1
                 : EXPR_LT superclass
                   {
-                    OCTAVE_YYUSE ($1);
-
-                    $$ = parser.make_classdef_superclass_list ($2);
+                    $$ = parser.make_classdef_superclass_list ($1, $2);
                   }
                 | superclass_list1 EXPR_AND superclass
                   {
-                    OCTAVE_YYUSE ($2);
-
-                    $$ = parser.append_classdef_superclass ($1, $3);
+                    $$ = parser.append_classdef_superclass ($1, $2, $3);
                   }
                 ;
 
@@ -1985,18 +1895,13 @@
                 ;
 
 properties_block
-                : properties_beg stash_comment opt_sep attr_list property_list END
+                : properties_beg opt_sep attr_list property_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_classdef_properties_block
-                           ($1, $4, $5, $6, lc, tc)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_classdef_properties_block ($1, $3, $4, $5)))
                       {
-                        // make_classdef_properties_block deleted $4,
-                        // $5, LC, and TC.
+                        // make_classdef_properties_block deleted $3 and $4.
                         YYABORT;
                       }
                   }
@@ -2035,18 +1940,18 @@
                     // identifier that becomes the next element in the
                     // list.  If the element at the end of the list
                     // doesn't have a doc string, see whether the
-                    // element we are adding is stroing an end-of-line
+                    // element we are adding is storing an end-of-line
                     // comment for us to use.
 
                     octave::tree_classdef_property *last_elt = $1->back ();
 
                     if (! last_elt->have_doc_string ())
                       {
-                        octave::comment_list *cl = $3->comments ();
-
-                        if (cl)
+                        octave::comment_list comments = $3->leading_comments ();
+
+                        if (! comments.empty ())
                           {
-                            octave::comment_elt elt = cl->front ();
+                            octave::comment_elt elt = comments.front ();
 
                             if (elt.is_end_of_line ())
                               last_elt->doc_string (elt.text ());
@@ -2057,22 +1962,17 @@
                   }
                 ;
 
-class_property  : stash_comment identifier arg_validation
-                  { $$ = parser.make_classdef_property ($1, $2, $3); }
+class_property  : identifier arg_validation
+                  { $$ = parser.make_classdef_property ($1, $2); }
                 ;
 
-methods_block   : methods_beg stash_comment opt_sep attr_list methods_list END
+methods_block   : methods_beg opt_sep attr_list method_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_classdef_methods_block
-                           ($1, $4, $5, $6, lc, tc)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_classdef_methods_block ($1, $3, $4, $5)))
                       {
-                        // make_classdef_methods_block deleted $4, $5,
-                        // LC, and TC.
+                        // make_classdef_methods_block deleted $3 and $4.
                         YYABORT;
                       }
                   }
@@ -2087,7 +1987,7 @@
 
 method_decl1    : identifier
                   {
-                    if (! ($$ = parser.start_classdef_external_method ($1, nullptr)))
+                    if (! ($$ = parser.start_classdef_external_method ($1)))
                       YYABORT;
                   }
                 | identifier param_list
@@ -2097,12 +1997,12 @@
                   }
                 ;
 
-method_decl     : stash_comment method_decl1
-                  { $$ = parser.finish_classdef_external_method ($2, nullptr, $1); }
-                | stash_comment return_list '='
+method_decl     : method_decl1
                   {
-                    OCTAVE_YYUSE ($3);
-
+                    $$ = parser.finish_classdef_external_method ($1);
+                  }
+                | return_list '='
+                  {
                     lexer.m_defining_fcn++;
                     lexer.m_parsed_function_name.push (false);
                   }
@@ -2111,7 +2011,7 @@
                     lexer.m_defining_fcn--;
                     lexer.m_parsed_function_name.pop ();
 
-                    $$ = parser.finish_classdef_external_method ($5, $2, $1);
+                    $$ = parser.finish_classdef_external_method ($4, $1, $2);
                   }
                 ;
 
@@ -2121,12 +2021,12 @@
                   { $$ = $1; }
                 ;
 
-methods_list    : // empty
+method_list     : // empty
                   {
                     lexer.m_classdef_element_names_are_keywords = true;
                     $$ = nullptr;
                   }
-                | methods_list1 opt_sep
+                | method_list1 opt_sep
                   {
                     OCTAVE_YYUSE ($2);
 
@@ -2135,9 +2035,9 @@
                   }
                 ;
 
-methods_list1   : method
-                  { $$ = parser.make_classdef_methods_list ($1); }
-                | methods_list1 opt_sep method
+method_list1    : method
+                  { $$ = parser.make_classdef_method_list ($1); }
+                | method_list1 opt_sep method
                   {
                     OCTAVE_YYUSE ($2);
 
@@ -2145,18 +2045,13 @@
                   }
                 ;
 
-events_block    : events_beg stash_comment opt_sep attr_list events_list END
+events_block    : events_beg opt_sep attr_list event_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_classdef_events_block
-                           ($1, $4, $5, $6, lc, tc)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_classdef_events_block ($1, $3, $4, $5)))
                       {
-                        // make_classdef_events_block deleted $4, $5,
-                        // LC, and TC.
+                        // make_classdef_events_block deleted $4 and $5.
                         YYABORT;
                       }
                   }
@@ -2169,12 +2064,12 @@
                   }
                 ;
 
-events_list     : // empty
+event_list      : // empty
                   {
                     lexer.m_classdef_element_names_are_keywords = true;
                     $$ = nullptr;
                   }
-                | events_list1 opt_sep
+                | event_list1 opt_sep
                   {
                     OCTAVE_YYUSE ($2);
 
@@ -2183,9 +2078,9 @@
                   }
                 ;
 
-events_list1    : class_event
-                  { $$ = parser.make_classdef_events_list ($1); }
-                | events_list1 opt_sep class_event
+event_list1     : class_event
+                  { $$ = parser.make_classdef_event_list ($1); }
+                | event_list1 opt_sep class_event
                   {
                     OCTAVE_YYUSE ($2);
 
@@ -2193,22 +2088,17 @@
                   }
                 ;
 
-class_event     : stash_comment identifier
-                  { $$ = parser.make_classdef_event ($1, $2); }
+class_event     : identifier
+                  { $$ = parser.make_classdef_event ($1); }
                 ;
 
-enum_block      : enumeration_beg stash_comment opt_sep attr_list enum_list END
+enum_block      : enumeration_beg opt_sep attr_list enum_list END
                   {
-                    OCTAVE_YYUSE ($3);
-
-                    octave::comment_list *lc = $2;
-                    octave::comment_list *tc = lexer.get_comment_list ();
-
-                    if (! ($$ = parser.make_classdef_enum_block
-                           ($1, $4, $5, $6, lc, tc)))
+                    OCTAVE_YYUSE ($2);
+
+                    if (! ($$ = parser.make_classdef_enum_block ($1, $3, $4, $5)))
                       {
-                        // make_classdef_enum_block deleted $4, $5, LC,
-                        // and TC.
+                        // make_classdef_enum_block deleted $3 and $4.
                         YYABORT;
                       }
                   }
@@ -2245,11 +2135,9 @@
                   }
                 ;
 
-class_enum      : stash_comment identifier '(' expression ')'
+class_enum      : identifier '(' expression ')'
                   {
-                    OCTAVE_YYUSE ($3, $5);
-
-                    $$ = parser.make_classdef_enum ($2, $4, $1);
+                    $$ = parser.make_classdef_enum ($1, $2, $3, $4);
                   }
                 ;
 
@@ -2272,12 +2160,6 @@
                   }
                 ;
 
-stash_comment   : // empty
-                  {
-                    $$ = lexer.get_comment_list ();
-                  }
-                ;
-
 parse_error     : LEXICAL_ERROR
                   {
                     $$ = 0;
@@ -2533,6 +2415,15 @@
     return list;
   }
 
+  template <typename LIST_T, typename ELT_T>
+  static LIST_T *
+  list_append (LIST_T *list, const token& /*sep_tok*/, ELT_T elt)
+  {
+    // FIXME XXX! need to capture SEP_TOK here
+    list->push_back (elt);
+    return list;
+  }
+
   std::size_t
   base_parser::parent_scope_info::size () const
   {
@@ -2886,9 +2777,9 @@
   }
 
   tree_black_hole *
-  base_parser::make_black_hole ()
-  {
-    return new tree_black_hole ();
+  base_parser::make_black_hole (token *tilde)
+  {
+    return new tree_black_hole (*tilde);
   }
 
   // Make a function handle.
@@ -2973,9 +2864,13 @@
   // Build a colon expression.
 
   tree_expression *
-  base_parser::make_colon_expression (tree_expression *base,
-                                      tree_expression *limit,
-                                      tree_expression *incr)
+  base_parser::make_colon_expression (tree_expression *base, token *colon_tok, tree_expression *limit)
+  {
+    return make_colon_expression (base, colon_tok, nullptr, nullptr, limit);
+  }
+
+  tree_expression *
+  base_parser::make_colon_expression (tree_expression *base, token *colon_1_tok, tree_expression *incr, token *colon_2_tok, tree_expression *limit)
   {
     tree_expression *retval = nullptr;
 
@@ -2991,8 +2886,10 @@
     int l = base->line ();
     int c = base->column ();
 
+    token tmp_colon_2_tok = colon_2_tok ? *colon_2_tok : token ();
+
     tree_colon_expression *expr
-      = new tree_colon_expression (base, limit, incr, l, c);
+      = new tree_colon_expression (base, *colon_1_tok, incr, tmp_colon_2_tok, limit, l, c);
 
     retval = expr;
 
@@ -3053,12 +2950,11 @@
   // Build a binary expression.
 
   tree_expression *
-  base_parser::make_binary_op (int op, tree_expression *op1,
-                               token *tok, tree_expression *op2)
+  base_parser::make_binary_op (tree_expression *op1, token *op_tok, tree_expression *op2)
   {
     octave_value::binary_op t = octave_value::unknown_binary_op;
 
-    switch (op)
+    switch (op_tok->token_id ())
       {
       case POW:
         t = octave_value::op_pow;
@@ -3137,8 +3033,8 @@
         break;
       }
 
-    int l = tok->line ();
-    int c = tok->column ();
+    int l = op_tok->line ();
+    int c = op_tok->column ();
 
     return maybe_compound_binary_expression (op1, op2, l, c, t);
   }
@@ -3181,12 +3077,11 @@
   // Build a boolean expression.
 
   tree_expression *
-  base_parser::make_boolean_op (int op, tree_expression *op1,
-                                token *tok, tree_expression *op2)
+  base_parser::make_boolean_op (tree_expression *op1, token *op_tok, tree_expression *op2)
   {
     tree_boolean_expression::type t;
 
-    switch (op)
+    switch (op_tok->token_id ())
       {
       case EXPR_AND_AND:
         t = tree_boolean_expression::bool_and;
@@ -3201,8 +3096,8 @@
         break;
       }
 
-    int l = tok->line ();
-    int c = tok->column ();
+    int l = op_tok->line ();
+    int c = op_tok->column ();
 
     return new tree_boolean_expression (op1, op2, l, c, t);
   }
@@ -3210,11 +3105,11 @@
   // Build a prefix expression.
 
   tree_expression *
-  base_parser::make_prefix_op (int op, tree_expression *op1, token *tok)
+  base_parser::make_prefix_op (token *op_tok, tree_expression *op1)
   {
     octave_value::unary_op t = octave_value::unknown_unary_op;
 
-    switch (op)
+    switch (op_tok->token_id ())
       {
       case '~':
       case '!':
@@ -3242,8 +3137,8 @@
         break;
       }
 
-    int l = tok->line ();
-    int c = tok->column ();
+    int l = op_tok->line ();
+    int c = op_tok->column ();
 
     return new tree_prefix_expression (op1, l, c, t);
   }
@@ -3251,11 +3146,11 @@
   // Build a postfix expression.
 
   tree_expression *
-  base_parser::make_postfix_op (int op, tree_expression *op1, token *tok)
+  base_parser::make_postfix_op (tree_expression *op1, token *op_tok)
   {
     octave_value::unary_op t = octave_value::unknown_unary_op;
 
-    switch (op)
+    switch (op_tok->token_id ())
       {
       case HERMITIAN:
         t = octave_value::op_hermitian;
@@ -3278,8 +3173,8 @@
         break;
       }
 
-    int l = tok->line ();
-    int c = tok->column ();
+    int l = op_tok->line ();
+    int c = op_tok->column ();
 
     return new tree_postfix_expression (op1, l, c, t);
   }
@@ -3287,24 +3182,16 @@
   // Build an unwind-protect command.
 
   tree_command *
-  base_parser::make_unwind_command (token *unwind_tok,
-                                    tree_statement_list *body,
-                                    tree_statement_list *cleanup_stmts,
-                                    token *end_tok,
-                                    comment_list *lc,
-                                    comment_list *mc)
+  base_parser::make_unwind_command (token *unwind_tok, tree_statement_list *body, token *cleanup_tok, tree_statement_list *cleanup_stmts, token *end_tok)
   {
     tree_command *retval = nullptr;
 
     if (end_token_ok (end_tok, token::unwind_protect_end))
       {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
         int l = unwind_tok->line ();
         int c = unwind_tok->column ();
 
-        retval = new tree_unwind_protect_command (body, cleanup_stmts,
-                                                  lc, mc, tc, l, c);
+        retval = new tree_unwind_protect_command (*unwind_tok, body, *cleanup_tok, cleanup_stmts, *end_tok, l, c);
       }
     else
       {
@@ -3320,25 +3207,20 @@
   // Build a try-catch command.
 
   tree_command *
-  base_parser::make_try_command (token *try_tok,
-                                 tree_statement_list *body,
-                                 char catch_sep,
-                                 tree_statement_list *cleanup_stmts,
-                                 token *end_tok,
-                                 comment_list *lc,
-                                 comment_list *mc)
+  base_parser::make_try_command (token *try_tok, tree_statement_list *body, token *catch_tok, char catch_sep, tree_statement_list *cleanup_stmts, token *end_tok)
   {
     tree_command *retval = nullptr;
 
     if (end_token_ok (end_tok, token::try_catch_end))
       {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
         int l = try_tok->line ();
         int c = try_tok->column ();
 
         tree_identifier *id = nullptr;
 
+        // Look for exception ID.  Could this be done in the grammar or
+        // does that create another shift-reduce conflict?
+
         if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ())
           {
             tree_statement *stmt = cleanup_stmts->front ();
@@ -3359,8 +3241,9 @@
               }
           }
 
-        retval = new tree_try_catch_command (body, cleanup_stmts, id,
-                                             lc, mc, tc, l, c);
+        token tmp_catch_tok = catch_tok ? *catch_tok : token ();
+
+        retval = new tree_try_catch_command (*try_tok, body, tmp_catch_tok, id, cleanup_stmts, *end_tok, l, c);
       }
     else
       {
@@ -3376,11 +3259,7 @@
   // Build a while command.
 
   tree_command *
-  base_parser::make_while_command (token *while_tok,
-                                   tree_expression *expr,
-                                   tree_statement_list *body,
-                                   token *end_tok,
-                                   comment_list *lc)
+  base_parser::make_while_command (token *while_tok, tree_expression *expr, tree_statement_list *body, token *end_tok)
   {
     tree_command *retval = nullptr;
 
@@ -3388,14 +3267,12 @@
 
     if (end_token_ok (end_tok, token::while_end))
       {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
         m_lexer.m_looping--;
 
         int l = while_tok->line ();
         int c = while_tok->column ();
 
-        retval = new tree_while_command (expr, body, lc, tc, l, c);
+        retval = new tree_while_command (*while_tok, expr, body, *end_tok, l, c);
       }
     else
       {
@@ -3411,44 +3288,35 @@
   // Build a do-until command.
 
   tree_command *
-  base_parser::make_do_until_command (token *until_tok,
-                                      tree_statement_list *body,
-                                      tree_expression *expr,
-                                      comment_list *lc)
+  base_parser::make_do_until_command (token *do_tok, tree_statement_list *body, token *until_tok, tree_expression *expr)
   {
     maybe_warn_assign_as_truth_value (expr);
 
-    comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
     m_lexer.m_looping--;
 
     int l = until_tok->line ();
     int c = until_tok->column ();
 
-    return new tree_do_until_command (expr, body, lc, tc, l, c);
+    return new tree_do_until_command (*do_tok, body, *until_tok, expr, l, c);
   }
 
   // Build a for command.
 
   tree_command *
-  base_parser::make_for_command (int tok_id, token *for_tok,
-                                 tree_argument_list *lhs,
-                                 tree_expression *expr,
-                                 tree_expression *maxproc,
-                                 tree_statement_list *body,
-                                 token *end_tok,
-                                 comment_list *lc)
+  base_parser::make_for_command (token *for_tok, token *open_paren, tree_argument_list *lhs, token *eq_tok, tree_expression *expr, token *sep_tok, tree_expression *maxproc, token *close_paren, tree_statement_list *body, token *end_tok)
   {
     tree_command *retval = nullptr;
 
-    bool parfor = tok_id == PARFOR;
+    bool parfor = for_tok->token_id () == PARFOR;
+
+    token tmp_open_paren = open_paren ? *open_paren : token ();
+    token tmp_close_paren = close_paren ? *close_paren : token ();
+    token tmp_sep_tok = sep_tok ? *sep_tok : token ();
 
     if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end))
       {
         expr->mark_as_for_cmd_expr ();
 
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
         m_lexer.m_looping--;
 
         int l = for_tok->line ();
@@ -3460,8 +3328,7 @@
 
             m_lexer.mark_as_variable (tmp->name ());
 
-            retval = new tree_simple_for_command (parfor, tmp, expr, maxproc,
-                                                  body, lc, tc, l, c);
+            retval = new tree_simple_for_command (parfor, *for_tok, tmp_open_paren, tmp, *eq_tok, expr, tmp_sep_tok, maxproc, tmp_close_paren, body, *end_tok, l, c);
 
             delete lhs;
           }
@@ -3478,8 +3345,7 @@
           {
             m_lexer.mark_as_variables (lhs->variable_names ());
 
-            retval = new tree_complex_for_command (lhs, expr, body,
-                                                   lc, tc, l, c);
+            retval = new tree_complex_for_command (*for_tok, lhs, *eq_tok, expr, body, *end_tok, l, c);
           }
       }
     else
@@ -3543,9 +3409,7 @@
   // Build an spmd command.
 
   tree_spmd_command *
-  base_parser::make_spmd_command (token *spmd_tok, tree_statement_list *body,
-                                  token *end_tok, comment_list *lc,
-                                  comment_list *tc)
+  base_parser::make_spmd_command (token *spmd_tok, tree_statement_list *body, token *end_tok)
   {
     tree_spmd_command *retval = nullptr;
 
@@ -3554,13 +3418,11 @@
         int l = spmd_tok->line ();
         int c = spmd_tok->column ();
 
-        retval = new tree_spmd_command (body, lc, tc, l, c);
+        retval = new tree_spmd_command (body, l, c);
       }
     else
       {
         delete body;
-        delete lc;
-        delete tc;
 
         end_token_error (end_tok, token::spmd_end);
       }
@@ -3571,51 +3433,42 @@
   // Start an if command.
 
   tree_if_command_list *
-  base_parser::start_if_command (tree_expression *expr,
-                                 tree_statement_list *list)
-  {
-    maybe_warn_assign_as_truth_value (expr);
-
-    // Line and column will be set in finish_if_command.
-
-    tree_if_clause *t = new tree_if_clause (expr, list);
-
-    return new tree_if_command_list (t);
+  base_parser::start_if_command (tree_if_clause *clause)
+  {
+    return new tree_if_command_list (clause);
   }
 
   // Finish an if command.
 
   tree_if_command *
-  base_parser::finish_if_command (token *if_tok,
-                                  tree_if_command_list *list,
-                                  token *end_tok,
-                                  comment_list *lc)
+  base_parser::finish_if_command (tree_if_command_list *list, tree_if_clause *else_clause, token *end_tok)
   {
     tree_if_command *retval = nullptr;
 
     if (end_token_ok (end_tok, token::if_end))
       {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
-        int l = if_tok->line ();
-        int c = if_tok->column ();
-
-        if (list && ! list->empty ())
+        if (else_clause)
+          list_append (list, else_clause);
+
+        token if_tok = list->if_token ();
+
+        int l = if_tok.line ();
+        int c = if_tok.column ();
+
+        tree_if_clause *elt = list->front ();
+
+        if (elt)
           {
-            tree_if_clause *elt = list->front ();
-
-            if (elt)
-              {
-                elt->line (l);
-                elt->column (c);
-              }
+            elt->line (l);
+            elt->column (c);
           }
 
-        retval = new tree_if_command (list, lc, tc, l, c);
+        retval = new tree_if_command (if_tok, list, *end_tok, l, c);
       }
     else
       {
         delete list;
+        delete else_clause;
 
         end_token_error (end_tok, token::if_end);
       }
@@ -3623,35 +3476,26 @@
     return retval;
   }
 
-  // Build an elseif clause.
+  // Build an if, elseif, or else clause.
 
   tree_if_clause *
-  base_parser::make_elseif_clause (token *elseif_tok,
-                                   tree_expression *expr,
-                                   tree_statement_list *list,
-                                   comment_list *lc)
-  {
-    maybe_warn_assign_as_truth_value (expr);
-
-    int l = elseif_tok->line ();
-    int c = elseif_tok->column ();
-
-    return new tree_if_clause (expr, list, lc, l, c);
-  }
-
-  tree_if_clause *
-  base_parser::make_else_clause (token *else_tok, comment_list *lc,
-                                 tree_statement_list *list)
-  {
-    int l = else_tok->line ();
-    int c = else_tok->column ();
-
-    return new tree_if_clause (list, lc, l, c);
+  base_parser::make_if_clause (token *tok, tree_expression *expr, tree_statement_list *list)
+  {
+    if (expr)
+      {
+        maybe_warn_assign_as_truth_value (expr);
+
+        maybe_convert_to_braindead_shortcircuit (expr);
+      }
+
+    int l = tok->line ();
+    int c = tok->column ();
+
+    return new tree_if_clause (*tok, expr, list, l, c);
   }
 
   tree_if_command_list *
-  base_parser::append_if_clause (tree_if_command_list *list,
-                                 tree_if_clause *clause)
+  base_parser::append_if_clause (tree_if_command_list *list, tree_if_clause *clause)
   {
     return list_append (list, clause);
   }
@@ -3659,18 +3503,12 @@
   // Finish a switch command.
 
   tree_switch_command *
-  base_parser::finish_switch_command (token *switch_tok,
-                                      tree_expression *expr,
-                                      tree_switch_case_list *list,
-                                      token *end_tok,
-                                      comment_list *lc)
+  base_parser::finish_switch_command (token *switch_tok, tree_expression *expr, tree_switch_case_list *list, token *end_tok)
   {
     tree_switch_command *retval = nullptr;
 
     if (end_token_ok (end_tok, token::switch_end))
       {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
         int l = switch_tok->line ();
         int c = switch_tok->column ();
 
@@ -3685,7 +3523,7 @@
               }
           }
 
-        retval = new tree_switch_command (expr, list, lc, tc, l, c);
+        retval = new tree_switch_command (*switch_tok, expr, list, *end_tok, l, c);
       }
     else
       {
@@ -3707,27 +3545,23 @@
   // Build a switch case.
 
   tree_switch_case *
-  base_parser::make_switch_case (token *case_tok,
-                                 tree_expression *expr,
-                                 tree_statement_list *list,
-                                 comment_list *lc)
+  base_parser::make_switch_case (token *case_tok, tree_expression *expr, tree_statement_list *list)
   {
     maybe_warn_variable_switch_label (expr);
 
     int l = case_tok->line ();
     int c = case_tok->column ();
 
-    return new tree_switch_case (expr, list, lc, l, c);
+    return new tree_switch_case (*case_tok, expr, list, l, c);
   }
 
   tree_switch_case *
-  base_parser::make_default_switch_case (token *default_tok, comment_list *lc,
-                                         tree_statement_list *list)
+  base_parser::make_default_switch_case (token *default_tok, tree_statement_list *list)
   {
     int l = default_tok->line ();
     int c = default_tok->column ();
 
-    return new tree_switch_case (list, lc, l, c);
+    return new tree_switch_case (*default_tok, list, l, c);
   }
 
   tree_switch_case_list *
@@ -3740,12 +3574,11 @@
   // Build an assignment to a variable.
 
   tree_expression *
-  base_parser::make_assign_op (int op, tree_argument_list *lhs,
-                               token *eq_tok, tree_expression *rhs)
+  base_parser::make_assign_op (tree_argument_list *lhs, token *eq_tok, tree_expression *rhs)
   {
     octave_value::assign_op t = octave_value::unknown_assign_op;
 
-    switch (op)
+    switch (eq_tok->token_id ())
       {
       case '=':
         t = octave_value::op_asn_eq;
@@ -3894,12 +3727,9 @@
     // First non-copyright comment in classdef body, before first
     // properties, methods, etc. block.
 
-    tree_statement *first_stmt = cmds->front ();
-    comment_list *leading_comments = first_stmt->comment_text ();
-
-    std::string doc_string;
-    if (leading_comments)
-      doc_string = leading_comments->find_doc_string ();
+    comment_list leading_comments = cmds->leading_comments ();
+
+    std::string doc_string = leading_comments.find_doc_string ();
 
     octave_user_script *script
       = new octave_user_script (m_lexer.m_fcn_file_full_name,
@@ -3951,23 +3781,31 @@
   // for a large mess.  Maybe this could be a bit better organized?
 
   tree_function_def *
-  base_parser::make_function (token *fcn_tok,
-                              tree_parameter_list *ret_list,
-                              tree_identifier *id,
-                              tree_parameter_list *param_list,
-                              tree_statement_list *body,
-                              tree_statement *end_fcn_stmt,
-                              comment_list *lc, comment_list *bc)
+  base_parser::make_function (token *fcn_tok, tree_parameter_list *ret_list, token *eq_tok, tree_identifier *id, tree_parameter_list *param_list, tree_statement_list *body, tree_statement *end_fcn_stmt)
   {
     // First non-copyright comments found above and below function keyword.
     comment_elt leading_doc_comment;
     comment_elt body_doc_comment;
 
-    if (lc)
-      leading_doc_comment = lc->find_doc_comment ();
-
-    if (bc)
-      body_doc_comment = bc->find_doc_comment ();
+    comment_list lc = fcn_tok->leading_comments ();
+
+    if (! lc.empty ())
+      leading_doc_comment = lc.find_doc_comment ();
+
+    if (body)
+      {
+        comment_list bc = body->leading_comments ();
+
+        if (! bc.empty ())
+          body_doc_comment = bc.find_doc_comment ();
+      }
+    else if (end_fcn_stmt)
+      {
+        comment_list ec = end_fcn_stmt->leading_comments ();
+
+        if (! ec.empty ())
+          body_doc_comment = ec.find_doc_comment ();
+      }
 
     // Choose which comment to use for doc string.
 
@@ -4004,7 +3842,7 @@
     octave_user_function *tmp_fcn
       = start_function (id, param_list, body, end_fcn_stmt, doc_string);
 
-    tree_function_def *retval = finish_function (ret_list, tmp_fcn, lc, l, c);
+    tree_function_def *retval = finish_function (fcn_tok, ret_list, eq_tok, tmp_fcn, l, c);
 
     recover_from_parsing_function ();
 
@@ -4043,9 +3881,6 @@
       = new octave_user_function (m_lexer.m_symtab_context.curr_scope (),
                                   param_list, nullptr, body);
 
-    comment_list *tc = m_lexer.m_comment_buf.get_comment_list ();
-
-    fcn->stash_trailing_comment (tc);
     fcn->stash_fcn_end_location (end_fcn_stmt->line (),
                                  end_fcn_stmt->column ());
 
@@ -4146,20 +3981,17 @@
   }
 
   tree_statement *
-  base_parser::make_end (const std::string& type, bool eof,
+  base_parser::make_end (const std::string& type, bool eof, token *end_tok,
                          const filepos& beg_pos, const filepos& /*end_pos*/)
   {
     int l = beg_pos.line ();
     int c = beg_pos.column ();
 
-    return make_statement (new tree_no_op_command (type, eof, l, c));
+    return make_statement (new tree_no_op_command (type, eof, *end_tok, l, c));
   }
 
   tree_function_def *
-  base_parser::finish_function (tree_parameter_list *ret_list,
-                                octave_user_function *fcn,
-                                comment_list *lc,
-                                int l, int c)
+  base_parser::finish_function (token *fcn_tok, tree_parameter_list *ret_list, token *eq_tok, octave_user_function *fcn, int l, int c)
   {
     tree_function_def *retval = nullptr;
 
@@ -4170,6 +4002,11 @@
 
     if (fcn)
       {
+        fcn->set_fcn_tok (*fcn_tok);
+
+        if (eq_tok)
+          fcn->set_eq_tok (*eq_tok);
+
         std::string fcn_nm = fcn->name ();
         std::string file = fcn->fcn_file_name ();
 
@@ -4183,9 +4020,6 @@
         fcn_scope.cache_fcn_file_name (file);
         fcn_scope.cache_dir_name (m_lexer.m_dir_name);
 
-        if (lc)
-          fcn->stash_leading_comment (lc);
-
         fcn->define_ret_list (ret_list);
 
         if (m_curr_fcn_depth > 0 || m_parsing_subfunctions)
@@ -4267,11 +4101,7 @@
   }
 
   tree_arguments_block *
-  base_parser::make_arguments_block (token *arguments_tok,
-                                     tree_args_block_attribute_list *attr_list,
-                                     tree_args_block_validation_list *validation_list,
-                                     token *end_tok,
-                                     comment_list *lc, comment_list *tc)
+  base_parser::make_arguments_block (token *arguments_tok, tree_args_block_attribute_list *attr_list, tree_args_block_validation_list *validation_list, token *end_tok)
   {
     tree_arguments_block *retval = nullptr;
 
@@ -4288,9 +4118,6 @@
       {
         delete attr_list;
         delete validation_list;
-
-        delete lc;
-        delete tc;
       }
 
     return retval;
@@ -4300,13 +4127,15 @@
   base_parser::make_arg_validation (tree_arg_size_spec *size_spec,
                                     tree_identifier *class_name,
                                     tree_arg_validation_fcns *validation_fcns,
+                                    token *eq_tok,
                                     tree_expression *default_value)
   {
     // FIXME: Validate arguments and convert to more specific types
     // (std::string for arg_name and class_name, etc).
 
-    return new tree_arg_validation (size_spec, class_name,
-                                    validation_fcns, default_value);
+    token tmp_eq_tok = eq_tok ? *eq_tok : token ();
+
+    return new tree_arg_validation (size_spec, class_name, validation_fcns, tmp_eq_tok, default_value);
   }
 
   tree_args_block_attribute_list *
@@ -4371,17 +4200,8 @@
   // and methods, and adding to the list of known objects) and creates
   // a parse tree containing meta information about the class.
 
-  // LC contains comments appearing before the classdef keyword.
-  // TC contains comments appearing between the classdef elements
-  // and the final end token for the classdef block.
-
   tree_classdef *
-  base_parser::make_classdef (token *tok,
-                              tree_classdef_attribute_list *a,
-                              tree_identifier *id,
-                              tree_classdef_superclass_list *sc,
-                              tree_classdef_body *body, token *end_tok,
-                              comment_list *lc, comment_list *bc, comment_list *tc)
+  base_parser::make_classdef (token *cdef_tok, tree_classdef_attribute_list *a, tree_identifier *id, tree_classdef_superclass_list *sc, tree_classdef_body *body, token *end_tok)
   {
     tree_classdef *retval = nullptr;
 
@@ -4407,9 +4227,6 @@
         delete id;
         delete sc;
         delete body;
-        delete lc;
-        delete bc;
-        delete tc;
 
         bison_error ("invalid classdef definition, the class name must match the filename", l, c);
 
@@ -4418,29 +4235,13 @@
       {
         if (end_token_ok (end_tok, token::classdef_end))
           {
-            int l = tok->line ();
-            int c = tok->column ();
-
-            // First non-copyright comments found above and below
-            // function keyword are candidates for the documentation
-            // string.  Use the first one that is not empty.
-
-            std::string doc_string;
-
-            if (lc)
-              doc_string = lc->find_doc_string ();
-
-            if (doc_string.empty () && bc)
-              doc_string = bc->find_doc_string ();
+            int l = cdef_tok->line ();
+            int c = cdef_tok->column ();
 
             if (! body)
               body = new tree_classdef_body ();
 
-            // FIXME - pass body comment to tree_classdef constructor.
-
-            retval = new tree_classdef (m_lexer.m_symtab_context.curr_scope (),
-                                        doc_string, a, id, sc, body, lc, tc,
-                                        m_curr_package_name, full_name, l, c);
+            retval = new tree_classdef (m_lexer.m_symtab_context.curr_scope (), *cdef_tok, a, id, sc, body, *end_tok, m_curr_package_name, full_name, l, c);
           }
         else
           {
@@ -4448,9 +4249,6 @@
             delete id;
             delete sc;
             delete body;
-            delete lc;
-            delete bc;
-            delete tc;
 
             end_token_error (end_tok, token::switch_end);
           }
@@ -4459,22 +4257,8 @@
     return retval;
   }
 
-  // LC contains comments appearing before the properties keyword.
-  // If this properties block appears first in the list of classdef
-  // elements, this comment list will be used for the help text for the
-  // classdef block.
-
-  // TC contains comments appearing between the list of properties
-  // and the final end token for the properties block and may be used to
-  // find the doc string for the final property in the list.
-
   tree_classdef_properties_block *
-  base_parser::make_classdef_properties_block (token *tok,
-                                               tree_classdef_attribute_list *a,
-                                               tree_classdef_property_list *plist,
-                                               token *end_tok,
-                                               comment_list *lc,
-                                               comment_list *tc)
+  base_parser::make_classdef_properties_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_property_list *plist, token *end_tok)
   {
     tree_classdef_properties_block *retval = nullptr;
 
@@ -4486,37 +4270,34 @@
         if (plist)
           {
             // If the element at the end of the list doesn't have a doc
-            // string, see whether the first element of TC is an
-            // end-of-line comment for us to use.
-
-            if (tc)
+            // string, see whether the first element of the comments
+            // attached to the end token is an end-of-line comment for
+            // us to use.
+
+            tree_classdef_property *last_elt = plist->back ();
+
+            if (last_elt && ! last_elt->have_doc_string ())
               {
-                tree_classdef_property *last_elt = plist->back ();
-
-                if (! last_elt->have_doc_string ())
+                comment_list comments = end_tok->leading_comments ();
+
+                if (! comments.empty ())
                   {
-                    comment_elt first_comment_elt = tc->front ();
-
-                    if (first_comment_elt.is_end_of_line ())
-                      {
-                        std::string eol_comment = first_comment_elt.text ();
-
-                        last_elt->doc_string (eol_comment);
-                      }
+                    comment_elt elt = comments.front ();
+
+                    if (elt.is_end_of_line ())
+                      last_elt->doc_string (elt.text ());
                   }
               }
           }
         else
           plist = new tree_classdef_property_list ();
 
-        retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c);
+        retval = new tree_classdef_properties_block (*tok, a, plist, *end_tok, l, c);
       }
     else
       {
         delete a;
         delete plist;
-        delete lc;
-        delete tc;
 
         end_token_error (end_tok, token::properties_end);
       }
@@ -4531,28 +4312,18 @@
   }
 
   tree_classdef_property *
-  base_parser::make_classdef_property (comment_list *lc, tree_identifier *id,
-                                       tree_arg_validation *av)
+  base_parser::make_classdef_property (tree_identifier *id, tree_arg_validation *av)
   {
     av->arg_name (id);
 
     if (av->size_spec () || av->class_name () || av->validation_fcns ())
       warning ("size, class, and validation function specifications are not yet supported for classdef properties; INCORRECT RESULTS ARE POSSIBLE!");
 
-    return new tree_classdef_property (av, lc);
-  }
-
-  // LC contains comments appearing before the methods keyword.
-  // If this methods block appears first in the list of classdef
-  // elements, this comment list will be used for the help text for the
-  // classdef block.
+    return new tree_classdef_property (av);
+  }
 
   tree_classdef_methods_block *
-  base_parser::make_classdef_methods_block (token *tok,
-                                            tree_classdef_attribute_list *a,
-                                            tree_classdef_methods_list *mlist,
-                                            token *end_tok, comment_list *lc,
-                                            comment_list *tc)
+  base_parser::make_classdef_methods_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_method_list *mlist, token *end_tok)
   {
     tree_classdef_methods_block *retval = nullptr;
 
@@ -4562,16 +4333,14 @@
         int c = tok->column ();
 
         if (! mlist)
-          mlist = new tree_classdef_methods_list ();
-
-        retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c);
+          mlist = new tree_classdef_method_list ();
+
+        retval = new tree_classdef_methods_block (*tok, a, mlist, *end_tok, l, c);
       }
     else
       {
         delete a;
         delete mlist;
-        delete lc;
-        delete tc;
 
         end_token_error (end_tok, token::methods_end);
       }
@@ -4579,22 +4348,8 @@
     return retval;
   }
 
-  // LC contains comments appearing before the events keyword.
-  // If this events block appears first in the list of classdef
-  // elements, this comment list will be used for the help text for the
-  // classdef block.
-
-  // TC contains comments appearing between the list of events and
-  // the final end token for the events block and may be used to find
-  // the doc string for the final event in the list.
-
   tree_classdef_events_block *
-  base_parser::make_classdef_events_block (token *tok,
-                                           tree_classdef_attribute_list *a,
-                                           tree_classdef_events_list *elist,
-                                           token *end_tok,
-                                           comment_list *lc,
-                                           comment_list *tc)
+  base_parser::make_classdef_events_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_event_list *elist, token *end_tok)
   {
     tree_classdef_events_block *retval = nullptr;
 
@@ -4604,16 +4359,14 @@
         int c = tok->column ();
 
         if (! elist)
-          elist = new tree_classdef_events_list ();
-
-        retval = new tree_classdef_events_block (a, elist, lc, tc, l, c);
+          elist = new tree_classdef_event_list ();
+
+        retval = new tree_classdef_events_block (*tok, a, elist, *end_tok, l, c);
       }
     else
       {
         delete a;
         delete elist;
-        delete lc;
-        delete tc;
 
         end_token_error (end_tok, token::events_end);
       }
@@ -4621,35 +4374,20 @@
     return retval;
   }
 
-  tree_classdef_events_list *
-  base_parser::make_classdef_events_list (tree_classdef_event *e)
-  {
-    return new tree_classdef_events_list (e);
+  tree_classdef_event_list *
+  base_parser::make_classdef_event_list (tree_classdef_event *e)
+  {
+    return new tree_classdef_event_list (e);
   }
 
   tree_classdef_event *
-  base_parser::make_classdef_event (comment_list *lc, tree_identifier *id)
-  {
-    return new tree_classdef_event (id, lc);
-  }
-
-  // LC contains comments appearing before the enumeration keyword.
-  // If this enumeration block appears first in the list of classdef
-  // elements, this comment list will be used for the help text for the
-  // classdef block.
-
-  // TC contains comments appearing between the list of
-  // enumerations and the final end token for the enumeration block and
-  // may be used to find the doc string for the final enumeration in the
-  // list.
+  base_parser::make_classdef_event (tree_identifier *id)
+  {
+    return new tree_classdef_event (id);
+  }
 
   tree_classdef_enum_block *
-  base_parser::make_classdef_enum_block (token *tok,
-                                         tree_classdef_attribute_list *a,
-                                         tree_classdef_enum_list *elist,
-                                         token *end_tok,
-                                         comment_list *lc,
-                                         comment_list *tc)
+  base_parser::make_classdef_enum_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_enum_list *elist, token *end_tok)
   {
     tree_classdef_enum_block *retval = nullptr;
 
@@ -4661,14 +4399,12 @@
         if (! elist)
           elist = new tree_classdef_enum_list ();
 
-        retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c);
+        retval = new tree_classdef_enum_block (*tok, a, elist, *end_tok, l, c);
       }
     else
       {
         delete a;
         delete elist;
-        delete lc;
-        delete tc;
 
         end_token_error (end_tok, token::enumeration_end);
       }
@@ -4683,10 +4419,9 @@
   }
 
   tree_classdef_enum *
-  base_parser::make_classdef_enum (tree_identifier *id, tree_expression *expr,
-                                   comment_list *lc)
-  {
-    return new tree_classdef_enum (id, expr, lc);
+  base_parser::make_classdef_enum (tree_identifier *id, token *open_paren, tree_expression *expr, token *close_paren)
+  {
+    return new tree_classdef_enum (id, *open_paren, expr, *close_paren);
   }
 
   tree_classdef_property_list *
@@ -4696,8 +4431,8 @@
     return list_append (list, elt);
   }
 
-  tree_classdef_events_list *
-  base_parser::append_classdef_event (tree_classdef_events_list *list,
+  tree_classdef_event_list *
+  base_parser::append_classdef_event (tree_classdef_event_list *list,
                                       tree_classdef_event *elt)
   {
     return list_append (list, elt);
@@ -4711,21 +4446,24 @@
   }
 
   tree_classdef_superclass_list *
-  base_parser::make_classdef_superclass_list (tree_classdef_superclass *sc)
-  {
+  base_parser::make_classdef_superclass_list (token *lt_tok, tree_classdef_superclass *sc)
+  {
+    sc->set_separator (*lt_tok);
+
     return new tree_classdef_superclass_list (sc);
   }
 
   tree_classdef_superclass *
   base_parser::make_classdef_superclass (token *fqident)
   {
-    return new tree_classdef_superclass (fqident->text ());
+    return new tree_classdef_superclass (*fqident);
   }
 
   tree_classdef_superclass_list *
-  base_parser::append_classdef_superclass (tree_classdef_superclass_list *list,
-                                           tree_classdef_superclass *elt)
-  {
+  base_parser::append_classdef_superclass (tree_classdef_superclass_list *list, token *and_tok, tree_classdef_superclass *elt)
+  {
+    elt->set_separator (*and_tok);
+
     return list_append (list, elt);
   }
 
@@ -4736,25 +4474,29 @@
   }
 
   tree_classdef_attribute *
-  base_parser::make_classdef_attribute (tree_identifier *id,
-                                        tree_expression *expr)
+  base_parser::make_classdef_attribute (tree_identifier *id)
+  {
+    return make_classdef_attribute (id, nullptr, nullptr);
+  }
+
+  tree_classdef_attribute *
+  base_parser::make_classdef_attribute (tree_identifier *id, token *eq_tok, tree_expression *expr)
   {
     return (expr
-            ? new tree_classdef_attribute (id, expr)
+            ? new tree_classdef_attribute (id, *eq_tok, expr)
             : new tree_classdef_attribute (id));
   }
 
   tree_classdef_attribute *
-  base_parser::make_not_classdef_attribute (tree_identifier *id)
-  {
-    return new tree_classdef_attribute (id, false);
+  base_parser::make_not_classdef_attribute (token *not_tok, tree_identifier *id)
+  {
+    return new tree_classdef_attribute (*not_tok, id, false);
   }
 
   tree_classdef_attribute_list *
-  base_parser::append_classdef_attribute (tree_classdef_attribute_list *list,
-                                          tree_classdef_attribute *elt)
-  {
-    return list_append (list, elt);
+  base_parser::append_classdef_attribute (tree_classdef_attribute_list *list, token *sep_tok, tree_classdef_attribute *elt)
+  {
+    return list_append (list, *sep_tok, elt);
   }
 
   tree_classdef_body *
@@ -4859,17 +4601,15 @@
   }
 
   tree_function_def *
-  base_parser::finish_classdef_external_method (octave_user_function *fcn,
-                                                tree_parameter_list *ret_list,
-                                                comment_list *cl)
+  base_parser::finish_classdef_external_method (octave_user_function *fcn, tree_parameter_list *ret_list, token *eq_tok)
   {
     if (! ret_list)
       ret_list = new tree_parameter_list (tree_parameter_list::out);
 
     fcn->define_ret_list (ret_list);
 
-    if (cl)
-      fcn->stash_leading_comment (cl);
+    if (eq_tok)
+      fcn->set_eq_tok (*eq_tok);
 
     int l = fcn->beginning_line ();
     int c = fcn->beginning_column ();
@@ -4877,8 +4617,8 @@
     return new tree_function_def (fcn, l, c);
   }
 
-  tree_classdef_methods_list *
-  base_parser::make_classdef_methods_list (tree_function_def *fcn_def)
+  tree_classdef_method_list *
+  base_parser::make_classdef_method_list (tree_function_def *fcn_def)
   {
     octave_value fcn;
 
@@ -4887,11 +4627,11 @@
 
     delete fcn_def;
 
-    return new tree_classdef_methods_list (fcn);
-  }
-
-  tree_classdef_methods_list *
-  base_parser::append_classdef_method (tree_classdef_methods_list *list,
+    return new tree_classdef_method_list (fcn);
+  }
+
+  tree_classdef_method_list *
+  base_parser::append_classdef_method (tree_classdef_method_list *list,
                                        tree_function_def *fcn_def)
   {
     octave_value fcn;
@@ -4907,8 +4647,7 @@
   }
 
   bool
-  base_parser::finish_classdef_file (tree_classdef *cls,
-                                     tree_statement_list *local_fcns)
+  base_parser::finish_classdef_file (tree_classdef *cls, tree_statement_list *local_fcns, token *eof_tok)
   {
     parse_tree_validator validator;
 
@@ -4959,6 +4698,8 @@
             std::string nm = fcn->name ();
             std::string file = fcn->fcn_file_name ();
 
+            fcn->attach_trailing_comments (eof_tok->leading_comments ());
+
             symtab.install_local_function (nm, ov_fcn, file);
           }
 
@@ -4975,9 +4716,7 @@
   // Make an index expression.
 
   tree_index_expression *
-  base_parser::make_index_expression (tree_expression *expr,
-                                      tree_argument_list *args,
-                                      char type)
+  base_parser::make_index_expression (tree_expression *expr, token *open_delim, tree_argument_list *args, token *close_delim, char type)
   {
     tree_index_expression *retval = nullptr;
 
@@ -4996,14 +4735,17 @@
         if (! expr->is_postfix_indexed ())
           expr->set_postfix_index (type);
 
+        token tmp_open_delim = open_delim ? *open_delim : token ();
+        token tmp_close_delim = close_delim ? *close_delim : token ();
+
         if (expr->is_index_expression ())
           {
             retval = dynamic_cast<tree_index_expression *> (expr);
 
-            retval->append (args, type);
+            retval->append (tmp_open_delim, args, tmp_close_delim, type);
           }
         else
-          retval = new tree_index_expression (expr, args, l, c, type);
+          retval = new tree_index_expression (expr, tmp_open_delim, args, tmp_close_delim, l, c, type);
       }
 
     return retval;
@@ -5012,8 +4754,7 @@
   // Make an indirect reference expression.
 
   tree_index_expression *
-  base_parser::make_indirect_ref (tree_expression *expr,
-                                  const std::string& elt)
+  base_parser::make_indirect_ref (tree_expression *expr, token *dot_tok, token *struct_elt_tok)
   {
     tree_index_expression *retval = nullptr;
 
@@ -5027,10 +4768,10 @@
       {
         retval = dynamic_cast<tree_index_expression *> (expr);
 
-        retval->append (elt);
+        retval->append (*dot_tok, *struct_elt_tok);
       }
     else
-      retval = new tree_index_expression (expr, elt, l, c);
+      retval = new tree_index_expression (expr, *dot_tok, *struct_elt_tok, l, c);
 
     m_lexer.m_looking_at_indirect_ref = false;
 
@@ -5040,8 +4781,7 @@
   // Make an indirect reference expression with dynamic field name.
 
   tree_index_expression *
-  base_parser::make_indirect_ref (tree_expression *expr,
-                                  tree_expression *elt)
+  base_parser::make_indirect_ref (tree_expression *expr, token *dot_tok, token *open_paren, tree_expression *elt, token *close_paren)
   {
     tree_index_expression *retval = nullptr;
 
@@ -5055,10 +4795,10 @@
       {
         retval = dynamic_cast<tree_index_expression *> (expr);
 
-        retval->append (elt);
+        retval->append (*dot_tok, *open_paren, elt, *close_paren);
       }
     else
-      retval = new tree_index_expression (expr, elt, l, c);
+      retval = new tree_index_expression (expr, *dot_tok, *open_paren, elt, *close_paren, l, c);
 
     m_lexer.m_looking_at_indirect_ref = false;
 
@@ -5068,8 +4808,7 @@
   // Make a declaration command.
 
   tree_decl_command *
-  base_parser::make_decl_command (int tok_id, token *tok,
-                                  tree_decl_init_list *lst)
+  base_parser::make_decl_command (token *tok, tree_decl_init_list *lst)
   {
     tree_decl_command *retval = nullptr;
 
@@ -5079,7 +4818,7 @@
     if (lst)
       m_lexer.mark_as_variables (lst->variable_names ());
 
-    switch (tok_id)
+    switch (tok->token_id ())
       {
       case GLOBAL:
         {
@@ -5287,11 +5026,12 @@
   // Finish building an array_list.
 
   tree_expression *
-  base_parser::finish_array_list (tree_array_list *array_list,
-                                  token */*open_delim*/, token *close_delim)
+  base_parser::finish_array_list (token *open_delim, tree_array_list *array_list, token *close_delim)
   {
     tree_expression *retval = array_list;
 
+    array_list->mark_in_delims (*open_delim, *close_delim);
+
     array_list->set_location (close_delim->line (), close_delim->column ());
 
     if (array_list->all_elements_are_constant ())
@@ -5351,11 +5091,10 @@
   // Finish building a matrix list.
 
   tree_expression *
-  base_parser::finish_matrix (tree_matrix *m, token *open_delim,
-                              token *close_delim)
+  base_parser::finish_matrix (token *open_delim, tree_matrix *m, token *close_delim)
   {
     return (m
-            ? finish_array_list (m, open_delim, close_delim)
+            ? finish_array_list (open_delim, m, close_delim)
             : new tree_constant (octave_null_matrix::instance,
                                  close_delim->line (), close_delim->column ()));
   }
@@ -5367,22 +5106,21 @@
   }
 
   tree_matrix *
-  base_parser::append_matrix_row (tree_matrix *matrix, tree_argument_list *row)
+  base_parser::append_matrix_row (tree_matrix *matrix, token *sep_tok, tree_argument_list *row)
   {
     if (! matrix)
       return make_matrix (row);
 
-    return row ? list_append (matrix, row) : matrix;
+    return row ? list_append (matrix, *sep_tok, row) : matrix;
   }
 
   // Finish building a cell list.
 
   tree_expression *
-  base_parser::finish_cell (tree_cell *c, token *open_delim,
-                            token *close_delim)
+  base_parser::finish_cell (token *open_delim, tree_cell *c, token *close_delim)
   {
     return (c
-            ? finish_array_list (c, open_delim, close_delim)
+            ? finish_array_list (open_delim, c, close_delim)
             : new tree_constant (octave_value (Cell ()),
                                  close_delim->line (), close_delim->column ()));
   }
@@ -5394,29 +5132,20 @@
   }
 
   tree_cell *
-  base_parser::append_cell_row (tree_cell *cell, tree_argument_list *row)
+  base_parser::append_cell_row (tree_cell *cell, token *sep_tok, tree_argument_list *row)
   {
     if (! cell)
       return make_cell (row);
 
-    return row ? list_append (cell, row) : cell;
+    return row ? list_append (cell, *sep_tok, row) : cell;
   }
 
   tree_identifier *
   base_parser::make_identifier (token *ident)
   {
-    // Find the token in the symbol table.
     symbol_scope scope = m_lexer.m_symtab_context.curr_scope ();
 
-    std::string nm = ident->text ();
-
-    symbol_record sr = (scope ? scope.insert (nm) : symbol_record (nm));
-
-
-    int l = ident->line ();
-    int c = ident->column ();
-
-    return new tree_identifier (sr, l, c);
+    return new tree_identifier (scope, *ident);
   }
 
   tree_superclass_ref *
@@ -5484,9 +5213,7 @@
   tree_statement *
   base_parser::make_statement (T *arg)
   {
-    comment_list *comment = m_lexer.get_comment_list ();
-
-    return new tree_statement (arg, comment);
+    return new tree_statement (arg);
   }
 
   tree_statement_list *
@@ -5512,10 +5239,9 @@
   }
 
   tree_argument_list *
-  base_parser::append_argument_list (tree_argument_list *list,
-                                     tree_expression *expr)
-  {
-    return list_append (list, expr);
+  base_parser::append_argument_list (tree_argument_list *list, token *sep_tok, tree_expression *expr)
+  {
+    return list_append (list, *sep_tok, expr);
   }
 
   tree_parameter_list *
@@ -5525,31 +5251,27 @@
   }
 
   tree_parameter_list *
-  base_parser::make_parameter_list (tree_parameter_list::in_or_out io,
-                                    tree_decl_elt *t)
+  base_parser::make_parameter_list (tree_parameter_list::in_or_out io, tree_decl_elt *t)
   {
     return new tree_parameter_list (io, t);
   }
 
   tree_parameter_list *
-  base_parser::make_parameter_list (tree_parameter_list::in_or_out io,
-                                    tree_identifier *id)
+  base_parser::make_parameter_list (tree_parameter_list::in_or_out io, tree_identifier *id)
   {
     return new tree_parameter_list (io, id);
   }
 
   tree_parameter_list *
-  base_parser::append_parameter_list (tree_parameter_list *list,
-                                      tree_decl_elt *t)
-  {
-    return list_append (list, t);
+  base_parser::append_parameter_list (tree_parameter_list *list, token *sep_tok, tree_decl_elt *t)
+  {
+    return list_append (list, *sep_tok, t);
   }
 
   tree_parameter_list *
-  base_parser::append_parameter_list (tree_parameter_list *list,
-                                      tree_identifier *id)
-  {
-    return list_append (list, new tree_decl_elt (id));
+  base_parser::append_parameter_list (tree_parameter_list *list, token *sep_tok, tree_identifier *id)
+  {
+    return list_append (list, *sep_tok, new tree_decl_elt (id));
   }
 
   void
@@ -5949,8 +5671,7 @@
   void
   base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr)
   {
-    if (expr->is_assignment_expression ()
-        && expr->paren_count () < 2)
+    if (expr->is_assignment_expression () && expr->delim_count () < 2)
       {
         if (m_lexer.m_fcn_file_full_name.empty ())
           warning_with_id
--- a/libinterp/parse-tree/parse.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/parse.h	Tue Apr 02 16:11:12 2024 -0400
@@ -48,7 +48,6 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-class comment_list;
 class parse_exception;
 class tree;
 class tree_anon_fcn_handle;
@@ -67,9 +66,9 @@
 class tree_classdef_enum_block;
 class tree_classdef_enum_list;
 class tree_classdef_events_block;
-class tree_classdef_events_list;
+class tree_classdef_event_list;
 class tree_classdef_methods_block;
-class tree_classdef_methods_list;
+class tree_classdef_method_list;
 class tree_classdef_properties_block;
 class tree_classdef_property_list;
 class tree_classdef_superclass_list;
@@ -236,17 +235,17 @@
   // Build a constant.
   OCTINTERP_API tree_constant * make_constant (token *tok);
 
-  OCTINTERP_API tree_black_hole * make_black_hole ();
+  OCTINTERP_API tree_black_hole * make_black_hole (token *tilde);
 
   OCTINTERP_API tree_matrix * make_matrix (tree_argument_list *row);
 
   OCTINTERP_API tree_matrix *
-  append_matrix_row (tree_matrix *matrix, tree_argument_list *row);
+  append_matrix_row (tree_matrix *matrix, token *sep_tok, tree_argument_list *row);
 
   OCTINTERP_API tree_cell * make_cell (tree_argument_list *row);
 
   OCTINTERP_API tree_cell *
-  append_cell_row (tree_cell *cell, tree_argument_list *row);
+  append_cell_row (tree_cell *cell, token *sep_tok, tree_argument_list *row);
 
   // Build a function handle.
   OCTINTERP_API tree_fcn_handle * make_fcn_handle (token *tok);
@@ -258,13 +257,15 @@
 
   // Build a colon expression.
   OCTINTERP_API tree_expression *
-  make_colon_expression (tree_expression *base, tree_expression *limit,
-                         tree_expression *incr = nullptr);
+  make_colon_expression (tree_expression *base, token *colon_tok, tree_expression *limit);
+
+  // Build a colon expression.
+  OCTINTERP_API tree_expression *
+  make_colon_expression (tree_expression *base, token *colon_1_tok, tree_expression *incr, token *colon_2_tok, tree_expression *limit);
 
   // Build a binary expression.
   OCTINTERP_API tree_expression *
-  make_binary_op (int op, tree_expression *op1, token *tok,
-                  tree_expression *op2);
+  make_binary_op (tree_expression *op1, token *op_tok, tree_expression *op2);
 
   // Maybe convert EXPR to a braindead_shortcircuit expression.
   OCTINTERP_API void
@@ -272,47 +273,35 @@
 
   // Build a boolean expression.
   OCTINTERP_API tree_expression *
-  make_boolean_op (int op, tree_expression *op1, token *tok,
-                   tree_expression *op2);
+  make_boolean_op (tree_expression *op1, token *op_tok, tree_expression *op2);
 
   // Build a prefix expression.
   OCTINTERP_API tree_expression *
-  make_prefix_op (int op, tree_expression *op1, token *tok);
+  make_prefix_op (token *op_tok, tree_expression *op1);
 
   // Build a postfix expression.
   OCTINTERP_API tree_expression *
-  make_postfix_op (int op, tree_expression *op1, token *tok);
+  make_postfix_op (tree_expression *op1, token *op_tok);
 
   // Build an unwind-protect command.
   OCTINTERP_API tree_command *
-  make_unwind_command (token *unwind_tok, tree_statement_list *body,
-                       tree_statement_list *cleanup, token *end_tok,
-                       comment_list *lc, comment_list *mc);
+  make_unwind_command (token *unwind_tok, tree_statement_list *body, token *cleanup_tok, tree_statement_list *cleanup, token *end_tok);
 
   // Build a try-catch command.
   OCTINTERP_API tree_command *
-  make_try_command (token *try_tok, tree_statement_list *body,
-                    char catch_sep, tree_statement_list *cleanup,
-                    token *end_tok, comment_list *lc,
-                    comment_list *mc);
+  make_try_command (token *try_tok, tree_statement_list *body, token *catch_tok, char catch_sep, tree_statement_list *cleanup, token *end_tok);
 
   // Build a while command.
   OCTINTERP_API tree_command *
-  make_while_command (token *while_tok, tree_expression *expr,
-                      tree_statement_list *body, token *end_tok,
-                      comment_list *lc);
+  make_while_command (token *while_tok, tree_expression *expr, tree_statement_list *body, token *end_tok);
 
   // Build a do-until command.
   OCTINTERP_API tree_command *
-  make_do_until_command (token *until_tok, tree_statement_list *body,
-                         tree_expression *expr, comment_list *lc);
+  make_do_until_command (token *do_tok, tree_statement_list *body, token *until_tok, tree_expression *expr);
 
   // Build a for command.
   OCTINTERP_API tree_command *
-  make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs,
-                    tree_expression *expr, tree_expression *maxproc,
-                    tree_statement_list *body, token *end_tok,
-                    comment_list *lc);
+  make_for_command (token *for_tok, token *open_paren, tree_argument_list *lhs, token *eq_tok, tree_expression *expr, token *sep_tok, tree_expression *maxproc, token *close_paren, tree_statement_list *body, token *end_tok);
 
   // Build a break command.
   OCTINTERP_API tree_command * make_break_command (token *break_tok);
@@ -326,55 +315,43 @@
   // Build an spmd command.
 
   OCTINTERP_API tree_spmd_command *
-  make_spmd_command (token *spmd_tok, tree_statement_list *body,
-                     token *end_tok, comment_list *lc, comment_list *tc);
+  make_spmd_command (token *spmd_tok, tree_statement_list *body, token *end_tok);
 
   // Start an if command.
   OCTINTERP_API tree_if_command_list *
-  start_if_command (tree_expression *expr, tree_statement_list *list);
+  start_if_command (tree_if_clause *clause);
 
   // Finish an if command.
   OCTINTERP_API tree_if_command *
-  finish_if_command (token *if_tok, tree_if_command_list *list,
-                     token *end_tok, comment_list *lc);
+  finish_if_command (tree_if_command_list *list, tree_if_clause *else_clause, token *end_tok);
 
   // Build an elseif clause.
   OCTINTERP_API tree_if_clause *
-  make_elseif_clause (token *elseif_tok, tree_expression *expr,
-                      tree_statement_list *list, comment_list *lc);
-
-  OCTINTERP_API tree_if_clause *
-  make_else_clause (token *else_tok, comment_list *lc,
-                    tree_statement_list *list);
+  make_if_clause (token *if_tok, tree_expression *expr, tree_statement_list *list);
 
   OCTINTERP_API tree_if_command_list *
   append_if_clause (tree_if_command_list *list, tree_if_clause *clause);
 
   // Finish a switch command.
   OCTINTERP_API tree_switch_command *
-  finish_switch_command (token *switch_tok, tree_expression *expr,
-                         tree_switch_case_list *list, token *end_tok,
-                         comment_list *lc);
+  finish_switch_command (token *switch_tok, tree_expression *expr, tree_switch_case_list *list, token *end_tok);
 
   OCTINTERP_API tree_switch_case_list *
   make_switch_case_list (tree_switch_case *switch_case);
 
   // Build a switch case.
   OCTINTERP_API tree_switch_case *
-  make_switch_case (token *case_tok, tree_expression *expr,
-                    tree_statement_list *list, comment_list *lc);
+  make_switch_case (token *case_tok, tree_expression *expr, tree_statement_list *list);
 
   OCTINTERP_API tree_switch_case *
-  make_default_switch_case (token *default_tok, comment_list *lc,
-                            tree_statement_list *list);
+  make_default_switch_case (token *default_tok, tree_statement_list *list);
 
   OCTINTERP_API tree_switch_case_list *
   append_switch_case (tree_switch_case_list *list, tree_switch_case *elt);
 
   // Build an assignment to a variable.
   OCTINTERP_API tree_expression *
-  make_assign_op (int op, tree_argument_list *lhs, token *eq_tok,
-                  tree_expression *rhs);
+  make_assign_op (tree_argument_list *lhs, token *eq_tok, tree_expression *rhs);
 
   // Define a script.
   OCTINTERP_API void
@@ -386,10 +363,7 @@
 
   // Define a function.
   OCTINTERP_API tree_function_def *
-  make_function (token *fcn_tok, tree_parameter_list *ret_list,
-                 tree_identifier *id, tree_parameter_list *param_list,
-                 tree_statement_list *body, tree_statement *end_fcn_stmt,
-                 comment_list *lc, comment_list *bc);
+  make_function (token *fcn_tok, tree_parameter_list *ret_list, token *eq_tok, tree_identifier *id, tree_parameter_list *param_list, tree_statement_list *body, tree_statement *end_fcn_stmt);
 
   // Begin defining a function.
   OCTINTERP_API octave_user_function *
@@ -399,8 +373,7 @@
 
   // Create a no-op statement for end_function.
   OCTINTERP_API tree_statement *
-  make_end (const std::string& type, bool eof,
-            const filepos& beg_pos, const filepos& end_pos);
+  make_end (const std::string& type, bool eof, token *tok, const filepos& beg_pos, const filepos& end_pos);
 
   // Do most of the work for defining a function.
   OCTINTERP_API octave_user_function *
@@ -408,19 +381,14 @@
 
   // Finish defining a function.
   OCTINTERP_API tree_function_def *
-  finish_function (tree_parameter_list *ret_list,
-                   octave_user_function *fcn, comment_list *lc,
-                   int l, int c);
+  finish_function (token *fcn_tok, tree_parameter_list *ret_list, token *eq_tok, octave_user_function *fcn, int l, int c);
 
   OCTINTERP_API tree_statement_list *
   append_function_body (tree_statement_list *body, tree_statement_list *list);
 
   // Make an arguments validation block.
   OCTINTERP_API tree_arguments_block *
-  make_arguments_block (token *arguments_tok,
-                        tree_args_block_attribute_list *attr_list,
-                        tree_args_block_validation_list *validation_list,
-                        token *end_tok, comment_list *lc, comment_list *tc);
+  make_arguments_block (token *arguments_tok, tree_args_block_attribute_list *attr_list, tree_args_block_validation_list *validation_list, token *end_tok);
 
   OCTINTERP_API tree_args_block_attribute_list *
   make_args_attribute_list (tree_identifier *attribute_name);
@@ -430,7 +398,8 @@
   make_arg_validation (tree_arg_size_spec *size_spec,
                        tree_identifier *class_name,
                        tree_arg_validation_fcns *validation_fcns,
-                       tree_expression *default_value);
+                       token *eq_tok = nullptr,
+                       tree_expression *default_value = nullptr);
 
   // Make an argument validation list.
   OCTINTERP_API tree_args_block_validation_list *
@@ -454,94 +423,73 @@
   recover_from_parsing_function ();
 
   OCTINTERP_API tree_classdef *
-  make_classdef (token *tok, tree_classdef_attribute_list *a,
-                 tree_identifier *id, tree_classdef_superclass_list *sc,
-                 tree_classdef_body *body, token *end_tok,
-                 comment_list *lc, comment_list *bc, comment_list *tc);
+  make_classdef (token *tok, tree_classdef_attribute_list *a, tree_identifier *id, tree_classdef_superclass_list *sc, tree_classdef_body *body, token *end_tok);
 
   OCTINTERP_API tree_classdef_properties_block *
-  make_classdef_properties_block (token *tok,
-                                  tree_classdef_attribute_list *a,
-                                  tree_classdef_property_list *plist,
-                                  token *end_tok, comment_list *lc,
-                                  comment_list *tc);
+  make_classdef_properties_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_property_list *plist, token *end_tok);
 
   OCTINTERP_API tree_classdef_property_list *
   make_classdef_property_list (tree_classdef_property *prop);
 
   OCTINTERP_API tree_classdef_property *
-  make_classdef_property (comment_list *lc, tree_identifier *id,
-                          tree_arg_validation *av);
+  make_classdef_property (tree_identifier *id, tree_arg_validation *av);
 
   OCTINTERP_API tree_classdef_property_list *
   append_classdef_property (tree_classdef_property_list *list,
                             tree_classdef_property *elt);
 
   OCTINTERP_API tree_classdef_methods_block *
-  make_classdef_methods_block (token *tok,
-                               tree_classdef_attribute_list *a,
-                               tree_classdef_methods_list *mlist,
-                               token *end_tok, comment_list *lc,
-                               comment_list *tc);
+  make_classdef_methods_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_method_list *mlist, token *end_tok);
 
   OCTINTERP_API tree_classdef_events_block *
-  make_classdef_events_block (token *tok,
-                              tree_classdef_attribute_list *a,
-                              tree_classdef_events_list *elist,
-                              token *end_tok, comment_list *lc,
-                              comment_list *tc);
+  make_classdef_events_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_event_list *elist, token *end_tok);
 
-  OCTINTERP_API tree_classdef_events_list *
-  make_classdef_events_list (tree_classdef_event *e);
+  OCTINTERP_API tree_classdef_event_list *
+  make_classdef_event_list (tree_classdef_event *e);
 
   OCTINTERP_API tree_classdef_event *
-  make_classdef_event (comment_list *lc, tree_identifier *id);
+  make_classdef_event (tree_identifier *id);
 
-  OCTINTERP_API tree_classdef_events_list *
-  append_classdef_event (tree_classdef_events_list *list,
+  OCTINTERP_API tree_classdef_event_list *
+  append_classdef_event (tree_classdef_event_list *list,
                          tree_classdef_event *elt);
 
   OCTINTERP_API tree_classdef_enum_block *
-  make_classdef_enum_block (token *tok,
-                            tree_classdef_attribute_list *a,
-                            tree_classdef_enum_list *elist,
-                            token *end_tok, comment_list *lc,
-                            comment_list *tc);
+  make_classdef_enum_block (token *tok, tree_classdef_attribute_list *a, tree_classdef_enum_list *elist, token *end_tok);
 
   OCTINTERP_API tree_classdef_enum_list *
   make_classdef_enum_list (tree_classdef_enum *e);
 
   OCTINTERP_API tree_classdef_enum *
-  make_classdef_enum (tree_identifier *id, tree_expression *expr,
-                      comment_list *lc);
+  make_classdef_enum (tree_identifier *id, token *open_paren, tree_expression *expr, token *close_paren);
 
   OCTINTERP_API tree_classdef_enum_list *
   append_classdef_enum (tree_classdef_enum_list *list,
                         tree_classdef_enum *elt);
 
   OCTINTERP_API tree_classdef_superclass_list *
-  make_classdef_superclass_list (tree_classdef_superclass *sc);
+  make_classdef_superclass_list (token *lt_tok, tree_classdef_superclass *sc);
 
   OCTINTERP_API tree_classdef_superclass *
   make_classdef_superclass (token *fqident);
 
   OCTINTERP_API tree_classdef_superclass_list *
-  append_classdef_superclass (tree_classdef_superclass_list *list,
-                              tree_classdef_superclass *elt);
+  append_classdef_superclass (tree_classdef_superclass_list *list, token *and_tok, tree_classdef_superclass *elt);
 
   OCTINTERP_API tree_classdef_attribute_list *
   make_classdef_attribute_list (tree_classdef_attribute *attr);
 
   OCTINTERP_API tree_classdef_attribute *
-  make_classdef_attribute (tree_identifier *id,
-                           tree_expression *expr = nullptr);
+  make_classdef_attribute (tree_identifier *id);
 
   OCTINTERP_API tree_classdef_attribute *
-  make_not_classdef_attribute (tree_identifier *id);
+  make_classdef_attribute (tree_identifier *id, token *eq_tok, tree_expression *expr);
+
+  OCTINTERP_API tree_classdef_attribute *
+  make_not_classdef_attribute (token *not_tok, tree_identifier *id);
 
   OCTINTERP_API tree_classdef_attribute_list *
-  append_classdef_attribute (tree_classdef_attribute_list *list,
-                             tree_classdef_attribute *elt);
+  append_classdef_attribute (tree_classdef_attribute_list *list, token *sep_tok, tree_classdef_attribute *elt);
 
   OCTINTERP_API tree_classdef_body *
   make_classdef_body (tree_classdef_properties_block *pb);
@@ -572,41 +520,36 @@
                               tree_classdef_enum_block *block);
 
   OCTINTERP_API octave_user_function *
-  start_classdef_external_method (tree_identifier *id,
-                                  tree_parameter_list *pl);
+  start_classdef_external_method (tree_identifier *id, tree_parameter_list *pl = nullptr);
 
   OCTINTERP_API tree_function_def *
-  finish_classdef_external_method (octave_user_function *fcn,
-                                   tree_parameter_list *ret_list,
-                                   comment_list *cl);
+  finish_classdef_external_method (octave_user_function *fcn, tree_parameter_list *ret_list = nullptr, token *eq_tok = nullptr);
 
-  OCTINTERP_API tree_classdef_methods_list *
-  make_classdef_methods_list (tree_function_def *fcn_def);
+  OCTINTERP_API tree_classdef_method_list *
+  make_classdef_method_list (tree_function_def *fcn_def);
 
-  OCTINTERP_API tree_classdef_methods_list *
-  append_classdef_method (tree_classdef_methods_list *list,
+  OCTINTERP_API tree_classdef_method_list *
+  append_classdef_method (tree_classdef_method_list *list,
                           tree_function_def *fcn_def);
 
   OCTINTERP_API bool
-  finish_classdef_file (tree_classdef *cls,
-                        tree_statement_list *local_fcns);
+  finish_classdef_file (tree_classdef *cls, tree_statement_list *local_fcns, token *eof_tok);
 
   // Make an index expression.
   OCTINTERP_API tree_index_expression *
-  make_index_expression (tree_expression *expr,
-                         tree_argument_list *args, char type);
+  make_index_expression (tree_expression *expr, token *open_paren, tree_argument_list *args, token *close_paren, char type);
 
   // Make an indirect reference expression.
   OCTINTERP_API tree_index_expression *
-  make_indirect_ref (tree_expression *expr, const std::string&);
+  make_indirect_ref (tree_expression *expr, token *dot_tok, token *struct_elt_tok);
 
   // Make an indirect reference expression with dynamic field name.
   OCTINTERP_API tree_index_expression *
-  make_indirect_ref (tree_expression *expr, tree_expression *field);
+  make_indirect_ref (tree_expression *expr, token *dot_tok, token *open_paren, tree_expression *field, token *close_paren);
 
   // Make a declaration command.
   OCTINTERP_API tree_decl_command *
-  make_decl_command (int tok_id, token *tok, tree_decl_init_list *lst);
+  make_decl_command (token *tok, tree_decl_init_list *lst);
 
   OCTINTERP_API tree_decl_init_list *
   make_decl_init_list (tree_decl_elt *elt);
@@ -632,16 +575,15 @@
   // Finish building an array_list (common action for finish_matrix
   // and finish_cell).
   OCTINTERP_API tree_expression *
-  finish_array_list (tree_array_list *a, token *open_delim,
-                     token *close_delim);
+  finish_array_list (token *open_delim, tree_array_list *a, token *close_delim);
 
   // Finish building a matrix list.
   OCTINTERP_API tree_expression *
-  finish_matrix (tree_matrix *m, token *open_delim, token *close_delim);
+  finish_matrix (token *open_delim, tree_matrix *m, token *close_delim);
 
   // Finish building a cell list.
   OCTINTERP_API tree_expression *
-  finish_cell (tree_cell *c, token *open_delim, token *close_delim);
+  finish_cell (token *open_delim, tree_cell *c, token *close_delim);
 
   OCTINTERP_API tree_identifier *
   make_identifier (token *ident);
@@ -673,7 +615,7 @@
   make_argument_list (tree_expression *expr);
 
   OCTINTERP_API tree_argument_list *
-  append_argument_list (tree_argument_list *list, tree_expression *expr);
+  append_argument_list (tree_argument_list *list, token *sep_tok, tree_expression *expr);
 
   OCTINTERP_API tree_parameter_list *
   make_parameter_list (tree_parameter_list::in_or_out io);
@@ -682,14 +624,13 @@
   make_parameter_list (tree_parameter_list::in_or_out io, tree_decl_elt *t);
 
   OCTINTERP_API tree_parameter_list *
-  make_parameter_list (tree_parameter_list::in_or_out io,
-                       tree_identifier *id);
+  make_parameter_list (tree_parameter_list::in_or_out io, tree_identifier *id);
 
   OCTINTERP_API tree_parameter_list *
-  append_parameter_list (tree_parameter_list *list, tree_decl_elt *t);
+  append_parameter_list (tree_parameter_list *list, token *sep_tok, tree_decl_elt *t);
 
   OCTINTERP_API tree_parameter_list *
-  append_parameter_list (tree_parameter_list *list, tree_identifier *id);
+  append_parameter_list (tree_parameter_list *list, token *sep_tok, tree_identifier *id);
 
   // Don't allow parsing command syntax.  If the parser/lexer is
   // reset, this setting is also reset to the default (allow command
--- a/libinterp/parse-tree/pt-arg-list.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-arg-list.h	Tue Apr 02 16:11:12 2024 -0400
@@ -35,7 +35,9 @@
 
 #include "str-vec.h"
 
+#include "pt-delimiter-list.h"
 #include "pt-walk.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -64,6 +66,12 @@
 
   ~tree_argument_list ();
 
+  tree_argument_list * mark_in_delims (const token& open_delim, const token& close_delim)
+  {
+    m_delims.push (open_delim, close_delim);
+    return this;
+  }
+
   bool has_magic_tilde () const
   {
     return m_list_includes_magic_tilde;
@@ -108,6 +116,8 @@
   bool m_list_includes_magic_tilde;
 
   bool m_simple_assign_lhs;
+
+  tree_delimiter_list m_delims;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-args-block.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-args-block.h	Tue Apr 02 16:11:12 2024 -0400
@@ -41,6 +41,8 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+class comment_list;
+
 class tree_arg_size_spec
 {
 public:
@@ -102,10 +104,11 @@
   tree_arg_validation (tree_arg_size_spec *size_spec,
                        tree_identifier *class_name,
                        tree_arg_validation_fcns *validation_fcns,
+                       const token& eq_tok,
                        tree_expression *default_value)
     : m_arg_name (nullptr), m_size_spec (size_spec),
       m_class_name (class_name), m_validation_fcns (validation_fcns),
-      m_default_value (default_value)
+      m_eq_tok (eq_tok), m_default_value (default_value)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_arg_validation)
@@ -149,6 +152,7 @@
   tree_arg_size_spec *m_size_spec;
   tree_identifier *m_class_name;
   tree_arg_validation_fcns *m_validation_fcns;
+  token m_eq_tok;
   tree_expression *m_default_value;
 };
 
@@ -211,12 +215,8 @@
 {
 public:
 
-  tree_arguments_block (tree_args_block_attribute_list *attr_list,
-                        tree_args_block_validation_list *validation_list,
-                        int l = -1, int c = -1)
-    : tree_command (l, c), m_attr_list (attr_list),
-      m_validation_list (validation_list),
-      m_lead_comm (nullptr), m_trail_comm (nullptr)
+  tree_arguments_block (tree_args_block_attribute_list *attr_list, tree_args_block_validation_list *validation_list, int l = -1, int c = -1)
+    : tree_command (l, c), m_attr_list (attr_list), m_validation_list (validation_list)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_arguments_block)
@@ -225,9 +225,6 @@
   {
     delete m_attr_list;
     delete m_validation_list;
-
-    delete m_lead_comm;
-    delete m_trail_comm;
   }
 
   tree_args_block_attribute_list * attribute_list ()
@@ -240,10 +237,6 @@
     return m_validation_list;
   }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
-
   void accept (tree_walker& tw)
   {
     tw.visit_arguments_block (*this);
@@ -254,12 +247,6 @@
   tree_args_block_attribute_list *m_attr_list;
 
   tree_args_block_validation_list *m_validation_list;
-
-  // Comment preceding ARGUMENTS token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDARGUMENTS token.
-  comment_list *m_trail_comm;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-assign.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-assign.h	Tue Apr 02 16:11:12 2024 -0400
@@ -34,9 +34,11 @@
 class octave_value;
 class octave_value_list;
 
+#include "comment-list.h"
 #include "ov.h"
 #include "pt-exp.h"
 #include "pt-walk.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -64,6 +66,8 @@
 
   ~tree_simple_assignment ();
 
+  comment_list leading_comments () const { return m_lhs->leading_comments (); }
+
   bool rvalue_ok () const { return true; }
 
   bool is_assignment_expression () const { return true; }
--- a/libinterp/parse-tree/pt-classdef.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-classdef.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -29,6 +29,7 @@
 
 #include <iostream>
 
+#include "comment-list.h"
 #include "ov.h"
 #include "ov-classdef.h"
 #include "pt-args-block.h"
@@ -121,33 +122,39 @@
 
 // Classdef property
 
-std::string
-check_for_doc_string (comment_list *comments)
+static std::string
+check_for_doc_string (const comment_list& comments)
 {
-  // If the comment list ends in a block comment or full-line comment,
-  // then it is the doc string for this property.
+  if (! comments.empty ())
+    {
+      // If the comment list ends in a block comment or full-line
+      // comment, then it is the doc string for this property.
 
-  if (comments)
-    {
-      comment_elt last_elt = comments->back ();
+      comment_elt last_elt = comments.back ();
 
-      if (last_elt.is_block () || last_elt.is_full_line ())
+      if (! last_elt.is_copyright ()
+          && (last_elt.is_block () || last_elt.is_full_line ()))
         return last_elt.text ();
     }
 
   return "";
 }
 
-tree_classdef_property::tree_classdef_property (tree_arg_validation *av,
-    comment_list *comments)
-  : m_av (av), m_comments (comments),
-    m_doc_string (check_for_doc_string (m_comments))
+tree_classdef_property::tree_classdef_property (tree_arg_validation *av)
+  : m_av (av), m_doc_string (check_for_doc_string (leading_comments ()))
 { }
 
 tree_classdef_property::~tree_classdef_property ()
 {
   delete m_av;
-  delete m_comments;
+}
+
+comment_list
+tree_classdef_property::leading_comments ()
+{
+  tree_identifier *id = ident ();
+
+  return id->leading_comments ();
 }
 
 tree_identifier *
@@ -178,21 +185,19 @@
 
 // Classdef properties_block
 
-// Classdef methods_list
+// Classdef method_list
 
 // Classdef methods_block
 
 // Classdef event
 
-tree_classdef_event::tree_classdef_event (tree_identifier *i,
-    comment_list *comments)
-  : m_id (i), m_comments (comments),
-    m_doc_string (check_for_doc_string (m_comments))
+tree_classdef_event::tree_classdef_event (tree_identifier *i)
+  : m_id (i)
 { }
 
-// Classdef events_list
+// Classdef event_list
 
-tree_classdef_events_list::~tree_classdef_events_list ()
+tree_classdef_event_list::~tree_classdef_event_list ()
 {
   while (! empty ())
     {
@@ -206,11 +211,8 @@
 
 // Classdef enum
 
-tree_classdef_enum::tree_classdef_enum (tree_identifier *i,
-                                        tree_expression *e,
-                                        comment_list *comments)
-  : m_id (i), m_expr (e), m_comments (comments),
-    m_doc_string (check_for_doc_string (m_comments))
+tree_classdef_enum::tree_classdef_enum (tree_identifier *i, const token& open_paren, tree_expression *e, const token& close_paren)
+  : m_id (i), m_open_paren (open_paren), m_expr (e), m_close_paren (close_paren)
 { }
 
 // Classdef enum_list
@@ -230,82 +232,55 @@
 // Classdef body
 
 tree_classdef_body::tree_classdef_body ()
-  : m_properties_lst (), m_methods_lst (), m_events_lst (), m_enum_lst ()
+  : m_property_lst (), m_method_lst (), m_event_lst (), m_enum_lst ()
 { }
 
 tree_classdef_body::tree_classdef_body (tree_classdef_properties_block *pb)
-  : m_properties_lst (), m_methods_lst (), m_events_lst (), m_enum_lst (),
-    m_doc_string (pb ? get_doc_string (pb->leading_comment ()) : "")
+  : m_property_lst (), m_method_lst (), m_event_lst (), m_enum_lst ()
 {
   append (pb);
 }
 
 tree_classdef_body::tree_classdef_body (tree_classdef_methods_block *mb)
-  : m_properties_lst (), m_methods_lst (), m_events_lst (), m_enum_lst (),
-    m_doc_string (mb ? get_doc_string (mb->leading_comment ()) : "")
+  : m_property_lst (), m_method_lst (), m_event_lst (), m_enum_lst ()
 {
   append (mb);
 }
 
 tree_classdef_body::tree_classdef_body (tree_classdef_events_block *evb)
-  : m_properties_lst (), m_methods_lst (), m_events_lst (), m_enum_lst (),
-    m_doc_string (evb ? get_doc_string (evb->leading_comment ()) : "")
+  : m_property_lst (), m_method_lst (), m_event_lst (), m_enum_lst ()
 {
   append (evb);
 }
 
 tree_classdef_body::tree_classdef_body (tree_classdef_enum_block *enb)
-  : m_properties_lst (), m_methods_lst (), m_events_lst (), m_enum_lst (),
-    m_doc_string (enb ? get_doc_string (enb->leading_comment ()) : "")
+  : m_property_lst (), m_method_lst (), m_event_lst (), m_enum_lst ()
 {
   append (enb);
 }
 
+comment_list
+tree_classdef_body::leading_comments () const
+{
+  if (! m_all_elements.empty ())
+    {
+      tree_base_classdef_block *element = m_all_elements.front ();
+
+      if (element)
+        return element->leading_comments ();
+    }
+
+  return comment_list ();
+}
+
 tree_classdef_body::~tree_classdef_body ()
 {
-  while (! m_properties_lst.empty ())
-    {
-      auto p = m_properties_lst.begin ();
-      delete *p;
-      m_properties_lst.erase (p);
-    }
-
-  while (! m_methods_lst.empty ())
+  while (! m_all_elements.empty ())
     {
-      auto p = m_methods_lst.begin ();
+      auto p = m_all_elements.begin ();
       delete *p;
-      m_methods_lst.erase (p);
-    }
-
-  while (! m_events_lst.empty ())
-    {
-      auto p = m_events_lst.begin ();
-      delete *p;
-      m_events_lst.erase (p);
+      m_all_elements.erase (p);
     }
-
-  while (! m_enum_lst.empty ())
-    {
-      auto p = m_enum_lst.begin ();
-      delete *p;
-      m_enum_lst.erase (p);
-    }
-}
-
-std::string
-tree_classdef_body::get_doc_string (comment_list *comments) const
-{
-  // Grab the first comment from the list and use it as the doc string
-  // for this classdef body.
-
-  if (comments)
-    {
-      comment_elt first_elt = comments->front ();
-
-      return first_elt.text ();
-    }
-
-  return "";
 }
 
 // Classdef
--- a/libinterp/parse-tree/pt-classdef.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-classdef.h	Tue Apr 02 16:11:12 2024 -0400
@@ -30,18 +30,19 @@
 
 class octave_value;
 
-#include "comment-list.h"
 #include "pt-cmd.h"
+#include "pt-delimiter-list.h"
 #include "pt-exp.h"
 #include "pt-walk.h"
 #include "pt-id.h"
+#include "token.h"
 
 #include <list>
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+class coment_list;
 class interpreter;
-
 class tree_arg_validation;
 
 class tree_superclass_ref : public tree_expression
@@ -128,13 +129,16 @@
 {
 public:
 
-  tree_classdef_attribute (tree_identifier *i = nullptr,
-                           tree_expression *e = nullptr)
-    : m_id (i), m_expr (e), m_neg (false)
+  tree_classdef_attribute (tree_identifier *i)
+    : m_id (i)
   { }
 
-  tree_classdef_attribute (tree_identifier *i, bool b)
-    : m_id (i), m_expr (nullptr), m_neg (b)
+  tree_classdef_attribute (tree_identifier *i, const token eq_tok, tree_expression *e)
+    : m_id (i), m_eq_tok (eq_tok), m_expr (e)
+  { }
+
+  tree_classdef_attribute (const token& not_tok, tree_identifier *i, bool b)
+    : m_not_tok (not_tok), m_id (i), m_neg (b)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_classdef_attribute)
@@ -158,9 +162,11 @@
 
 private:
 
+  token m_not_tok;
   tree_identifier *m_id;
-  tree_expression *m_expr;
-  bool m_neg;
+  token m_eq_tok;
+  tree_expression *m_expr {nullptr};
+  bool m_neg {false};
 };
 
 class tree_classdef_attribute_list : public std::list<tree_classdef_attribute *>
@@ -179,25 +185,37 @@
 
   ~tree_classdef_attribute_list ();
 
+  tree_classdef_attribute_list * mark_in_delims (const token& open_delim, token& close_delim)
+  {
+    m_delims.push (open_delim, close_delim);
+    return this;
+  }
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_attribute_list (*this);
   }
+
+private:
+
+  tree_delimiter_list m_delims;
 };
 
 class tree_classdef_superclass
 {
 public:
 
-  tree_classdef_superclass (const std::string& cname)
-    : m_cls_name (cname)
+  tree_classdef_superclass (const token& fqident)
+    : m_fqident (fqident)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_superclass)
 
   ~tree_classdef_superclass () = default;
 
-  std::string class_name () { return m_cls_name; }
+  void set_separator (const token& sep_tok) { m_sep_tok = sep_tok; }
+
+  std::string class_name () { return m_fqident.text (); }
 
   void accept (tree_walker& tw)
   {
@@ -206,7 +224,13 @@
 
 private:
 
-  std::string m_cls_name;
+  // The '<' or '&&' token introducing an element of a superclass list
+  // element.  Is there a better name for it?
+
+  token m_sep_tok;
+
+  // The fully-qualified identifier token for this superclass element.
+  token m_fqident;
 };
 
 class tree_classdef_superclass_list
@@ -235,76 +259,84 @@
   }
 };
 
-template <typename T>
-class tree_classdef_element : public tree
+class tree_base_classdef_block : public tree
 {
 public:
 
-  tree_classdef_element (tree_classdef_attribute_list *a, T *elt_list,
-                         comment_list *lc, comment_list *tc,
-                         int l = -1, int c = -1)
-    : tree (l, c), m_attr_list (a), m_elt_list (elt_list),
-      m_lead_comm (lc), m_trail_comm (tc)
+  tree_base_classdef_block (const token& block_tok, tree_classdef_attribute_list *a, const token& end_tok, int l = -1, int c = -1)
+    : tree (l, c), m_block_tok (block_tok), m_attr_list (a), m_end_tok (end_tok)
   { }
 
-  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_element)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_base_classdef_block)
 
-  ~tree_classdef_element ()
+  ~tree_base_classdef_block ()
   {
     delete m_attr_list;
-    delete m_elt_list;
-    delete m_lead_comm;
-    delete m_trail_comm;
   }
 
+  comment_list leading_comments () const { return m_block_tok.leading_comments (); }
+
   tree_classdef_attribute_list * attribute_list () { return m_attr_list; }
 
-  T * element_list () { return m_elt_list; }
-
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
-
   void accept (tree_walker&) { }
 
 private:
 
+  token m_block_tok;
+
   // List of attributes that apply to this class.
   tree_classdef_attribute_list *m_attr_list;
 
-  // The list of objects contained in this block.
-  T *m_elt_list;
+  token m_end_tok;
+};
+
+template <typename T>
+class tree_classdef_block : public tree_base_classdef_block
+{
+public:
+
+  tree_classdef_block (const token& block_tok, tree_classdef_attribute_list *a, T *elt_list, const token& end_tok, int l = -1, int c = -1)
+    : tree_base_classdef_block (block_tok, a, end_tok, l, c), m_elt_list (elt_list)
+  { }
+
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_block)
 
-  // Comments preceding the token marking the beginning of the block.
-  comment_list *m_lead_comm;
+  ~tree_classdef_block ()
+  {
+    delete m_elt_list;
+  }
+
+  T * element_list () { return m_elt_list; }
 
-  // Comments preceding the END token marking the end of the block.
-  comment_list *m_trail_comm;
+private:
+
+  T *m_elt_list;
 };
 
+// FIXME: should this class be derived from tree?
+
 class tree_classdef_property
 {
 public:
 
-  tree_classdef_property (tree_arg_validation *av,
-                          comment_list *comments = nullptr);
+  tree_classdef_property (tree_arg_validation *av);
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_property)
 
   ~tree_classdef_property ();
 
-  tree_identifier * ident ();
-
-  tree_expression * expression ();
+  comment_list leading_comments ();
 
-  comment_list * comments () const { return m_comments; }
-
-  void doc_string (const std::string& txt) { m_doc_string = txt; }
+  void doc_string (const std::string& s) { m_doc_string = s; }
 
   std::string doc_string () const { return m_doc_string; }
 
   bool have_doc_string () const { return ! m_doc_string.empty (); }
 
+  tree_identifier * ident ();
+
+  tree_expression * expression ();
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_property (*this);
@@ -313,7 +345,7 @@
 private:
 
   tree_arg_validation *m_av;
-  comment_list *m_comments;
+
   std::string m_doc_string;
 };
 
@@ -338,65 +370,61 @@
   }
 };
 
-class tree_classdef_properties_block
-  : public tree_classdef_element<tree_classdef_property_list>
+class tree_classdef_properties_block : public tree_classdef_block<tree_classdef_property_list>
 {
 public:
 
-  tree_classdef_properties_block (tree_classdef_attribute_list *a,
-                                  tree_classdef_property_list *plist,
-                                  comment_list *lc, comment_list *tc,
-                                  int l = -1, int c = -1)
-    : tree_classdef_element<tree_classdef_property_list> (a, plist, lc, tc, l, c)
+  tree_classdef_properties_block (const token& block_tok, tree_classdef_attribute_list *a, tree_classdef_property_list *plist, const token& end_tok, int l = -1, int c = -1)
+    : tree_classdef_block<tree_classdef_property_list> (block_tok, a, plist, end_tok, l, c)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_properties_block)
 
   ~tree_classdef_properties_block () = default;
 
+  tree_classdef_property_list * property_list () { return element_list (); }
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_properties_block (*this);
   }
 };
 
-class tree_classdef_methods_list : public std::list<octave_value>
+class tree_classdef_method_list : public std::list<octave_value>
 {
 public:
 
-  tree_classdef_methods_list () { }
+  tree_classdef_method_list () { }
 
-  tree_classdef_methods_list (const octave_value& f) { push_back (f); }
+  tree_classdef_method_list (const octave_value& f) { push_back (f); }
 
-  tree_classdef_methods_list (const std::list<octave_value>& a)
+  tree_classdef_method_list (const std::list<octave_value>& a)
     : std::list<octave_value> (a) { }
 
-  OCTAVE_DISABLE_COPY_MOVE (tree_classdef_methods_list)
+  OCTAVE_DISABLE_COPY_MOVE (tree_classdef_method_list)
 
-  ~tree_classdef_methods_list () = default;
+  ~tree_classdef_method_list () = default;
 
   void accept (tree_walker& tw)
   {
-    tw.visit_classdef_methods_list (*this);
+    tw.visit_classdef_method_list (*this);
   }
 };
 
-class tree_classdef_methods_block
-  : public tree_classdef_element<tree_classdef_methods_list>
+class tree_classdef_methods_block : public tree_classdef_block<tree_classdef_method_list>
 {
 public:
 
-  tree_classdef_methods_block (tree_classdef_attribute_list *a,
-                               tree_classdef_methods_list *mlist,
-                               comment_list *lc, comment_list *tc,
-                               int l = -1, int c = -1)
-    : tree_classdef_element<tree_classdef_methods_list> (a, mlist, lc, tc, l, c)
+  tree_classdef_methods_block (const token& block_tok, tree_classdef_attribute_list *a, tree_classdef_method_list *mlist, const token& end_tok, int l = -1, int c = -1)
+    : tree_classdef_block<tree_classdef_method_list> (block_tok, a, mlist, end_tok, l, c)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_methods_block)
 
   ~tree_classdef_methods_block () = default;
 
+  tree_classdef_method_list * method_list () { return element_list (); }
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_methods_block (*this);
@@ -407,27 +435,17 @@
 {
 public:
 
-  tree_classdef_event (tree_identifier *i = nullptr,
-                       comment_list *comments = nullptr);
+  tree_classdef_event (tree_identifier *i = nullptr);
 
   OCTAVE_DISABLE_COPY_MOVE (tree_classdef_event)
 
   ~tree_classdef_event ()
   {
     delete m_id;
-    delete m_comments;
   }
 
   tree_identifier * ident () { return m_id; }
 
-  comment_list * comments () const { return m_comments; }
-
-  void doc_string (const std::string& txt) { m_doc_string = txt; }
-
-  std::string doc_string () const { return m_doc_string; }
-
-  bool have_doc_string () const { return ! m_doc_string.empty (); }
-
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_event (*this);
@@ -436,48 +454,44 @@
 private:
 
   tree_identifier *m_id;
-  comment_list *m_comments;
-  std::string m_doc_string;
 };
 
-class tree_classdef_events_list : public std::list<tree_classdef_event *>
+class tree_classdef_event_list : public std::list<tree_classdef_event *>
 {
 public:
 
-  tree_classdef_events_list () { }
+  tree_classdef_event_list () { }
 
-  tree_classdef_events_list (tree_classdef_event *e) { push_back (e); }
+  tree_classdef_event_list (tree_classdef_event *e) { push_back (e); }
 
-  tree_classdef_events_list (const std::list<tree_classdef_event *>& a)
+  tree_classdef_event_list (const std::list<tree_classdef_event *>& a)
     : std::list<tree_classdef_event *> (a)
   { }
 
-  OCTAVE_DISABLE_COPY_MOVE (tree_classdef_events_list)
+  OCTAVE_DISABLE_COPY_MOVE (tree_classdef_event_list)
 
-  ~tree_classdef_events_list ();
+  ~tree_classdef_event_list ();
 
   void accept (tree_walker& tw)
   {
-    tw.visit_classdef_events_list (*this);
+    tw.visit_classdef_event_list (*this);
   }
 };
 
-class tree_classdef_events_block
-  : public tree_classdef_element<tree_classdef_events_list>
+class tree_classdef_events_block : public tree_classdef_block<tree_classdef_event_list>
 {
 public:
 
-  tree_classdef_events_block (tree_classdef_attribute_list *a,
-                              tree_classdef_events_list *elist,
-                              comment_list *lc, comment_list *tc,
-                              int l = -1, int c = -1)
-    : tree_classdef_element<tree_classdef_events_list> (a, elist, lc, tc, l, c)
+  tree_classdef_events_block (const token& block_tok, tree_classdef_attribute_list *a, tree_classdef_event_list *elist, const token& end_tok, int l = -1, int c = -1)
+    : tree_classdef_block<tree_classdef_event_list> (block_tok, a, elist, end_tok, l, c)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_events_block)
 
   ~tree_classdef_events_block () = default;
 
+  tree_classdef_event_list * event_list () { return element_list (); }
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_events_block (*this);
@@ -488,8 +502,7 @@
 {
 public:
 
-  tree_classdef_enum (tree_identifier *i, tree_expression *e,
-                      comment_list *comments);
+  tree_classdef_enum (tree_identifier *i, const token& open_paren, tree_expression *e, const token& close_paren);
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_enum)
 
@@ -497,20 +510,15 @@
   {
     delete m_id;
     delete m_expr;
-    delete m_comments;
   }
 
   tree_identifier * ident () { return m_id; }
 
+  token open_paren () const { return m_open_paren; }
+
   tree_expression * expression () { return m_expr; }
 
-  comment_list * comments () const { return m_comments; }
-
-  void doc_string (const std::string& txt) { m_doc_string = txt; }
-
-  std::string doc_string () const { return m_doc_string; }
-
-  bool have_doc_string () const { return ! m_doc_string.empty (); }
+  token close_paren () const { return m_close_paren; }
 
   void accept (tree_walker& tw)
   {
@@ -520,9 +528,9 @@
 private:
 
   tree_identifier *m_id;
+  token m_open_paren;
   tree_expression *m_expr;
-  comment_list *m_comments;
-  std::string m_doc_string;
+  token m_close_paren;
 };
 
 class tree_classdef_enum_list : public std::list<tree_classdef_enum *>
@@ -547,49 +555,43 @@
   }
 };
 
-class tree_classdef_enum_block
-  : public tree_classdef_element<tree_classdef_enum_list>
+class tree_classdef_enum_block : public tree_classdef_block<tree_classdef_enum_list>
 {
 public:
 
-  tree_classdef_enum_block (tree_classdef_attribute_list *a,
-                            tree_classdef_enum_list *elist,
-                            comment_list *lc, comment_list *tc,
-                            int l = -1, int c = -1)
-    : tree_classdef_element<tree_classdef_enum_list> (a, elist, lc, tc, l, c)
+  tree_classdef_enum_block (const token& block_tok, tree_classdef_attribute_list *a, tree_classdef_enum_list *elist, const token& end_tok, int l = -1, int c = -1)
+    : tree_classdef_block<tree_classdef_enum_list> (block_tok, a, elist, end_tok, l, c)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef_enum_block)
 
   ~tree_classdef_enum_block () = default;
 
+  tree_classdef_enum_list * enum_list () { return element_list (); }
+
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_enum_block (*this);
   }
 };
 
+// FIXME: should this class be derived from tree?
+
 class tree_classdef_body
 {
 public:
 
-  typedef std::list<tree_classdef_properties_block *>::iterator
-    properties_list_iterator;
-  typedef std::list<tree_classdef_properties_block *>::const_iterator
-    properties_list_const_iterator;
+  typedef std::list<tree_classdef_properties_block *>::iterator property_list_iterator;
+  typedef std::list<tree_classdef_properties_block *>::const_iterator property_list_const_iterator;
 
-  typedef std::list<tree_classdef_methods_block *>::iterator
-    methods_list_iterator;
-  typedef std::list<tree_classdef_methods_block *>::const_iterator
-    methods_list_const_iterator;
+  typedef std::list<tree_classdef_methods_block *>::iterator method_list_iterator;
+  typedef std::list<tree_classdef_methods_block *>::const_iterator method_list_const_iterator;
 
-  typedef std::list<tree_classdef_events_block *>::iterator events_list_iterator;
-  typedef std::list<tree_classdef_events_block *>::const_iterator
-    events_list_const_iterator;
+  typedef std::list<tree_classdef_events_block *>::iterator event_list_iterator;
+  typedef std::list<tree_classdef_events_block *>::const_iterator event_list_const_iterator;
 
   typedef std::list<tree_classdef_enum_block *>::iterator enum_list_iterator;
-  typedef std::list<tree_classdef_enum_block *>::const_iterator
-    enum_list_const_iterator;
+  typedef std::list<tree_classdef_enum_block *>::const_iterator enum_list_const_iterator;
 
   tree_classdef_body ();
 
@@ -605,43 +607,49 @@
 
   ~tree_classdef_body ();
 
+  comment_list leading_comments () const;
+
   tree_classdef_body * append (tree_classdef_properties_block *pb)
   {
-    m_properties_lst.push_back (pb);
+    m_property_lst.push_back (pb);
+    m_all_elements.push_back (pb);
     return this;
   }
 
   tree_classdef_body * append (tree_classdef_methods_block *mb)
   {
-    m_methods_lst.push_back (mb);
+    m_method_lst.push_back (mb);
+    m_all_elements.push_back (mb);
     return this;
   }
 
   tree_classdef_body * append (tree_classdef_events_block *evb)
   {
-    m_events_lst.push_back (evb);
+    m_event_lst.push_back (evb);
+    m_all_elements.push_back (evb);
     return this;
   }
 
   tree_classdef_body * append (tree_classdef_enum_block *enb)
   {
     m_enum_lst.push_back (enb);
+    m_all_elements.push_back (enb);
     return this;
   }
 
-  std::list<tree_classdef_properties_block *> properties_list ()
+  std::list<tree_classdef_properties_block *> property_list ()
   {
-    return m_properties_lst;
+    return m_property_lst;
   }
 
-  std::list<tree_classdef_methods_block *> methods_list ()
+  std::list<tree_classdef_methods_block *> method_list ()
   {
-    return m_methods_lst;
+    return m_method_lst;
   }
 
-  std::list<tree_classdef_events_block *> events_list ()
+  std::list<tree_classdef_events_block *> event_list ()
   {
-    return m_events_lst;
+    return m_event_lst;
   }
 
   std::list<tree_classdef_enum_block *> enum_list ()
@@ -649,12 +657,6 @@
     return m_enum_lst;
   }
 
-  void doc_string (const std::string& txt) { m_doc_string = txt; }
-
-  std::string doc_string () const { return m_doc_string; }
-
-  bool have_doc_string () const { return ! m_doc_string.empty (); }
-
   void accept (tree_walker& tw)
   {
     tw.visit_classdef_body (*this);
@@ -662,17 +664,15 @@
 
 private:
 
-  std::string get_doc_string (comment_list *comment) const;
-
-  std::list<tree_classdef_properties_block *> m_properties_lst;
+  std::list<tree_classdef_properties_block *> m_property_lst;
 
-  std::list<tree_classdef_methods_block *> m_methods_lst;
+  std::list<tree_classdef_methods_block *> m_method_lst;
 
-  std::list<tree_classdef_events_block *> m_events_lst;
+  std::list<tree_classdef_events_block *> m_event_lst;
 
   std::list<tree_classdef_enum_block *> m_enum_lst;
 
-  std::string m_doc_string;
+  std::list<tree_base_classdef_block *> m_all_elements;
 };
 
 // Classdef definition.
@@ -681,17 +681,11 @@
 {
 public:
 
-  tree_classdef (const symbol_scope& scope, const std::string& help_text,
-                 tree_classdef_attribute_list *a, tree_identifier *i,
-                 tree_classdef_superclass_list *sc,
-                 tree_classdef_body *b, comment_list *lc,
-                 comment_list *tc, const std::string& pn = "",
-                 const std::string& fn = "", int l = -1, int c = -1)
-    : tree_command (l, c), m_scope (scope), m_help_text (help_text),
-      m_attr_list (a), m_id (i),
-      m_supclass_list (sc), m_element_list (b), m_lead_comm (lc),
-      m_trail_comm (tc), m_pack_name (pn), m_file_name (fn)
-  { }
+  tree_classdef (const symbol_scope& scope, const token& cdef_tok, tree_classdef_attribute_list *a, tree_identifier *i, tree_classdef_superclass_list *sc, tree_classdef_body *b, const token& end_tok, const std::string& pn = "", const std::string& fn = "", int l = -1, int c = -1)
+    : tree_command (l, c), m_scope (scope), m_cdef_tok (cdef_tok), m_attr_list (a), m_id (i), m_supclass_list (sc), m_body (b), m_end_tok (end_tok), m_pack_name (pn), m_file_name (fn)
+  {
+    cache_doc_string ();
+  }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_classdef)
 
@@ -700,9 +694,7 @@
     delete m_attr_list;
     delete m_id;
     delete m_supclass_list;
-    delete m_element_list;
-    delete m_lead_comm;
-    delete m_trail_comm;
+    delete m_body;
   }
 
   symbol_scope scope () { return m_scope; }
@@ -715,10 +707,9 @@
   tree_classdef_superclass_list *
   superclass_list () { return m_supclass_list; }
 
-  tree_classdef_body * body () { return m_element_list; }
+  tree_classdef_body * body () { return m_body; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-  comment_list * trailing_comment () { return m_trail_comm; }
+  comment_list leading_comments () const { return m_cdef_tok.leading_comments (); }
 
   std::string package_name () const { return m_pack_name; }
 
@@ -727,10 +718,7 @@
   octave_value make_meta_class (interpreter& interp,
                                 bool is_at_folder = false);
 
-  std::string doc_string () const
-  {
-    return m_help_text;
-  }
+  std::string doc_string () const { return m_doc_string; }
 
   void accept (tree_walker& tw)
   {
@@ -739,13 +727,31 @@
 
 private:
 
+  void cache_doc_string ()
+  {
+    // First non-copyright comments found above and below classdef
+    // keyword are candidates for the documentation string.  Use the
+    // first one that is not empty.
+
+    comment_list comments = m_cdef_tok.leading_comments ();
+
+    m_doc_string = comments.find_doc_string ();
+
+    if (m_doc_string.empty ())
+      {
+        comments = m_body->leading_comments ();
+
+        m_doc_string = comments.find_doc_string ();
+      }
+  }
+
   // The scope that was used when parsing the classdef object and that
   // corresponds to any identifiers that were found in attribute lists
   // (for example).  Used again when computing the meta class object.
 
   symbol_scope m_scope;
 
-  std::string m_help_text;
+  token m_cdef_tok;
 
   tree_classdef_attribute_list *m_attr_list;
 
@@ -753,10 +759,11 @@
 
   tree_classdef_superclass_list *m_supclass_list;
 
-  tree_classdef_body *m_element_list;
+  tree_classdef_body *m_body;
 
-  comment_list *m_lead_comm;
-  comment_list *m_trail_comm;
+  token m_end_tok;
+
+  std::string m_doc_string;
 
   std::string m_pack_name;
   std::string m_file_name;
--- a/libinterp/parse-tree/pt-cmd.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-cmd.h	Tue Apr 02 16:11:12 2024 -0400
@@ -30,10 +30,12 @@
 
 #include <string>
 
+#include "comment-list.h"
 #include "ov-fcn.h"
 #include "pt.h"
 #include "pt-bp.h"
 #include "pt-walk.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -57,14 +59,25 @@
 {
 public:
 
-  tree_no_op_command (const std::string& cmd = "no_op", bool e = false,
-                      int l = -1, int c = -1)
-    : tree_command (l, c), m_eof (e), m_orig_cmd (cmd) { }
+  tree_no_op_command (const std::string& cmd, bool eof, const token& tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_eof (eof), m_tok (tok), m_orig_cmd (cmd) { }
 
-  OCTAVE_DISABLE_COPY_MOVE (tree_no_op_command)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_no_op_command)
 
   ~tree_no_op_command () = default;
 
+  comment_list leading_comments () const { return m_tok.leading_comments (); }
+
+  void attach_trailing_comments (const comment_list& lst)
+  {
+    m_tok.trailing_comments (lst);
+  }
+
+  comment_list trailing_comments () const
+  {
+    return m_tok.trailing_comments ();
+  }
+
   void accept (tree_walker& tw)
   {
     tw.visit_no_op_command (*this);
@@ -83,6 +96,9 @@
 
   bool m_eof;
 
+  // If defined, may be END token or EOF.
+  token m_tok;
+
   std::string m_orig_cmd;
 };
 
--- a/libinterp/parse-tree/pt-colon.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-colon.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -41,9 +41,10 @@
 {
   tree_colon_expression *new_ce
     = new tree_colon_expression (m_base ? m_base->dup (scope) : nullptr,
+                                 m_colon_1_tok,
+                                 m_increment ? m_increment->dup (scope) : nullptr,
+                                 m_colon_2_tok,
                                  m_limit ? m_limit->dup (scope) : nullptr,
-                                 m_increment ? m_increment->dup (scope)
-                                 : nullptr,
                                  line (), column ());
 
   new_ce->copy_base (*this);
--- a/libinterp/parse-tree/pt-colon.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-colon.h	Tue Apr 02 16:11:12 2024 -0400
@@ -46,19 +46,13 @@
 {
 public:
 
-  tree_colon_expression (int l = -1, int c = -1)
-    : tree_expression (l, c), m_base (nullptr), m_limit (nullptr),
-      m_increment (nullptr), m_save_base (false) { }
+  tree_colon_expression (tree_expression *base, const token& colon_1_tok, tree_expression *limit, int l = -1, int c = -1)
+    : tree_expression (l, c), m_base (base), m_colon_1_tok (colon_1_tok), m_limit (limit)
+  { }
 
-  tree_colon_expression (tree_expression *bas, tree_expression *lim,
-                         int l = -1, int c = -1)
-    : tree_expression (l, c), m_base (bas), m_limit (lim),
-      m_increment (nullptr), m_save_base (false) { }
-
-  tree_colon_expression (tree_expression *bas, tree_expression *lim,
-                         tree_expression *inc, int l = -1, int c = -1)
-    : tree_expression (l, c), m_base (bas), m_limit (lim),
-      m_increment (inc), m_save_base (false) { }
+  tree_colon_expression (tree_expression *base, const token& colon_1_tok, tree_expression *increment, const token& colon_2_tok, tree_expression *limit, int l = -1, int c = -1)
+    : tree_expression (l, c), m_base (base), m_colon_1_tok (colon_1_tok), m_increment (increment), m_colon_2_tok (colon_2_tok), m_limit (limit)
+  { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_colon_expression)
 
@@ -103,10 +97,12 @@
 
   // The components of the expression.
   tree_expression *m_base;
+  token m_colon_1_tok;
+  tree_expression *m_increment {nullptr};
+  token m_colon_2_tok;
   tree_expression *m_limit;
-  tree_expression *m_increment;
 
-  bool m_save_base;
+  bool m_save_base {false};
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-delimiter-list.h	Tue Apr 02 16:11:12 2024 -0400
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2024 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_tree_delimiter_list_h)
+#define octave_tree_delimiter_list_h 1
+
+#include "octave-config.h"
+
+#include <stack>
+
+#include "token.h"
+
+OCTAVE_BEGIN_NAMESPACE(octave)
+
+class tree_delimiter_list
+{
+public:
+
+  typedef std::pair<token, token> element_type;
+
+  OCTAVE_DEFAULT_CONSTRUCT_COPY_MOVE_DELETE (tree_delimiter_list)
+
+    size_t count () const { return m_delimiters.size (); }
+
+  void push (const token& open_delim, const token& close_delim)
+  {
+    m_delimiters.push (element_type (open_delim, close_delim));
+  }
+
+private:
+
+  std::stack<element_type> m_delimiters;
+};
+
+OCTAVE_END_NAMESPACE(octave)
+
+#endif
--- a/libinterp/parse-tree/pt-eval.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-eval.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -3441,7 +3441,7 @@
   if (expr)
     {
       tree_expression *expr_dup = expr->dup (new_scope);
-      tree_statement *stmt = new tree_statement (expr_dup, nullptr);
+      tree_statement *stmt = new tree_statement (expr_dup);
       stmt_list = new tree_statement_list (stmt);
     }
 
--- a/libinterp/parse-tree/pt-except.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-except.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -52,9 +52,6 @@
   delete m_expr_id;
   delete m_try_code;
   delete m_catch_code;
-  delete m_lead_comm;
-  delete m_mid_comm;
-  delete m_trail_comm;
 }
 
 // Simple exception handling.
@@ -63,9 +60,6 @@
 {
   delete m_unwind_protect_code;
   delete m_cleanup_code;
-  delete m_lead_comm;
-  delete m_mid_comm;
-  delete m_trail_comm;
 }
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-except.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-except.h	Tue Apr 02 16:11:12 2024 -0400
@@ -43,20 +43,8 @@
 {
 public:
 
-  tree_try_catch_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_try_code (nullptr), m_catch_code (nullptr),
-      m_expr_id (nullptr), m_lead_comm (nullptr), m_mid_comm (nullptr),
-      m_trail_comm (nullptr)
-  { }
-
-  tree_try_catch_command (tree_statement_list *tc, tree_statement_list *cc,
-                          tree_identifier *id,
-                          comment_list *cl = nullptr,
-                          comment_list *cm = nullptr,
-                          comment_list *ct = nullptr,
-                          int l = -1, int c = -1)
-    : tree_command (l, c), m_try_code (tc), m_catch_code (cc),
-      m_expr_id (id), m_lead_comm (cl), m_mid_comm (cm), m_trail_comm (ct)
+  tree_try_catch_command (const token try_tok, tree_statement_list *tc, const token catch_tok, tree_identifier *id, tree_statement_list *cc, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_try_tok (try_tok), m_try_code (tc), m_catch_tok (catch_tok), m_expr_id (id), m_catch_code (cc), m_end_tok (end_tok)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_try_catch_command)
@@ -69,12 +57,6 @@
 
   tree_statement_list * cleanup () { return m_catch_code; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * middle_comment () { return m_mid_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
-
   void accept (tree_walker& tw)
   {
     tw.visit_try_catch_command (*this);
@@ -82,23 +64,20 @@
 
 private:
 
+  token m_try_tok;
+
   // The first block of code to attempt to execute.
   tree_statement_list *m_try_code;
 
-  // The code to execute if an error occurs in the first block.
-  tree_statement_list *m_catch_code;
+  token m_catch_tok;
 
   // Identifier to modify.
   tree_identifier *m_expr_id;
 
-  // Comment preceding TRY token.
-  comment_list *m_lead_comm;
+  // The code to execute if an error occurs in the first block.
+  tree_statement_list *m_catch_code;
 
-  // Comment preceding CATCH token.
-  comment_list *m_mid_comm;
-
-  // Comment preceding END_TRY_CATCH token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 // Simple exception handling.
@@ -107,20 +86,8 @@
 {
 public:
 
-  tree_unwind_protect_command (int l = -1, int c = -1)
-    : tree_command (l, c),
-      m_unwind_protect_code (nullptr), m_cleanup_code (nullptr),
-      m_lead_comm (nullptr), m_mid_comm (nullptr), m_trail_comm (nullptr)
-  { }
-
-  tree_unwind_protect_command (tree_statement_list *tc,
-                               tree_statement_list *cc,
-                               comment_list *cl = nullptr,
-                               comment_list *cm = nullptr,
-                               comment_list *ct = nullptr,
-                               int l = -1, int c = -1)
-    : tree_command (l, c), m_unwind_protect_code (tc), m_cleanup_code (cc),
-      m_lead_comm (cl), m_mid_comm (cm), m_trail_comm (ct)
+  tree_unwind_protect_command (const token& unwind_tok, tree_statement_list *tc, const token& cleanup_tok, tree_statement_list *cc, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_unwind_tok (unwind_tok), m_unwind_protect_code (tc), m_cleanup_tok (cleanup_tok), m_cleanup_code (cc), m_end_tok (end_tok)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_unwind_protect_command)
@@ -131,12 +98,6 @@
 
   tree_statement_list * cleanup () { return m_cleanup_code; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * middle_comment () { return m_mid_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
-
   void accept (tree_walker& tw)
   {
     tw.visit_unwind_protect_command (*this);
@@ -144,21 +105,18 @@
 
 private:
 
+  token m_unwind_tok;
+
   // The first body of code to attempt to execute.
   tree_statement_list *m_unwind_protect_code;
 
+  token m_cleanup_tok;
+
   // The body of code to execute no matter what happens in the first
   // body of code.
   tree_statement_list *m_cleanup_code;
 
-  // Comment preceding UNWIND_PROTECT token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding UNWIND_PROTECT_CLEANUP token.
-  comment_list *m_mid_comm;
-
-  // Comment preceding END_UNWIND_PROTECT token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-exp.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-exp.h	Tue Apr 02 16:11:12 2024 -0400
@@ -34,7 +34,9 @@
 class octave_value;
 
 #include "pt.h"
+#include "pt-delimiter-list.h"
 #include "pt-eval.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -48,8 +50,7 @@
 public:
 
   tree_expression (int l = -1, int c = -1)
-    : tree (l, c), m_num_parens (0), m_postfix_index_type ('\0'),
-      m_for_cmd_expr (false), m_print_flag (false) { }
+    : tree (l, c), m_postfix_index_type ('\0'), m_for_cmd_expr (false), m_print_flag (false) { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_expression)
 
@@ -85,7 +86,14 @@
 
   virtual octave_lvalue lvalue (tree_evaluator&);
 
-  int paren_count () const { return m_num_parens; }
+  // The number of times this expression appears directly inside a set
+  // of delimiters.
+  //
+  //   (([e1]) + e2)  ==> 2 for expression e1
+  //                  ==> 1 for expression ([e1]) + e2
+  //                  ==> 0 for expression e2
+
+  size_t delim_count () const { return m_delims.count (); }
 
   bool is_postfix_indexed () const
   { return (m_postfix_index_type != '\0'); }
@@ -107,9 +115,9 @@
 
   bool is_for_cmd_expr () const { return m_for_cmd_expr; }
 
-  tree_expression * mark_in_parens ()
+  tree_expression * mark_in_delims (const token& open_delim, const token& close_delim)
   {
-    m_num_parens++;
+    m_delims.push (open_delim, close_delim);
     return this;
   }
 
@@ -127,9 +135,9 @@
 
   virtual void copy_base (const tree_expression& e)
   {
-    m_num_parens = e.m_num_parens;
     m_postfix_index_type = e.m_postfix_index_type;
     m_print_flag = e.m_print_flag;
+    m_delims = e.m_delims;
   }
 
   virtual octave_value evaluate (tree_evaluator& tw, int nargout = 1) = 0;
@@ -139,14 +147,6 @@
 
 protected:
 
-  // A count of the number of times this expression appears directly
-  // inside a set of parentheses.
-  //
-  //   (((e1)) + e2)  ==> 2 for expression e1
-  //                  ==> 1 for expression ((e1)) + e2
-  //                  ==> 0 for expression e2
-  int m_num_parens;
-
   // The first index type associated with this expression.  This field
   // is 0 (character '\0') if the expression has no associated index.
   // See the code in tree_identifier::rvalue for the rationale.
@@ -158,6 +158,9 @@
 
   // Print result of rvalue for this expression?
   bool m_print_flag;
+
+  // Tokens for any delimiters surrounding this expression.
+  tree_delimiter_list m_delims;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-id.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-id.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -81,8 +81,7 @@
 
   symbol_record new_sym = scope.find_symbol (name ());
 
-  tree_identifier *new_id
-    = new tree_identifier (new_sym, line (), column ());
+  tree_identifier *new_id = new tree_identifier (new_sym, m_token);
 
   new_id->copy_base (*this);
 
--- a/libinterp/parse-tree/pt-id.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-id.h	Tue Apr 02 16:11:12 2024 -0400
@@ -35,11 +35,13 @@
 class octave_value_list;
 class octave_function;
 
+#include "comment-list.h"
 #include "oct-lvalue.h"
 #include "pt-bp.h"
 #include "pt-exp.h"
 #include "pt-walk.h"
 #include "symscope.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -53,12 +55,15 @@
 
 public:
 
-  tree_identifier (int l = -1, int c = -1)
-    : tree_expression (l, c), m_sym () { }
+  tree_identifier (const token& tok)
+    : tree_expression (tok.line (), tok.column ()), m_sym (), m_token (tok)
+  { }
 
-  tree_identifier (const symbol_record& s,
-                   int l = -1, int c = -1)
-    : tree_expression (l, c), m_sym (s) { }
+  tree_identifier (symbol_scope& scope, const token& tok)
+    : tree_expression (tok.line (), tok.column ()),
+      m_sym (scope ? scope.insert (tok.text ()) : symbol_record (tok.text ())),
+      m_token (tok)
+  { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_identifier)
 
@@ -68,6 +73,8 @@
 
   std::string name () const { return m_sym.name (); }
 
+  comment_list leading_comments () const { return m_token.leading_comments (); }
+
   virtual bool is_black_hole () const { return false; }
 
   void mark_as_formal_parameter () { m_sym.mark_formal (); }
@@ -105,18 +112,38 @@
 
   symbol_record symbol () const { return m_sym; }
 
+  tree_identifier * mark_get_set (const token& get_set_tok, const token& dot_tok)
+  {
+    m_get_set_tok = get_set_tok;
+    m_dot_tok = dot_tok;
+
+    return this;
+  }
+
 protected:
 
+  tree_identifier (symbol_record& sym, const token& tok)
+    : tree_expression (tok.line (), tok.column ()), m_sym (sym), m_token (tok)
+  { }
+
   // The symbol record that this identifier references.
   symbol_record m_sym;
+
+  // These will be defined for get.ID or set.ID function names.
+  token m_get_set_tok;
+  token m_dot_tok;
+
+  // The IDENT token from the lexer.
+  token m_token;
 };
 
 class tree_black_hole : public tree_identifier
 {
 public:
 
-  tree_black_hole (int l = -1, int c = -1)
-    : tree_identifier (l, c) { }
+  tree_black_hole (const token& token)
+    : tree_identifier (token)
+  { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_black_hole)
 
@@ -128,7 +155,7 @@
 
   tree_black_hole * dup (symbol_scope&) const
   {
-    return new tree_black_hole;
+    return new tree_black_hole (m_token);
   }
 
   octave_lvalue lvalue (tree_evaluator& tw);
--- a/libinterp/parse-tree/pt-idx.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-idx.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -47,38 +47,31 @@
 // Index expressions.
 
 tree_index_expression::tree_index_expression (int l, int c)
-  : tree_expression (l, c), m_expr (nullptr), m_args (0), m_type (),
-    m_arg_nm (), m_dyn_field (), m_word_list_cmd (false) { }
+  : tree_expression (l, c)
+{ }
 
-tree_index_expression::tree_index_expression (tree_expression *e,
-    tree_argument_list *lst,
-    int l, int c, char t)
-  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
-    m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
+tree_index_expression::tree_index_expression (tree_expression *e, const token& open_delim, tree_argument_list *lst, const token& close_delim, int l, int c, char t)
+  : tree_expression (l, c), m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
 {
-  append (lst, t);
+  append (open_delim, lst, close_delim, t);
 }
 
-tree_index_expression::tree_index_expression (tree_expression *e,
-    const std::string& n,
-    int l, int c)
-  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
-    m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
+tree_index_expression::tree_index_expression (tree_expression *e, const token& dot_tok, const token& struct_elt_tok, int l, int c)
+  : tree_expression (l, c), m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
 {
-  append (n);
+  append (dot_tok, struct_elt_tok);
 }
 
-tree_index_expression::tree_index_expression (tree_expression *e,
-    tree_expression *df,
-    int l, int c)
-  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
-    m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
+tree_index_expression::tree_index_expression (tree_expression *e, const token& dot_tok, const token& open_paren, tree_expression *df, const token& close_paren, int l, int c)
+  : tree_expression (l, c), m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
 {
-  append (df);
+  append (dot_tok, open_paren, df, close_paren);
 }
 
+// FIXME: Need to handle open_delim and close_delim.
+
 tree_index_expression *
-tree_index_expression::append (tree_argument_list *lst, char t)
+tree_index_expression::append (const token& /*open_delim*/, tree_argument_list *lst, const token& /*close_delim*/, char t)
 {
   m_args.push_back (lst);
   m_type.append (1, t);
@@ -91,19 +84,23 @@
   return this;
 }
 
+// FIXME: Need to handle dot_tok.
+
 tree_index_expression *
-tree_index_expression::append (const std::string& n)
+tree_index_expression::append (const token& /*dot_tok*/, const token& struct_elt_tok)
 {
   m_args.push_back (static_cast<tree_argument_list *> (nullptr));
   m_type += '.';
-  m_arg_nm.push_back (n);
+  m_arg_nm.push_back (struct_elt_tok.text ());
   m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
 
   return this;
 }
 
+// FIXME: Need to handle dot_tok, open_paren, and close_paren.
+
 tree_index_expression *
-tree_index_expression::append (tree_expression *df)
+tree_index_expression::append (const token& /*dot_tok*/, const token& /*open_paren*/, tree_expression *df, const token& /*close_paren*/)
 {
   m_args.push_back (static_cast<tree_argument_list *> (nullptr));
   m_type += '.';
--- a/libinterp/parse-tree/pt-idx.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-idx.h	Tue Apr 02 16:11:12 2024 -0400
@@ -52,26 +52,22 @@
 {
 public:
 
-  tree_index_expression (tree_expression *e = nullptr,
-                         tree_argument_list *lst = nullptr,
-                         int l = -1, int c = -1, char t = '(');
+  tree_index_expression (tree_expression *e, const token& open_delim, tree_argument_list *lst, const token& close_delim, int l, int c, char t);
 
-  tree_index_expression (tree_expression *e, const std::string& n,
-                         int l = -1, int c = -1);
+  tree_index_expression (tree_expression *e, const token& dot_tok, const token& struct_elt_tok, int l = -1, int c = -1);
 
-  tree_index_expression (tree_expression *e, tree_expression *df,
-                         int l = -1, int c = -1);
+  tree_index_expression (tree_expression *e, const token& dot_tok, const token& open_paren, tree_expression *df, const token& close_paren, int l = -1, int c = -1);
 
   OCTAVE_DISABLE_COPY_MOVE (tree_index_expression)
 
   ~tree_index_expression ();
 
   tree_index_expression *
-  append (tree_argument_list *lst = nullptr, char t = '(');
+  append (const token& open_delim, tree_argument_list *lst, const token& close_delim, char t = '(');
 
-  tree_index_expression * append (const std::string& n);
+  tree_index_expression * append (const token& dot_tok, const token& struct_elt_tok);
 
-  tree_index_expression * append (tree_expression *df);
+  tree_index_expression * append (const token& dot_tok, const token& open_paren, tree_expression *df, const token& close_paren);
 
   bool is_index_expression () const { return true; }
 
@@ -121,7 +117,7 @@
 private:
 
   // The LHS of this index expression.
-  tree_expression *m_expr;
+  tree_expression *m_expr {nullptr};
 
   // The indices (only valid if type == paren || type == brace).
   std::list<tree_argument_list *> m_args;
@@ -137,7 +133,7 @@
   std::list<tree_expression *> m_dyn_field;
 
   // TRUE if this expression was parsed as a word list command.
-  bool m_word_list_cmd;
+  bool m_word_list_cmd {false};
 
   tree_index_expression (int l, int c);
 
--- a/libinterp/parse-tree/pt-loop.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-loop.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -39,9 +39,15 @@
 tree_while_command::~tree_while_command ()
 {
   delete m_expr;
-  delete m_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
+  delete m_body;
+}
+
+// Do-until.
+
+tree_do_until_command::~tree_do_until_command ()
+{
+  delete m_body;
+  delete m_expr;
 }
 
 // For.
@@ -51,18 +57,14 @@
   delete m_lhs;
   delete m_expr;
   delete m_maxproc;
-  delete m_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
+  delete m_body;
 }
 
 tree_complex_for_command::~tree_complex_for_command ()
 {
   delete m_lhs;
   delete m_expr;
-  delete m_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
+  delete m_body;
 }
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-loop.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-loop.h	Tue Apr 02 16:11:12 2024 -0400
@@ -35,6 +35,7 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+class comment_list;
 class tree_argument_list;
 class tree_expression;
 class tree_statement_list;
@@ -45,25 +46,8 @@
 {
 public:
 
-  tree_while_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_expr (nullptr), m_list (nullptr),
-      m_lead_comm (nullptr), m_trail_comm (nullptr)
-  { }
-
-  tree_while_command (tree_expression *e,
-                      comment_list *lc = nullptr,
-                      comment_list *tc = nullptr,
-                      int l = -1, int c = -1)
-    : tree_command (l, c), m_expr (e), m_list (nullptr),
-      m_lead_comm (lc), m_trail_comm (tc)
-  { }
-
-  tree_while_command (tree_expression *e, tree_statement_list *lst,
-                      comment_list *lc = nullptr,
-                      comment_list *tc = nullptr,
-                      int l = -1, int c = -1)
-    : tree_command (l, c), m_expr (e), m_list (lst), m_lead_comm (lc),
-      m_trail_comm (tc)
+  tree_while_command (const token& while_tok, tree_expression *expr, tree_statement_list *body, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_while_tok (while_tok), m_expr (expr), m_body (body), m_end_tok (end_tok)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_while_command)
@@ -72,64 +56,60 @@
 
   tree_expression * condition () { return m_expr; }
 
-  tree_statement_list * body () { return m_list; }
-
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
+  tree_statement_list * body () { return m_body; }
 
   void accept (tree_walker& tw)
   {
     tw.visit_while_command (*this);
   }
 
-protected:
+private:
+
+  token m_while_tok;
 
   // Expression to test.
   tree_expression *m_expr;
 
   // List of commands to execute.
-  tree_statement_list *m_list;
+  tree_statement_list *m_body {nullptr};
 
-  // Comment preceding WHILE token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDWHILE token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 // Do-Until.
 
-class tree_do_until_command : public tree_while_command
+class tree_do_until_command : public tree_command
 {
 public:
 
-  tree_do_until_command (int l = -1, int c = -1)
-    : tree_while_command (l, c)
-  { }
-
-  tree_do_until_command (tree_expression *e,
-                         comment_list *lc = nullptr,
-                         comment_list *tc = nullptr,
-                         int l = -1, int c = -1)
-    : tree_while_command (e, lc, tc, l, c)
-  { }
-
-  tree_do_until_command (tree_expression *e, tree_statement_list *lst,
-                         comment_list *lc = nullptr,
-                         comment_list *tc = nullptr,
-                         int l = -1, int c = -1)
-    : tree_while_command (e, lst, lc, tc, l, c)
+  tree_do_until_command (const token& do_tok, tree_statement_list *body, const token& until_tok, tree_expression *expr, int l = -1, int c = -1)
+    : tree_command (l, c), m_do_tok (do_tok), m_body (body), m_until_tok (until_tok), m_expr (expr)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_do_until_command)
 
-  ~tree_do_until_command () = default;
+  ~tree_do_until_command ();
+
+  tree_statement_list * body () { return m_body; }
+
+  tree_expression * condition () { return m_expr; }
 
   void accept (tree_walker& tw)
   {
     tw.visit_do_until_command (*this);
   }
+
+private:
+
+  token m_do_tok;
+
+  // List of commands to execute.
+  tree_statement_list *m_body {nullptr};
+
+  token m_until_tok;
+
+  // Expression to test.
+  tree_expression *m_expr;
 };
 
 // For.
@@ -138,29 +118,19 @@
 {
 public:
 
-  tree_simple_for_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_parallel (false), m_lhs (nullptr),
-      m_expr (nullptr), m_maxproc (nullptr), m_list (nullptr),
-      m_lead_comm (nullptr), m_trail_comm (nullptr)
-  { }
-
-  tree_simple_for_command (bool parallel_arg, tree_expression *le,
-                           tree_expression *re,
-                           tree_expression *maxproc_arg,
-                           tree_statement_list *lst,
-                           comment_list *lc = nullptr,
-                           comment_list *tc = nullptr,
-                           int l = -1, int c = -1)
-    : tree_command (l, c), m_parallel (parallel_arg), m_lhs (le),
-      m_expr (re), m_maxproc (maxproc_arg), m_list (lst),
-      m_lead_comm (lc), m_trail_comm (tc)
+  tree_simple_for_command (bool parfor, const token& for_tok, const token& open_paren, tree_expression *le, const token& eq_tok,
+                           tree_expression *re, const token& sep_tok, tree_expression *maxproc_arg, const token& close_paren,
+                           tree_statement_list *body, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_parfor (parfor), m_for_tok (for_tok), m_open_paren (open_paren), m_lhs (le), m_eq_tok (eq_tok),
+      m_expr (re), m_sep_tok (sep_tok), m_maxproc (maxproc_arg), m_close_paren (close_paren),
+      m_body (body), m_end_tok (end_tok)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_simple_for_command)
 
   ~tree_simple_for_command ();
 
-  bool in_parallel () { return m_parallel; }
+  bool in_parallel () { return m_parfor; }
 
   tree_expression * left_hand_side () { return m_lhs; }
 
@@ -168,11 +138,7 @@
 
   tree_expression * maxproc_expr () { return m_maxproc; }
 
-  tree_statement_list * body () { return m_list; }
-
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
+  tree_statement_list * body () { return m_body; }
 
   void accept (tree_walker& tw)
   {
@@ -180,46 +146,44 @@
   }
 
 private:
-  // TRUE means operate in parallel (subject to the value of the
-  // maxproc expression).
-  bool m_parallel;
+
+  // FIXME: it would be better to get this info from FOR_TOK.
+  bool m_parfor {false};
+
+  token m_for_tok;
+
+  token m_open_paren;
 
   // Expression to modify.
   tree_expression *m_lhs;
 
+  token m_eq_tok;
+
   // Expression to evaluate.
   tree_expression *m_expr;
 
+  token m_sep_tok;
+
   // Expression to tell how many processors should be used (only valid
   // if parallel is TRUE).
-  tree_expression *m_maxproc;
+  tree_expression *m_maxproc {nullptr};
+
+  token m_close_paren;
 
   // List of commands to execute.
-  tree_statement_list *m_list;
+  tree_statement_list *m_body;
 
-  // Comment preceding FOR token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDFOR token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 class tree_complex_for_command : public tree_command
 {
 public:
 
-  tree_complex_for_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_lhs (nullptr), m_expr (nullptr),
-      m_list (nullptr), m_lead_comm (nullptr), m_trail_comm (nullptr)
-  { }
-
-  tree_complex_for_command (tree_argument_list *le, tree_expression *re,
-                            tree_statement_list *lst,
-                            comment_list *lc = nullptr,
-                            comment_list *tc = nullptr,
-                            int l = -1, int c = -1)
-    : tree_command (l, c), m_lhs (le), m_expr (re), m_list (lst),
-      m_lead_comm (lc), m_trail_comm (tc)
+  tree_complex_for_command (const token& for_tok, tree_argument_list *le, const token& eq_tok, tree_expression *re,
+                            tree_statement_list *body, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_for_tok (for_tok), m_lhs (le), m_eq_tok (eq_tok), m_expr (re),
+      m_body (body), m_end_tok (end_tok)
   { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_complex_for_command)
@@ -230,11 +194,7 @@
 
   tree_expression * control_expr () { return m_expr; }
 
-  tree_statement_list * body () { return m_list; }
-
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
+  tree_statement_list * body () { return m_body; }
 
   void accept (tree_walker& tw)
   {
@@ -243,20 +203,20 @@
 
 private:
 
+  token m_for_tok;
+
   // Expression to modify.
   tree_argument_list *m_lhs;
 
+  token m_eq_tok;
+
   // Expression to evaluate.
   tree_expression *m_expr;
 
   // List of commands to execute.
-  tree_statement_list *m_list;
+  tree_statement_list *m_body;
 
-  // Comment preceding FOR token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDFOR token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-misc.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-misc.h	Tue Apr 02 16:11:12 2024 -0400
@@ -73,6 +73,14 @@
 
   ~tree_parameter_list ();
 
+  tree_parameter_list * mark_in_delims (const token& open_delim, const token& close_delim)
+  {
+    m_open_delim = open_delim;
+    m_close_delim = close_delim;
+
+    return this;
+  }
+
   void mark_as_formal_parameters ();
 
   void mark_varargs () { m_marked_for_varargs = 1; }
@@ -109,6 +117,9 @@
   // -1: takes varargs only
   // 0: does not take varargs.
   int m_marked_for_varargs;
+
+  token m_open_delim;
+  token m_close_delim;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-pr-code.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-pr-code.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -238,7 +238,7 @@
 void
 tree_print_code::visit_simple_for_command (tree_simple_for_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -281,8 +281,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << (cmd.in_parallel () ? "endparfor" : "endfor");
@@ -291,7 +289,7 @@
 void
 tree_print_code::visit_complex_for_command (tree_complex_for_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -324,8 +322,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "endfor";
@@ -334,7 +330,7 @@
 void
 tree_print_code::visit_spmd_command (tree_spmd_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -353,8 +349,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "endspmd";
@@ -395,11 +389,11 @@
 void
 tree_print_code::visit_octave_user_function_header (octave_user_function& fcn)
 {
-  comment_list *leading_comment = fcn.leading_comment ();
+  comment_list leading_comments = fcn.leading_comments ();
 
-  if (leading_comment)
+  if (! leading_comments.empty ())
     {
-      print_comment_list (leading_comment);
+      print_comment_list (leading_comments);
       newline ();
     }
 
@@ -430,7 +424,7 @@
 void
 tree_print_code::visit_octave_user_function_trailer (octave_user_function& fcn)
 {
-  print_indented_comment (fcn.trailing_comment ());
+  print_indented_comment (fcn.trailing_comments ());
 
   newline ();
 }
@@ -486,7 +480,7 @@
 void
 tree_print_code::visit_if_command (tree_if_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -497,8 +491,6 @@
   if (list)
     list->accept (*this);
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "endif";
@@ -519,7 +511,7 @@
         {
           if (! first_elt)
             {
-              print_indented_comment (elt->leading_comment ());
+              print_indented_comment (elt->leading_comments ());
 
               indent ();
 
@@ -566,7 +558,7 @@
         case '(':
           {
             char nc = m_nesting.top ();
-            if ((nc == '[' || nc == '{') && expr.paren_count () == 0)
+            if ((nc == '[' || nc == '{') && expr.delim_count () == 0)
               m_os << '(';
             else
               m_os << " (";
@@ -584,7 +576,7 @@
         case '{':
           {
             char nc = m_nesting.top ();
-            if ((nc == '[' || nc == '{') && expr.paren_count () == 0)
+            if ((nc == '[' || nc == '{') && expr.delim_count () == 0)
               m_os << '{';
             else
               m_os << " {";
@@ -896,7 +888,7 @@
 void
 tree_print_code::visit_statement (tree_statement& stmt)
 {
-  print_comment_list (stmt.comment_text ());
+  print_comment_list (stmt.leading_comments ());
 
   tree_command *cmd = stmt.command ();
 
@@ -938,7 +930,7 @@
 void
 tree_print_code::visit_switch_case (tree_switch_case& cs)
 {
-  print_comment_list (cs.leading_comment ());
+  print_comment_list (cs.leading_comments ());
 
   indent ();
 
@@ -971,7 +963,7 @@
 void
 tree_print_code::visit_switch_command (tree_switch_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -995,7 +987,7 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.leading_comment ());
+  print_indented_comment (cmd.leading_comments ());
 
   indent ();
 
@@ -1005,7 +997,7 @@
 void
 tree_print_code::visit_try_catch_command (tree_try_catch_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -1025,8 +1017,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.middle_comment ());
-
   indent ();
 
   m_os << "catch";
@@ -1050,8 +1040,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "end_try_catch";
@@ -1060,7 +1048,7 @@
 void
 tree_print_code::visit_unwind_protect_command (tree_unwind_protect_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -1079,8 +1067,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.middle_comment ());
-
   indent ();
 
   m_os << "unwind_protect_cleanup";
@@ -1098,8 +1084,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "end_unwind_protect";
@@ -1108,7 +1092,7 @@
 void
 tree_print_code::visit_while_command (tree_while_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -1132,8 +1116,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "endwhile";
@@ -1142,7 +1124,7 @@
 void
 tree_print_code::visit_do_until_command (tree_do_until_command& cmd)
 {
-  print_comment_list (cmd.leading_comment ());
+  print_comment_list (cmd.leading_comments ());
 
   indent ();
 
@@ -1161,8 +1143,6 @@
       decrement_indent_level ();
     }
 
-  print_indented_comment (cmd.trailing_comment ());
-
   indent ();
 
   m_os << "until ";
@@ -1247,7 +1227,7 @@
 void
 tree_print_code::print_parens (const tree_expression& expr, const char *txt)
 {
-  int n = expr.paren_count ();
+  int n = expr.delim_count ();
 
   for (int i = 0; i < n; i++)
     m_os << txt;
@@ -1314,26 +1294,23 @@
 }
 
 void
-tree_print_code::print_comment_list (comment_list *comment_list)
+tree_print_code::print_comment_list (const comment_list& comment_list)
 {
-  if (comment_list)
-    {
-      auto p = comment_list->begin ();
+  auto p = comment_list.begin ();
 
-      while (p != comment_list->end ())
-        {
-          comment_elt elt = *p++;
+  while (p != comment_list.end ())
+    {
+      comment_elt elt = *p++;
 
-          print_comment_elt (elt);
+      print_comment_elt (elt);
 
-          if (p != comment_list->end ())
-            newline ();
-        }
+      if (p != comment_list.end ())
+        newline ();
     }
 }
 
 void
-tree_print_code::print_indented_comment (comment_list *comment_list)
+tree_print_code::print_indented_comment (const comment_list& comment_list)
 {
   increment_indent_level ();
 
--- a/libinterp/parse-tree/pt-pr-code.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-pr-code.h	Tue Apr 02 16:11:12 2024 -0400
@@ -195,11 +195,11 @@
 
   void print_parens (const tree_expression& expr, const char *txt);
 
-  void print_comment_list (comment_list *comment_list);
+  void print_comment_list (const comment_list& comment_list);
 
   void print_comment_elt (const comment_elt& comment_elt);
 
-  void print_indented_comment (comment_list *comment_list);
+  void print_indented_comment (const comment_list& comment_list);
 
   // Must create with an output stream!
 
--- a/libinterp/parse-tree/pt-select.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-select.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -39,7 +39,6 @@
 {
   delete m_expr;
   delete m_list;
-  delete m_lead_comm;
 }
 
 // If.
@@ -47,8 +46,6 @@
 tree_if_command::~tree_if_command ()
 {
   delete m_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
 }
 
 // Switch cases.
@@ -57,7 +54,6 @@
 {
   delete m_label;
   delete m_list;
-  delete m_lead_comm;
 }
 
 // Switch.
@@ -66,8 +62,6 @@
 {
   delete m_expr;
   delete m_list;
-  delete m_lead_comm;
-  delete m_trail_comm;
 }
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-select.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-select.h	Tue Apr 02 16:11:12 2024 -0400
@@ -33,9 +33,11 @@
 #include "comment-list.h"
 #include "pt-cmd.h"
 #include "pt-walk.h"
+#include "token.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+class comment_list;
 class tree_expression;
 class tree_statement_list;
 
@@ -45,30 +47,23 @@
 {
 public:
 
-  tree_if_clause (int l = -1, int c = -1)
-    : tree (l, c), m_expr (nullptr), m_list (nullptr), m_lead_comm (nullptr)
+  tree_if_clause (const token& tok, tree_expression *e, tree_statement_list *sl, int l = -1, int c = -1)
+    : tree (l, c), m_tok (tok), m_expr (e), m_list (sl)
   { }
 
-  tree_if_clause (tree_statement_list *sl, comment_list *lc = nullptr,
-                  int l = -1, int c = -1)
-    : tree (l, c), m_expr (nullptr), m_list (sl), m_lead_comm (lc) { }
-
-  tree_if_clause (tree_expression *e, tree_statement_list *sl,
-                  comment_list *lc = nullptr,
-                  int l = -1, int c = -1)
-    : tree (l, c), m_expr (e), m_list (sl), m_lead_comm (lc) { }
-
-  OCTAVE_DISABLE_COPY_MOVE (tree_if_clause)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_if_clause)
 
   ~tree_if_clause ();
 
+  token if_token () const { return m_tok; }
+
   bool is_else_clause () { return ! m_expr; }
 
   tree_expression * condition () { return m_expr; }
 
   tree_statement_list * commands () { return m_list; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
+  comment_list leading_comments () const { return m_tok.leading_comments (); }
 
   void accept (tree_walker& tw)
   {
@@ -77,14 +72,13 @@
 
 private:
 
+  token m_tok;
+
   // The condition to test.
-  tree_expression *m_expr;
+  tree_expression *m_expr = nullptr;
 
   // The list of statements to evaluate if expr is true.
   tree_statement_list *m_list;
-
-  // Comment preceding ELSE or ELSEIF token.
-  comment_list *m_lead_comm;
 };
 
 class tree_if_command_list : public std::list<tree_if_clause *>
@@ -107,6 +101,17 @@
       }
   }
 
+  token if_token () const
+  {
+    if (! empty ())
+      {
+        tree_if_clause *p = front ();
+        return p->if_token ();
+      }
+
+    return token ();
+  }
+
   void accept (tree_walker& tw)
   {
     tw.visit_if_command_list (*this);
@@ -117,25 +122,21 @@
 {
 public:
 
-  tree_if_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_list (nullptr),
-      m_lead_comm (nullptr), m_trail_comm (nullptr)
+  tree_if_command (const token& if_tok, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_if_tok (if_tok), m_end_tok (end_tok)
   { }
 
-  tree_if_command (tree_if_command_list *lst, comment_list *lc,
-                   comment_list *tc, int l = -1, int c = -1)
-    : tree_command (l, c), m_list (lst), m_lead_comm (lc), m_trail_comm (tc)
+  tree_if_command (const token& if_tok, tree_if_command_list *lst, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_if_tok (if_tok), m_list (lst), m_end_tok (end_tok)
   { }
 
-  OCTAVE_DISABLE_COPY_MOVE (tree_if_command)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_if_command)
 
   ~tree_if_command ();
 
   tree_if_command_list * cmd_list () { return m_list; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
+  comment_list leading_comments () const { return m_if_tok.leading_comments (); }
 
   void accept (tree_walker& tw)
   {
@@ -144,14 +145,12 @@
 
 private:
 
-  // List of if commands (if, elseif, elseif, ... else, endif)
-  tree_if_command_list *m_list;
+  token m_if_tok;
 
-  // Comment preceding IF token.
-  comment_list *m_lead_comm;
+  // List of if commands (if, elseif, elseif, ... else, endif)
+  tree_if_command_list *m_list = nullptr;
 
-  // Comment preceding ENDIF token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 // Switch.
@@ -160,20 +159,15 @@
 {
 public:
 
-  tree_switch_case (int l = -1, int c = -1)
-    : tree (l, c), m_label (nullptr), m_list (nullptr), m_lead_comm (nullptr)
+  tree_switch_case (const token& tok, tree_statement_list *sl, int l = -1, int c = -1)
+    : tree (l, c), m_tok (tok), m_list (sl)
   { }
 
-  tree_switch_case (tree_statement_list *sl, comment_list *lc = nullptr,
-                    int l = -1, int c = -1)
-    : tree (l, c), m_label (nullptr), m_list (sl), m_lead_comm (lc) { }
+  tree_switch_case (const token& tok, tree_expression *e, tree_statement_list *sl, int l = -1, int c = -1)
+    : tree (l, c), m_tok (tok), m_label (e), m_list (sl)
+  { }
 
-  tree_switch_case (tree_expression *e, tree_statement_list *sl,
-                    comment_list *lc = nullptr,
-                    int l = -1, int c = -1)
-    : tree (l, c), m_label (e), m_list (sl), m_lead_comm (lc) { }
-
-  OCTAVE_DISABLE_COPY_MOVE (tree_switch_case)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_switch_case)
 
   ~tree_switch_case ();
 
@@ -183,7 +177,7 @@
 
   tree_statement_list * commands () { return m_list; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
+  comment_list leading_comments () const { return m_tok.leading_comments (); }
 
   void accept (tree_walker& tw)
   {
@@ -192,14 +186,13 @@
 
 private:
 
+  token m_tok;
+
   // The case label.
-  tree_expression *m_label;
+  tree_expression *m_label = nullptr;
 
   // The list of statements to evaluate if the label matches.
   tree_statement_list *m_list;
-
-  // Comment preceding CASE or OTHERWISE token.
-  comment_list *m_lead_comm;
 };
 
 class tree_switch_case_list : public std::list<tree_switch_case *>
@@ -232,17 +225,11 @@
 {
 public:
 
-  tree_switch_command (int l = -1, int c = -1)
-    : tree_command (l, c), m_expr (nullptr), m_list (nullptr),
-      m_lead_comm (nullptr), m_trail_comm (nullptr) { }
+  tree_switch_command (const token& switch_tok, tree_expression *e, tree_switch_case_list *lst, const token& end_tok, int l = -1, int c = -1)
+    : tree_command (l, c), m_switch_tok (switch_tok), m_expr (e), m_list (lst), m_end_tok (end_tok)
+  { }
 
-  tree_switch_command (tree_expression *e, tree_switch_case_list *lst,
-                       comment_list *lc, comment_list *tc,
-                       int l = -1, int c = -1)
-    : tree_command (l, c), m_expr (e), m_list (lst), m_lead_comm (lc),
-      m_trail_comm (tc) { }
-
-  OCTAVE_DISABLE_COPY_MOVE (tree_switch_command)
+  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_switch_command)
 
   ~tree_switch_command ();
 
@@ -250,9 +237,7 @@
 
   tree_switch_case_list * case_list () { return m_list; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
+  comment_list leading_comments () const { return m_switch_tok.leading_comments (); }
 
   void accept (tree_walker& tw)
   {
@@ -261,17 +246,15 @@
 
 private:
 
+  token m_switch_tok;
+
   // Value on which to switch.
   tree_expression *m_expr;
 
   // List of cases (case 1, case 2, ..., default)
   tree_switch_case_list *m_list;
 
-  // Comment preceding SWITCH token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDSWITCH token.
-  comment_list *m_trail_comm;
+  token m_end_tok;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-spmd.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-spmd.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -36,8 +36,6 @@
 tree_spmd_command::~tree_spmd_command ()
 {
   delete m_body;
-  delete m_lead_comm;
-  delete m_trail_comm;
 }
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-spmd.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-spmd.h	Tue Apr 02 16:11:12 2024 -0400
@@ -33,7 +33,7 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-class tree_comment_list;
+class comment_list;
 class tree_statement_list;
 
 // Spmd.
@@ -42,9 +42,8 @@
 {
 public:
 
-  tree_spmd_command (tree_statement_list *body, comment_list *lc,
-                     comment_list *tc, int l = -1, int c = -1)
-    : tree_command (l, c), m_body (body), m_lead_comm (lc), m_trail_comm (tc)
+  tree_spmd_command (tree_statement_list *body, int l = -1, int c = -1)
+    : tree_command (l, c), m_body (body)
   { }
 
   OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_spmd_command)
@@ -53,10 +52,6 @@
 
   tree_statement_list * body () { return m_body; }
 
-  comment_list * leading_comment () { return m_lead_comm; }
-
-  comment_list * trailing_comment () { return m_trail_comm; }
-
   void accept (tree_walker& tw)
   {
     tw.visit_spmd_command (*this);
@@ -66,12 +61,6 @@
 
   // List of commands.
   tree_statement_list *m_body;
-
-  // Comment preceding SPMD token.
-  comment_list *m_lead_comm;
-
-  // Comment preceding ENDSPMD token.
-  comment_list *m_trail_comm;
 };
 
 OCTAVE_END_NAMESPACE(octave)
--- a/libinterp/parse-tree/pt-stmt.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-stmt.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -57,7 +57,6 @@
 {
   delete m_command;
   delete m_expression;
-  delete m_comment_list;
 }
 
 void
@@ -107,6 +106,14 @@
             : false);
 }
 
+comment_list
+tree_statement::leading_comments () const
+{
+  return (m_command
+          ? m_command->leading_comments ()
+          : m_expression->leading_comments ());
+}
+
 std::string
 tree_statement::bp_cond () const
 {
@@ -182,6 +189,20 @@
   return retval;
 }
 
+comment_list
+tree_statement_list::leading_comments () const
+{
+  if (! empty ())
+    {
+      tree_statement *elt = front ();
+
+      if (elt)
+        return elt->leading_comments ();
+    }
+
+  return comment_list ();
+}
+
 // Create a "breakpoint" tree-walker, and get it to "walk" this
 // statement list
 // (FIXME: What does that do???)
--- a/libinterp/parse-tree/pt-stmt.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-stmt.h	Tue Apr 02 16:11:12 2024 -0400
@@ -54,14 +54,16 @@
 public:
 
   tree_statement ()
-    : m_command (nullptr), m_expression (nullptr),
-      m_comment_list (nullptr) { }
+    : m_command (nullptr), m_expression (nullptr)
+  { }
 
-  tree_statement (tree_command *c, comment_list *cl)
-    : m_command (c), m_expression (nullptr), m_comment_list (cl) { }
+  tree_statement (tree_command *c)
+    : m_command (c), m_expression (nullptr)
+  { }
 
-  tree_statement (tree_expression *e, comment_list *cl)
-    : m_command (nullptr), m_expression (e), m_comment_list (cl) { }
+  tree_statement (tree_expression *e)
+    : m_command (nullptr), m_expression (e)
+  { }
 
   OCTAVE_DISABLE_COPY_MOVE (tree_statement)
 
@@ -83,6 +85,8 @@
 
   bool is_active_breakpoint (tree_evaluator& tw) const;
 
+  comment_list leading_comments () const;
+
   std::string bp_cond () const;
 
   int line () const;
@@ -96,11 +100,9 @@
 
   tree_expression * expression () { return m_expression; }
 
-  comment_list * comment_text () { return m_comment_list; }
-
   bool is_null_statement () const
   {
-    return ! (m_command || m_expression || m_comment_list);
+    return ! (m_command || m_expression);
   }
 
   bool is_end_of_fcn_or_script () const;
@@ -129,9 +131,6 @@
 
   // Expression to evaluate.
   tree_expression *m_expression;
-
-  // Comment associated with this statement.
-  comment_list *m_comment_list;
 };
 
 // A list of statements to evaluate.
@@ -172,6 +171,8 @@
 
   bool is_script_body () const { return m_script_body; }
 
+  comment_list leading_comments () const;
+
   int set_breakpoint (int line, const std::string& condition);
 
   void delete_breakpoint (int line);
--- a/libinterp/parse-tree/pt-walk.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-walk.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -722,14 +722,14 @@
 void
 tree_walker::visit_classdef_properties_block (tree_classdef_properties_block& blk)
 {
-  tree_classdef_property_list *property_list = blk.element_list ();
+  tree_classdef_property_list *property_list = blk.property_list ();
 
   if (property_list)
     property_list->accept (*this);
 }
 
 void
-tree_walker::visit_classdef_methods_list (tree_classdef_methods_list& lst)
+tree_walker::visit_classdef_method_list (tree_classdef_method_list& lst)
 {
   for (auto ov_meth : lst)
     {
@@ -743,10 +743,10 @@
 void
 tree_walker::visit_classdef_methods_block (tree_classdef_methods_block& blk)
 {
-  tree_classdef_methods_list *methods_list = blk.element_list ();
+  tree_classdef_method_list *method_list = blk.method_list ();
 
-  if (methods_list)
-    methods_list->accept (*this);
+  if (method_list)
+    method_list->accept (*this);
 }
 
 void
@@ -756,7 +756,7 @@
 }
 
 void
-tree_walker::visit_classdef_events_list (tree_classdef_events_list& lst)
+tree_walker::visit_classdef_event_list (tree_classdef_event_list& lst)
 {
   for (auto *elt : lst)
     {
@@ -768,10 +768,10 @@
 void
 tree_walker::visit_classdef_events_block (tree_classdef_events_block& blk)
 {
-  tree_classdef_events_list *events_list = blk.element_list ();
+  tree_classdef_event_list *event_list = blk.event_list ();
 
-  if (events_list)
-    events_list->accept (*this);
+  if (event_list)
+    event_list->accept (*this);
 }
 
 void
@@ -793,7 +793,7 @@
 void
 tree_walker::visit_classdef_enum_block (tree_classdef_enum_block& blk)
 {
-  tree_classdef_enum_list *enum_list = blk.element_list ();
+  tree_classdef_enum_list *enum_list = blk.enum_list ();
 
   if (enum_list)
     enum_list->accept (*this);
@@ -802,20 +802,20 @@
 void
 tree_walker::visit_classdef_body (tree_classdef_body& body)
 {
-  for (auto *elt : body.properties_list ())
+  for (auto *elt : body.property_list ())
     {
       if (elt)
         elt->accept (*this);
     }
 
-  for (auto *elt : body.methods_list ())
+  for (auto *elt : body.method_list ())
     {
       if (elt)
         elt->accept (*this);
     }
 
 
-  for (auto *elt : body.events_list ())
+  for (auto *elt : body.event_list ())
     {
       if (elt)
         elt->accept (*this);
--- a/libinterp/parse-tree/pt-walk.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt-walk.h	Tue Apr 02 16:11:12 2024 -0400
@@ -96,10 +96,10 @@
 class tree_classdef_property;
 class tree_classdef_property_list;
 class tree_classdef_properties_block;
-class tree_classdef_methods_list;
+class tree_classdef_method_list;
 class tree_classdef_methods_block;
 class tree_classdef_event;
-class tree_classdef_events_list;
+class tree_classdef_event_list;
 class tree_classdef_events_block;
 class tree_classdef_enum;
 class tree_classdef_enum_list;
@@ -233,13 +233,13 @@
 
   virtual void visit_classdef_properties_block (tree_classdef_properties_block&);
 
-  virtual void visit_classdef_methods_list (tree_classdef_methods_list&);
+  virtual void visit_classdef_method_list (tree_classdef_method_list&);
 
   virtual void visit_classdef_methods_block (tree_classdef_methods_block&);
 
   virtual void visit_classdef_event (tree_classdef_event&);
 
-  virtual void visit_classdef_events_list (tree_classdef_events_list&);
+  virtual void visit_classdef_event_list (tree_classdef_event_list&);
 
   virtual void visit_classdef_events_block (tree_classdef_events_block&);
 
--- a/libinterp/parse-tree/pt.cc	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt.cc	Tue Apr 02 16:11:12 2024 -0400
@@ -30,6 +30,7 @@
 #include <sstream>
 #include <string>
 
+#include "comment-list.h"
 #include "interpreter.h"
 #include "ov-fcn.h"
 #include "pt.h"
@@ -39,6 +40,12 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+comment_list
+tree::leading_comments () const
+{
+  return comment_list ();
+}
+
 // Hide the details of the string buffer so that we are less likely to
 // create a memory leak.
 
--- a/libinterp/parse-tree/pt.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/pt.h	Tue Apr 02 16:11:12 2024 -0400
@@ -36,6 +36,7 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
+class comment_list;
 class tree_evaluator;
 class tree_walker;
 
@@ -67,6 +68,9 @@
     m_column_num = c;
   }
 
+  // FIXME: maybe make this a pure virtual function?
+  virtual comment_list leading_comments () const;
+
   virtual void set_breakpoint (const std::string& condition)
   {
     if (m_bp_cond)
--- a/libinterp/parse-tree/token.h	Tue Apr 02 12:59:14 2024 -0400
+++ b/libinterp/parse-tree/token.h	Tue Apr 02 16:11:12 2024 -0400
@@ -31,6 +31,7 @@
 #include <string>
 #include <variant>
 
+#include "comment-list.h"
 #include "error.h"
 #include "filepos.h"
 #include "ov.h"
@@ -43,6 +44,7 @@
 
   enum token_type
   {
+    invalid_token,
     generic_token,
     keyword_token,
     string_token,
@@ -73,32 +75,36 @@
 
 public:
 
-  token (int id, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_comment_list (lst)
+  token ()
+    : m_type_tag (invalid_token)
   { }
 
-  token (int id, bool is_kw, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (is_kw ? keyword_token : generic_token), m_comment_list (lst)
+  token (int id, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_leading_comments (lst)
   { }
 
-  token (int id, const char *s, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (string_token), m_tok_info (s), m_comment_list (lst)
+  token (int id, bool is_kw, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (is_kw ? keyword_token : generic_token), m_leading_comments (lst)
   { }
 
-  token (int id, const std::string& s, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (string_token), m_tok_info (s), m_comment_list (lst)
+  token (int id, const char *s, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (string_token), m_tok_info (s), m_leading_comments (lst)
+  { }
+
+  token (int id, const std::string& s, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (string_token), m_tok_info (s), m_leading_comments (lst)
   { }
 
-  token (int id, const octave_value& val, const std::string& s, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (numeric_token), m_tok_info (val), m_orig_text (s), m_comment_list (lst)
+  token (int id, const octave_value& val, const std::string& s, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (numeric_token), m_tok_info (val), m_orig_text (s), m_leading_comments (lst)
   { }
 
-  token (int id, end_tok_type t, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (ettype_token), m_tok_info (t), m_comment_list (lst)
+  token (int id, end_tok_type t, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (ettype_token), m_tok_info (t), m_leading_comments (lst)
   { }
 
-  token (int id, const std::string& meth, const std::string& cls, const filepos& beg_pos, const filepos& end_pos, comment_list *lst = nullptr)
-    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (scls_name_token), m_tok_info (meth, cls), m_comment_list (lst)
+  token (int id, const std::string& meth, const std::string& cls, const filepos& beg_pos, const filepos& end_pos, const comment_list& lst = comment_list ())
+    : m_beg_pos (beg_pos), m_end_pos (end_pos), m_tok_id (id), m_type_tag (scls_name_token), m_tok_info (meth, cls), m_leading_comments (lst)
   { }
 
   OCTAVE_DEFAULT_COPY_MOVE_DELETE (token)
@@ -123,6 +129,12 @@
   void beg_pos (const filepos& pos) { m_beg_pos = pos; }
   void end_pos (const filepos& pos) { m_end_pos = pos; }
 
+  comment_list leading_comments () const { return m_leading_comments; }
+  comment_list trailing_comments () const { return m_trailing_comments; }
+
+  void leading_comments (const comment_list& lst) { m_leading_comments = lst; }
+  void trailing_comments (const comment_list& lst) { m_trailing_comments = lst; }
+
   // These will probably be removed.
   int line () const { return m_beg_pos.line (); }
   int column () const { return m_beg_pos.column (); }
@@ -153,7 +165,7 @@
   filepos m_beg_pos;
   filepos m_end_pos;
 
-  int m_tok_id;
+  int m_tok_id {-1};
 
   token_type m_type_tag {generic_token};
 
@@ -241,7 +253,12 @@
 
   std::string m_orig_text;
 
-  comment_list *m_comment_list;
+  // Comments that appear prior to the token.
+  comment_list m_leading_comments;
+
+  // Comments that appear after the token.  This list is only used to
+  // hold comments that appear after the last token in a file.
+  comment_list m_trailing_comments;
 };
 
 OCTAVE_END_NAMESPACE(octave)