Mercurial > hg > octave-lyh
changeset 2764:2c0f259cf83d
[project @ 1997-03-01 02:30:26 by jwe]
author | jwe |
---|---|
date | Sat, 01 Mar 1997 02:30:29 +0000 |
parents | d9d00d7e271e |
children | c44d1e4cd35b |
files | src/ChangeLog src/SLList-misc.cc src/lex.h src/lex.l src/octave.gperf src/parse.y src/pt-cmd.cc src/pt-cmd.h src/pt-misc.cc src/pt-misc.h src/pt-pr-code.cc src/pt-pr-code.h src/pt-walk.h src/syswait.h src/token.h |
diffstat | 15 files changed, 488 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,34 @@ Fri Feb 28 01:49:48 1997 John W. Eaton <jwe@bevo.che.wisc.edu> + Implement switch statement: + + * parse.y (Vwarn_variable_switch_label): New static variable. + (warn_variable_switch_label): New function. + (symbols_of_parse): Provide warn_variable_switch_label as Octave + variable here. + (make_switch_case, finish_switch_command): New functions. + (maybe_warn_variable_switch_label): New function. + (end_error): Handle endswitch. + (switch_command, case_list, case_list1, switch_case, default_case): + New nonterminals. + (command): Add switch_command here. + * lex.l (is_keyword): Handle switch, case, otherwise, and endswitch. + * octave_gperf: Recognize switch, case, otherwise, and endswitch. + * token.h (end_tok_type): New item, switch_end. + * pt-cmd.cc (tree_switch_command): New class. + * pt-misc.cc (tree_switch_case, tree_switch_case_list): New classes. + * pt-pr-code.cc (tree_print_code::visit_switch_case, + tree_print_code::visit_switch_case_list, + tree_print_code::visit_switch_command): New functions. + * pt-walk.h (tree_walker::visit_switch_case, + tree_walker::visit_switch_case_list, + tree_walker::visit_switch_command): New pure virtual declarations. + Implement new switch statement. + * SLList-misc.cc: Instantiate lists of pointers to + tree_switch_case objects too. + + * lex.h, lex.l, parse.y: Delete all references to lexer_flags::iffing. + * syswait.h: Include sys/wait.h on NeXT systems, but don't use the WIFEXTED, WEXITSTATUS, and WIFSIGNALLED macros defined there. Also define waitpid in terms of wait4. From Rex A. Dieter
--- a/src/SLList-misc.cc +++ b/src/SLList-misc.cc @@ -39,10 +39,12 @@ template class SLNode<tree_if_clause *>; template class SLList<tree_if_clause *>; +template class SLList<tree_switch_case *>; +template class SLNode<tree_switch_case *>; + template class SLList<tree_global *>; template class SLNode<tree_global *>; - /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/lex.h +++ b/src/lex.h @@ -149,10 +149,6 @@ // Nonzero means we think we are looking at a set command. int doing_set; - // Nonzero means we're in the middle of defining a conditional - // expression. - int iffing; - // Nonzero means we're looking at the range part of a plot command. int in_plot_range;
--- a/src/lex.l +++ b/src/lex.l @@ -959,11 +959,13 @@ { case all_va_args_kw: case break_kw: + case case_kw: case catch_kw: case continue_kw: case else_kw: case elseif_kw: case global_kw: + case otherwise_kw: case return_kw: case unwind_protect_cleanup_kw: break; @@ -992,6 +994,10 @@ yylval.tok_val = new token (token::if_end, l, c); break; + case endswitch_kw: + yylval.tok_val = new token (token::switch_end, l, c); + break; + case endwhile_kw: yylval.tok_val = new token (token::while_end, l, c); break; @@ -1003,11 +1009,8 @@ break; case if_kw: - promptflag--; - lexer_flags.iffing++; - break; - case try_kw: + case switch_kw: case unwind_protect_kw: promptflag--; break; @@ -1908,7 +1911,6 @@ plotting = 0; // Not initially inside a loop or if statement. - iffing = 0; looping = 0; // Not initially looking at indirect references.
--- a/src/octave.gperf +++ b/src/octave.gperf @@ -4,6 +4,7 @@ { all_va_args_kw, break_kw, + case_kw, catch_kw, continue_kw, else_kw, @@ -14,6 +15,7 @@ endfor_kw, endfunction_kw, endif_kw, + endswitch_kw, endwhile_kw, for_kw, function_kw, @@ -21,8 +23,10 @@ gplot_kw, gsplot_kw, if_kw, + otherwise_kw, replot_kw, return_kw, + switch_kw, try_kw, unwind_protect_kw, unwind_protect_cleanup_kw, @@ -34,6 +38,7 @@ %% all_va_args, ALL_VA_ARGS, all_va_args_kw break, BREAK, break_kw +case, CASE, case_kw catch, CATCH, catch_kw continue, CONTINUE, continue_kw else, ELSE, else_kw @@ -44,6 +49,7 @@ endfor, END, endfor_kw endfunction, END, endfunction_kw endif, END, endif_kw +endswitch, END, endswitch_kw endwhile, END, endwhile_kw for, FOR, for_kw function, FCN, function_kw @@ -51,8 +57,10 @@ gplot, PLOT, gplot_kw gsplot, PLOT, gsplot_kw if, IF, if_kw +otherwise, OTHERWISE, otherwise_kw replot, PLOT, replot_kw return, FUNC_RET, return_kw +switch, SWITCH, switch_kw try, TRY, try_kw unwind_protect, UNWIND, unwind_protect_kw unwind_protect_cleanup, CLEANUP, unwind_protect_cleanup_kw
--- a/src/parse.y +++ b/src/parse.y @@ -72,6 +72,9 @@ // static bool Vwarn_assign_as_truth_value; +// If TRUE, generate a warning for variable swich labels. +static bool Vwarn_variable_switch_label; + // If TRUE, generate a warning for the comma in things like // // octave> global a, b = 2 @@ -119,6 +122,9 @@ // test in a logical expression. static void maybe_warn_assign_as_truth_value (tree_expression *expr); +// Maybe print a warning about switch labels that aren't constants. +static void maybe_warn_variable_switch_label (tree_expression *expr); + // Create a plot command. static tree_plot_command *make_plot_command (token *tok, plot_limits *range, subplot_list *list); @@ -196,6 +202,15 @@ static tree_if_clause *make_elseif_clause (tree_expression *expr, tree_statement_list *list); +// Finish a switch command. +static tree_switch_command *finish_switch_command + (token *switch_tok, tree_expression *expr, + tree_switch_case_list *list, token *end_tok); + +// Build a switch case. +static tree_switch_case *make_switch_case + (tree_expression *expr, tree_statement_list *list); + // Build an assignment to a variable. static tree_expression *make_simple_assignment (tree_index_expression *var, token *eq_tok, tree_expression *expr); @@ -271,6 +286,9 @@ tree_if_command *tree_if_command_type; tree_if_clause *tree_if_clause_type; tree_if_command_list *tree_if_command_list_type; + tree_switch_command *tree_switch_command_type; + tree_switch_case *tree_switch_case_type; + tree_switch_case_list *tree_switch_case_list_type; tree_global *tree_global_type; tree_global_init_list *tree_global_init_list_type; tree_global_command *tree_global_command_type; @@ -300,6 +318,7 @@ %token <tok_val> TEXT STYLE %token <tok_val> FOR WHILE %token <tok_val> IF ELSEIF ELSE +%token <tok_val> SWITCH CASE OTHERWISE %token <tok_val> BREAK CONTINUE FUNC_RET %token <tok_val> UNWIND CLEANUP %token <tok_val> TRY CATCH @@ -333,6 +352,9 @@ %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_switch_command_type> switch_command +%type <tree_switch_case_type> switch_case default_case +%type <tree_switch_case_list_type> case_list1 case_list %type <tree_global_type> global_decl2 %type <tree_global_init_list_type> global_decl1 %type <tree_global_command_type> global_decl @@ -618,11 +640,10 @@ { $$ = $1; } | global_decl { $$ = $1; } + | switch_command + { $$ = $1; } | if_command - { - lexer_flags.iffing--; - $$ = $1; - } + { $$ = $1; } | UNWIND opt_sep opt_list CLEANUP opt_sep opt_list END { if (! ($$ = make_unwind_command ($1, $3, $6, $7))) @@ -699,6 +720,39 @@ { $$ = new tree_if_clause ($3); } ; +switch_command : SWITCH expression opt_sep case_list END + { + if (! ($$ = finish_switch_command ($1, $2, $4, $5))) + ABORT_PARSE; + } + ; + +case_list : case_list1 + { $$ = $1; } + | case_list1 default_case + { + $1->append ($2); + $$ = $1; + } + ; + +case_list1 : switch_case + { $$ = new tree_switch_case_list ($1); } + | case_list1 switch_case + { + $1->append ($2); + $$ = $1; + } + ; + +switch_case : CASE opt_sep expression opt_sep list + { $$ = make_switch_case ($3, $5); } + ; + +default_case : OTHERWISE opt_sep opt_list + { $$ = new tree_switch_case ($3); } + ; + screwed_again : // empty { lexer_flags.maybe_screwed_again++; } ; @@ -1280,6 +1334,10 @@ end_error ("try", ettype, l, c); break; + case token::switch_end: + end_error ("switch", ettype, l, c); + break; + case token::unwind_protect_end: end_error ("unwind_protect", ettype, l, c); break; @@ -1351,6 +1409,17 @@ } } +// Maybe print a warning about switch labels that aren't constants. + +static void +maybe_warn_variable_switch_label (tree_expression *expr) +{ + if (Vwarn_variable_switch_label && ! expr->is_constant ()) + { + warning ("variable switch label"); + } +} + // Create a plot command. static tree_plot_command * @@ -1975,6 +2044,35 @@ return new tree_if_clause (expr, list); } +// Finish a switch command. + +static tree_switch_command * +finish_switch_command (token *switch_tok, tree_expression *expr, + tree_switch_case_list *list, token *end_tok) +{ + tree_switch_command *retval = 0; + + if (! check_end (end_tok, token::switch_end)) + { + int l = switch_tok->line (); + int c = switch_tok->column (); + + retval = new tree_switch_command (expr, list, l, c); + } + + return retval; +} + +// Build a switch case. + +static tree_switch_case * +make_switch_case (tree_expression *expr, tree_statement_list *list) +{ + maybe_warn_variable_switch_label (expr); + + return new tree_switch_case (expr, list); +} + // Build an assignment to a variable. static tree_expression * @@ -2274,6 +2372,15 @@ return 0; } +static int +warn_variable_switch_label (void) +{ + Vwarn_variable_switch_label + = check_preference ("warn_variable_switch_label"); + + return 0; +} + void symbols_of_parse (void) { @@ -2287,8 +2394,11 @@ "produce warning if function name conflicts with file name"); DEFVAR (warn_missing_semicolon, 0.0, 0, warn_missing_semicolon, - "produce a warning if a statement in a function file is not + "produce a warning if a statement in a function file is not\n\ terminated with a semicolon"); + + DEFVAR (warn_variable_switch_label, 0.0, 0, warn_variable_switch_label, + "produce warning for variables used as switch labels"); } /*
--- a/src/pt-cmd.cc +++ b/src/pt-cmd.cc @@ -517,6 +517,50 @@ tw.visit_if_command (*this); } +// Switch. + +tree_switch_command::~tree_switch_command (void) +{ + delete expr; + delete list; +} + +void +tree_switch_command::eval (void) +{ + if (expr) + { + octave_value val = expr->eval (0); + + if (! error_state) + { + if (list) + list->eval (val); + + if (error_state) + eval_error (); + } + else + eval_error (); + } + else + ::error ("missing value in switch command near line %d, column %d", + line (), column ()); +} + +void +tree_switch_command::eval_error (void) +{ + ::error ("evaluating switch command near line %d, column %d", + line (), column ()); +} + +void +tree_switch_command::accept (tree_walker& tw) +{ + tw.visit_switch_command (*this); +} + // Simple exception handling. tree_try_catch_command::~tree_try_catch_command (void)
--- a/src/pt-cmd.h +++ b/src/pt-cmd.h @@ -34,6 +34,7 @@ class tree_statement_list; class tree_global_init_list; class tree_if_command_list; +class tree_switch_case_list; class tree_expression; class tree_index_expression; class tree_identifier; @@ -46,6 +47,7 @@ class tree_while_command; class tree_for_command; class tree_if_command; +class tree_switch_command; class tree_try_catch_command; class tree_unwind_protect_command; class tree_no_op_command; @@ -212,8 +214,6 @@ void eval (void); - void eval_error (void); - tree_if_command_list *cmd_list (void) { return list; } void accept (tree_walker& tw); @@ -224,6 +224,41 @@ tree_if_command_list *list; }; +// Switch. + +class +tree_switch_command : public tree_command +{ +public: + + tree_switch_command (int l = -1, int c = -1) + : tree_command (l, c), expr (0), list (0) { } + + tree_switch_command (tree_expression *e, tree_switch_case_list *lst, + int l = -1, int c = -1) + : tree_command (l, c), expr (e), list (lst) { } + + ~tree_switch_command (void); + + void eval (void); + + void eval_error (void); + + tree_expression *switch_value (void) { return expr; } + + tree_switch_case_list *case_list (void) { return list; } + + void accept (tree_walker& tw); + +private: + + // Value on which to switch. + tree_expression *expr; + + // List of cases (case 1, case 2, ..., default) + tree_switch_case_list *list; +}; + // Simple exception handling. class
--- a/src/pt-misc.cc +++ b/src/pt-misc.cc @@ -529,6 +529,95 @@ tw.visit_if_command_list (*this); } +// Switch. + +tree_switch_case::~tree_switch_case (void) +{ + delete label; + delete list; +} + +bool +tree_switch_case::label_matches (const octave_value& val) +{ + bool retval = false; + + octave_value label_value = label->eval (false); + + if (! error_state) + { + if (label_value.is_defined ()) + { + octave_value tmp = do_binary_op (octave_value::eq, + val, label_value); + + if (! error_state) + { + if (tmp.is_defined ()) + retval = tmp.is_true (); + else + eval_error (); + } + else + eval_error (); + } + else + eval_error (); + } + else + eval_error (); + + return retval; +} + +int +tree_switch_case::eval (const octave_value& val) +{ + int retval = 0; + + if (is_default_case () || label_matches (val)) + { + if (list) + list->eval (true); + + retval = 1; + } + + return retval; +} + +void +tree_switch_case::eval_error (void) +{ + ::error ("evaluating switch case label"); +} + +void +tree_switch_case::accept (tree_walker& tw) +{ + tw.visit_switch_case (*this); +} + +// List of switch cases. + +void +tree_switch_case_list::eval (const octave_value& val) +{ + for (Pix p = first (); p != 0; next (p)) + { + tree_switch_case *t = this->operator () (p); + + if (t->eval (val) || error_state) + break; + } +} + +void +tree_switch_case_list::accept (tree_walker& tw) +{ + tw.visit_switch_case_list (*this); +} + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/pt-misc.h +++ b/src/pt-misc.h @@ -47,6 +47,10 @@ class tree_va_return_list; class tree_global; class tree_global_init_list; +class tree_if_clause; +class tree_if_command_list; +class tree_switch_case; +class tree_switch_case_list; class tree_walker; @@ -373,6 +377,70 @@ void accept (tree_walker& tw); }; +class +tree_switch_case +{ +public: + + tree_switch_case (void) : label (0), list (0) { } + + tree_switch_case (tree_statement_list *l) + : label (0), list (l) { } + + tree_switch_case (tree_expression *e, tree_statement_list *l) + : label (e), list (l) { } + + ~tree_switch_case (void); + + bool is_default_case (void) + { return ! label; } + + bool label_matches (const octave_value& val); + + int eval (const octave_value& val); + + void eval_error (void); + + tree_expression *case_label (void) { return label; } + + tree_statement_list *commands (void) { return list; } + + void accept (tree_walker& tw); + +private: + + // The case label. + tree_expression *label; + + // The list of statements to evaluate if the label matches. + tree_statement_list *list; +}; + +class +tree_switch_case_list : public SLList<tree_switch_case *> +{ +public: + + tree_switch_case_list (void) + : SLList<tree_switch_case *> () { } + + tree_switch_case_list (tree_switch_case *t) + : SLList<tree_switch_case *> () { append (t); } + + ~tree_switch_case_list (void) + { + while (! empty ()) + { + tree_switch_case *t = remove_front (); + delete t; + } + } + + void eval (const octave_value& val); + + void accept (tree_walker& tw); +}; + #endif /*
--- a/src/pt-pr-code.cc +++ b/src/pt-pr-code.cc @@ -413,6 +413,77 @@ } void +tree_print_code::visit_switch_case (tree_switch_case& cs) +{ + indent (); + + if (cs.is_default_case ()) + os << "otherwise"; + else + os << "case "; + + tree_expression *label = cs.case_label (); + + if (label) + label->accept (*this); + + newline (); + + increment_indent_level (); + + tree_statement_list *list = cs.commands (); + + if (list) + { + list->accept (*this); + + decrement_indent_level (); + } +} + +void +tree_print_code::visit_switch_case_list (tree_switch_case_list& lst) +{ + Pix p = lst.first (); + + while (p) + { + tree_switch_case *elt = lst (p); + + if (elt) + elt->accept (*this); + + lst.next (p); + } +} + +void +tree_print_code::visit_switch_command (tree_switch_command& cmd) +{ + indent (); + + os << "switch "; + + tree_expression *expr = cmd.switch_value (); + + if (expr) + expr->accept (*this); + + newline (); + + increment_indent_level (); + + tree_switch_case_list *list = cmd.case_list (); + + if (list) + list->accept (*this); + + indent (); + + os << "endswitch"; +} + +void tree_print_code::visit_index_expression (tree_index_expression& expr) { indent ();
--- a/src/pt-pr-code.h +++ b/src/pt-pr-code.h @@ -78,6 +78,12 @@ void visit_if_command_list (tree_if_command_list&); + void visit_switch_case (tree_switch_case&); + + void visit_switch_case_list (tree_switch_case_list&); + + void visit_switch_command (tree_switch_command&); + void visit_index_expression (tree_index_expression&); void visit_indirect_ref (tree_indirect_ref&);
--- a/src/pt-walk.h +++ b/src/pt-walk.h @@ -84,6 +84,15 @@ visit_if_command_list (tree_if_command_list&) = 0; virtual void + visit_switch_case (tree_switch_case&) = 0; + + virtual void + visit_switch_case_list (tree_switch_case_list&) = 0; + + virtual void + visit_switch_command (tree_switch_command&) = 0; + + virtual void visit_index_expression (tree_index_expression&) = 0; virtual void