changeset 9476:d9b25c5b8ee5

handle classdef syntax in lexer and parser
author Ryan Rusaw
date Thu, 30 Jul 2009 16:26:39 -0400
parents 983de84e4bf3
children 4d3d90253e8a
files src/ChangeLog src/input.cc src/input.h src/lex.h src/lex.l src/octave.gperf src/parse.y src/token.cc src/token.h
diffstat 9 files changed, 626 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/ChangeLog	Thu Jul 30 16:26:39 2009 -0400
@@ -1,7 +1,58 @@
-2009-07-30  Jaroslav Hajek  <highegg@gmail.com>
-
-	* data.cc (Fmerge): Rename to Fifelse.
-
+2009-07-30  Ryan Rusaw  <rrusaw@gmail.com>
+
+	* input.cc (reading_classdef_file): New file-scope variable.
+	(gnu_readline): Also set curr_stream if reading_classdef_file.
+	(octave_gets, get_input_from_file):
+	Handle classdef files like other input files.
+	* input.h (reading_classdef_file): Provide decl.
+
+	* octave.gperf (classdef, endclassdef, endevents, endmethods,
+	endproperties, events, get, methods, properties, set): New keywords.
+
+	* lex.l: Handle classdef filees like other input files.
+	Recognize superclass method identifiers and metaclass query constructs.
+	(is_keyword_token): Recognize endclassdef, endevents, endmethods,
+	endproperties, get, set, properties, methods, and events keywords.
+	(maybe_classdef_get_set_method, parsing_classdef): New variables.
+	(handle_superclass_identifier, handle_meta_identifier):
+	New static functions.
+	(lexical_feedback::init): Initialize parsing_classdef and
+	maybe_classdef_get_set_method.
+	(display_token): Handle SUPERCLASSREF, METAQUERY, GET, SET,
+	PROPERTIES, METHODS, EVENTS, and  CLASSDEF tokens.
+	* lex.h (maybe_classdef_get_set_method, parsing_classdef):
+	Provide decls.
+	* parse.y (%union): New placeholder type, dummy_type.
+	(SUPERCLASSREF, METAQUERY, GET, SET, PROPERTIES, METHODS, EVENTS,
+	CLASSDEF): New tokens.
+	(superclass_identifier, meta_identifier, classdef_beg,
+	classdef_end, classdef1, classdef, opt_attr_list, attr_list, attr,
+	opt_superclasses, superclasses, class_body, properties_beg,
+	properties_block, properties_list, class_property, methods_beg,
+	methods_block, methods_list, events_beg, events_block,
+	events_list, class_event): New non-terminals.
+	(primary_expr): Include superclass_identifier and meta_identifier
+	as possible primary_exprs.
+	(function_beg): If parsing classdef file, set
+	lexer_flags.maybe_classdef_get_set_method to true.
+	be recognized.
+	(fcn_name): Accept GET '.' identifier or SET '.' identifier.
+	(end_error): Handle endclassdef.
+	(looking_at_classdef_keyword): New function.
+	(gobble_leading_whitespace): Handle classdef.
+	* token.h, token.cc (sc, mc):
+	New union fields for symbol classdef symbol_record info.
+	(token::token (symbol_table::symbol_record *,
+	symbol_table::symbol_record *, int, int),
+	token::token (symbol_table::symbol_record *,
+	symbol_table::symbol_record *, symbol_table::symbol_record *, int,
+	int)): New constructors.
+	(token::method_rec, token::class_rec, token::package_rec,
+	token::meta_class_rec, token::meta_package_rec): New methods.
+	(token_type): New enum values: scls_rec_token, meta_rec_token.
+	(end_tok_type): New enum values: classdef_end, events_end,
+	methods_end, properties_end.
+	
 2009-07-30  David Grundberg  <individ@acc.umu.se>
 
 	* symtab.h (symbol_table::parent_scope): Remove.
@@ -49,6 +100,10 @@
 
 2009-07-30  Jaroslav Hajek  <highegg@gmail.com>
 
+	* data.cc (Fmerge): Rename to Fifelse.
+
+2009-07-30  Jaroslav Hajek  <highegg@gmail.com>
+
 	* data.cc (Fmerge): New DEFUN.
 	(do_merge): New helper function.
 
--- a/src/input.cc	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/input.cc	Thu Jul 30 16:26:39 2009 -0400
@@ -115,6 +115,9 @@
 // TRUE means we're parsing a function file.
 bool reading_fcn_file = false;
 
+// TRUE means we're parsing a classdef file.
+bool reading_classdef_file = false;
+
 // Simple name of function file we are reading.
 std::string curr_fcn_file_name;
 
@@ -216,7 +219,7 @@
 
       FILE *curr_stream = command_editor::get_input_stream ();
 
-      if (reading_fcn_file || reading_script_file)
+      if (reading_fcn_file || reading_script_file || reading_classdef_file)
 	curr_stream = ff_instream;
 
       retval = octave_fgets (curr_stream);
@@ -259,6 +262,7 @@
 
   if ((interactive || forced_interactive)
       && (! (reading_fcn_file
+	     || reading_classdef_file
 	     || reading_script_file
 	     || input_from_startup_file
 	     || input_from_command_line_file)))
@@ -304,7 +308,7 @@
 	     || history_skip_auto_repeated_debugging_command))
 	command_history::add (current_input_line);
 
-      if (! (reading_fcn_file || reading_script_file))
+      if (! (reading_fcn_file || reading_script_file || reading_classdef_file))
 	{
 	  octave_diary << current_input_line;
 
@@ -314,9 +318,9 @@
 
       do_input_echo (current_input_line);
     }
-  else if (! (reading_fcn_file || reading_script_file))
+  else if (! (reading_fcn_file || reading_script_file || reading_classdef_file))
     octave_diary << "\n";
-  
+
   return retval;
 }
 
@@ -386,7 +390,7 @@
       // Make sure input ends with a new line character.
       if (chars_left == 0 && buf[len-1] != '\n')
 	{
-	  if (len < max_size) 
+	  if (len < max_size)
 	    {
 	      // There is enough room to plug the newline character in
 	      // the buffer.
@@ -409,7 +413,7 @@
     {
       status = 0;
     }
-  else    
+  else
     status = -1;
 
   return status;
@@ -429,7 +433,7 @@
   if (! instream && warn)
     warning ("%s: no such file or directory", name.c_str ());
 
-  if (reading_fcn_file || reading_script_file)
+  if (reading_fcn_file || reading_script_file || reading_classdef_file)
     ff_instream = instream;
   else
     command_editor::set_input_stream (instream);
@@ -689,7 +693,7 @@
 	  // global_command = 0;
 
 	  if (octave_completion_matches_called)
-	    octave_completion_matches_called = false;	    
+	    octave_completion_matches_called = false;
 	}
 
       // Unmark forced variables.
--- a/src/input.h	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/input.h	Thu Jul 30 16:26:39 2009 -0400
@@ -66,6 +66,9 @@
 // TRUE means we're parsing a script file.
 extern bool reading_script_file;
 
+// TRUE means we're parsing a classdef file.
+extern bool reading_classdef_file;
+
 // If we are reading from an M-file, this is it.
 extern FILE *ff_instream;
 
--- a/src/lex.h	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/lex.h	Thu Jul 30 16:26:39 2009 -0400
@@ -121,9 +121,17 @@
   // Should only matter if current_function_level > 0
   bool parsed_function_name;
 
-  // TRUE means we are parsing a class method.
+  // TRUE means we are parsing a class method in function or classdef file.
   bool parsing_class_method;
 
+  // TRUE means we are parsing a class method declaration line in a
+  // classdef file and can accept a property get or set method name.
+  // For example, "get.PropertyName" is recognized as a function name.
+  bool maybe_classdef_get_set_method;
+
+  // TRUE means we are parsing a classdef file
+  bool parsing_classdef;
+
   // Return transpose or start a string?
   bool quote_is_transpose;
 
--- a/src/lex.l	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/lex.l	Thu Jul 30 16:26:39 2009 -0400
@@ -289,6 +289,8 @@
 static void handle_number (void);
 static int handle_string (char delim);
 static int handle_close_bracket (bool spc_gobbled, int bracket_type);
+static int handle_superclass_identifier (void);
+static int handle_meta_identifier (void);
 static int handle_identifier (void);
 static bool have_continuation (bool trailing_comments_ok = true);
 static bool have_ellipsis_continuation (bool trailing_comments_ok = true);
@@ -690,7 +692,7 @@
       {
 	warning ("block comment open at end of input");
 
-	if ((reading_fcn_file || reading_script_file)
+	if ((reading_fcn_file || reading_script_file || reading_classdef_file)
 	    && ! curr_fcn_file_name.empty ())
 	  warning ("near line %d of file `%s.m'",
 		   input_line_number, curr_fcn_file_name.c_str ());
@@ -714,7 +716,43 @@
   }
 
 %{
-// Function handles.
+// Superclass method identifiers. 
+%}
+
+{IDENT}@{IDENT}{S}* |
+{IDENT}@{IDENT}.{IDENT}{S}* {
+    LEXER_DEBUG ("{IDENT}@{IDENT}{S}*|{IDENT}@{IDENT}.{IDENT}{S}*");
+
+    int id_tok = handle_superclass_identifier ();
+
+    if (id_tok >= 0)
+      {
+        lexer_flags.looking_for_object_index = true;
+
+        COUNT_TOK_AND_RETURN (SUPERCLASSREF);
+      }
+  }
+  
+%{
+// Metaclass query
+%}  
+  
+\?{IDENT}{S}* | 
+\?{IDENT}.{IDENT}{S}* {
+    LEXER_DEBUG ("\?{IDENT}{S}* | \?{IDENT}.{IDENT}{S}*");
+    
+    int id_tok = handle_meta_identifier ();
+
+    if (id_tok >= 0)
+      {
+        lexer_flags.looking_for_object_index = true;
+
+        COUNT_TOK_AND_RETURN (METAQUERY);
+      }
+  }  
+
+%{
+// Function handles and superclass references
 %}
 
 "@" {
@@ -729,6 +767,7 @@
     lexer_flags.at_beginning_of_statement = false;
 
     COUNT_TOK_AND_RETURN ('@');
+      
   }
 
 %{
@@ -874,7 +913,6 @@
 "<<"	{ LEXER_DEBUG ("<<"); XBIN_OP_RETURN (LSHIFT, false, false); }
 ">>"	{ LEXER_DEBUG (">>"); XBIN_OP_RETURN (RSHIFT, false, false); }
 
-
 {NOT} {
     LEXER_DEBUG ("{NOT}");
 
@@ -1065,7 +1103,7 @@
     }
 
   // Can be reset by defining a function.
-  if (! (reading_script_file || reading_fcn_file))
+  if (! (reading_script_file || reading_fcn_file || reading_classdef_file))
     {
       current_input_column = 1;
       input_line_number = command_editor::current_command_number ();
@@ -1075,6 +1113,7 @@
   // input.
   if ((interactive || forced_interactive)
       && ! (reading_fcn_file
+        || reading_classdef_file
 	    || reading_script_file
 	    || get_input_from_eval_string
 	    || input_from_startup_file))
@@ -1417,10 +1456,11 @@
 	  break;
 
 	case end_kw:
-	  if (inside_any_object_index ()
-	      || (lexer_flags.defining_func
-		  && ! (lexer_flags.looking_at_return_list
-			|| lexer_flags.parsed_function_name)))
+	  if (! reading_classdef_file
+	      && (inside_any_object_index ()
+		  || (lexer_flags.defining_func
+		      && ! (lexer_flags.looking_at_return_list
+			    || lexer_flags.parsed_function_name))))
 	    return 0;
 
 	  yylval.tok_val = new token (token::simple_end, l, c);
@@ -1461,6 +1501,26 @@
 	  yylval.tok_val = new token (token::while_end, l, c);
 	  lexer_flags.at_beginning_of_statement = true;
 	  break;
+	  
+	case endclassdef_kw:
+	  yylval.tok_val = new token (token::classdef_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endevents_kw:
+	  yylval.tok_val = new token (token::events_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endmethods_kw:
+	  yylval.tok_val = new token (token::methods_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endproperties_kw:
+	  yylval.tok_val = new token (token::properties_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
 
 	case for_kw:
 	case while_kw:
@@ -1485,19 +1545,43 @@
 	  promptflag--;
 	  break;
 
+	case get_kw:
+	case set_kw:  
+	  // 'get' and 'set' are keywords in classdef method
+	  // declarations.
+	  if (! lexer_flags.maybe_classdef_get_set_method)
+	    return 0;
+	  break;
+
+	case properties_kw:
+	case methods_kw:
+	case events_kw:
+	  // 'properties', 'methods' and 'events' are keywords for
+	  // classdef blocks.
+	  if (! lexer_flags.parsing_classdef)
+	    return 0;
+	  // fall through ...
+
+	case classdef_kw:
+	  // 'classdef' is always a keyword.
+	  promptflag--;
+	  break;	  
+
 	case function_kw:
 	  promptflag--;
 
 	  lexer_flags.defining_func = true;
 	  lexer_flags.parsed_function_name = false;
 
-	  if (! (reading_fcn_file || reading_script_file))
+	  if (! (reading_fcn_file || reading_script_file
+		 || reading_classdef_file))
 	    input_line_number = 1;
 	  break;
 
         case magic_file_kw:
 	  {
-	    if ((reading_fcn_file || reading_script_file)
+	    if ((reading_fcn_file || reading_script_file
+		 || reading_classdef_file)
 		&& ! curr_fcn_file_full_name.empty ())
 	      yylval.tok_val = new token (curr_fcn_file_full_name, l, c);
 	    else
@@ -2963,6 +3047,80 @@
   return retval;
 }
 
+static int
+handle_superclass_identifier (void)
+{
+  eat_continuation ();
+
+  std::string pkg;  
+  std::string meth = strip_trailing_whitespace (yytext); 
+  size_t pos = meth.find ("@");
+  std::string cls = meth.substr (pos).substr (1);
+  meth = meth.substr (0, pos - 1);  
+  
+  pos = cls.find (".");
+  if (pos != std::string::npos)
+    {	 
+      pkg = cls.substr (pos).substr (1);
+      cls = cls.substr (0, pos - 1);
+    }
+    
+  int kw_token = (is_keyword_token (meth) || is_keyword_token (cls)
+		  || is_keyword_token (pkg));
+  if (kw_token)
+    {
+      error ("method, class and package names may not be keywords");
+      return LEXICAL_ERROR;
+    }
+ 
+  yylval.tok_val
+    = new token (meth.empty () ? 0 : &(symbol_table::insert (meth)),
+                 cls.empty () ? 0 : &(symbol_table::insert (cls)),
+                 pkg.empty () ? 0 : &(symbol_table::insert (pkg)),
+		 input_line_number, current_input_column);				   
+  token_stack.push (yylval.tok_val);
+  
+  lexer_flags.convert_spaces_to_comma = true;
+  current_input_column += yyleng;
+  
+  return SUPERCLASSREF;
+}
+
+static int
+handle_meta_identifier (void)
+{
+  eat_continuation ();
+
+  std::string pkg;
+  std::string cls = strip_trailing_whitespace (yytext).substr (1);
+  size_t pos = cls.find (".");
+  
+  if (pos != std::string::npos)
+    {	 
+      pkg = cls.substr (pos).substr (1);
+      cls = cls.substr (0, pos - 1);
+    }
+  
+  int kw_token = is_keyword_token (cls) || is_keyword_token (pkg);
+  if (kw_token)
+    {
+       error ("class and package names may not be keywords");
+      return LEXICAL_ERROR;
+    }
+  
+  yylval.tok_val
+    = new token (cls.empty () ? 0 : &(symbol_table::insert (cls)),
+		 pkg.empty () ? 0 : &(symbol_table::insert (pkg)),
+		 input_line_number, current_input_column);
+
+  token_stack.push (yylval.tok_val);
+                   
+  lexer_flags.convert_spaces_to_comma = true;
+  current_input_column += yyleng;
+  
+  return METAQUERY;
+}
+
 // Figure out exactly what kind of token to return when we have seen
 // an identifier.  Handles keywords.  Return -1 if the identifier
 // should be ignored.
@@ -3153,6 +3311,10 @@
   defining_func = false;
   parsed_function_name = false;
   parsing_class_method = false;
+  
+  // Not initially defining a class with classdef.
+  maybe_classdef_get_set_method = false;
+  parsing_classdef = false;
 
   // Not initiallly looking at a function handle.
   looking_at_function_handle = 0;
@@ -3400,6 +3562,14 @@
     case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break;
     case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break;
     case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break;
+    case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break;
+    case METAQUERY: std::cerr << "METAQUERY\n"; break;
+    case GET: std::cerr << "GET\n"; break;
+    case SET: std::cerr << "SET\n"; break;
+    case PROPERTIES: std::cerr << "PROPERTIES\n"; break;
+    case METHODS: std::cerr << "METHODS\n"; break;
+    case EVENTS: std::cerr << "EVENTS\n"; break;
+    case CLASSDEF: std::cerr << "CLASSDEF\n"; break;
     case '\n': std::cerr << "\\n\n"; break;
     case '\r': std::cerr << "\\r\n"; break;
     case '\t': std::cerr << "TAB\n"; break;
--- a/src/octave.gperf	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/octave.gperf	Thu Jul 30 16:26:39 2009 -0400
@@ -30,6 +30,7 @@
   break_kw,
   case_kw,
   catch_kw,
+  classdef_kw,
   continue_kw,
   do_kw,
   else_kw,
@@ -37,19 +38,28 @@
   end_kw,
   end_try_catch_kw,
   end_unwind_protect_kw,
+  endclassdef_kw,
+  endevents_kw,
   endfor_kw,
   endfunction_kw,
   endif_kw,
+  endmethods_kw,
+  endproperties_kw,
   endswitch_kw,
   endwhile_kw,
+  events_kw,
   for_kw,
   function_kw,
+  get_kw,
   global_kw,
   if_kw,
   magic_file_kw,
   magic_line_kw,
+  methods_kw,
   otherwise_kw,
+  properties_kw,
   return_kw,
+  set_kw,
   static_kw,
   switch_kw,
   try_kw,
@@ -64,6 +74,7 @@
 break, BREAK, break_kw
 case, CASE, case_kw
 catch, CATCH, catch_kw
+classdef, CLASSDEF, classdef_kw
 continue, CONTINUE, continue_kw
 do, DO, do_kw
 else, ELSE, else_kw
@@ -71,18 +82,27 @@
 end, END, end_kw
 end_try_catch, END, end_try_catch_kw
 end_unwind_protect, END, end_unwind_protect_kw
+endclassdef, END, endclassdef_kw 
+endevents, END, endevents_kw
 endfor, END, endfor_kw
 endfunction, END, endfunction_kw
 endif, END, endif_kw
+endmethods, END, endmethods_kw
+endproperties, END, endproperties_kw
 endswitch, END, endswitch_kw
 endwhile, END, endwhile_kw
+events, EVENTS, events_kw
 for, FOR, for_kw
 function, FCN, function_kw
+get, GET, get_kw
 global, GLOBAL, global_kw
 if, IF, if_kw
+methods, METHODS, methods_kw
 otherwise, OTHERWISE, otherwise_kw
 persistent, STATIC, static_kw
+properties, PROPERTIES, properties_kw
 return, FUNC_RET, return_kw
+set, SET, set_kw
 static, STATIC, static_kw
 switch, SWITCH, switch_kw
 try, TRY, try_kw
--- a/src/parse.y	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/parse.y	Thu Jul 30 16:26:39 2009 -0400
@@ -410,6 +410,7 @@
   tree_statement *tree_statement_type;
   tree_statement_list *tree_statement_list_type;
   octave_user_function *octave_user_function_type;
+  void *dummy_type;
 }
 
 // Tokens with line and column information.
@@ -436,15 +437,22 @@
 %token <tok_val> TRY CATCH
 %token <tok_val> GLOBAL STATIC
 %token <tok_val> FCN_HANDLE
+%token <tok_val> PROPERTIES
+%token <tok_val> METHODS
+%token <tok_val> EVENTS
+%token <tok_val> METAQUERY
+%token <tok_val> SUPERCLASSREF
+%token <tok_val> GET SET
 
 // Other tokens.
 %token END_OF_INPUT LEXICAL_ERROR
-%token FCN SCRIPT_FILE FUNCTION_FILE
+%token FCN SCRIPT_FILE FUNCTION_FILE CLASSDEF
 // %token VARARGIN VARARGOUT
 %token CLOSE_BRACE
 
 // Nonterminals we construct.
-%type <comment_type> stash_comment function_beg
+%type <comment_type> stash_comment function_beg classdef_beg
+%type <comment_type> properties_beg methods_beg events_beg
 %type <sep_type> sep_no_nl opt_sep_no_nl sep opt_sep
 %type <tree_type> input
 %type <tree_constant_type> string constant magic_colon
@@ -456,15 +464,18 @@
 %type <tree_expression_type> primary_expr postfix_expr prefix_expr binary_expr
 %type <tree_expression_type> simple_expr colon_expr assign_expr expression
 %type <tree_identifier_type> identifier fcn_name
-%type <octave_user_function_type> function1 function2
+%type <tree_identifier_type> superclass_identifier meta_identifier
+%type <octave_user_function_type> function1 function2 classdef1
 %type <tree_index_expression_type> word_list_cmd
 %type <tree_colon_expression_type> colon_expr1
 %type <tree_argument_list_type> arg_list word_list assign_lhs
 %type <tree_argument_list_type> cell_or_matrix_row
 %type <tree_parameter_list_type> param_list param_list1 param_list2
 %type <tree_parameter_list_type> return_list return_list1
+%type <tree_parameter_list_type> superclasses opt_superclasses
 %type <tree_command_type> command select_command loop_command
-%type <tree_command_type> jump_command except_command function script_file
+%type <tree_command_type> jump_command except_command function
+%type <tree_command_type> script_file classdef
 %type <tree_command_type> function_file function_list
 %type <tree_if_command_type> if_command
 %type <tree_if_clause_type> elseif_clause else_clause
@@ -475,9 +486,22 @@
 %type <tree_decl_elt_type> decl2
 %type <tree_decl_init_list_type> decl1
 %type <tree_decl_command_type> declaration
-%type <tree_statement_type> statement function_end
+%type <tree_statement_type> statement function_end classdef_end
 %type <tree_statement_list_type> simple_list simple_list1 list list1
 %type <tree_statement_list_type> opt_list input1
+// These types need to be specified.
+%type <dummy_type> attr
+%type <dummy_type> class_event
+%type <dummy_type> class_property
+%type <dummy_type> properties_list
+%type <dummy_type> properties_block
+%type <dummy_type> methods_list
+%type <dummy_type> methods_block
+%type <dummy_type> opt_attr_list
+%type <dummy_type> attr_list
+%type <dummy_type> events_list
+%type <dummy_type> events_block
+%type <dummy_type> class_body
 
 // Precedence and associativity.
 %left ';' ',' '\n'
@@ -601,6 +625,15 @@
 		  }
 		;
 
+superclass_identifier
+		: SUPERCLASSREF
+		  { $$ = new tree_identifier ($1->line (), $1->column ()); }
+		;
+	    
+meta_identifier	: METAQUERY
+		  { $$ = new tree_identifier ($1->line (), $1->column ()); }
+		;	    
+
 string		: DQ_STRING
 		  { $$ = make_constant (DQ_STRING, $1); }
 		| SQ_STRING
@@ -696,7 +729,7 @@
 anon_fcn_handle	: '@' param_list statement
 		  { $$ = make_anon_fcn_handle ($2, $3); }
 		;
-
+	
 primary_expr	: identifier
 		  { $$ = $1; }
 		| constant
@@ -707,6 +740,10 @@
 		  { $$ = $1; }
 		| cell
 		  { $$ = $1; }
+		| meta_identifier
+		  { $$ = $1; }
+		| superclass_identifier
+		  { $$ = $1; }
 		| '(' expression ')'
 		  { $$ = $2->mark_in_parens (); }
 		;
@@ -925,6 +962,8 @@
 		  { $$ = $1; }
 		| script_file
 		  { $$ = $1; }
+		| classdef
+		  { $$ = $1; }
 		;
 
 // =====================
@@ -1264,6 +1303,7 @@
 // =============
 
 function_file   : FUNCTION_FILE function_list opt_sep END_OF_INPUT
+		  { $$ = 0; }
 		;
 
 function_list   : function
@@ -1275,7 +1315,12 @@
 // ===================
 
 function_beg	: push_fcn_symtab FCN stash_comment
-		  { $$ = $3; }
+		  {
+		    $$ = $3;
+
+		    if (reading_classdef_file || lexer_flags.parsing_classdef) 
+		      lexer_flags.maybe_classdef_get_set_method = true; 
+		  }
 		;
 
 function	: function_beg function1
@@ -1296,9 +1341,20 @@
 
 		    lexer_flags.parsed_function_name = true;
 		    lexer_flags.defining_func = false;
-
+		    lexer_flags.maybe_classdef_get_set_method = false;
+            
 		    $$ = $1;
 		  }
+		| GET '.' identifier
+		  {
+		    lexer_flags.maybe_classdef_get_set_method = false;
+		    $$ = $3;
+		  }
+		| SET '.' identifier
+		  {
+		    lexer_flags.maybe_classdef_get_set_method = false;
+		    $$ = $3;
+		  }
 		;
 
 function1	: fcn_name function2
@@ -1349,11 +1405,152 @@
 			YYABORT;
 		      }
 
+		    if (reading_classdef_file)
+		      {
+		        yyerror ("classdef body open at end of input");
+		        YYABORT;
+		      }
+
 		    $$ = make_end ("endfunction", input_line_number,
 				   current_input_column);
 		  }
 		;
 
+// ========
+// Classdef
+// ========
+
+classdef_beg	: CLASSDEF stash_comment
+		  {
+		    $$ = 0;
+		    lexer_flags.parsing_classdef = true;
+		  }
+		;
+
+classdef_end	: END
+		  {
+		    lexer_flags.parsing_classdef = false;
+
+		    if (end_token_ok ($1, token::classdef_end))
+		      $$ = make_end ("endclassdef", $1->line (), $1->column ());
+		    else
+		      ABORT_PARSE;
+		  }
+		;
+
+classdef1	: classdef_beg opt_attr_list identifier opt_superclasses
+		  { $$ = 0; }
+		;
+
+classdef	: classdef1 '\n' class_body '\n' stash_comment classdef_end
+		  { $$ = 0; }
+		;
+
+opt_attr_list	: // empty
+		  { $$ = 0; }
+		| '(' attr_list ')'
+		  { $$ = 0; }
+		;
+
+attr_list	: attr
+		  { $$ = 0; }
+		| attr_list ',' attr
+		  { $$ = 0; }
+		;
+
+attr		: identifier
+		  { $$ = 0; }
+		| identifier '=' decl_param_init expression
+		  { $$ = 0; }
+		| EXPR_NOT identifier
+		  { $$ = 0; }
+		;
+
+opt_superclasses
+		: // empty
+		  { $$ = 0; }
+		| superclasses
+		  { $$ = 0; }
+		;
+
+superclasses	: EXPR_LT identifier '.' identifier
+		  { $$ = 0; }
+		| EXPR_LT identifier
+		  { $$ = 0; }
+		| superclasses EXPR_AND identifier '.' identifier
+		  { $$ = 0; }
+		| superclasses EXPR_AND identifier
+		  { $$ = 0; }
+		;
+
+class_body	: properties_block
+		  { $$ = 0; }
+		| methods_block
+		  { $$ = 0; }
+		| events_block
+		  { $$ = 0; }
+		| class_body '\n' properties_block
+		  { $$ = 0; }
+		| class_body '\n' methods_block
+		  { $$ = 0; }
+		| class_body '\n' events_block
+		  { $$ = 0; }
+		;
+
+properties_beg	: PROPERTIES stash_comment
+		  { $$ = 0; }
+		;
+
+properties_block
+		: properties_beg opt_attr_list '\n' properties_list '\n' END
+		  { $$ = 0; }
+		;
+
+properties_list
+		: class_property
+		  { $$ = 0; }
+		| properties_list '\n' class_property
+		  { $$ = 0; }
+		;
+
+class_property	: identifier
+		  { $$ = 0; }
+		| identifier '=' decl_param_init expression ';'
+		  { $$ = 0; }
+		;
+
+methods_beg	: METHODS stash_comment
+		  { $$ = 0; }
+		;
+
+methods_block	: methods_beg opt_attr_list '\n' methods_list '\n' END
+		  { $$ = 0; }
+		;
+
+methods_list	: function
+		  { $$ = 0; }
+		| methods_list '\n' function
+		  { $$ = 0; }
+		;
+
+events_beg	: EVENTS stash_comment
+		  { $$ = 0; }
+		;
+
+events_block	: events_beg opt_attr_list '\n' events_list '\n' END
+		  { $$ = 0; }
+		;
+
+events_list	: class_event
+		  { $$ = 0; }
+		| events_list '\n' class_event
+		  { $$ = 0; }
+		;
+
+class_event	: identifier
+		  { $$ = 0; }
+		;
+ 
 // =============
 // Miscellaneous
 // =============
@@ -1414,7 +1611,7 @@
 
   std::ostringstream output_buf;
 
-  if (reading_fcn_file || reading_script_file)
+  if (reading_fcn_file || reading_script_file || reading_classdef_file)
     output_buf << "parse error near line " << input_line_number
 	       << " of file " << curr_fcn_file_full_name;
   else
@@ -1474,6 +1671,10 @@
       error (fmt, type, "endfunction", l, c);
       break;
 
+    case token::classdef_end:
+      error (fmt, type, "endclassdef", l, c);
+      break;
+
     case token::if_end:
       error (fmt, type, "endif", l, c);
       break;
@@ -1520,6 +1721,10 @@
 
       switch (expected)
 	{
+	case token::classdef_end:
+	  end_error ("classdef", ettype, l, c);
+	  break;
+
 	case token::for_end:
 	  end_error ("for", ettype, l, c);
 	  break;
@@ -2658,7 +2863,7 @@
       }
   }
 
-  if (reading_fcn_file || autoloading)
+  if (reading_fcn_file || reading_classdef_file || autoloading)
     {
       octave_time now;
 
@@ -3135,6 +3340,25 @@
   return (c == EOF);
 }
 
+static bool
+looking_at_classdef_keyword (FILE *ffile)
+{
+  bool status = false;
+
+  long pos = ftell (ffile);
+
+  char buf [10];
+  fgets (buf, 10, ffile);
+  size_t len = strlen (buf);
+  if (len > 8 && strncmp (buf, "classdef", 8) == 0
+      && ! (isalnum (buf[8]) || buf[8] == '_'))
+    status = true;
+
+  fseek (ffile, pos, SEEK_SET);
+
+  return status;
+ }
+
 static std::string
 gobble_leading_white_space (FILE *ffile, bool& eof)
 {
@@ -3263,6 +3487,9 @@
 	  unwind_protect::protect_var (parser_end_of_input);
 	  unwind_protect::protect_var (reading_fcn_file);
 	  unwind_protect::protect_var (reading_script_file);
+	  unwind_protect::protect_var (reading_classdef_file);
+	  unwind_protect::protect_var (Vecho_executing_commands);
+
 
 	  get_input_from_eval_string = false;
 	  parser_end_of_input = false;
@@ -3271,20 +3498,33 @@
 	    {
 	      file_type = "function";
 
-	      unwind_protect::protect_var (Vecho_executing_commands);
+	      Vecho_executing_commands = ECHO_OFF;
+
+	      reading_classdef_file = false;
+	      reading_fcn_file = true;
+	      reading_script_file = false;
+	    }
+	  else if (! force_script && looking_at_classdef_keyword (ffile))
+	    {
+	      file_type = "classdef";
 
 	      Vecho_executing_commands = ECHO_OFF;
-	      reading_fcn_file = true;
+
+	      reading_classdef_file = true;
+	      reading_fcn_file = false;
+	      reading_script_file = false;
 	    }
 	  else
 	    {
 	      file_type = "script";
 
+	      Vecho_executing_commands = ECHO_OFF;
+
+	      reading_classdef_file = false;
 	      reading_fcn_file = false;
+	      reading_script_file = true;
 	    }
 
-	  reading_script_file = ! reading_fcn_file;
-	  
 	  YY_BUFFER_STATE old_buf = current_buffer ();
 	  YY_BUFFER_STATE new_buf = create_buffer (ffile);
 
--- a/src/token.cc	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/token.cc	Thu Jul 30 16:26:39 2009 -0400
@@ -1,7 +1,7 @@
 /*
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2002, 2004, 2005,
-              2007 John W. Eaton
+              2007, 2009 John W. Eaton
 
 This file is part of Octave.
 
@@ -81,6 +81,28 @@
   sr = s;
 }
 
+token::token (symbol_table::symbol_record *cls,
+              symbol_table::symbol_record *pkg, int l, int c)
+{
+  line_num = l;
+  column_num = c;
+  type_tag = meta_rec_token;
+  mc.cr = cls;
+  mc.pr = pkg;
+}
+
+token::token (symbol_table::symbol_record *mth,
+              symbol_table::symbol_record *cls,
+              symbol_table::symbol_record *pkg, int l, int c)
+{
+  line_num = l;
+  column_num = c;
+  type_tag = scls_rec_token;
+  sc.mr = mth;
+  sc.cr = cls;
+  sc.pr = pkg;
+}
+
 token::~token (void)
 {
   if (type_tag == string_token)
@@ -122,6 +144,41 @@
   return sr;
 }
 
+symbol_table::symbol_record *
+token::method_rec (void)
+{
+  assert (type_tag == scls_rec_token);
+  return sc.mr;
+}
+
+symbol_table::symbol_record *
+token::class_rec (void)
+{
+  assert (type_tag == scls_rec_token);
+  return sc.cr;
+}
+
+symbol_table::symbol_record *
+token::package_rec (void)
+{
+  assert (type_tag == scls_rec_token);
+  return sc.pr;
+}
+
+symbol_table::symbol_record *
+token::meta_class_rec (void)
+{
+  assert (type_tag == meta_rec_token);
+  return mc.cr;
+}
+
+symbol_table::symbol_record *
+token::meta_package_rec (void)
+{
+  assert (type_tag == meta_rec_token);
+  return mc.pr;
+}
+
 std::string
 token::text_rep (void)
 {
--- a/src/token.h	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/token.h	Thu Jul 30 16:26:39 2009 -0400
@@ -1,7 +1,7 @@
 /*
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2002, 2004, 2005,
-              2007, 2008 John W. Eaton
+              2007, 2008, 2009 John W. Eaton
 
 This file is part of Octave.
 
@@ -38,15 +38,21 @@
       double_token,
       ettype_token,
       pttype_token,
-      sym_rec_token
+      sym_rec_token,
+      scls_rec_token,
+      meta_rec_token
     };
 
   enum end_tok_type
     {
       simple_end,
+      classdef_end,
+      events_end,
       for_end,
       function_end,
       if_end,
+      methods_end,
+      properties_end,
       switch_end,
       while_end,
       try_catch_end,
@@ -67,6 +73,11 @@
   token (end_tok_type t, int l = -1, int c = -1);
   token (plot_tok_type t, int l = -1, int c = -1);
   token (symbol_table::symbol_record *s, int l = -1, int c = -1);
+  token (symbol_table::symbol_record *cls,
+         symbol_table::symbol_record *pkg, int l = -1, int c = -1);
+  token (symbol_table::symbol_record *mth,
+         symbol_table::symbol_record *cls,
+         symbol_table::symbol_record *pkg, int l = -1, int c = -1);
 
   ~token (void);
 
@@ -79,6 +90,13 @@
   plot_tok_type pttype (void);
   symbol_table::symbol_record *sym_rec (void);
 
+  symbol_table::symbol_record *method_rec (void);
+  symbol_table::symbol_record *class_rec (void);
+  symbol_table::symbol_record *package_rec (void);
+
+  symbol_table::symbol_record *meta_class_rec (void);
+  symbol_table::symbol_record *meta_package_rec (void);
+
   std::string text_rep (void);
 
 private:
@@ -99,6 +117,17 @@
       end_tok_type et;
       plot_tok_type pt;
       symbol_table::symbol_record *sr;
+      struct
+        {
+          symbol_table::symbol_record *mr;
+          symbol_table::symbol_record *cr;
+          symbol_table::symbol_record *pr;
+        } sc;
+      struct
+        {
+          symbol_table::symbol_record *cr;
+          symbol_table::symbol_record *pr;
+        } mc;
     };
   std::string orig_text;
 };