Mercurial > hg > octave-terminal
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 +++ b/src/ChangeLog @@ -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 +++ b/src/input.cc @@ -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 +++ b/src/input.h @@ -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 +++ b/src/lex.h @@ -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 +++ b/src/lex.l @@ -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 +++ b/src/octave.gperf @@ -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 +++ b/src/parse.y @@ -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 +++ b/src/token.cc @@ -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 +++ b/src/token.h @@ -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; };