1//////////////////////////////////////////////////////////////////////// 2// 3// Copyright (C) 1993-2021 The Octave Project Developers 4// 5// See the file COPYRIGHT.md in the top-level directory of this 6// distribution or <https://octave.org/copyright/>. 7// 8// This file is part of Octave. 9// 10// Octave is free software: you can redistribute it and/or modify it 11// under the terms of the GNU General Public License as published by 12// the Free Software Foundation, either version 3 of the License, or 13// (at your option) any later version. 14// 15// Octave is distributed in the hope that it will be useful, but 16// WITHOUT ANY WARRANTY; without even the implied warranty of 17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18// GNU General Public License for more details. 19// 20// You should have received a copy of the GNU General Public License 21// along with Octave; see the file COPYING. If not, see 22// <https://www.gnu.org/licenses/>. 23// 24//////////////////////////////////////////////////////////////////////// 25 26// Parser for Octave. 27 28// C decarations. 29 30%{ 31 32#define YYDEBUG 1 33 34#if defined (HAVE_CONFIG_H) 35# include "config.h" 36#endif 37 38#include <cassert> 39#include <cstdio> 40#include <cstdlib> 41 42#include <iostream> 43#include <map> 44#include <sstream> 45 46#include "Matrix.h" 47#include "cmd-edit.h" 48#include "cmd-hist.h" 49#include "file-ops.h" 50#include "file-stat.h" 51#include "oct-env.h" 52#include "oct-time.h" 53#include "quit.h" 54 55#include "Cell.h" 56#include "anon-fcn-validator.h" 57#include "builtin-defun-decls.h" 58#include "defun.h" 59#include "dynamic-ld.h" 60#include "error.h" 61#include "input.h" 62#include "interpreter-private.h" 63#include "interpreter.h" 64#include "lex.h" 65#include "load-path.h" 66#include "lo-sysdep.h" 67#include "oct-hist.h" 68#include "oct-map.h" 69#include "ov-classdef.h" 70#include "ov-fcn-handle.h" 71#include "ov-usr-fcn.h" 72#include "ov-null-mat.h" 73#include "pager.h" 74#include "parse.h" 75#include "pt-all.h" 76#include "pt-eval.h" 77#include "symtab.h" 78#include "token.h" 79#include "unwind-prot.h" 80#include "utils.h" 81#include "variables.h" 82 83// oct-parse.h must be included after pt-all.h 84#include "oct-parse.h" 85 86extern int octave_lex (YYSTYPE *, void *); 87 88// Forward declarations for some functions defined at the bottom of 89// the file. 90 91static void yyerror (octave::base_parser& parser, const char *s); 92 93#define lexer (parser.get_lexer ()) 94#define scanner lexer.m_scanner 95 96// Previous versions of Octave used Bison's YYUSE macro to avoid 97// warnings about unused values in rules. But that Bison macro was 98// apparently never intended to be public. So define our own. All we 99// need to do is mention the symantic value somewhere in the rule. It 100// doesn't actually need to be used to avoid the Bison warning, so just 101// define this macro to discard its parameter. 102#define OCTAVE_YYUSE(X) 103 104#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) 105 // Disable this warning for code that is generated by Bison, 106 // including grammar rules. Push the current state so we can 107 // restore the warning state prior to functions we define at 108 // the bottom of the file. 109# pragma GCC diagnostic push 110# pragma GCC diagnostic ignored "-Wold-style-cast" 111#endif 112 113%} 114 115// Bison declarations. 116 117// The grammar currently has 9 shift/reduce conflicts. Ensure that 118// we notice if that number changes. 119 120%expect 9 121 122// We are using the pure parser interface and the reentrant lexer 123// interface but the Octave parser and lexer are NOT properly 124// reentrant because both still use many global variables. It should be 125// safe to create a parser object and call it while another parser 126// object is active (to parse a callback function while the main 127// interactive parser is waiting for input, for example) if you take 128// care to properly save and restore (typically with an unwind_protect 129// object) relevant global values before and after the nested call. 130 131%define api.pure 132// No spaces inside the braces for the prefix and push-pull definitions! 133%define api.prefix {octave_} 134%define api.push-pull both 135%parse-param { octave::base_parser& parser } 136%lex-param { void *lexer.scanner } 137 138%union 139{ 140 int dummy_type; 141 142 // The type of the basic tokens returned by the lexer. 143 octave::token *tok_val; 144 145 // Comment strings that we need to deal with mid-rule. 146 octave::comment_list *comment_type; 147 148 // Types for the nonterminals we generate. 149 char punct_type; 150 octave::tree *tree_type; 151 octave::tree_matrix *tree_matrix_type; 152 octave::tree_cell *tree_cell_type; 153 octave::tree_expression *tree_expression_type; 154 octave::tree_constant *tree_constant_type; 155 octave::tree_fcn_handle *tree_fcn_handle_type; 156 octave::tree_superclass_ref *tree_superclass_ref_type; 157 octave::tree_metaclass_query *tree_metaclass_query_type; 158 octave::tree_function_def *tree_function_def_type; 159 octave::tree_anon_fcn_handle *tree_anon_fcn_handle_type; 160 octave::tree_identifier *tree_identifier_type; 161 octave::tree_index_expression *tree_index_expression_type; 162 octave::tree_colon_expression *tree_colon_expression_type; 163 octave::tree_argument_list *tree_argument_list_type; 164 octave::tree_parameter_list *tree_parameter_list_type; 165 octave::tree_command *tree_command_type; 166 octave::tree_if_command *tree_if_command_type; 167 octave::tree_if_clause *tree_if_clause_type; 168 octave::tree_if_command_list *tree_if_command_list_type; 169 octave::tree_switch_command *tree_switch_command_type; 170 octave::tree_switch_case *tree_switch_case_type; 171 octave::tree_switch_case_list *tree_switch_case_list_type; 172 octave::tree_decl_elt *tree_decl_elt_type; 173 octave::tree_decl_init_list *tree_decl_init_list_type; 174 octave::tree_decl_command *tree_decl_command_type; 175 octave::tree_statement *tree_statement_type; 176 octave::tree_statement_list *tree_statement_list_type; 177 octave_user_function *octave_user_function_type; 178 179 octave::tree_classdef *tree_classdef_type; 180 octave::tree_classdef_attribute* tree_classdef_attribute_type; 181 octave::tree_classdef_attribute_list* tree_classdef_attribute_list_type; 182 octave::tree_classdef_superclass* tree_classdef_superclass_type; 183 octave::tree_classdef_superclass_list* tree_classdef_superclass_list_type; 184 octave::tree_classdef_body* tree_classdef_body_type; 185 octave::tree_classdef_property* tree_classdef_property_type; 186 octave::tree_classdef_property_list* tree_classdef_property_list_type; 187 octave::tree_classdef_properties_block* tree_classdef_properties_block_type; 188 octave::tree_classdef_methods_list* tree_classdef_methods_list_type; 189 octave::tree_classdef_methods_block* tree_classdef_methods_block_type; 190 octave::tree_classdef_event* tree_classdef_event_type; 191 octave::tree_classdef_events_list* tree_classdef_events_list_type; 192 octave::tree_classdef_events_block* tree_classdef_events_block_type; 193 octave::tree_classdef_enum* tree_classdef_enum_type; 194 octave::tree_classdef_enum_list* tree_classdef_enum_list_type; 195 octave::tree_classdef_enum_block* tree_classdef_enum_block_type; 196} 197 198// Tokens with line and column information. 199%token <tok_val> '=' ':' '-' '+' '*' '/' 200%token <tok_val> '(' ')' '[' ']' '{' '}' '.' '@' 201%token <tok_val> ',' ';' '\n' 202%token <tok_val> ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ 203%token <tok_val> EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ AND_EQ OR_EQ 204%token <tok_val> EXPR_AND_AND EXPR_OR_OR 205%token <tok_val> EXPR_AND EXPR_OR EXPR_NOT 206%token <tok_val> EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT 207%token <tok_val> LEFTDIV EMUL EDIV ELEFTDIV EPLUS EMINUS 208%token <tok_val> HERMITIAN TRANSPOSE 209%token <tok_val> PLUS_PLUS MINUS_MINUS POW EPOW 210%token <tok_val> NUM IMAG_NUM 211%token <tok_val> STRUCT_ELT 212%token <tok_val> NAME 213%token <tok_val> END 214%token <tok_val> DQ_STRING SQ_STRING 215%token <tok_val> FOR PARFOR WHILE DO UNTIL 216%token <tok_val> IF ELSEIF ELSE 217%token <tok_val> SWITCH CASE OTHERWISE 218%token <tok_val> BREAK CONTINUE FUNC_RET 219%token <tok_val> UNWIND CLEANUP 220%token <tok_val> TRY CATCH 221%token <tok_val> GLOBAL PERSISTENT 222%token <tok_val> FCN_HANDLE 223%token <tok_val> CLASSDEF 224%token <tok_val> PROPERTIES METHODS EVENTS ENUMERATION 225%token <tok_val> METAQUERY 226%token <tok_val> SUPERCLASSREF 227%token <tok_val> FQ_IDENT 228%token <tok_val> GET SET 229%token <tok_val> FCN 230%token <tok_val> LEXICAL_ERROR 231%token <tok_val> END_OF_INPUT 232 233// Other tokens. 234%token <dummy_type> INPUT_FILE 235// %token VARARGIN VARARGOUT 236 237// Nonterminals we construct. 238%type <dummy_type> indirect_ref_op decl_param_init 239%type <dummy_type> push_fcn_symtab push_script_symtab begin_file 240%type <dummy_type> param_list_beg param_list_end stmt_begin anon_fcn_begin 241%type <dummy_type> parsing_local_fcns parse_error 242%type <comment_type> stash_comment 243%type <tok_val> function_beg classdef_beg 244%type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep 245%type <tree_type> input 246%type <tree_constant_type> string constant magic_colon 247%type <tree_anon_fcn_handle_type> anon_fcn_handle 248%type <tree_fcn_handle_type> fcn_handle 249%type <tree_matrix_type> matrix_rows 250%type <tree_cell_type> cell_rows 251%type <tree_expression_type> matrix cell 252%type <tree_expression_type> primary_expr oper_expr power_expr 253%type <tree_expression_type> simple_expr colon_expr assign_expr expression 254%type <tree_identifier_type> identifier fcn_name magic_tilde 255%type <tree_superclass_ref_type> superclass_identifier 256%type <tree_metaclass_query_type> meta_identifier 257%type <tree_index_expression_type> word_list_cmd 258%type <tree_argument_list_type> arg_list word_list assign_lhs 259%type <tree_argument_list_type> cell_or_matrix_row 260%type <tree_parameter_list_type> opt_param_list param_list 261%type <tree_parameter_list_type> param_list1 param_list2 262%type <tree_parameter_list_type> return_list return_list1 263%type <tree_command_type> command select_command loop_command 264%type <tree_command_type> jump_command except_command 265%type <tree_function_def_type> function 266%type <tree_classdef_type> classdef 267%type <tree_command_type> file 268%type <tree_if_command_type> if_command 269%type <tree_if_clause_type> elseif_clause else_clause 270%type <tree_if_command_list_type> if_cmd_list1 if_cmd_list 271%type <tree_switch_command_type> switch_command 272%type <tree_switch_case_type> switch_case default_case 273%type <tree_switch_case_list_type> case_list1 case_list 274%type <tree_decl_elt_type> decl2 param_list_elt 275%type <tree_decl_init_list_type> decl1 276%type <tree_decl_command_type> declaration 277%type <tree_statement_type> statement function_end 278%type <tree_statement_list_type> simple_list simple_list1 list list1 279%type <tree_statement_list_type> opt_list 280%type <tree_statement_list_type> opt_fcn_list fcn_list fcn_list1 281%type <tree_classdef_attribute_type> attr 282%type <tree_classdef_attribute_list_type> attr_list attr_list1 283%type <tree_classdef_superclass_type> superclass 284%type <tree_classdef_superclass_list_type> superclass_list superclass_list1 285%type <tree_classdef_body_type> class_body class_body1 286%type <tree_classdef_property_type> class_property 287%type <tree_classdef_property_list_type> property_list property_list1 288%type <tree_classdef_properties_block_type> properties_block 289%type <tree_classdef_methods_list_type> methods_list methods_list1 290%type <tree_classdef_methods_block_type> methods_block 291%type <tree_classdef_event_type> class_event 292%type <tree_classdef_events_list_type> events_list events_list1 293%type <tree_classdef_events_block_type> events_block 294%type <tree_classdef_enum_type> class_enum 295%type <tree_classdef_enum_list_type> enum_list enum_list1 296%type <tree_classdef_enum_block_type> enum_block 297%type <tree_function_def_type> method_decl method 298%type <octave_user_function_type> method_decl1 299 300// Precedence and associativity. 301%right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ 302%left EXPR_OR_OR 303%left EXPR_AND_AND 304%left EXPR_OR 305%left EXPR_AND 306%left EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT 307%left ':' 308%left '-' '+' EPLUS EMINUS 309%left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV 310%right UNARY EXPR_NOT 311%left POW EPOW HERMITIAN TRANSPOSE 312%right PLUS_PLUS MINUS_MINUS 313%left '(' '.' '{' 314 315// How to clean up if there is a parse error. We handle deleting tokens 316// and comments separately and separators are just characters. The 317// remaining items are dynamically allocated parse tree objects that 318// must be deleted. Use the wildcard case (<*>) to detect unhandled 319// cases (for example, a new semantic type is added but not handled 320// here). 321 322%destructor { } <tok_val> 323%destructor { } <punct_type> 324%destructor { } <comment_type> 325%destructor { } <> 326 327%destructor { delete $$; } <tree_type> 328%destructor { delete $$; } <tree_matrix_type> 329%destructor { delete $$; } <tree_cell_type> 330%destructor { delete $$; } <tree_expression_type> 331%destructor { delete $$; } <tree_constant_type> 332%destructor { delete $$; } <tree_fcn_handle_type> 333%destructor { delete $$; } <tree_superclass_ref_type> 334%destructor { delete $$; } <tree_metaclass_query_type> 335%destructor { delete $$; } <tree_function_def_type> 336%destructor { delete $$; } <tree_anon_fcn_handle_type> 337%destructor { delete $$; } <tree_identifier_type> 338%destructor { delete $$; } <tree_index_expression_type> 339%destructor { delete $$; } <tree_argument_list_type> 340%destructor { delete $$; } <tree_parameter_list_type> 341%destructor { delete $$; } <tree_command_type> 342%destructor { delete $$; } <tree_if_command_type> 343%destructor { delete $$; } <tree_if_clause_type> 344%destructor { delete $$; } <tree_if_command_list_type> 345%destructor { delete $$; } <tree_switch_command_type> 346%destructor { delete $$; } <tree_switch_case_type> 347%destructor { delete $$; } <tree_switch_case_list_type> 348%destructor { delete $$; } <tree_decl_elt_type> 349%destructor { delete $$; } <tree_decl_init_list_type> 350%destructor { delete $$; } <tree_decl_command_type> 351%destructor { delete $$; } <tree_statement_type> 352%destructor { delete $$; } <tree_statement_list_type> 353%destructor { delete $$; } <octave_user_function_type> 354 355%destructor { delete $$; } <tree_classdef_type> 356%destructor { delete $$; } <tree_classdef_attribute_type> 357%destructor { delete $$; } <tree_classdef_attribute_list_type> 358%destructor { delete $$; } <tree_classdef_superclass_type> 359%destructor { delete $$; } <tree_classdef_superclass_list_type> 360%destructor { delete $$; } <tree_classdef_body_type> 361%destructor { delete $$; } <tree_classdef_property_type> 362%destructor { delete $$; } <tree_classdef_property_list_type> 363%destructor { delete $$; } <tree_classdef_properties_block_type> 364%destructor { delete $$; } <tree_classdef_methods_list_type> 365%destructor { delete $$; } <tree_classdef_methods_block_type> 366%destructor { delete $$; } <tree_classdef_event_type> 367%destructor { delete $$; } <tree_classdef_events_list_type> 368%destructor { delete $$; } <tree_classdef_events_block_type> 369%destructor { delete $$; } <tree_classdef_enum_type> 370%destructor { delete $$; } <tree_classdef_enum_list_type> 371%destructor { delete $$; } <tree_classdef_enum_block_type> 372 373// Defining a generic destructor generates a warning if destructors are 374// already explicitly declared for all types. 375// 376// %destructor { 377// warning_with_id 378// ("Octave:parser-destructor", 379// "possible memory leak in cleanup following parse error"); 380// } <*> 381 382// Where to start. 383%start input 384 385%% 386 387// ============================== 388// Statements and statement lists 389// ============================== 390 391input : simple_list '\n' 392 { 393 OCTAVE_YYUSE ($2); 394 395 $$ = nullptr; 396 std::shared_ptr<octave::tree_statement_list> tmp_lst ($1); 397 parser.statement_list (tmp_lst); 398 YYACCEPT; 399 } 400 | simple_list END_OF_INPUT 401 { 402 OCTAVE_YYUSE ($2); 403 404 $$ = nullptr; 405 lexer.m_end_of_input = true; 406 std::shared_ptr<octave::tree_statement_list> tmp_lst ($1); 407 parser.statement_list (tmp_lst); 408 YYACCEPT; 409 } 410 | parse_error 411 { 412 $$ = nullptr; 413 YYABORT; 414 } 415 ; 416 417simple_list : opt_sep_no_nl 418 { 419 OCTAVE_YYUSE ($1); 420 421 $$ = nullptr; 422 } 423 | simple_list1 opt_sep_no_nl 424 { $$ = parser.set_stmt_print_flag ($1, $2, false); } 425 ; 426 427simple_list1 : statement 428 { $$ = parser.make_statement_list ($1); } 429 | simple_list1 sep_no_nl statement 430 { $$ = parser.append_statement_list ($1, $2, $3, false); } 431 ; 432 433opt_list : // empty 434 { $$ = new octave::tree_statement_list (); } 435 | list 436 { $$ = $1; } 437 ; 438 439list : list1 opt_sep 440 { $$ = parser.set_stmt_print_flag ($1, $2, true); } 441 ; 442 443list1 : statement 444 { $$ = parser.make_statement_list ($1); } 445 | list1 sep statement 446 { $$ = parser.append_statement_list ($1, $2, $3, true); } 447 ; 448 449opt_fcn_list : // empty 450 { $$ = new octave::tree_statement_list (); } 451 | fcn_list 452 { $$ = $1; } 453 ; 454 455fcn_list : fcn_list1 opt_sep 456 { 457 OCTAVE_YYUSE ($2); 458 459 $$ = $1; 460 } 461 ; 462 463fcn_list1 : function 464 { 465 octave::tree_statement *stmt = parser.make_statement ($1); 466 $$ = new octave::tree_statement_list (stmt); 467 } 468 | fcn_list1 opt_sep function 469 { 470 octave::tree_statement *stmt = parser.make_statement ($3); 471 $$ = parser.append_statement_list ($1, $2, stmt, false); 472 } 473 ; 474 475statement : expression 476 { $$ = parser.make_statement ($1); } 477 | command 478 { $$ = parser.make_statement ($1); } 479 | word_list_cmd 480 { $$ = parser.make_statement ($1); } 481 ; 482 483// ================= 484// Word-list command 485// ================= 486 487// These are not really like expressions since they can't appear on 488// the RHS of an assignment. But they are also not like commands (IF, 489// WHILE, etc. 490 491word_list_cmd : identifier word_list 492 { 493 $$ = parser.make_index_expression ($1, $2, '('); 494 if (! $$) 495 { 496 // make_index_expression deleted $1 and $2. 497 YYABORT; 498 } 499 $$->mark_word_list_cmd (); 500 } 501 ; 502 503word_list : string 504 { $$ = new octave::tree_argument_list ($1); } 505 | word_list string 506 { 507 $1->append ($2); 508 $$ = $1; 509 } 510 ; 511 512// =========== 513// Expressions 514// =========== 515 516identifier : NAME 517 { 518 $$ = new octave::tree_identifier ($1->sym_rec (), 519 $1->line (), 520 $1->column ()); 521 } 522 ; 523 524superclass_identifier 525 : SUPERCLASSREF 526 { 527 std::string meth = $1->superclass_method_name (); 528 std::string cls = $1->superclass_class_name (); 529 530 $$ = new octave::tree_superclass_ref (meth, cls, 531 $1->line (), 532 $1->column ()); 533 } 534 ; 535 536meta_identifier : METAQUERY 537 { 538 std::string cls = $1->text (); 539 540 $$ = new octave::tree_metaclass_query (cls, $1->line (), 541 $1->column ()); 542 } 543 ; 544 545string : DQ_STRING 546 { $$ = parser.make_constant (DQ_STRING, $1); } 547 | SQ_STRING 548 { $$ = parser.make_constant (SQ_STRING, $1); } 549 ; 550 551constant : NUM 552 { $$ = parser.make_constant (NUM, $1); } 553 | IMAG_NUM 554 { $$ = parser.make_constant (IMAG_NUM, $1); } 555 | string 556 { $$ = $1; } 557 ; 558 559matrix : '[' matrix_rows ']' 560 { $$ = parser.finish_matrix ($2, $1, $3); } 561 ; 562 563matrix_rows : cell_or_matrix_row 564 { $$ = $1 ? new octave::tree_matrix ($1) : nullptr; } 565 | matrix_rows ';' cell_or_matrix_row 566 { 567 OCTAVE_YYUSE ($2); 568 569 if ($1) 570 { 571 if ($3) 572 $1->append ($3); 573 574 $$ = $1; 575 } 576 else 577 $$ = $3 ? new octave::tree_matrix ($3) : nullptr; 578 } 579 ; 580 581cell : '{' cell_rows '}' 582 { $$ = parser.finish_cell ($2, $1, $3); } 583 ; 584 585cell_rows : cell_or_matrix_row 586 { $$ = $1 ? new octave::tree_cell ($1) : nullptr; } 587 | cell_rows ';' cell_or_matrix_row 588 { 589 OCTAVE_YYUSE ($2); 590 591 if ($1) 592 { 593 if ($3) 594 $1->append ($3); 595 596 $$ = $1; 597 } 598 else 599 $$ = $3 ? new octave::tree_cell ($3) : nullptr; 600 } 601 ; 602 603// tree_argument_list objects can't be empty or have leading or trailing 604// commas, but those are all allowed in matrix and cell array rows. 605 606// FIXME: is tree_argument_list the best object for this purpose, or 607// should we have a separate one intended specifically to represent the 608// list of objects that make up elements in cell and matrix expressions? 609 610cell_or_matrix_row 611 : // empty 612 { $$ = nullptr; } 613 | ',' 614 { 615 OCTAVE_YYUSE ($1); 616 617 $$ = nullptr; 618 } 619 | arg_list 620 { $$ = $1; } 621 | arg_list ',' 622 { 623 OCTAVE_YYUSE ($2); 624 625 $$ = $1; 626 } 627 | ',' arg_list 628 { 629 OCTAVE_YYUSE ($1); 630 631 $$ = $2; 632 } 633 | ',' arg_list ',' 634 { 635 OCTAVE_YYUSE ($1); 636 OCTAVE_YYUSE ($3); 637 638 $$ = $2; 639 } 640 ; 641 642fcn_handle : FCN_HANDLE 643 { $$ = parser.make_fcn_handle ($1); } 644 ; 645 646// Note that we are deliberately not setting the beginning of statement 647// flag after recognizing the parameter list because we don't want to 648// accept word list commands in anonymous function bodies. 649 650anon_fcn_handle : '@' param_list anon_fcn_begin expression 651 { 652 $$ = parser.make_anon_fcn_handle ($2, $4, $1->beg_pos ()); 653 if (! $$) 654 { 655 // make_anon_fcn_handle deleted $2 and $4. 656 YYABORT; 657 } 658 659 lexer.m_parsing_anon_fcn_body = false; 660 lexer.m_nesting_level.remove (); 661 } 662 | '@' param_list anon_fcn_begin error 663 { 664 OCTAVE_YYUSE ($1); 665 OCTAVE_YYUSE ($2); 666 667 lexer.m_parsing_anon_fcn_body = false; 668 669 $$ = nullptr; 670 parser.bison_error ("anonymous function bodies must be single expressions"); 671 YYABORT; 672 } 673 ; 674 675primary_expr : identifier 676 { $$ = $1; } 677 | constant 678 { $$ = $1; } 679 | fcn_handle 680 { $$ = $1; } 681 | matrix 682 { 683 lexer.m_looking_at_matrix_or_assign_lhs = false; 684 $$ = $1; 685 } 686 | cell 687 { $$ = $1; } 688 | meta_identifier 689 { $$ = $1; } 690 | superclass_identifier 691 { $$ = $1; } 692 | '(' expression ')' 693 { 694 OCTAVE_YYUSE ($1); 695 OCTAVE_YYUSE ($3); 696 697 $$ = $2->mark_in_parens (); 698 } 699 ; 700 701magic_colon : ':' 702 { 703 OCTAVE_YYUSE ($1); 704 705 octave_value tmp (octave_value::magic_colon_t); 706 $$ = new octave::tree_constant (tmp); 707 } 708 ; 709 710magic_tilde : EXPR_NOT 711 { 712 OCTAVE_YYUSE ($1); 713 714 $$ = new octave::tree_black_hole (); 715 } 716 ; 717 718arg_list : expression 719 { $$ = new octave::tree_argument_list ($1); } 720 | magic_colon 721 { $$ = new octave::tree_argument_list ($1); } 722 | magic_tilde 723 { $$ = new octave::tree_argument_list ($1); } 724 | arg_list ',' magic_colon 725 { 726 OCTAVE_YYUSE ($2); 727 728 $1->append ($3); 729 $$ = $1; 730 } 731 | arg_list ',' magic_tilde 732 { 733 OCTAVE_YYUSE ($2); 734 735 $1->append ($3); 736 $$ = $1; 737 } 738 | arg_list ',' expression 739 { 740 OCTAVE_YYUSE ($2); 741 742 $1->append ($3); 743 $$ = $1; 744 } 745 ; 746 747indirect_ref_op : '.' 748 { 749 OCTAVE_YYUSE ($1); 750 751 $$ = 0; 752 lexer.m_looking_at_indirect_ref = true; 753 } 754 ; 755 756oper_expr : primary_expr 757 { $$ = $1; } 758 | oper_expr PLUS_PLUS 759 { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); } 760 | oper_expr MINUS_MINUS 761 { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); } 762 | oper_expr '(' ')' 763 { 764 OCTAVE_YYUSE ($2); 765 OCTAVE_YYUSE ($3); 766 767 $$ = parser.make_index_expression ($1, nullptr, '('); 768 if (! $$) 769 { 770 // make_index_expression deleted $1. 771 YYABORT; 772 } 773 } 774 | oper_expr '(' arg_list ')' 775 { 776 OCTAVE_YYUSE ($2); 777 OCTAVE_YYUSE ($4); 778 779 $$ = parser.make_index_expression ($1, $3, '('); 780 if (! $$) 781 { 782 // make_index_expression deleted $1 and $3. 783 YYABORT; 784 } 785 } 786 | oper_expr '{' '}' 787 { 788 OCTAVE_YYUSE ($2); 789 OCTAVE_YYUSE ($3); 790 791 $$ = parser.make_index_expression ($1, nullptr, '{'); 792 if (! $$) 793 { 794 // make_index_expression deleted $1. 795 YYABORT; 796 } 797 } 798 | oper_expr '{' arg_list '}' 799 { 800 OCTAVE_YYUSE ($2); 801 OCTAVE_YYUSE ($4); 802 803 $$ = parser.make_index_expression ($1, $3, '{'); 804 if (! $$) 805 { 806 // make_index_expression deleted $1 and $3. 807 YYABORT; 808 } 809 } 810 | oper_expr HERMITIAN 811 { $$ = parser.make_postfix_op (HERMITIAN, $1, $2); } 812 | oper_expr TRANSPOSE 813 { $$ = parser.make_postfix_op (TRANSPOSE, $1, $2); } 814 | oper_expr indirect_ref_op STRUCT_ELT 815 { $$ = parser.make_indirect_ref ($1, $3->text ()); } 816 | oper_expr indirect_ref_op '(' expression ')' 817 { 818 OCTAVE_YYUSE ($3); 819 OCTAVE_YYUSE ($5); 820 821 $$ = parser.make_indirect_ref ($1, $4); 822 } 823 | PLUS_PLUS oper_expr %prec UNARY 824 { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); } 825 | MINUS_MINUS oper_expr %prec UNARY 826 { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); } 827 | EXPR_NOT oper_expr %prec UNARY 828 { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); } 829 | '+' oper_expr %prec UNARY 830 { $$ = parser.make_prefix_op ('+', $2, $1); } 831 | '-' oper_expr %prec UNARY 832 { $$ = parser.make_prefix_op ('-', $2, $1); } 833 | oper_expr POW power_expr 834 { $$ = parser.make_binary_op (POW, $1, $2, $3); } 835 | oper_expr EPOW power_expr 836 { $$ = parser.make_binary_op (EPOW, $1, $2, $3); } 837 | oper_expr '+' oper_expr 838 { $$ = parser.make_binary_op ('+', $1, $2, $3); } 839 | oper_expr '-' oper_expr 840 { $$ = parser.make_binary_op ('-', $1, $2, $3); } 841 | oper_expr '*' oper_expr 842 { $$ = parser.make_binary_op ('*', $1, $2, $3); } 843 | oper_expr '/' oper_expr 844 { $$ = parser.make_binary_op ('/', $1, $2, $3); } 845 | oper_expr EPLUS oper_expr 846 { $$ = parser.make_binary_op ('+', $1, $2, $3); } 847 | oper_expr EMINUS oper_expr 848 { $$ = parser.make_binary_op ('-', $1, $2, $3); } 849 | oper_expr EMUL oper_expr 850 { $$ = parser.make_binary_op (EMUL, $1, $2, $3); } 851 | oper_expr EDIV oper_expr 852 { $$ = parser.make_binary_op (EDIV, $1, $2, $3); } 853 | oper_expr LEFTDIV oper_expr 854 { $$ = parser.make_binary_op (LEFTDIV, $1, $2, $3); } 855 | oper_expr ELEFTDIV oper_expr 856 { $$ = parser.make_binary_op (ELEFTDIV, $1, $2, $3); } 857 ; 858 859power_expr : primary_expr 860 { $$ = $1; } 861 | power_expr PLUS_PLUS 862 { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); } 863 | power_expr MINUS_MINUS 864 { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); } 865 | power_expr '(' ')' 866 { 867 OCTAVE_YYUSE ($2); 868 OCTAVE_YYUSE ($3); 869 870 $$ = parser.make_index_expression ($1, nullptr, '('); 871 if (! $$) 872 { 873 // make_index_expression deleted $1. 874 YYABORT; 875 } 876 } 877 | power_expr '(' arg_list ')' 878 { 879 OCTAVE_YYUSE ($2); 880 OCTAVE_YYUSE ($4); 881 882 $$ = parser.make_index_expression ($1, $3, '('); 883 if (! $$) 884 { 885 // make_index_expression deleted $1 and $3. 886 YYABORT; 887 } 888 } 889 | power_expr '{' '}' 890 { 891 OCTAVE_YYUSE ($2); 892 OCTAVE_YYUSE ($3); 893 894 $$ = parser.make_index_expression ($1, nullptr, '{'); 895 if (! $$) 896 { 897 // make_index_expression deleted $1. 898 YYABORT; 899 } 900 } 901 | power_expr '{' arg_list '}' 902 { 903 OCTAVE_YYUSE ($2); 904 OCTAVE_YYUSE ($4); 905 906 $$ = parser.make_index_expression ($1, $3, '{'); 907 if (! $$) 908 { 909 // make_index_expression deleted $1 and $3. 910 YYABORT; 911 } 912 } 913 | power_expr indirect_ref_op STRUCT_ELT 914 { $$ = parser.make_indirect_ref ($1, $3->text ()); } 915 | power_expr indirect_ref_op '(' expression ')' 916 { 917 OCTAVE_YYUSE ($3); 918 OCTAVE_YYUSE ($5); 919 920 $$ = parser.make_indirect_ref ($1, $4); 921 } 922 | PLUS_PLUS power_expr %prec POW 923 { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); } 924 | MINUS_MINUS power_expr %prec POW 925 { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); } 926 | EXPR_NOT power_expr %prec POW 927 { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); } 928 | '+' power_expr %prec POW 929 { $$ = parser.make_prefix_op ('+', $2, $1); } 930 | '-' power_expr %prec POW 931 { $$ = parser.make_prefix_op ('-', $2, $1); } 932 ; 933 934colon_expr : oper_expr ':' oper_expr 935 { 936 OCTAVE_YYUSE ($2); 937 938 $$ = parser.make_colon_expression ($1, $3); 939 940 if (! $$) 941 { 942 // finish_colon_expression deleted $1 and $3. 943 YYABORT; 944 } 945 } 946 | oper_expr ':' oper_expr ':' oper_expr 947 { 948 OCTAVE_YYUSE ($2); 949 OCTAVE_YYUSE ($4); 950 951 $$ = parser.make_colon_expression ($1, $5, $3); 952 953 if (! $$) 954 { 955 // finish_colon_expression deleted $1, $3, and $5. 956 YYABORT; 957 } 958 } 959 ; 960 961simple_expr : oper_expr 962 { $$ = $1; } 963 | colon_expr 964 { $$ = $1; } 965 | simple_expr EXPR_LT simple_expr 966 { $$ = parser.make_binary_op (EXPR_LT, $1, $2, $3); } 967 | simple_expr EXPR_LE simple_expr 968 { $$ = parser.make_binary_op (EXPR_LE, $1, $2, $3); } 969 | simple_expr EXPR_EQ simple_expr 970 { $$ = parser.make_binary_op (EXPR_EQ, $1, $2, $3); } 971 | simple_expr EXPR_GE simple_expr 972 { $$ = parser.make_binary_op (EXPR_GE, $1, $2, $3); } 973 | simple_expr EXPR_GT simple_expr 974 { $$ = parser.make_binary_op (EXPR_GT, $1, $2, $3); } 975 | simple_expr EXPR_NE simple_expr 976 { $$ = parser.make_binary_op (EXPR_NE, $1, $2, $3); } 977 | simple_expr EXPR_AND simple_expr 978 { $$ = parser.make_binary_op (EXPR_AND, $1, $2, $3); } 979 | simple_expr EXPR_OR simple_expr 980 { $$ = parser.make_binary_op (EXPR_OR, $1, $2, $3); } 981 | simple_expr EXPR_AND_AND simple_expr 982 { $$ = parser.make_boolean_op (EXPR_AND_AND, $1, $2, $3); } 983 | simple_expr EXPR_OR_OR simple_expr 984 { $$ = parser.make_boolean_op (EXPR_OR_OR, $1, $2, $3); } 985 ; 986 987assign_lhs : simple_expr 988 { 989 $$ = parser.validate_matrix_for_assignment ($1); 990 991 if ($$) 992 { lexer.m_looking_at_matrix_or_assign_lhs = false; } 993 else 994 { 995 // validate_matrix_for_assignment deleted $1. 996 YYABORT; 997 } 998 } 999 ; 1000 1001assign_expr : assign_lhs '=' expression 1002 { $$ = parser.make_assign_op ('=', $1, $2, $3); } 1003 | assign_lhs ADD_EQ expression 1004 { $$ = parser.make_assign_op (ADD_EQ, $1, $2, $3); } 1005 | assign_lhs SUB_EQ expression 1006 { $$ = parser.make_assign_op (SUB_EQ, $1, $2, $3); } 1007 | assign_lhs MUL_EQ expression 1008 { $$ = parser.make_assign_op (MUL_EQ, $1, $2, $3); } 1009 | assign_lhs DIV_EQ expression 1010 { $$ = parser.make_assign_op (DIV_EQ, $1, $2, $3); } 1011 | assign_lhs LEFTDIV_EQ expression 1012 { $$ = parser.make_assign_op (LEFTDIV_EQ, $1, $2, $3); } 1013 | assign_lhs POW_EQ expression 1014 { $$ = parser.make_assign_op (POW_EQ, $1, $2, $3); } 1015 | assign_lhs EMUL_EQ expression 1016 { $$ = parser.make_assign_op (EMUL_EQ, $1, $2, $3); } 1017 | assign_lhs EDIV_EQ expression 1018 { $$ = parser.make_assign_op (EDIV_EQ, $1, $2, $3); } 1019 | assign_lhs ELEFTDIV_EQ expression 1020 { $$ = parser.make_assign_op (ELEFTDIV_EQ, $1, $2, $3); } 1021 | assign_lhs EPOW_EQ expression 1022 { $$ = parser.make_assign_op (EPOW_EQ, $1, $2, $3); } 1023 | assign_lhs AND_EQ expression 1024 { $$ = parser.make_assign_op (AND_EQ, $1, $2, $3); } 1025 | assign_lhs OR_EQ expression 1026 { $$ = parser.make_assign_op (OR_EQ, $1, $2, $3); } 1027 ; 1028 1029expression : simple_expr 1030 { 1031 if ($1 && ($1->is_matrix () || $1->iscell ())) 1032 { 1033 if (parser.validate_array_list ($1)) 1034 $$ = $1; 1035 else 1036 { 1037 delete $1; 1038 YYABORT; 1039 } 1040 } 1041 else 1042 $$ = $1; 1043 } 1044 | assign_expr 1045 { 1046 if (! $1) 1047 YYABORT; 1048 1049 $$ = $1; 1050 } 1051 | anon_fcn_handle 1052 { $$ = $1; } 1053 ; 1054 1055// ================================================ 1056// Commands, declarations, and function definitions 1057// ================================================ 1058 1059command : declaration 1060 { $$ = $1; } 1061 | select_command 1062 { $$ = $1; } 1063 | loop_command 1064 { $$ = $1; } 1065 | jump_command 1066 { $$ = $1; } 1067 | except_command 1068 { $$ = $1; } 1069 | function 1070 { $$ = $1; } 1071 | file 1072 { $$ = $1; } 1073 ; 1074 1075// ====================== 1076// Declaration statements 1077// ====================== 1078 1079declaration : GLOBAL decl1 1080 { 1081 $$ = parser.make_decl_command (GLOBAL, $1, $2); 1082 lexer.m_looking_at_decl_list = false; 1083 } 1084 | PERSISTENT decl1 1085 { 1086 $$ = parser.make_decl_command (PERSISTENT, $1, $2); 1087 lexer.m_looking_at_decl_list = false; 1088 } 1089 ; 1090 1091decl1 : decl2 1092 { $$ = new octave::tree_decl_init_list ($1); } 1093 | decl1 decl2 1094 { 1095 $1->append ($2); 1096 $$ = $1; 1097 } 1098 ; 1099 1100decl_param_init : // empty 1101 { 1102 $$ = 0; 1103 lexer.m_looking_at_initializer_expression = true; 1104 } 1105 1106decl2 : identifier 1107 { $$ = new octave::tree_decl_elt ($1); } 1108 | identifier '=' decl_param_init expression 1109 { 1110 OCTAVE_YYUSE ($2); 1111 1112 lexer.m_looking_at_initializer_expression = false; 1113 $$ = new octave::tree_decl_elt ($1, $4); 1114 } 1115 ; 1116 1117// ==================== 1118// Selection statements 1119// ==================== 1120 1121select_command : if_command 1122 { $$ = $1; } 1123 | switch_command 1124 { $$ = $1; } 1125 ; 1126 1127// ============ 1128// If statement 1129// ============ 1130 1131if_command : IF stash_comment if_cmd_list END 1132 { 1133 if (! ($$ = parser.finish_if_command ($1, $3, $4, $2))) 1134 { 1135 // finish_if_command deleted $3. 1136 YYABORT; 1137 } 1138 } 1139 ; 1140 1141if_cmd_list : if_cmd_list1 1142 { $$ = $1; } 1143 | if_cmd_list1 else_clause 1144 { 1145 $1->append ($2); 1146 $$ = $1; 1147 } 1148 ; 1149 1150if_cmd_list1 : expression stmt_begin opt_sep opt_list 1151 { 1152 OCTAVE_YYUSE ($3); 1153 1154 $1->mark_braindead_shortcircuit (); 1155 1156 $$ = parser.start_if_command ($1, $4); 1157 } 1158 | if_cmd_list1 elseif_clause 1159 { 1160 $1->append ($2); 1161 $$ = $1; 1162 } 1163 ; 1164 1165elseif_clause : ELSEIF stash_comment opt_sep expression stmt_begin opt_sep opt_list 1166 { 1167 OCTAVE_YYUSE ($3); 1168 OCTAVE_YYUSE ($6); 1169 1170 $4->mark_braindead_shortcircuit (); 1171 1172 $$ = parser.make_elseif_clause ($1, $4, $7, $2); 1173 } 1174 ; 1175 1176else_clause : ELSE stash_comment opt_sep opt_list 1177 { 1178 OCTAVE_YYUSE ($1); 1179 OCTAVE_YYUSE ($3); 1180 1181 $$ = new octave::tree_if_clause ($4, $2); 1182 } 1183 ; 1184 1185// ================ 1186// Switch statement 1187// ================ 1188 1189switch_command : SWITCH stash_comment expression opt_sep case_list END 1190 { 1191 OCTAVE_YYUSE ($4); 1192 1193 if (! ($$ = parser.finish_switch_command ($1, $3, $5, $6, $2))) 1194 { 1195 // finish_switch_command deleted $3 adn $5. 1196 YYABORT; 1197 } 1198 } 1199 ; 1200 1201case_list : // empty 1202 { $$ = new octave::tree_switch_case_list (); } 1203 | default_case 1204 { $$ = new octave::tree_switch_case_list ($1); } 1205 | case_list1 1206 { $$ = $1; } 1207 | case_list1 default_case 1208 { 1209 $1->append ($2); 1210 $$ = $1; 1211 } 1212 ; 1213 1214case_list1 : switch_case 1215 { $$ = new octave::tree_switch_case_list ($1); } 1216 | case_list1 switch_case 1217 { 1218 $1->append ($2); 1219 $$ = $1; 1220 } 1221 ; 1222 1223switch_case : CASE stash_comment opt_sep expression stmt_begin opt_sep opt_list 1224 { 1225 OCTAVE_YYUSE ($3); 1226 OCTAVE_YYUSE ($6); 1227 1228 $$ = parser.make_switch_case ($1, $4, $7, $2); 1229 } 1230 ; 1231 1232default_case : OTHERWISE stash_comment opt_sep opt_list 1233 { 1234 OCTAVE_YYUSE ($1); 1235 OCTAVE_YYUSE ($3); 1236 1237 $$ = new octave::tree_switch_case ($4, $2); 1238 } 1239 ; 1240 1241// ======= 1242// Looping 1243// ======= 1244 1245loop_command : WHILE stash_comment expression stmt_begin opt_sep opt_list END 1246 { 1247 OCTAVE_YYUSE ($5); 1248 1249 $3->mark_braindead_shortcircuit (); 1250 1251 if (! ($$ = parser.make_while_command ($1, $3, $6, $7, $2))) 1252 { 1253 // make_while_command deleted $3 and $6. 1254 YYABORT; 1255 } 1256 } 1257 | DO stash_comment opt_sep opt_list UNTIL expression 1258 { 1259 OCTAVE_YYUSE ($1); 1260 OCTAVE_YYUSE ($3); 1261 1262 $$ = parser.make_do_until_command ($5, $4, $6, $2); 1263 } 1264 | FOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END 1265 { 1266 OCTAVE_YYUSE ($4); 1267 OCTAVE_YYUSE ($7); 1268 1269 if (! ($$ = parser.make_for_command (FOR, $1, $3, $5, 1270 nullptr, $8, $9, $2))) 1271 { 1272 // make_for_command deleted $3, $5, and $8. 1273 YYABORT; 1274 } 1275 } 1276 | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END 1277 { 1278 OCTAVE_YYUSE ($3); 1279 OCTAVE_YYUSE ($5); 1280 OCTAVE_YYUSE ($7); 1281 OCTAVE_YYUSE ($8); 1282 1283 if (! ($$ = parser.make_for_command (FOR, $1, $4, $6, 1284 nullptr, $9, $10, $2))) 1285 { 1286 // make_for_command deleted $4, $6, and $9. 1287 YYABORT; 1288 } 1289 } 1290 | PARFOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END 1291 { 1292 OCTAVE_YYUSE ($4); 1293 OCTAVE_YYUSE ($7); 1294 1295 if (! ($$ = parser.make_for_command (PARFOR, $1, $3, $5, 1296 nullptr, $8, $9, $2))) 1297 { 1298 // make_for_command deleted $3, $5, and $8. 1299 YYABORT; 1300 } 1301 } 1302 | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END 1303 { 1304 OCTAVE_YYUSE ($3); 1305 OCTAVE_YYUSE ($5); 1306 OCTAVE_YYUSE ($7); 1307 OCTAVE_YYUSE ($9); 1308 OCTAVE_YYUSE ($10); 1309 1310 if (! ($$ = parser.make_for_command (PARFOR, $1, $4, $6, 1311 $8, $11, $12, $2))) 1312 { 1313 // make_for_command deleted $4, $6, $8, and $11. 1314 YYABORT; 1315 } 1316 } 1317 ; 1318 1319// ======= 1320// Jumping 1321// ======= 1322 1323jump_command : BREAK 1324 { 1325 if (! ($$ = parser.make_break_command ($1))) 1326 YYABORT; 1327 } 1328 | CONTINUE 1329 { 1330 if (! ($$ = parser.make_continue_command ($1))) 1331 YYABORT; 1332 } 1333 | FUNC_RET 1334 { $$ = parser.make_return_command ($1); } 1335 ; 1336 1337// ========== 1338// Exceptions 1339// ========== 1340 1341except_command : UNWIND stash_comment opt_sep opt_list CLEANUP 1342 stash_comment opt_sep opt_list END 1343 { 1344 OCTAVE_YYUSE ($3); 1345 OCTAVE_YYUSE ($5); 1346 OCTAVE_YYUSE ($7); 1347 1348 if (! ($$ = parser.make_unwind_command ($1, $4, $8, $9, $2, $6))) 1349 { 1350 // make_unwind_command deleted $4 and $8. 1351 YYABORT; 1352 } 1353 } 1354 | TRY stash_comment opt_sep opt_list CATCH stash_comment 1355 opt_sep opt_list END 1356 { 1357 OCTAVE_YYUSE ($3); 1358 OCTAVE_YYUSE ($5); 1359 OCTAVE_YYUSE ($7); 1360 1361 if (! ($$ = parser.make_try_command ($1, $4, $7, $8, $9, $2, $6))) 1362 { 1363 // make_try_command deleted $4 and $8. 1364 YYABORT; 1365 } 1366 } 1367 | TRY stash_comment opt_sep opt_list END 1368 { 1369 OCTAVE_YYUSE ($3); 1370 1371 if (! ($$ = parser.make_try_command ($1, $4, 0, nullptr, 1372 $5, $2, nullptr))) 1373 { 1374 // make_try_command deleted $4. 1375 YYABORT; 1376 } 1377 } 1378 ; 1379 1380// =========================================== 1381// Some 'subroutines' for function definitions 1382// =========================================== 1383 1384push_fcn_symtab : // empty 1385 { 1386 if (! parser.push_fcn_symtab ()) 1387 YYABORT; 1388 1389 $$ = 0; 1390 } 1391 ; 1392 1393// =========================== 1394// List of function parameters 1395// =========================== 1396 1397param_list_beg : '(' 1398 { 1399 OCTAVE_YYUSE ($1); 1400 1401 $$ = 0; 1402 lexer.m_looking_at_parameter_list = true; 1403 1404 if (lexer.m_looking_at_function_handle) 1405 { 1406 // Will get a real name later. 1407 lexer.m_symtab_context.push (octave::symbol_scope ("parser:param_lsit_beg")); 1408 lexer.m_looking_at_function_handle--; 1409 lexer.m_looking_at_anon_fcn_args = true; 1410 } 1411 } 1412 ; 1413 1414param_list_end : ')' 1415 { 1416 OCTAVE_YYUSE ($1); 1417 1418 $$ = 0; 1419 lexer.m_looking_at_parameter_list = false; 1420 lexer.m_looking_for_object_index = false; 1421 } 1422 ; 1423 1424opt_param_list : // empty 1425 { $$ = nullptr; } 1426 | param_list 1427 { $$ = $1; } 1428 ; 1429 1430param_list : param_list_beg param_list1 param_list_end 1431 { 1432 if ($2) 1433 lexer.mark_as_variables ($2->variable_names ()); 1434 1435 $$ = $2; 1436 } 1437 | param_list_beg error 1438 { 1439 $$ = nullptr; 1440 parser.bison_error ("invalid parameter list"); 1441 YYABORT; 1442 } 1443 ; 1444 1445param_list1 : // empty 1446 { $$ = new octave::tree_parameter_list (octave::tree_parameter_list::in); } 1447 | param_list2 1448 { 1449 $1->mark_as_formal_parameters (); 1450 1451 if (parser.validate_param_list ($1, octave::tree_parameter_list::in)) 1452 { 1453 lexer.mark_as_variables ($1->variable_names ()); 1454 $$ = $1; 1455 } 1456 else 1457 { 1458 delete $1; 1459 YYABORT; 1460 } 1461 } 1462 ; 1463 1464param_list2 : param_list_elt 1465 { $$ = new octave::tree_parameter_list (octave::tree_parameter_list::in, $1); } 1466 | param_list2 ',' param_list_elt 1467 { 1468 OCTAVE_YYUSE ($2); 1469 1470 $1->append ($3); 1471 $$ = $1; 1472 } 1473 ; 1474 1475param_list_elt : decl2 1476 { $$ = $1; } 1477 | magic_tilde 1478 { $$ = new octave::tree_decl_elt ($1); } 1479 ; 1480 1481// =================================== 1482// List of function return value names 1483// =================================== 1484 1485return_list : '[' ']' 1486 { 1487 OCTAVE_YYUSE ($1); 1488 OCTAVE_YYUSE ($2); 1489 1490 lexer.m_looking_at_return_list = false; 1491 1492 $$ = new octave::tree_parameter_list (octave::tree_parameter_list::out); 1493 } 1494 | identifier 1495 { 1496 lexer.m_looking_at_return_list = false; 1497 1498 octave::tree_parameter_list *tmp 1499 = new octave::tree_parameter_list (octave::tree_parameter_list::out, $1); 1500 1501 // Even though this parameter list can contain only 1502 // a single identifier, we still need to validate it 1503 // to check for varargin or varargout. 1504 1505 if (parser.validate_param_list (tmp, octave::tree_parameter_list::out)) 1506 $$ = tmp; 1507 else 1508 { 1509 delete tmp; 1510 YYABORT; 1511 } 1512 } 1513 | '[' return_list1 ']' 1514 { 1515 OCTAVE_YYUSE ($1); 1516 OCTAVE_YYUSE ($3); 1517 1518 lexer.m_looking_at_return_list = false; 1519 1520 // Check for duplicate parameter names, varargin, 1521 // or varargout. 1522 1523 if (parser.validate_param_list ($2, octave::tree_parameter_list::out)) 1524 $$ = $2; 1525 else 1526 { 1527 delete $2; 1528 YYABORT; 1529 } 1530 } 1531 ; 1532 1533return_list1 : identifier 1534 { 1535 $$ = new octave::tree_parameter_list (octave::tree_parameter_list::out, new octave::tree_decl_elt ($1)); 1536 } 1537 | return_list1 ',' identifier 1538 { 1539 OCTAVE_YYUSE ($2); 1540 1541 $1->append (new octave::tree_decl_elt ($3)); 1542 $$ = $1; 1543 } 1544 ; 1545 1546// ======================= 1547// Script or function file 1548// ======================= 1549 1550parsing_local_fcns 1551 : // empty 1552 { parser.parsing_local_functions (true); } 1553 ; 1554 1555push_script_symtab : // empty 1556 { 1557 $$ = 0; 1558 1559 // This scope may serve as the parent scope for local 1560 // functions in classdef files.. 1561 lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_script_symtab")); 1562 } 1563 ; 1564 1565begin_file : push_script_symtab INPUT_FILE 1566 { $$ = 0; } 1567 ; 1568 1569file : begin_file opt_nl opt_list END_OF_INPUT 1570 { 1571 OCTAVE_YYUSE ($2); 1572 1573 if (lexer.m_reading_fcn_file) 1574 { 1575 // Delete the dummy statement_list we created 1576 // after parsing the function. Any function 1577 // definitions found in the file have already 1578 // been stored in the symbol table or in 1579 // base_parser::m_primary_fcn. 1580 1581 // Unused symbol table context. 1582 lexer.m_symtab_context.pop (); 1583 1584 delete $3; 1585 } 1586 else 1587 { 1588 octave::tree_statement *end_of_script 1589 = parser.make_end ("endscript", true, 1590 $4->beg_pos (), $4->end_pos ()); 1591 1592 parser.make_script ($3, end_of_script); 1593 } 1594 1595 $$ = nullptr; 1596 } 1597 | begin_file opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT 1598 { 1599 OCTAVE_YYUSE ($2); 1600 OCTAVE_YYUSE ($5); 1601 OCTAVE_YYUSE ($7); 1602 1603 // Unused symbol table context. 1604 lexer.m_symtab_context.pop (); 1605 1606 parser.finish_classdef_file ($3, $6); 1607 1608 $$ = nullptr; 1609 } 1610 ; 1611 1612// =================== 1613// Function definition 1614// =================== 1615 1616function_beg : push_fcn_symtab FCN 1617 { 1618 $$ = $2; 1619 if (lexer.m_reading_classdef_file 1620 || lexer.m_parsing_classdef) 1621 lexer.m_maybe_classdef_get_set_method = true; 1622 } 1623 ; 1624 1625fcn_name : identifier 1626 { 1627 $$ = parser.make_fcn_name ($1); 1628 if (! $$) 1629 { 1630 // make_fcn_name deleted $1. 1631 YYABORT; 1632 } 1633 } 1634 | GET '.' identifier 1635 { 1636 OCTAVE_YYUSE ($1); 1637 OCTAVE_YYUSE ($2); 1638 1639 lexer.m_parsed_function_name.top () = true; 1640 lexer.m_maybe_classdef_get_set_method = false; 1641 lexer.m_parsing_classdef_get_method = true; 1642 $$ = $3; 1643 } 1644 | SET '.' identifier 1645 { 1646 OCTAVE_YYUSE ($1); 1647 OCTAVE_YYUSE ($2); 1648 1649 lexer.m_parsed_function_name.top () = true; 1650 lexer.m_maybe_classdef_get_set_method = false; 1651 lexer.m_parsing_classdef_set_method = true; 1652 $$ = $3; 1653 } 1654 ; 1655 1656function_end : END 1657 { 1658 parser.endfunction_found (true); 1659 1660 if (parser.end_token_ok ($1, octave::token::function_end)) 1661 $$ = parser.make_end ("endfunction", false, 1662 $1->beg_pos (), $1->end_pos ()); 1663 else 1664 { 1665 parser.end_token_error ($1, octave::token::function_end); 1666 YYABORT; 1667 } 1668 } 1669 | END_OF_INPUT 1670 { 1671// A lot of tests are based on the assumption that this is OK 1672// if (lexer.m_reading_script_file) 1673// { 1674// parser.bison_error ("function body open at end of script"); 1675// YYABORT; 1676// } 1677 1678 if (parser.endfunction_found ()) 1679 { 1680 parser.bison_error ("inconsistent function endings -- " 1681 "if one function is explicitly ended, " 1682 "so must all the others"); 1683 YYABORT; 1684 } 1685 1686 if (! (lexer.m_reading_fcn_file || lexer.m_reading_script_file 1687 || lexer.input_from_eval_string ())) 1688 { 1689 parser.bison_error ("function body open at end of input"); 1690 YYABORT; 1691 } 1692 1693 if (lexer.m_reading_classdef_file) 1694 { 1695 parser.bison_error ("classdef body open at end of input"); 1696 YYABORT; 1697 } 1698 1699 $$ = parser.make_end ("endfunction", true, 1700 $1->beg_pos (), $1->end_pos ()); 1701 } 1702 ; 1703 1704function : function_beg stash_comment fcn_name 1705 opt_param_list opt_sep opt_list function_end 1706 { 1707 OCTAVE_YYUSE ($5); 1708 1709 $$ = parser.make_function ($1, nullptr, $3, $4, $6, $7, $2); 1710 } 1711 | function_beg stash_comment return_list '=' fcn_name 1712 opt_param_list opt_sep opt_list function_end 1713 { 1714 OCTAVE_YYUSE ($4); 1715 OCTAVE_YYUSE ($7); 1716 1717 $$ = parser.make_function ($1, $3, $5, $6, $8, $9, $2); 1718 } 1719 ; 1720 1721// ======== 1722// Classdef 1723// ======== 1724 1725classdef_beg : CLASSDEF 1726 { 1727 if (! lexer.m_reading_classdef_file) 1728 { 1729 parser.bison_error ("classdef must appear inside a file containing only a class definition"); 1730 YYABORT; 1731 } 1732 1733 // Create invalid parent scope. 1734 lexer.m_symtab_context.push (octave::symbol_scope ()); 1735 lexer.m_parsing_classdef = true; 1736 lexer.m_parsing_classdef_decl = true; 1737 1738 $$ = $1; 1739 } 1740 ; 1741 1742classdef : classdef_beg stash_comment attr_list identifier opt_sep superclass_list class_body END 1743 { 1744 OCTAVE_YYUSE ($5); 1745 1746 octave::comment_list *lc = $2; 1747 octave::comment_list *tc = lexer.get_comment (); 1748 1749 lexer.m_parsing_classdef = false; 1750 1751 if (! ($$ = parser.make_classdef ($1, $3, $4, $6, $7, $8, 1752 lc, tc))) 1753 { 1754 // make_classdef deleted $3, $4, $6, $7, LC, and 1755 // TC. 1756 YYABORT; 1757 } 1758 } 1759 ; 1760 1761attr_list : // empty 1762 { $$ = nullptr; } 1763 | '(' attr_list1 ')' opt_sep 1764 { 1765 OCTAVE_YYUSE ($1); 1766 OCTAVE_YYUSE ($3); 1767 OCTAVE_YYUSE ($4); 1768 1769 $$ = $2; 1770 } 1771 ; 1772 1773attr_list1 : attr 1774 { $$ = new octave::tree_classdef_attribute_list ($1); } 1775 | attr_list1 ',' attr 1776 { 1777 OCTAVE_YYUSE ($2); 1778 1779 $1->append ($3); 1780 $$ = $1; 1781 } 1782 ; 1783 1784attr : identifier 1785 { $$ = new octave::tree_classdef_attribute ($1); } 1786 | identifier '=' decl_param_init expression 1787 { 1788 OCTAVE_YYUSE ($2); 1789 1790 lexer.m_looking_at_initializer_expression = false; 1791 $$ = new octave::tree_classdef_attribute ($1, $4); 1792 } 1793 | EXPR_NOT identifier 1794 { 1795 OCTAVE_YYUSE ($1); 1796 1797 $$ = new octave::tree_classdef_attribute ($2, false); 1798 } 1799 ; 1800 1801superclass_list : // empty 1802 { 1803 lexer.m_parsing_classdef_decl = false; 1804 lexer.m_parsing_classdef_superclass = false; 1805 1806 $$ = nullptr; 1807 } 1808 | superclass_list1 opt_sep 1809 { 1810 OCTAVE_YYUSE ($2); 1811 1812 lexer.m_parsing_classdef_decl = false; 1813 lexer.m_parsing_classdef_superclass = false; 1814 1815 $$ = $1; 1816 } 1817 ; 1818 1819superclass_list1 1820 : EXPR_LT superclass 1821 { 1822 OCTAVE_YYUSE ($1); 1823 1824 $$ = new octave::tree_classdef_superclass_list ($2); 1825 } 1826 | superclass_list1 EXPR_AND superclass 1827 { 1828 OCTAVE_YYUSE ($2); 1829 1830 $1->append ($3); 1831 $$ = $1; 1832 } 1833 ; 1834 1835superclass : FQ_IDENT 1836 { $$ = new octave::tree_classdef_superclass ($1->text ()); } 1837 ; 1838 1839class_body : // empty 1840 { $$ = nullptr; } 1841 | class_body1 opt_sep 1842 { 1843 OCTAVE_YYUSE ($2); 1844 1845 $$ = $1; 1846 } 1847 ; 1848 1849class_body1 : properties_block 1850 { $$ = new octave::tree_classdef_body ($1); } 1851 | methods_block 1852 { $$ = new octave::tree_classdef_body ($1); } 1853 | events_block 1854 { $$ = new octave::tree_classdef_body ($1); } 1855 | enum_block 1856 { $$ = new octave::tree_classdef_body ($1); } 1857 | class_body1 opt_sep properties_block 1858 { 1859 OCTAVE_YYUSE ($2); 1860 1861 $1->append ($3); 1862 $$ = $1; 1863 } 1864 | class_body1 opt_sep methods_block 1865 { 1866 OCTAVE_YYUSE ($2); 1867 1868 $1->append ($3); 1869 $$ = $1; 1870 } 1871 | class_body1 opt_sep events_block 1872 { 1873 OCTAVE_YYUSE ($2); 1874 1875 $1->append ($3); 1876 $$ = $1; 1877 } 1878 | class_body1 opt_sep enum_block 1879 { 1880 OCTAVE_YYUSE ($2); 1881 1882 $1->append ($3); 1883 $$ = $1; 1884 } 1885 ; 1886 1887properties_block 1888 : PROPERTIES stash_comment opt_sep attr_list property_list END 1889 { 1890 OCTAVE_YYUSE ($3); 1891 1892 octave::comment_list *lc = $2; 1893 octave::comment_list *tc = lexer.get_comment (); 1894 1895 if (! ($$ = parser.make_classdef_properties_block 1896 ($1, $4, $5, $6, lc, tc))) 1897 { 1898 // make_classdef_properties_block deleted $4, 1899 // $5, LC, and TC. 1900 YYABORT; 1901 } 1902 } 1903 ; 1904 1905property_list : // empty 1906 { $$ = nullptr; } 1907 | property_list1 opt_sep 1908 { 1909 OCTAVE_YYUSE ($2); 1910 1911 $$ = $1; 1912 } 1913 ; 1914 1915property_list1 1916 : class_property 1917 { $$ = new octave::tree_classdef_property_list ($1); } 1918 | property_list1 sep class_property 1919 { 1920 OCTAVE_YYUSE ($2); 1921 1922 // We don't look ahead to grab end-of-line comments. 1923 // Instead, they are grabbed when we see the 1924 // identifier that becomes the next element in the 1925 // list. If the element at the end of the list 1926 // doesn't have a doc string, see whether the 1927 // element we are adding is stroing an end-of-line 1928 // comment for us to use. 1929 1930 octave::tree_classdef_property *last_elt = $1->back (); 1931 1932 if (! last_elt->have_doc_string ()) 1933 { 1934 octave::comment_list *cl = $3->comments (); 1935 1936 if (cl) 1937 { 1938 octave::comment_elt elt = cl->front (); 1939 1940 if (elt.is_end_of_line ()) 1941 last_elt->doc_string (elt.text ()); 1942 } 1943 } 1944 1945 $1->append ($3); 1946 $$ = $1; 1947 } 1948 ; 1949 1950class_property : stash_comment identifier 1951 { 1952 $$ = new octave::tree_classdef_property ($2, $1); 1953 } 1954 | stash_comment identifier '=' decl_param_init expression 1955 { 1956 OCTAVE_YYUSE ($3); 1957 1958 lexer.m_looking_at_initializer_expression = false; 1959 1960 $$ = new octave::tree_classdef_property ($2, $5, $1); 1961 } 1962 ; 1963 1964methods_block : METHODS stash_comment opt_sep attr_list methods_list END 1965 { 1966 OCTAVE_YYUSE ($3); 1967 1968 octave::comment_list *lc = $2; 1969 octave::comment_list *tc = lexer.get_comment (); 1970 1971 if (! ($$ = parser.make_classdef_methods_block 1972 ($1, $4, $5, $6, lc, tc))) 1973 { 1974 // make_classdef_methods_block deleted $4, $5, 1975 // LC, and TC. 1976 YYABORT; 1977 } 1978 } 1979 ; 1980 1981method_decl1 : identifier 1982 { 1983 if (! ($$ = parser.start_classdef_external_method ($1, nullptr))) 1984 YYABORT; 1985 } 1986 | identifier param_list 1987 { 1988 if (! ($$ = parser.start_classdef_external_method ($1, $2))) 1989 YYABORT; 1990 } 1991 ; 1992 1993method_decl : stash_comment method_decl1 1994 { $$ = parser.finish_classdef_external_method ($2, nullptr, $1); } 1995 | stash_comment return_list '=' 1996 { 1997 OCTAVE_YYUSE ($3); 1998 1999 lexer.m_defining_func++; 2000 lexer.m_parsed_function_name.push (false); 2001 } 2002 method_decl1 2003 { 2004 lexer.m_defining_func--; 2005 lexer.m_parsed_function_name.pop (); 2006 2007 $$ = parser.finish_classdef_external_method ($5, $2, $1); 2008 } 2009 ; 2010 2011method : method_decl 2012 { $$ = $1; } 2013 | function 2014 { $$ = $1; } 2015 ; 2016 2017methods_list : // empty 2018 { $$ = nullptr; } 2019 | methods_list1 opt_sep 2020 { 2021 OCTAVE_YYUSE ($2); 2022 2023 $$ = $1; 2024 } 2025 ; 2026 2027methods_list1 : method 2028 { 2029 octave_value fcn; 2030 if ($1) 2031 fcn = $1->function (); 2032 delete $1; 2033 $$ = new octave::tree_classdef_methods_list (fcn); 2034 } 2035 | methods_list1 opt_sep method 2036 { 2037 OCTAVE_YYUSE ($2); 2038 2039 octave_value fcn; 2040 if ($3) 2041 fcn = $3->function (); 2042 delete $3; 2043 2044 $1->append (fcn); 2045 $$ = $1; 2046 } 2047 ; 2048 2049events_block : EVENTS stash_comment opt_sep attr_list events_list END 2050 { 2051 OCTAVE_YYUSE ($3); 2052 2053 octave::comment_list *lc = $2; 2054 octave::comment_list *tc = lexer.get_comment (); 2055 2056 if (! ($$ = parser.make_classdef_events_block 2057 ($1, $4, $5, $6, lc, tc))) 2058 { 2059 // make_classdef_events_block deleted $4, $5, 2060 // LC, and TC. 2061 YYABORT; 2062 } 2063 } 2064 ; 2065 2066events_list : // empty 2067 { $$ = nullptr; } 2068 | events_list1 opt_sep 2069 { 2070 OCTAVE_YYUSE ($2); 2071 2072 $$ = $1; 2073 } 2074 ; 2075 2076events_list1 : class_event 2077 { $$ = new octave::tree_classdef_events_list ($1); } 2078 | events_list1 opt_sep class_event 2079 { 2080 OCTAVE_YYUSE ($2); 2081 2082 $1->append ($3); 2083 $$ = $1; 2084 } 2085 ; 2086 2087class_event : stash_comment identifier 2088 { $$ = new octave::tree_classdef_event ($2, $1); } 2089 ; 2090 2091enum_block : ENUMERATION stash_comment opt_sep attr_list enum_list END 2092 { 2093 OCTAVE_YYUSE ($3); 2094 2095 octave::comment_list *lc = $2; 2096 octave::comment_list *tc = lexer.get_comment (); 2097 2098 if (! ($$ = parser.make_classdef_enum_block 2099 ($1, $4, $5, $6, lc, tc))) 2100 { 2101 // make_classdef_enum_block deleted $4, $5, LC, 2102 // and TC. 2103 YYABORT; 2104 } 2105 } 2106 ; 2107 2108enum_list : // empty 2109 { $$ = nullptr; } 2110 | enum_list1 opt_sep 2111 { 2112 OCTAVE_YYUSE ($2); 2113 2114 $$ = $1; 2115 } 2116 ; 2117 2118enum_list1 : class_enum 2119 { $$ = new octave::tree_classdef_enum_list ($1); } 2120 | enum_list1 opt_sep class_enum 2121 { 2122 OCTAVE_YYUSE ($2); 2123 2124 $1->append ($3); 2125 $$ = $1; 2126 } 2127 ; 2128 2129class_enum : stash_comment identifier '(' expression ')' 2130 { 2131 OCTAVE_YYUSE ($3); 2132 OCTAVE_YYUSE ($5); 2133 2134 $$ = new octave::tree_classdef_enum ($2, $4, $1); 2135 } 2136 ; 2137 2138// ============= 2139// Miscellaneous 2140// ============= 2141 2142stmt_begin : // empty 2143 { 2144 $$ = 0; 2145 lexer.m_at_beginning_of_statement = true; 2146 } 2147 ; 2148 2149anon_fcn_begin : // empty 2150 { 2151 $$ = 0; 2152 lexer.m_at_beginning_of_statement = true; 2153 lexer.m_parsing_anon_fcn_body = true; 2154 } 2155 ; 2156 2157stash_comment : // empty 2158 { $$ = lexer.get_comment (); } 2159 ; 2160 2161parse_error : LEXICAL_ERROR 2162 { 2163 $$ = 0; 2164 std::string msg = $1->text (); 2165 parser.bison_error (msg.c_str ()); 2166 } 2167 | error 2168 { $$ = 0; } 2169 ; 2170 2171sep_no_nl : ',' 2172 { 2173 OCTAVE_YYUSE ($1); 2174 2175 $$ = ','; 2176 } 2177 | ';' 2178 { 2179 OCTAVE_YYUSE ($1); 2180 2181 $$ = ';'; 2182 } 2183 | sep_no_nl ',' 2184 { 2185 OCTAVE_YYUSE ($2); 2186 2187 $$ = $1; 2188 } 2189 | sep_no_nl ';' 2190 { 2191 OCTAVE_YYUSE ($2); 2192 2193 $$ = $1; 2194 } 2195 ; 2196 2197opt_sep_no_nl : // empty 2198 { $$ = 0; } 2199 | sep_no_nl 2200 { $$ = $1; } 2201 ; 2202 2203opt_nl : // empty 2204 { $$ = 0; } 2205 | nl 2206 { $$ = $1; } 2207 ; 2208 2209nl : '\n' 2210 { 2211 OCTAVE_YYUSE ($1); 2212 2213 $$ = '\n'; 2214 } 2215 | nl '\n' 2216 { 2217 OCTAVE_YYUSE ($2); 2218 2219 $$ = $1; 2220 } 2221 ; 2222 2223sep : ',' 2224 { 2225 OCTAVE_YYUSE ($1); 2226 2227 $$ = ','; 2228 } 2229 | ';' 2230 { 2231 OCTAVE_YYUSE ($1); 2232 2233 $$ = ';'; 2234 } 2235 | '\n' 2236 { 2237 OCTAVE_YYUSE ($1); 2238 2239 $$ = '\n'; 2240 } 2241 | sep ',' 2242 { 2243 OCTAVE_YYUSE ($2); 2244 2245 $$ = $1; 2246 } 2247 | sep ';' 2248 { 2249 OCTAVE_YYUSE ($2); 2250 2251 $$ = $1; 2252 } 2253 | sep '\n' 2254 { 2255 OCTAVE_YYUSE ($2); 2256 2257 $$ = $1; 2258 } 2259 ; 2260 2261opt_sep : // empty 2262 { $$ = 0; } 2263 | sep 2264 { $$ = $1; } 2265 ; 2266 2267%% 2268 2269#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) 2270 // Restore prevailing warning state for remainder of the file. 2271# pragma GCC diagnostic pop 2272#endif 2273 2274// Generic error messages. 2275 2276#undef lexer 2277#undef scanner 2278 2279static void 2280yyerror (octave::base_parser& parser, const char *s) 2281{ 2282 parser.bison_error (s); 2283} 2284 2285namespace octave 2286{ 2287 std::size_t 2288 base_parser::parent_scope_info::size (void) const 2289 { 2290 return m_info.size (); 2291 } 2292 2293 void 2294 base_parser::parent_scope_info::push (const value_type& elt) 2295 { 2296 m_info.push_back (elt); 2297 } 2298 2299 void 2300 base_parser::parent_scope_info::push (const symbol_scope& scope) 2301 { 2302 push (value_type (scope, "")); 2303 } 2304 2305 void 2306 base_parser::parent_scope_info::pop (void) 2307 { 2308 m_info.pop_back (); 2309 } 2310 2311 bool 2312 base_parser::parent_scope_info::name_ok (const std::string& name) 2313 { 2314 // Name can't be the same as any parent function or any other 2315 // function we've already seen. We could maintain a complex 2316 // tree structure of names, or we can just store the set of 2317 // full names of all the functions, which must be unique. 2318 2319 std::string full_name; 2320 2321 for (std::size_t i = 0; i < size()-1; i++) 2322 { 2323 const value_type& elt = m_info[i]; 2324 2325 if (name == elt.second) 2326 return false; 2327 2328 full_name += elt.second + ">"; 2329 } 2330 2331 full_name += name; 2332 2333 if (m_all_names.find (full_name) != m_all_names.end ()) 2334 { 2335 // Return false (failure) if we are parsing a subfunction, local 2336 // function, or nested function. Otherwise, it is OK to have a 2337 // duplicate name. 2338 2339 return ! (m_parser.parsing_subfunctions () 2340 || m_parser.parsing_local_functions () 2341 || m_parser.curr_fcn_depth () > 0); 2342 } 2343 2344 m_all_names.insert (full_name); 2345 2346 return true; 2347 } 2348 2349 bool 2350 base_parser::parent_scope_info::name_current_scope (const std::string& name) 2351 { 2352 if (! name_ok (name)) 2353 return false; 2354 2355 if (size () > 0) 2356 m_info.back().second = name; 2357 2358 return true; 2359 } 2360 2361 symbol_scope 2362 base_parser::parent_scope_info::parent_scope (void) const 2363 { 2364 return size () > 1 ? m_info[size()-2].first : symbol_scope (); 2365 } 2366 2367 std::string 2368 base_parser::parent_scope_info::parent_name (void) const 2369 { 2370 return m_info[size()-2].second; 2371 } 2372 2373 void base_parser::parent_scope_info::clear (void) 2374 { 2375 m_info.clear (); 2376 m_all_names.clear (); 2377 } 2378 2379 base_parser::base_parser (base_lexer& lxr) 2380 : m_endfunction_found (false), m_autoloading (false), 2381 m_fcn_file_from_relative_lookup (false), 2382 m_parsing_subfunctions (false), m_parsing_local_functions (false), 2383 m_max_fcn_depth (-1), m_curr_fcn_depth (-1), m_primary_fcn_scope (), 2384 m_curr_class_name (), m_curr_package_name (), m_function_scopes (*this), 2385 m_primary_fcn (), m_subfunction_names (), m_classdef_object (), 2386 m_stmt_list (), m_lexer (lxr), m_parser_state (yypstate_new ()) 2387 { } 2388 2389 base_parser::~base_parser (void) 2390 { 2391 delete &m_lexer; 2392 2393 // FIXME: Deleting the internal Bison parser state structure does 2394 // not clean up any partial parse trees in the event of an interrupt or 2395 // error. It's not clear how to safely do that with the C language 2396 // parser that Bison generates. The C++ language parser that Bison 2397 // generates would do it for us automatically whenever an exception 2398 // is thrown while parsing input, but there is currently no C++ 2399 // interface for a push parser. 2400 2401 yypstate_delete (static_cast<yypstate *> (m_parser_state)); 2402 } 2403 2404 void 2405 base_parser::reset (void) 2406 { 2407 m_endfunction_found = false; 2408 m_autoloading = false; 2409 m_fcn_file_from_relative_lookup = false; 2410 m_parsing_subfunctions = false; 2411 m_parsing_local_functions = false; 2412 m_max_fcn_depth = -1; 2413 m_curr_fcn_depth = -1; 2414 m_primary_fcn_scope = symbol_scope (); 2415 m_curr_class_name = ""; 2416 m_curr_package_name = ""; 2417 m_function_scopes.clear (); 2418 m_primary_fcn = octave_value (); 2419 m_subfunction_names.clear (); 2420 m_classdef_object.reset (); 2421 m_stmt_list.reset (); 2422 2423 m_lexer.reset (); 2424 2425 yypstate_delete (static_cast<yypstate *> (m_parser_state)); 2426 m_parser_state = yypstate_new (); 2427 } 2428 2429 // Error messages for mismatched end tokens. 2430 2431 static std::string 2432 end_token_as_string (token::end_tok_type ettype) 2433 { 2434 std::string retval = "<unknown>"; 2435 2436 switch (ettype) 2437 { 2438 case token::simple_end: 2439 retval = "end"; 2440 break; 2441 2442 case token::classdef_end: 2443 retval = "endclassdef"; 2444 break; 2445 2446 case token::enumeration_end: 2447 retval = "endenumeration"; 2448 break; 2449 2450 case token::events_end: 2451 retval = "endevents"; 2452 break; 2453 2454 case token::for_end: 2455 retval = "endfor"; 2456 break; 2457 2458 case token::function_end: 2459 retval = "endfunction"; 2460 break; 2461 2462 case token::if_end: 2463 retval = "endif"; 2464 break; 2465 2466 case token::methods_end: 2467 retval = "endmethods"; 2468 break; 2469 2470 case token::parfor_end: 2471 retval = "endparfor"; 2472 break; 2473 2474 case token::properties_end: 2475 retval = "endproperties"; 2476 break; 2477 2478 case token::switch_end: 2479 retval = "endswitch"; 2480 break; 2481 2482 case token::try_catch_end: 2483 retval = "end_try_catch"; 2484 break; 2485 2486 case token::unwind_protect_end: 2487 retval = "end_unwind_protect"; 2488 break; 2489 2490 case token::while_end: 2491 retval = "endwhile"; 2492 break; 2493 2494 default: 2495 panic_impossible (); 2496 break; 2497 } 2498 2499 return retval; 2500 } 2501 2502 void 2503 base_parser::statement_list (std::shared_ptr<tree_statement_list>& lst) 2504 { 2505 if (! lst) 2506 return; 2507 2508 if (m_stmt_list) 2509 { 2510 // Append additional code to existing statement list. 2511 2512 while (! lst->empty ()) 2513 { 2514 m_stmt_list->push_back (lst->front ()); 2515 lst->pop_front (); 2516 } 2517 } 2518 else 2519 m_stmt_list = lst; 2520 } 2521 2522 void 2523 base_parser::end_token_error (token *tok, token::end_tok_type expected) 2524 { 2525 std::string msg = ("'" + end_token_as_string (expected) 2526 + "' command matched by '" 2527 + end_token_as_string (tok->ettype ()) + "'"); 2528 2529 bison_error (msg, tok->beg_pos ()); 2530 } 2531 2532 // Check to see that end tokens are properly matched. 2533 2534 bool 2535 base_parser::end_token_ok (token *tok, token::end_tok_type expected) 2536 { 2537 token::end_tok_type ettype = tok->ettype (); 2538 2539 return ettype == expected || ettype == token::simple_end; 2540 } 2541 2542 bool 2543 base_parser::push_fcn_symtab (void) 2544 { 2545 m_curr_fcn_depth++; 2546 2547 if (m_max_fcn_depth < m_curr_fcn_depth) 2548 m_max_fcn_depth = m_curr_fcn_depth; 2549 2550 // Will get a real name later. 2551 m_lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_fcn_symtab")); 2552 m_function_scopes.push (m_lexer.m_symtab_context.curr_scope ()); 2553 2554 if (! m_lexer.m_reading_script_file && m_curr_fcn_depth == 0 2555 && ! m_parsing_subfunctions) 2556 { 2557 m_primary_fcn_scope = m_lexer.m_symtab_context.curr_scope (); 2558 m_primary_fcn_scope.mark_primary_fcn_scope (); 2559 } 2560 2561 if (m_lexer.m_reading_script_file && m_curr_fcn_depth > 0) 2562 { 2563 bison_error ("nested functions not implemented in this context"); 2564 2565 return false; 2566 } 2567 2568 return true; 2569 } 2570 2571 // Make a constant. 2572 2573 tree_constant * 2574 base_parser::make_constant (int op, token *tok_val) 2575 { 2576 int l = tok_val->line (); 2577 int c = tok_val->column (); 2578 2579 tree_constant *retval = nullptr; 2580 2581 switch (op) 2582 { 2583 case NUM: 2584 { 2585 octave_value tmp (tok_val->number ()); 2586 retval = new tree_constant (tmp, l, c); 2587 retval->stash_original_text (tok_val->text_rep ()); 2588 } 2589 break; 2590 2591 case IMAG_NUM: 2592 { 2593 octave_value tmp (Complex (0.0, tok_val->number ())); 2594 retval = new tree_constant (tmp, l, c); 2595 retval->stash_original_text (tok_val->text_rep ()); 2596 } 2597 break; 2598 2599 case DQ_STRING: 2600 case SQ_STRING: 2601 { 2602 std::string txt = tok_val->text (); 2603 2604 char delim = op == DQ_STRING ? '"' : '\''; 2605 octave_value tmp (txt, delim); 2606 2607 if (txt.empty ()) 2608 { 2609 if (op == DQ_STRING) 2610 tmp = octave_null_str::instance; 2611 else 2612 tmp = octave_null_sq_str::instance; 2613 } 2614 2615 retval = new tree_constant (tmp, l, c); 2616 2617 if (op == DQ_STRING) 2618 txt = undo_string_escapes (txt); 2619 2620 // FIXME: maybe this should also be handled by 2621 // tok_val->text_rep () for character strings? 2622 retval->stash_original_text (delim + txt + delim); 2623 } 2624 break; 2625 2626 default: 2627 panic_impossible (); 2628 break; 2629 } 2630 2631 return retval; 2632 } 2633 2634 // Make a function handle. 2635 2636 tree_fcn_handle * 2637 base_parser::make_fcn_handle (token *tok_val) 2638 { 2639 int l = tok_val->line (); 2640 int c = tok_val->column (); 2641 2642 tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c); 2643 2644 return retval; 2645 } 2646 2647 // Make an anonymous function handle. 2648 2649 tree_anon_fcn_handle * 2650 base_parser::make_anon_fcn_handle (tree_parameter_list *param_list, 2651 tree_expression *expr, 2652 const filepos& at_pos) 2653 { 2654 // FIXME: We need to examine EXPR and issue an error if any 2655 // sub-expression contains an assignment, compound assignment, 2656 // increment, or decrement operator. 2657 2658 anon_fcn_validator validator (param_list, expr); 2659 2660 if (! validator.ok ()) 2661 { 2662 delete param_list; 2663 delete expr; 2664 2665 bison_error (validator.message (), validator.line (), 2666 validator.column ()); 2667 2668 return nullptr; 2669 } 2670 2671 symbol_scope fcn_scope = m_lexer.m_symtab_context.curr_scope (); 2672 symbol_scope parent_scope = m_lexer.m_symtab_context.parent_scope (); 2673 2674 m_lexer.m_symtab_context.pop (); 2675 2676 expr->set_print_flag (false); 2677 2678 fcn_scope.mark_static (); 2679 2680 int at_line = at_pos.line (); 2681 int at_column = at_pos.column (); 2682 2683 tree_anon_fcn_handle *retval 2684 = new tree_anon_fcn_handle (param_list, expr, fcn_scope, 2685 parent_scope, at_line, at_column); 2686 2687 std::ostringstream buf; 2688 2689 tree_print_code tpc (buf); 2690 2691 retval->accept (tpc); 2692 2693 std::string file = m_lexer.m_fcn_file_full_name; 2694 if (! file.empty ()) 2695 buf << ": file: " << file; 2696 else if (m_lexer.input_from_terminal ()) 2697 buf << ": *terminal input*"; 2698 else if (m_lexer.input_from_eval_string ()) 2699 buf << ": *eval string*"; 2700 buf << ": line: " << at_line << " column: " << at_column; 2701 2702 std::string scope_name = buf.str (); 2703 2704 fcn_scope.cache_name (scope_name); 2705 2706 // FIXME: Stash the filename. This does not work and produces 2707 // errors when executed. 2708 //retval->stash_file_name (m_lexer.m_fcn_file_name); 2709 2710 return retval; 2711 } 2712 2713 // Build a colon expression. 2714 2715 tree_expression * 2716 base_parser::make_colon_expression (tree_expression *base, 2717 tree_expression *limit, 2718 tree_expression *incr) 2719 { 2720 tree_expression *retval = nullptr; 2721 2722 if (! base || ! limit) 2723 { 2724 delete base; 2725 delete limit; 2726 delete incr; 2727 2728 return retval; 2729 } 2730 2731 int l = base->line (); 2732 int c = base->column (); 2733 2734 tree_colon_expression *expr 2735 = new tree_colon_expression (base, limit, incr, l, c); 2736 2737 retval = expr; 2738 2739 if (base->is_constant () && limit->is_constant () 2740 && (! incr || incr->is_constant ())) 2741 { 2742 interpreter& interp = __get_interpreter__ ("finish_colon_expression"); 2743 2744 try 2745 { 2746 // If the evaluation generates a warning message, restore 2747 // the previous value of last_warning_message and skip the 2748 // conversion to a constant value. 2749 2750 unwind_protect frame; 2751 2752 error_system& es = interp.get_error_system (); 2753 2754 frame.add_method (es, &error_system::set_last_warning_message, 2755 es.last_warning_message ("")); 2756 2757 frame.add_method (es, &error_system::set_discard_warning_messages, 2758 es.discard_warning_messages (true)); 2759 2760 tree_evaluator& tw = interp.get_evaluator (); 2761 2762 octave_value tmp = expr->evaluate (tw); 2763 2764 std::string msg = es.last_warning_message (); 2765 2766 if (msg.empty ()) 2767 { 2768 tree_constant *tc_retval 2769 = new tree_constant (tmp, expr->line (), expr->column ()); 2770 2771 std::ostringstream buf; 2772 2773 tree_print_code tpc (buf); 2774 2775 expr->accept (tpc); 2776 2777 tc_retval->stash_original_text (buf.str ()); 2778 2779 delete expr; 2780 2781 retval = tc_retval; 2782 } 2783 } 2784 catch (const execution_exception&) 2785 { 2786 interp.recover_from_exception (); 2787 } 2788 } 2789 2790 return retval; 2791 } 2792 2793 // Build a binary expression. 2794 2795 tree_expression * 2796 base_parser::make_binary_op (int op, tree_expression *op1, 2797 token *tok_val, tree_expression *op2) 2798 { 2799 octave_value::binary_op t = octave_value::unknown_binary_op; 2800 2801 switch (op) 2802 { 2803 case POW: 2804 t = octave_value::op_pow; 2805 break; 2806 2807 case EPOW: 2808 t = octave_value::op_el_pow; 2809 break; 2810 2811 case '+': 2812 t = octave_value::op_add; 2813 break; 2814 2815 case '-': 2816 t = octave_value::op_sub; 2817 break; 2818 2819 case '*': 2820 t = octave_value::op_mul; 2821 break; 2822 2823 case '/': 2824 t = octave_value::op_div; 2825 break; 2826 2827 case EMUL: 2828 t = octave_value::op_el_mul; 2829 break; 2830 2831 case EDIV: 2832 t = octave_value::op_el_div; 2833 break; 2834 2835 case LEFTDIV: 2836 t = octave_value::op_ldiv; 2837 break; 2838 2839 case ELEFTDIV: 2840 t = octave_value::op_el_ldiv; 2841 break; 2842 2843 case EXPR_LT: 2844 t = octave_value::op_lt; 2845 break; 2846 2847 case EXPR_LE: 2848 t = octave_value::op_le; 2849 break; 2850 2851 case EXPR_EQ: 2852 t = octave_value::op_eq; 2853 break; 2854 2855 case EXPR_GE: 2856 t = octave_value::op_ge; 2857 break; 2858 2859 case EXPR_GT: 2860 t = octave_value::op_gt; 2861 break; 2862 2863 case EXPR_NE: 2864 t = octave_value::op_ne; 2865 break; 2866 2867 case EXPR_AND: 2868 t = octave_value::op_el_and; 2869 break; 2870 2871 case EXPR_OR: 2872 t = octave_value::op_el_or; 2873 break; 2874 2875 default: 2876 panic_impossible (); 2877 break; 2878 } 2879 2880 int l = tok_val->line (); 2881 int c = tok_val->column (); 2882 2883 return maybe_compound_binary_expression (op1, op2, l, c, t); 2884 } 2885 2886 // Build a boolean expression. 2887 2888 tree_expression * 2889 base_parser::make_boolean_op (int op, tree_expression *op1, 2890 token *tok_val, tree_expression *op2) 2891 { 2892 tree_boolean_expression::type t; 2893 2894 switch (op) 2895 { 2896 case EXPR_AND_AND: 2897 t = tree_boolean_expression::bool_and; 2898 break; 2899 2900 case EXPR_OR_OR: 2901 t = tree_boolean_expression::bool_or; 2902 break; 2903 2904 default: 2905 panic_impossible (); 2906 break; 2907 } 2908 2909 int l = tok_val->line (); 2910 int c = tok_val->column (); 2911 2912 return new tree_boolean_expression (op1, op2, l, c, t); 2913 } 2914 2915 // Build a prefix expression. 2916 2917 tree_expression * 2918 base_parser::make_prefix_op (int op, tree_expression *op1, token *tok_val) 2919 { 2920 octave_value::unary_op t = octave_value::unknown_unary_op; 2921 2922 switch (op) 2923 { 2924 case EXPR_NOT: 2925 t = octave_value::op_not; 2926 break; 2927 2928 case '+': 2929 t = octave_value::op_uplus; 2930 break; 2931 2932 case '-': 2933 t = octave_value::op_uminus; 2934 break; 2935 2936 case PLUS_PLUS: 2937 t = octave_value::op_incr; 2938 break; 2939 2940 case MINUS_MINUS: 2941 t = octave_value::op_decr; 2942 break; 2943 2944 default: 2945 panic_impossible (); 2946 break; 2947 } 2948 2949 int l = tok_val->line (); 2950 int c = tok_val->column (); 2951 2952 return new tree_prefix_expression (op1, l, c, t); 2953 } 2954 2955 // Build a postfix expression. 2956 2957 tree_expression * 2958 base_parser::make_postfix_op (int op, tree_expression *op1, token *tok_val) 2959 { 2960 octave_value::unary_op t = octave_value::unknown_unary_op; 2961 2962 switch (op) 2963 { 2964 case HERMITIAN: 2965 t = octave_value::op_hermitian; 2966 break; 2967 2968 case TRANSPOSE: 2969 t = octave_value::op_transpose; 2970 break; 2971 2972 case PLUS_PLUS: 2973 t = octave_value::op_incr; 2974 break; 2975 2976 case MINUS_MINUS: 2977 t = octave_value::op_decr; 2978 break; 2979 2980 default: 2981 panic_impossible (); 2982 break; 2983 } 2984 2985 int l = tok_val->line (); 2986 int c = tok_val->column (); 2987 2988 return new tree_postfix_expression (op1, l, c, t); 2989 } 2990 2991 // Build an unwind-protect command. 2992 2993 tree_command * 2994 base_parser::make_unwind_command (token *unwind_tok, 2995 tree_statement_list *body, 2996 tree_statement_list *cleanup_stmts, 2997 token *end_tok, 2998 comment_list *lc, 2999 comment_list *mc) 3000 { 3001 tree_command *retval = nullptr; 3002 3003 if (end_token_ok (end_tok, token::unwind_protect_end)) 3004 { 3005 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3006 3007 int l = unwind_tok->line (); 3008 int c = unwind_tok->column (); 3009 3010 retval = new tree_unwind_protect_command (body, cleanup_stmts, 3011 lc, mc, tc, l, c); 3012 } 3013 else 3014 { 3015 delete body; 3016 delete cleanup_stmts; 3017 3018 end_token_error (end_tok, token::unwind_protect_end); 3019 } 3020 3021 return retval; 3022 } 3023 3024 // Build a try-catch command. 3025 3026 tree_command * 3027 base_parser::make_try_command (token *try_tok, 3028 tree_statement_list *body, 3029 char catch_sep, 3030 tree_statement_list *cleanup_stmts, 3031 token *end_tok, 3032 comment_list *lc, 3033 comment_list *mc) 3034 { 3035 tree_command *retval = nullptr; 3036 3037 if (end_token_ok (end_tok, token::try_catch_end)) 3038 { 3039 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3040 3041 int l = try_tok->line (); 3042 int c = try_tok->column (); 3043 3044 tree_identifier *id = nullptr; 3045 3046 if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ()) 3047 { 3048 tree_statement *stmt = cleanup_stmts->front (); 3049 3050 if (stmt) 3051 { 3052 tree_expression *expr = stmt->expression (); 3053 3054 if (expr && expr->is_identifier ()) 3055 { 3056 id = dynamic_cast<tree_identifier *> (expr); 3057 3058 cleanup_stmts->pop_front (); 3059 3060 stmt->set_expression (nullptr); 3061 delete stmt; 3062 } 3063 } 3064 } 3065 3066 retval = new tree_try_catch_command (body, cleanup_stmts, id, 3067 lc, mc, tc, l, c); 3068 } 3069 else 3070 { 3071 delete body; 3072 delete cleanup_stmts; 3073 3074 end_token_error (end_tok, token::try_catch_end); 3075 } 3076 3077 return retval; 3078 } 3079 3080 // Build a while command. 3081 3082 tree_command * 3083 base_parser::make_while_command (token *while_tok, 3084 tree_expression *expr, 3085 tree_statement_list *body, 3086 token *end_tok, 3087 comment_list *lc) 3088 { 3089 tree_command *retval = nullptr; 3090 3091 maybe_warn_assign_as_truth_value (expr); 3092 3093 if (end_token_ok (end_tok, token::while_end)) 3094 { 3095 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3096 3097 m_lexer.m_looping--; 3098 3099 int l = while_tok->line (); 3100 int c = while_tok->column (); 3101 3102 retval = new tree_while_command (expr, body, lc, tc, l, c); 3103 } 3104 else 3105 { 3106 delete expr; 3107 delete body; 3108 3109 end_token_error (end_tok, token::while_end); 3110 } 3111 3112 return retval; 3113 } 3114 3115 // Build a do-until command. 3116 3117 tree_command * 3118 base_parser::make_do_until_command (token *until_tok, 3119 tree_statement_list *body, 3120 tree_expression *expr, 3121 comment_list *lc) 3122 { 3123 maybe_warn_assign_as_truth_value (expr); 3124 3125 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3126 3127 m_lexer.m_looping--; 3128 3129 int l = until_tok->line (); 3130 int c = until_tok->column (); 3131 3132 return new tree_do_until_command (expr, body, lc, tc, l, c); 3133 } 3134 3135 // Build a for command. 3136 3137 tree_command * 3138 base_parser::make_for_command (int tok_id, token *for_tok, 3139 tree_argument_list *lhs, 3140 tree_expression *expr, 3141 tree_expression *maxproc, 3142 tree_statement_list *body, 3143 token *end_tok, 3144 comment_list *lc) 3145 { 3146 tree_command *retval = nullptr; 3147 3148 bool parfor = tok_id == PARFOR; 3149 3150 if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end)) 3151 { 3152 expr->mark_as_for_cmd_expr (); 3153 3154 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3155 3156 m_lexer.m_looping--; 3157 3158 int l = for_tok->line (); 3159 int c = for_tok->column (); 3160 3161 if (lhs->length () == 1) 3162 { 3163 tree_expression *tmp = lhs->remove_front (); 3164 3165 retval = new tree_simple_for_command (parfor, tmp, expr, maxproc, 3166 body, lc, tc, l, c); 3167 3168 delete lhs; 3169 } 3170 else 3171 { 3172 if (parfor) 3173 { 3174 delete lhs; 3175 delete expr; 3176 delete maxproc; 3177 delete body; 3178 3179 bison_error ("invalid syntax for parfor statement"); 3180 } 3181 else 3182 retval = new tree_complex_for_command (lhs, expr, body, 3183 lc, tc, l, c); 3184 } 3185 } 3186 else 3187 { 3188 delete lhs; 3189 delete expr; 3190 delete maxproc; 3191 delete body; 3192 3193 end_token_error (end_tok, parfor ? token::parfor_end : token::for_end); 3194 } 3195 3196 return retval; 3197 } 3198 3199 // Build a break command. 3200 3201 tree_command * 3202 base_parser::make_break_command (token *break_tok) 3203 { 3204 int l = break_tok->line (); 3205 int c = break_tok->column (); 3206 3207 if (! m_lexer.m_looping) 3208 { 3209 bison_error ("break must appear within a loop"); 3210 return nullptr; 3211 } 3212 else 3213 return new tree_break_command (l, c); 3214 } 3215 3216 // Build a continue command. 3217 3218 tree_command * 3219 base_parser::make_continue_command (token *continue_tok) 3220 { 3221 int l = continue_tok->line (); 3222 int c = continue_tok->column (); 3223 3224 if (! m_lexer.m_looping) 3225 { 3226 bison_error ("continue must appear within a loop"); 3227 return nullptr; 3228 } 3229 else 3230 return new tree_continue_command (l, c); 3231 } 3232 3233 // Build a return command. 3234 3235 tree_command * 3236 base_parser::make_return_command (token *return_tok) 3237 { 3238 int l = return_tok->line (); 3239 int c = return_tok->column (); 3240 3241 return new tree_return_command (l, c); 3242 } 3243 3244 // Start an if command. 3245 3246 tree_if_command_list * 3247 base_parser::start_if_command (tree_expression *expr, 3248 tree_statement_list *list) 3249 { 3250 maybe_warn_assign_as_truth_value (expr); 3251 3252 tree_if_clause *t = new tree_if_clause (expr, list); 3253 3254 return new tree_if_command_list (t); 3255 } 3256 3257 // Finish an if command. 3258 3259 tree_if_command * 3260 base_parser::finish_if_command (token *if_tok, 3261 tree_if_command_list *list, 3262 token *end_tok, 3263 comment_list *lc) 3264 { 3265 tree_if_command *retval = nullptr; 3266 3267 if (end_token_ok (end_tok, token::if_end)) 3268 { 3269 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3270 3271 int l = if_tok->line (); 3272 int c = if_tok->column (); 3273 3274 if (list && ! list->empty ()) 3275 { 3276 tree_if_clause *elt = list->front (); 3277 3278 if (elt) 3279 { 3280 elt->line (l); 3281 elt->column (c); 3282 } 3283 } 3284 3285 retval = new tree_if_command (list, lc, tc, l, c); 3286 } 3287 else 3288 { 3289 delete list; 3290 3291 end_token_error (end_tok, token::if_end); 3292 } 3293 3294 return retval; 3295 } 3296 3297 // Build an elseif clause. 3298 3299 tree_if_clause * 3300 base_parser::make_elseif_clause (token *elseif_tok, 3301 tree_expression *expr, 3302 tree_statement_list *list, 3303 comment_list *lc) 3304 { 3305 maybe_warn_assign_as_truth_value (expr); 3306 3307 int l = elseif_tok->line (); 3308 int c = elseif_tok->column (); 3309 3310 return new tree_if_clause (expr, list, lc, l, c); 3311 } 3312 3313 // Finish a switch command. 3314 3315 tree_switch_command * 3316 base_parser::finish_switch_command (token *switch_tok, 3317 tree_expression *expr, 3318 tree_switch_case_list *list, 3319 token *end_tok, 3320 comment_list *lc) 3321 { 3322 tree_switch_command *retval = nullptr; 3323 3324 if (end_token_ok (end_tok, token::switch_end)) 3325 { 3326 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3327 3328 int l = switch_tok->line (); 3329 int c = switch_tok->column (); 3330 3331 if (list && ! list->empty ()) 3332 { 3333 tree_switch_case *elt = list->front (); 3334 3335 if (elt) 3336 { 3337 elt->line (l); 3338 elt->column (c); 3339 } 3340 } 3341 3342 retval = new tree_switch_command (expr, list, lc, tc, l, c); 3343 } 3344 else 3345 { 3346 delete expr; 3347 delete list; 3348 3349 end_token_error (end_tok, token::switch_end); 3350 } 3351 3352 return retval; 3353 } 3354 3355 // Build a switch case. 3356 3357 tree_switch_case * 3358 base_parser::make_switch_case (token *case_tok, 3359 tree_expression *expr, 3360 tree_statement_list *list, 3361 comment_list *lc) 3362 { 3363 maybe_warn_variable_switch_label (expr); 3364 3365 int l = case_tok->line (); 3366 int c = case_tok->column (); 3367 3368 return new tree_switch_case (expr, list, lc, l, c); 3369 } 3370 3371 // Build an assignment to a variable. 3372 3373 tree_expression * 3374 base_parser::make_assign_op (int op, tree_argument_list *lhs, 3375 token *eq_tok, tree_expression *rhs) 3376 { 3377 octave_value::assign_op t = octave_value::unknown_assign_op; 3378 3379 switch (op) 3380 { 3381 case '=': 3382 t = octave_value::op_asn_eq; 3383 break; 3384 3385 case ADD_EQ: 3386 t = octave_value::op_add_eq; 3387 break; 3388 3389 case SUB_EQ: 3390 t = octave_value::op_sub_eq; 3391 break; 3392 3393 case MUL_EQ: 3394 t = octave_value::op_mul_eq; 3395 break; 3396 3397 case DIV_EQ: 3398 t = octave_value::op_div_eq; 3399 break; 3400 3401 case LEFTDIV_EQ: 3402 t = octave_value::op_ldiv_eq; 3403 break; 3404 3405 case POW_EQ: 3406 t = octave_value::op_pow_eq; 3407 break; 3408 3409 case EMUL_EQ: 3410 t = octave_value::op_el_mul_eq; 3411 break; 3412 3413 case EDIV_EQ: 3414 t = octave_value::op_el_div_eq; 3415 break; 3416 3417 case ELEFTDIV_EQ: 3418 t = octave_value::op_el_ldiv_eq; 3419 break; 3420 3421 case EPOW_EQ: 3422 t = octave_value::op_el_pow_eq; 3423 break; 3424 3425 case AND_EQ: 3426 t = octave_value::op_el_and_eq; 3427 break; 3428 3429 case OR_EQ: 3430 t = octave_value::op_el_or_eq; 3431 break; 3432 3433 default: 3434 panic_impossible (); 3435 break; 3436 } 3437 3438 int l = eq_tok->line (); 3439 int c = eq_tok->column (); 3440 3441 if (! lhs->is_simple_assign_lhs () && t != octave_value::op_asn_eq) 3442 { 3443 // Multiple assignments like [x,y] OP= rhs are only valid for 3444 // '=', not '+=', etc. 3445 3446 delete lhs; 3447 delete rhs; 3448 3449 bison_error ("computed multiple assignment not allowed", 3450 eq_tok->beg_pos ()); 3451 3452 return nullptr; 3453 } 3454 3455 if (lhs->is_simple_assign_lhs ()) 3456 { 3457 // We are looking at a simple assignment statement like x = rhs; 3458 3459 tree_expression *tmp = lhs->remove_front (); 3460 3461 if ((tmp->is_identifier () || tmp->is_index_expression ()) 3462 && iskeyword (tmp->name ())) 3463 { 3464 std::string kw = tmp->name (); 3465 3466 delete tmp; 3467 delete lhs; 3468 delete rhs; 3469 3470 bison_error ("invalid assignment to keyword \"" + kw + "\"", 3471 eq_tok->beg_pos ()); 3472 3473 return nullptr; 3474 } 3475 3476 delete lhs; 3477 3478 return new tree_simple_assignment (tmp, rhs, false, l, c, t); 3479 } 3480 else 3481 { 3482 std::list<std::string> names = lhs->variable_names (); 3483 3484 for (const auto& kw : names) 3485 { 3486 if (iskeyword (kw)) 3487 { 3488 delete lhs; 3489 delete rhs; 3490 3491 bison_error ("invalid assignment to keyword \"" + kw + "\"", 3492 eq_tok->beg_pos ()); 3493 3494 return nullptr; 3495 } 3496 } 3497 3498 return new tree_multi_assignment (lhs, rhs, false, l, c); 3499 } 3500 } 3501 3502 // Define a script. 3503 3504 void 3505 base_parser::make_script (tree_statement_list *cmds, 3506 tree_statement *end_script) 3507 { 3508 if (! cmds) 3509 cmds = new tree_statement_list (); 3510 3511 cmds->append (end_script); 3512 3513 symbol_scope script_scope = m_lexer.m_symtab_context.curr_scope (); 3514 3515 script_scope.cache_name (m_lexer.m_fcn_file_full_name); 3516 script_scope.cache_fcn_file_name (m_lexer.m_fcn_file_full_name); 3517 script_scope.cache_dir_name (m_lexer.m_dir_name); 3518 3519 octave_user_script *script 3520 = new octave_user_script (m_lexer.m_fcn_file_full_name, 3521 m_lexer.m_fcn_file_name, script_scope, 3522 cmds, m_lexer.m_help_text); 3523 3524 m_lexer.m_symtab_context.pop (); 3525 m_lexer.m_help_text = ""; 3526 3527 sys::time now; 3528 3529 script->stash_fcn_file_time (now); 3530 script->stash_dir_name (m_lexer.m_dir_name); 3531 3532 m_primary_fcn = octave_value (script); 3533 } 3534 3535 tree_identifier * 3536 base_parser::make_fcn_name (tree_identifier *id) 3537 { 3538 std::string id_name = id->name (); 3539 3540 // Make classdef local functions unique from classdef methods. 3541 3542 if (m_parsing_local_functions && m_curr_fcn_depth == 0) 3543 id_name = m_lexer.m_fcn_file_name + ">" + id_name; 3544 3545 if (! m_function_scopes.name_current_scope (id_name)) 3546 { 3547 bison_error ("duplicate subfunction or nested function name", 3548 id->line (), id->column ()); 3549 3550 delete id; 3551 return nullptr; 3552 } 3553 3554 octave::symbol_scope curr_scope = m_lexer.m_symtab_context.curr_scope (); 3555 curr_scope.cache_name (id_name); 3556 3557 m_lexer.m_parsed_function_name.top () = true; 3558 m_lexer.m_maybe_classdef_get_set_method = false; 3559 3560 return id; 3561 } 3562 3563 // Define a function. 3564 3565 // FIXME: combining start_function, finish_function, and 3566 // recover_from_parsing_function should be possible, but it makes 3567 // for a large mess. Maybe this could be a bit better organized? 3568 3569 tree_function_def * 3570 base_parser::make_function (token *fcn_tok, 3571 tree_parameter_list *ret_list, 3572 tree_identifier *id, 3573 tree_parameter_list *param_list, 3574 tree_statement_list *body, 3575 tree_statement *end_fcn_stmt, 3576 comment_list *lc) 3577 { 3578 int l = fcn_tok->line (); 3579 int c = fcn_tok->column (); 3580 3581 octave_user_function *tmp_fcn 3582 = start_function (id, param_list, body, end_fcn_stmt); 3583 3584 tree_function_def *retval = finish_function (ret_list, tmp_fcn, lc, l, c); 3585 3586 recover_from_parsing_function (); 3587 3588 return retval; 3589 } 3590 3591 // Begin defining a function. 3592 3593 octave_user_function * 3594 base_parser::start_function (tree_identifier *id, 3595 tree_parameter_list *param_list, 3596 tree_statement_list *body, 3597 tree_statement *end_fcn_stmt) 3598 { 3599 // We'll fill in the return list later. 3600 3601 std::string id_name = id->name (); 3602 3603 delete id; 3604 3605 if (m_lexer.m_parsing_classdef_get_method) 3606 id_name.insert (0, "get."); 3607 else if (m_lexer.m_parsing_classdef_set_method) 3608 id_name.insert (0, "set."); 3609 3610 m_lexer.m_parsing_classdef_get_method = false; 3611 m_lexer.m_parsing_classdef_set_method = false; 3612 3613 if (! body) 3614 body = new tree_statement_list (); 3615 3616 body->append (end_fcn_stmt); 3617 3618 octave_user_function *fcn 3619 = new octave_user_function (m_lexer.m_symtab_context.curr_scope (), 3620 param_list, nullptr, body); 3621 3622 comment_list *tc = m_lexer.m_comment_buf.get_comment (); 3623 3624 fcn->stash_trailing_comment (tc); 3625 fcn->stash_fcn_end_location (end_fcn_stmt->line (), 3626 end_fcn_stmt->column ()); 3627 3628 // If input is coming from a file, issue a warning if the name of 3629 // the file does not match the name of the function stated in the 3630 // file. Matlab doesn't provide a diagnostic (it ignores the stated 3631 // name). 3632 if (! m_autoloading && m_lexer.m_reading_fcn_file 3633 && m_curr_fcn_depth == 0 && ! m_parsing_subfunctions) 3634 { 3635 // FIXME: should m_lexer.m_fcn_file_name already be 3636 // preprocessed when we get here? It seems to only be a 3637 // problem with relative filenames. 3638 3639 std::string nm = m_lexer.m_fcn_file_name; 3640 3641 std::size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ()); 3642 3643 if (pos != std::string::npos) 3644 nm = m_lexer.m_fcn_file_name.substr (pos+1); 3645 3646 if (nm != id_name) 3647 { 3648 warning_with_id 3649 ("Octave:function-name-clash", 3650 "function name '%s' does not agree with function filename '%s'", 3651 id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ()); 3652 3653 id_name = nm; 3654 } 3655 } 3656 3657 sys::time now; 3658 3659 fcn->stash_fcn_file_name (m_lexer.m_fcn_file_full_name); 3660 fcn->stash_fcn_file_time (now); 3661 fcn->stash_dir_name (m_lexer.m_dir_name); 3662 fcn->stash_package_name (m_lexer.m_package_name); 3663 fcn->mark_as_system_fcn_file (); 3664 fcn->stash_function_name (id_name); 3665 3666 if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_classdef_file || m_autoloading) 3667 { 3668 if (m_fcn_file_from_relative_lookup) 3669 fcn->mark_relative (); 3670 3671 if (m_lexer.m_parsing_class_method) 3672 { 3673 if (m_lexer.m_parsing_classdef) 3674 { 3675 if (m_curr_class_name == id_name) 3676 fcn->mark_as_classdef_constructor (); 3677 else 3678 fcn->mark_as_classdef_method (); 3679 } 3680 else 3681 { 3682 if (m_curr_class_name == id_name) 3683 fcn->mark_as_legacy_constructor (); 3684 else 3685 fcn->mark_as_legacy_method (); 3686 } 3687 3688 fcn->stash_dispatch_class (m_curr_class_name); 3689 } 3690 3691 std::string nm = fcn->fcn_file_name (); 3692 3693 sys::file_stat fs (nm); 3694 3695 if (fs && fs.is_newer (now)) 3696 warning_with_id ("Octave:future-time-stamp", 3697 "time stamp for '%s' is in the future", nm.c_str ()); 3698 } 3699 else if (! m_lexer.input_from_tmp_history_file () 3700 && ! m_lexer.m_force_script 3701 && m_lexer.m_reading_script_file 3702 && m_lexer.m_fcn_file_name == id_name) 3703 { 3704 warning ("function '%s' defined within script file '%s'", 3705 id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ()); 3706 } 3707 3708 // Record help text for functions other than nested functions. 3709 // We cannot currently record help for nested functions (bug #46008) 3710 // because the doc_string of the outermost function is read first, 3711 // whereas this function is called for the innermost function first. 3712 // We could have a stack of help_text in lexer. 3713 if (! m_lexer.m_help_text.empty () && m_curr_fcn_depth == 0) 3714 { 3715 fcn->document (m_lexer.m_help_text); 3716 3717 m_lexer.m_help_text = ""; 3718 } 3719 3720 if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0 3721 && ! m_parsing_subfunctions) 3722 m_primary_fcn = octave_value (fcn); 3723 3724 return fcn; 3725 } 3726 3727 tree_statement * 3728 base_parser::make_end (const std::string& type, bool eof, 3729 const filepos& beg_pos, const filepos& /*end_pos*/) 3730 { 3731 int l = beg_pos.line (); 3732 int c = beg_pos.column (); 3733 3734 return make_statement (new tree_no_op_command (type, eof, l, c)); 3735 } 3736 3737 tree_function_def * 3738 base_parser::finish_function (tree_parameter_list *ret_list, 3739 octave_user_function *fcn, 3740 comment_list *lc, 3741 int l, int c) 3742 { 3743 tree_function_def *retval = nullptr; 3744 3745 if (! ret_list) 3746 ret_list = new tree_parameter_list (tree_parameter_list::out); 3747 3748 ret_list->mark_as_formal_parameters (); 3749 3750 if (fcn) 3751 { 3752 std::string fcn_nm = fcn->name (); 3753 std::string file = fcn->fcn_file_name (); 3754 3755 std::string tmp = fcn_nm; 3756 if (! file.empty ()) 3757 tmp += ": " + file; 3758 3759 symbol_scope fcn_scope = fcn->scope (); 3760 fcn_scope.cache_name (tmp); 3761 fcn_scope.cache_fcn_name (fcn_nm); 3762 fcn_scope.cache_fcn_file_name (file); 3763 fcn_scope.cache_dir_name (m_lexer.m_dir_name); 3764 3765 if (lc) 3766 fcn->stash_leading_comment (lc); 3767 3768 fcn->define_ret_list (ret_list); 3769 3770 if (m_curr_fcn_depth > 0 || m_parsing_subfunctions) 3771 { 3772 fcn->stash_fcn_location (l, c); 3773 fcn->stash_parent_fcn_name (m_lexer.m_fcn_file_name); 3774 3775 octave_value ov_fcn (fcn); 3776 3777 if (m_endfunction_found && m_function_scopes.size () > 1) 3778 { 3779 fcn->mark_as_nested_function (); 3780 fcn_scope.set_nesting_depth (m_curr_fcn_depth); 3781 3782 symbol_scope pscope = m_function_scopes.parent_scope (); 3783 fcn_scope.set_parent (pscope); 3784 fcn_scope.set_primary_parent (m_primary_fcn_scope); 3785 pscope.install_nestfunction (fcn_nm, ov_fcn, fcn_scope); 3786 3787 // For nested functions, the list of parent functions is 3788 // set in symbol_scope::update_nest. 3789 } 3790 else 3791 { 3792 fcn->mark_as_subfunction (); 3793 m_subfunction_names.push_back (fcn_nm); 3794 fcn_scope.set_parent (m_primary_fcn_scope); 3795 if (m_parsing_subfunctions) 3796 fcn_scope.set_primary_parent (m_primary_fcn_scope); 3797 m_primary_fcn_scope.install_subfunction (fcn_nm, ov_fcn); 3798 3799 // Prepend name of primary fucntion to list of parent 3800 // functions (if any) for subfunction. 3801 3802 std::list<std::string> plst 3803 = fcn_scope.parent_fcn_names (); 3804 plst.push_front (m_primary_fcn_scope.fcn_name ()); 3805 fcn_scope.cache_parent_fcn_names (plst); 3806 } 3807 } 3808 3809 if (m_curr_fcn_depth == 0) 3810 fcn_scope.update_nest (); 3811 3812 if (! m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0) 3813 { 3814 // We are either reading a script file or defining a function 3815 // at the command line, so this definition creates a 3816 // tree_function object that is placed in the parse tree. 3817 // Otherwise, it is just inserted in the symbol table, 3818 // either as a subfunction or nested function (see above), 3819 // or as the primary function for the file, via 3820 // m_primary_fcn (see also load_fcn_from_file,, 3821 // parse_fcn_file, and 3822 // fcn_info::fcn_info_rep::find_user_function). 3823 3824 if (m_lexer.m_buffer_function_text) 3825 { 3826 fcn->cache_function_text (m_lexer.m_function_text, 3827 fcn->time_parsed ()); 3828 m_lexer.m_buffer_function_text = false; 3829 } 3830 3831 retval = new tree_function_def (fcn); 3832 } 3833 } 3834 3835 return retval; 3836 } 3837 3838 void 3839 base_parser::recover_from_parsing_function (void) 3840 { 3841 m_lexer.m_symtab_context.pop (); 3842 3843 if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0 3844 && ! m_parsing_subfunctions) 3845 m_parsing_subfunctions = true; 3846 3847 m_curr_fcn_depth--; 3848 m_function_scopes.pop (); 3849 3850 m_lexer.m_defining_func--; 3851 m_lexer.m_parsed_function_name.pop (); 3852 m_lexer.m_looking_at_return_list = false; 3853 m_lexer.m_looking_at_parameter_list = false; 3854 } 3855 3856 // A CLASSDEF block defines a class that has a constructor and other 3857 // methods, but it is not an executable command. Parsing the block 3858 // makes some changes in the symbol table (inserting the constructor 3859 // and methods, and adding to the list of known objects) and creates 3860 // a parse tree containing meta information about the class. 3861 3862 // LC contains comments appearing before the classdef keyword. 3863 // TC contains comments appearing between the classdef elements 3864 // and the final end token for the classdef block. 3865 3866 tree_classdef * 3867 base_parser::make_classdef (token *tok_val, 3868 tree_classdef_attribute_list *a, 3869 tree_identifier *id, 3870 tree_classdef_superclass_list *sc, 3871 tree_classdef_body *body, token *end_tok, 3872 comment_list *lc, comment_list *tc) 3873 { 3874 tree_classdef *retval = nullptr; 3875 3876 m_lexer.m_symtab_context.pop (); 3877 3878 std::string cls_name = id->name (); 3879 3880 std::string nm = m_lexer.m_fcn_file_name; 3881 3882 std::size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ()); 3883 3884 if (pos != std::string::npos) 3885 nm = m_lexer.m_fcn_file_name.substr (pos+1); 3886 3887 if (nm != cls_name) 3888 { 3889 int l = id->line (); 3890 int c = id->column (); 3891 3892 delete a; 3893 delete id; 3894 delete sc; 3895 delete body; 3896 delete lc; 3897 delete tc; 3898 3899 bison_error ("invalid classdef definition, the class name must match the filename", l, c); 3900 3901 } 3902 else 3903 { 3904 if (end_token_ok (end_tok, token::classdef_end)) 3905 { 3906 int l = tok_val->line (); 3907 int c = tok_val->column (); 3908 3909 if (! body) 3910 body = new tree_classdef_body (); 3911 3912 retval = new tree_classdef (m_lexer.m_symtab_context.curr_scope (), 3913 a, id, sc, body, lc, tc, 3914 m_curr_package_name, l, c); 3915 } 3916 else 3917 { 3918 delete a; 3919 delete id; 3920 delete sc; 3921 delete body; 3922 delete lc; 3923 delete tc; 3924 3925 end_token_error (end_tok, token::switch_end); 3926 } 3927 } 3928 3929 return retval; 3930 } 3931 3932 // LC contains comments appearing before the properties keyword. 3933 // If this properties block appears first in the list of classdef 3934 // elements, this comment list will be used for the help text for the 3935 // classdef block. 3936 3937 // TC contains comments appearing between the list of properties 3938 // and the final end token for the properties block and may be used to 3939 // find the doc string for the final property in the list. 3940 3941 tree_classdef_properties_block * 3942 base_parser::make_classdef_properties_block (token *tok_val, 3943 tree_classdef_attribute_list *a, 3944 tree_classdef_property_list *plist, 3945 token *end_tok, 3946 comment_list *lc, 3947 comment_list *tc) 3948 { 3949 tree_classdef_properties_block *retval = nullptr; 3950 3951 if (end_token_ok (end_tok, token::properties_end)) 3952 { 3953 int l = tok_val->line (); 3954 int c = tok_val->column (); 3955 3956 if (plist) 3957 { 3958 // If the element at the end of the list doesn't have a doc 3959 // string, see whether the first element of TC is an 3960 // end-of-line comment for us to use. 3961 3962 if (tc) 3963 { 3964 tree_classdef_property *last_elt = plist->back (); 3965 3966 if (! last_elt->have_doc_string ()) 3967 { 3968 comment_elt first_comment_elt = tc->front (); 3969 3970 if (first_comment_elt.is_end_of_line ()) 3971 { 3972 std::string eol_comment = first_comment_elt.text (); 3973 3974 last_elt->doc_string (eol_comment); 3975 } 3976 } 3977 } 3978 } 3979 else 3980 plist = new tree_classdef_property_list (); 3981 3982 retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); 3983 } 3984 else 3985 { 3986 delete a; 3987 delete plist; 3988 delete lc; 3989 delete tc; 3990 3991 end_token_error (end_tok, token::properties_end); 3992 } 3993 3994 return retval; 3995 } 3996 3997 // LC contains comments appearing before the methods keyword. 3998 // If this methods block appears first in the list of classdef 3999 // elements, this comment list will be used for the help text for the 4000 // classdef block. 4001 4002 tree_classdef_methods_block * 4003 base_parser::make_classdef_methods_block (token *tok_val, 4004 tree_classdef_attribute_list *a, 4005 tree_classdef_methods_list *mlist, 4006 token *end_tok, comment_list *lc, 4007 comment_list *tc) 4008 { 4009 tree_classdef_methods_block *retval = nullptr; 4010 4011 if (end_token_ok (end_tok, token::methods_end)) 4012 { 4013 int l = tok_val->line (); 4014 int c = tok_val->column (); 4015 4016 if (! mlist) 4017 mlist = new tree_classdef_methods_list (); 4018 4019 retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); 4020 } 4021 else 4022 { 4023 delete a; 4024 delete mlist; 4025 delete lc; 4026 delete tc; 4027 4028 end_token_error (end_tok, token::methods_end); 4029 } 4030 4031 return retval; 4032 } 4033 4034 // LC contains comments appearing before the events keyword. 4035 // If this events block appears first in the list of classdef 4036 // elements, this comment list will be used for the help text for the 4037 // classdef block. 4038 4039 // TC contains comments appearing between the list of events and 4040 // the final end token for the events block and may be used to find 4041 // the doc string for the final event in the list. 4042 4043 tree_classdef_events_block * 4044 base_parser::make_classdef_events_block (token *tok_val, 4045 tree_classdef_attribute_list *a, 4046 tree_classdef_events_list *elist, 4047 token *end_tok, 4048 comment_list *lc, 4049 comment_list *tc) 4050 { 4051 tree_classdef_events_block *retval = nullptr; 4052 4053 if (end_token_ok (end_tok, token::events_end)) 4054 { 4055 int l = tok_val->line (); 4056 int c = tok_val->column (); 4057 4058 if (! elist) 4059 elist = new tree_classdef_events_list (); 4060 4061 retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); 4062 } 4063 else 4064 { 4065 delete a; 4066 delete elist; 4067 delete lc; 4068 delete tc; 4069 4070 end_token_error (end_tok, token::events_end); 4071 } 4072 4073 return retval; 4074 } 4075 4076 // LC contains comments appearing before the enumeration keyword. 4077 // If this enumeration block appears first in the list of classdef 4078 // elements, this comment list will be used for the help text for the 4079 // classdef block. 4080 4081 // TC contains comments appearing between the list of 4082 // enumerations and the final end token for the enumeration block and 4083 // may be used to find the doc string for the final enumeration in the 4084 // list. 4085 4086 tree_classdef_enum_block * 4087 base_parser::make_classdef_enum_block (token *tok_val, 4088 tree_classdef_attribute_list *a, 4089 tree_classdef_enum_list *elist, 4090 token *end_tok, 4091 comment_list *lc, 4092 comment_list *tc) 4093 { 4094 tree_classdef_enum_block *retval = nullptr; 4095 4096 if (end_token_ok (end_tok, token::enumeration_end)) 4097 { 4098 int l = tok_val->line (); 4099 int c = tok_val->column (); 4100 4101 if (! elist) 4102 elist = new tree_classdef_enum_list (); 4103 4104 retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); 4105 } 4106 else 4107 { 4108 delete a; 4109 delete elist; 4110 delete lc; 4111 delete tc; 4112 4113 end_token_error (end_tok, token::enumeration_end); 4114 } 4115 4116 return retval; 4117 } 4118 4119 octave_user_function* 4120 base_parser::start_classdef_external_method (tree_identifier *id, 4121 tree_parameter_list *pl) 4122 { 4123 octave_user_function* retval = nullptr; 4124 4125 // External methods are only allowed within @-folders. In this case, 4126 // m_curr_class_name will be non-empty. 4127 4128 if (! m_curr_class_name.empty ()) 4129 { 4130 4131 std::string mname = id->name (); 4132 4133 // Methods that cannot be declared outside the classdef file: 4134 // - methods with '.' character (e.g. property accessors) 4135 // - class constructor 4136 // - 'delete' 4137 4138 if (mname.find_first_of (".") == std::string::npos 4139 && mname != "delete" 4140 && mname != m_curr_class_name) 4141 { 4142 // Create a dummy function that is used until the real method 4143 // is loaded. 4144 4145 retval = new octave_user_function (symbol_scope (), pl); 4146 4147 retval->stash_function_name (mname); 4148 4149 int l = id->line (); 4150 int c = id->column (); 4151 4152 retval->stash_fcn_location (l, c); 4153 } 4154 else 4155 bison_error ("invalid external method declaration, an external " 4156 "method cannot be the class constructor, 'delete' " 4157 "or have a dot (.) character in its name"); 4158 } 4159 else 4160 bison_error ("external methods are only allowed in @-folders"); 4161 4162 if (! retval) 4163 delete id; 4164 4165 return retval; 4166 } 4167 4168 tree_function_def * 4169 base_parser::finish_classdef_external_method (octave_user_function *fcn, 4170 tree_parameter_list *ret_list, 4171 comment_list *cl) 4172 { 4173 if (! ret_list) 4174 ret_list = new tree_parameter_list (tree_parameter_list::out); 4175 4176 fcn->define_ret_list (ret_list); 4177 4178 if (cl) 4179 fcn->stash_leading_comment (cl); 4180 4181 int l = fcn->beginning_line (); 4182 int c = fcn->beginning_column (); 4183 4184 return new tree_function_def (fcn, l, c); 4185 } 4186 4187 void 4188 base_parser::finish_classdef_file (tree_classdef *cls, 4189 tree_statement_list *local_fcns) 4190 { 4191 if (m_lexer.m_reading_classdef_file) 4192 m_classdef_object = std::shared_ptr<tree_classdef> (cls); 4193 4194 if (local_fcns) 4195 { 4196 symbol_table& symtab 4197 = __get_symbol_table__ ("base_parser::finish_classdef_file"); 4198 4199 for (tree_statement *elt : *local_fcns) 4200 { 4201 tree_command *cmd = elt->command (); 4202 4203 tree_function_def *fcn_def 4204 = dynamic_cast<tree_function_def *> (cmd); 4205 4206 octave_value ov_fcn = fcn_def->function (); 4207 octave_function *fcn = ov_fcn.function_value (); 4208 std::string nm = fcn->name (); 4209 std::string file = fcn->fcn_file_name (); 4210 4211 symtab.install_local_function (nm, ov_fcn, file); 4212 } 4213 4214 delete local_fcns; 4215 } 4216 } 4217 4218 // Make an index expression. 4219 4220 tree_index_expression * 4221 base_parser::make_index_expression (tree_expression *expr, 4222 tree_argument_list *args, 4223 char type) 4224 { 4225 tree_index_expression *retval = nullptr; 4226 4227 if (args && args->has_magic_tilde ()) 4228 { 4229 delete expr; 4230 delete args; 4231 4232 bison_error ("invalid use of empty argument (~) in index expression"); 4233 } 4234 else 4235 { 4236 int l = expr->line (); 4237 int c = expr->column (); 4238 4239 if (! expr->is_postfix_indexed ()) 4240 expr->set_postfix_index (type); 4241 4242 if (expr->is_index_expression ()) 4243 { 4244 tree_index_expression *tmp 4245 = dynamic_cast<tree_index_expression *> (expr); 4246 4247 tmp->append (args, type); 4248 4249 retval = tmp; 4250 } 4251 else 4252 retval = new tree_index_expression (expr, args, l, c, type); 4253 } 4254 4255 return retval; 4256 } 4257 4258 // Make an indirect reference expression. 4259 4260 tree_index_expression * 4261 base_parser::make_indirect_ref (tree_expression *expr, 4262 const std::string& elt) 4263 { 4264 tree_index_expression *retval = nullptr; 4265 4266 int l = expr->line (); 4267 int c = expr->column (); 4268 4269 if (! expr->is_postfix_indexed ()) 4270 expr->set_postfix_index ('.'); 4271 4272 if (expr->is_index_expression ()) 4273 { 4274 tree_index_expression *tmp 4275 = dynamic_cast<tree_index_expression *> (expr); 4276 4277 tmp->append (elt); 4278 4279 retval = tmp; 4280 } 4281 else 4282 retval = new tree_index_expression (expr, elt, l, c); 4283 4284 m_lexer.m_looking_at_indirect_ref = false; 4285 4286 return retval; 4287 } 4288 4289 // Make an indirect reference expression with dynamic field name. 4290 4291 tree_index_expression * 4292 base_parser::make_indirect_ref (tree_expression *expr, 4293 tree_expression *elt) 4294 { 4295 tree_index_expression *retval = nullptr; 4296 4297 int l = expr->line (); 4298 int c = expr->column (); 4299 4300 if (! expr->is_postfix_indexed ()) 4301 expr->set_postfix_index ('.'); 4302 4303 if (expr->is_index_expression ()) 4304 { 4305 tree_index_expression *tmp 4306 = dynamic_cast<tree_index_expression *> (expr); 4307 4308 tmp->append (elt); 4309 4310 retval = tmp; 4311 } 4312 else 4313 retval = new tree_index_expression (expr, elt, l, c); 4314 4315 m_lexer.m_looking_at_indirect_ref = false; 4316 4317 return retval; 4318 } 4319 4320 // Make a declaration command. 4321 4322 tree_decl_command * 4323 base_parser::make_decl_command (int tok, token *tok_val, 4324 tree_decl_init_list *lst) 4325 { 4326 tree_decl_command *retval = nullptr; 4327 4328 int l = tok_val->line (); 4329 int c = tok_val->column (); 4330 4331 if (lst) 4332 m_lexer.mark_as_variables (lst->variable_names ()); 4333 4334 switch (tok) 4335 { 4336 case GLOBAL: 4337 { 4338 retval = new tree_decl_command ("global", lst, l, c); 4339 retval->mark_global (); 4340 } 4341 break; 4342 4343 case PERSISTENT: 4344 if (m_curr_fcn_depth >= 0) 4345 { 4346 retval = new tree_decl_command ("persistent", lst, l, c); 4347 retval->mark_persistent (); 4348 } 4349 else 4350 { 4351 if (m_lexer.m_reading_script_file) 4352 warning ("ignoring persistent declaration near line %d of file '%s'", 4353 l, m_lexer.m_fcn_file_full_name.c_str ()); 4354 else 4355 warning ("ignoring persistent declaration near line %d", l); 4356 } 4357 break; 4358 4359 default: 4360 panic_impossible (); 4361 break; 4362 } 4363 4364 return retval; 4365 } 4366 4367 bool 4368 base_parser::validate_param_list (tree_parameter_list *lst, 4369 tree_parameter_list::in_or_out type) 4370 { 4371 std::set<std::string> dict; 4372 4373 for (tree_decl_elt *elt : *lst) 4374 { 4375 tree_identifier *id = elt->ident (); 4376 4377 if (id) 4378 { 4379 std::string name = id->name (); 4380 4381 if (id->is_black_hole ()) 4382 { 4383 if (type != tree_parameter_list::in) 4384 { 4385 bison_error ("invalid use of ~ in output list"); 4386 return false; 4387 } 4388 } 4389 else if (dict.find (name) != dict.end ()) 4390 { 4391 bison_error ("'" + name 4392 + "' appears more than once in parameter list"); 4393 return false; 4394 } 4395 else 4396 dict.insert (name); 4397 } 4398 } 4399 4400 std::string va_type = (type == tree_parameter_list::in 4401 ? "varargin" : "varargout"); 4402 4403 std::size_t len = lst->length (); 4404 4405 if (len > 0) 4406 { 4407 tree_decl_elt *elt = lst->back (); 4408 4409 tree_identifier *id = elt->ident (); 4410 4411 if (id && id->name () == va_type) 4412 { 4413 if (len == 1) 4414 lst->mark_varargs_only (); 4415 else 4416 lst->mark_varargs (); 4417 4418 tree_parameter_list::iterator p = lst->end (); 4419 --p; 4420 delete *p; 4421 lst->erase (p); 4422 } 4423 } 4424 4425 return true; 4426 } 4427 4428 bool 4429 base_parser::validate_array_list (tree_expression *e) 4430 { 4431 bool retval = true; 4432 4433 tree_array_list *al = dynamic_cast<tree_array_list *> (e); 4434 4435 for (tree_argument_list* row : *al) 4436 { 4437 if (row && row->has_magic_tilde ()) 4438 { 4439 retval = false; 4440 4441 if (e->is_matrix ()) 4442 bison_error ("invalid use of tilde (~) in matrix expression"); 4443 else 4444 bison_error ("invalid use of tilde (~) in cell expression"); 4445 4446 break; 4447 } 4448 } 4449 4450 return retval; 4451 } 4452 4453 tree_argument_list * 4454 base_parser::validate_matrix_for_assignment (tree_expression *e) 4455 { 4456 tree_argument_list *retval = nullptr; 4457 4458 if (e->is_constant ()) 4459 { 4460 tree_evaluator& tw 4461 = __get_evaluator__ ("validate_matrix_for_assignment"); 4462 4463 octave_value ov = e->evaluate (tw); 4464 4465 delete e; 4466 4467 if (ov.isempty ()) 4468 bison_error ("invalid empty left hand side of assignment"); 4469 else 4470 bison_error ("invalid constant left hand side of assignment"); 4471 } 4472 else 4473 { 4474 bool is_simple_assign = true; 4475 4476 tree_argument_list *tmp = nullptr; 4477 4478 if (e->is_matrix ()) 4479 { 4480 tree_matrix *mat = dynamic_cast<tree_matrix *> (e); 4481 4482 if (mat && mat->size () == 1) 4483 { 4484 tmp = mat->front (); 4485 mat->pop_front (); 4486 delete e; 4487 is_simple_assign = false; 4488 } 4489 } 4490 else 4491 tmp = new tree_argument_list (e); 4492 4493 if (tmp && tmp->is_valid_lvalue_list ()) 4494 { 4495 m_lexer.mark_as_variables (tmp->variable_names ()); 4496 retval = tmp; 4497 } 4498 else 4499 { 4500 delete tmp; 4501 4502 bison_error ("invalid left hand side of assignment"); 4503 } 4504 4505 if (retval && is_simple_assign) 4506 retval->mark_as_simple_assign_lhs (); 4507 } 4508 4509 return retval; 4510 } 4511 4512 // Finish building an array_list. 4513 4514 tree_expression * 4515 base_parser::finish_array_list (tree_array_list *array_list, 4516 token */*open_delim*/, token *close_delim) 4517 { 4518 tree_expression *retval = array_list; 4519 4520 array_list->set_location (close_delim->line (), close_delim->column ()); 4521 4522 if (array_list->all_elements_are_constant ()) 4523 { 4524 interpreter& interp = __get_interpreter__ ("finish_array_list"); 4525 4526 try 4527 { 4528 // If the evaluation generates a warning message, restore 4529 // the previous value of last_warning_message and skip the 4530 // conversion to a constant value. 4531 4532 unwind_protect frame; 4533 4534 error_system& es = interp.get_error_system (); 4535 4536 frame.add_method (es, &error_system::set_last_warning_message, 4537 es.last_warning_message ("")); 4538 4539 frame.add_method (es, &error_system::set_discard_warning_messages, 4540 es.discard_warning_messages (true)); 4541 4542 tree_evaluator& tw = interp.get_evaluator (); 4543 4544 octave_value tmp = array_list->evaluate (tw); 4545 4546 std::string msg = es.last_warning_message (); 4547 4548 if (msg.empty ()) 4549 { 4550 tree_constant *tc_retval 4551 = new tree_constant (tmp, close_delim->line (), 4552 close_delim->column ()); 4553 4554 std::ostringstream buf; 4555 4556 tree_print_code tpc (buf); 4557 4558 array_list->accept (tpc); 4559 4560 tc_retval->stash_original_text (buf.str ()); 4561 4562 delete array_list; 4563 4564 retval = tc_retval; 4565 } 4566 } 4567 catch (const execution_exception&) 4568 { 4569 interp.recover_from_exception (); 4570 } 4571 } 4572 4573 return retval; 4574 } 4575 4576 // Finish building a matrix list. 4577 4578 tree_expression * 4579 base_parser::finish_matrix (tree_matrix *m, token *open_delim, 4580 token *close_delim) 4581 { 4582 return (m 4583 ? finish_array_list (m, open_delim, close_delim) 4584 : new tree_constant (octave_null_matrix::instance, 4585 close_delim->line (), close_delim->column ())); 4586 } 4587 4588 // Finish building a cell list. 4589 4590 tree_expression * 4591 base_parser::finish_cell (tree_cell *c, token *open_delim, 4592 token *close_delim) 4593 { 4594 return (c 4595 ? finish_array_list (c, open_delim, close_delim) 4596 : new tree_constant (octave_value (Cell ()), 4597 close_delim->line (), close_delim->column ())); 4598 } 4599 4600 tree_statement_list * 4601 base_parser::set_stmt_print_flag (tree_statement_list *list, 4602 char sep, bool warn_missing_semi) 4603 { 4604 tree_statement *tmp = list->back (); 4605 4606 switch (sep) 4607 { 4608 case ';': 4609 tmp->set_print_flag (false); 4610 break; 4611 4612 case 0: 4613 case ',': 4614 case '\n': 4615 tmp->set_print_flag (true); 4616 if (warn_missing_semi) 4617 maybe_warn_missing_semi (list); 4618 break; 4619 4620 default: 4621 warning ("unrecognized separator type!"); 4622 break; 4623 } 4624 4625 // Even if a statement is null, we add it to the list then remove it 4626 // here so that the print flag is applied to the correct statement. 4627 4628 if (tmp->is_null_statement ()) 4629 { 4630 list->pop_back (); 4631 delete tmp; 4632 } 4633 4634 return list; 4635 } 4636 4637 // Finish building a statement. 4638 template <typename T> 4639 tree_statement * 4640 base_parser::make_statement (T *arg) 4641 { 4642 comment_list *comment = m_lexer.get_comment (); 4643 4644 return new tree_statement (arg, comment); 4645 } 4646 4647 tree_statement_list * 4648 base_parser::make_statement_list (tree_statement *stmt) 4649 { 4650 return new tree_statement_list (stmt); 4651 } 4652 4653 tree_statement_list * 4654 base_parser::append_statement_list (tree_statement_list *list, 4655 char sep, tree_statement *stmt, 4656 bool warn_missing_semi) 4657 { 4658 set_stmt_print_flag (list, sep, warn_missing_semi); 4659 4660 list->append (stmt); 4661 4662 return list; 4663 } 4664 4665 void 4666 base_parser::disallow_command_syntax (void) 4667 { 4668 m_lexer.m_allow_command_syntax = false; 4669 } 4670 4671 // FIXME: this function partially duplicates do_dbtype in debug.cc. 4672 static std::string 4673 get_file_line (const std::string& name, int line) 4674 { 4675 // NAME should be an absolute file name and the file should exist. 4676 4677 std::ifstream fs = sys::ifstream (name.c_str (), std::ios::in); 4678 4679 std::string text; 4680 4681 if (fs) 4682 { 4683 int i = 1; 4684 4685 do 4686 { 4687 if (! std::getline (fs, text)) 4688 { 4689 text = ""; 4690 break; 4691 } 4692 } 4693 while (i++ < line); 4694 } 4695 4696 return text; 4697 } 4698 4699 void 4700 base_parser::bison_error (const std::string& str) 4701 { 4702 bison_error (str, m_lexer.m_filepos); 4703 } 4704 4705 void 4706 base_parser::bison_error (const std::string& str, const filepos& pos) 4707 { 4708 bison_error (str, pos.line (), pos.column ()); 4709 } 4710 4711 void 4712 base_parser::bison_error (const std::string& str, int err_line, int err_col) 4713 { 4714 std::ostringstream output_buf; 4715 4716 if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_script_file 4717 || m_lexer.m_reading_classdef_file) 4718 output_buf << "parse error near line " << err_line 4719 << " of file " << m_lexer.m_fcn_file_full_name; 4720 else 4721 output_buf << "parse error:"; 4722 4723 if (str != "parse error") 4724 output_buf << "\n\n " << str; 4725 4726 output_buf << "\n\n"; 4727 4728 std::string curr_line; 4729 4730 if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_script_file 4731 || m_lexer.m_reading_classdef_file) 4732 curr_line = get_file_line (m_lexer.m_fcn_file_full_name, err_line); 4733 else 4734 curr_line = m_lexer.m_current_input_line; 4735 4736 // Adjust the error column for display because it is 1-based in the 4737 // lexer for easier reporting. 4738 err_col--; 4739 4740 if (! curr_line.empty ()) 4741 { 4742 // FIXME: we could do better if we just cached lines from the 4743 // input file in a list. See also functions for managing input 4744 // buffers in lex.ll. 4745 4746 std::size_t len = curr_line.length (); 4747 4748 if (curr_line[len-1] == '\n') 4749 curr_line.resize (len-1); 4750 4751 // Print the line, maybe with a pointer near the error token. 4752 4753 output_buf << ">>> " << curr_line << "\n"; 4754 4755 if (err_col == 0) 4756 err_col = len; 4757 4758 for (int i = 0; i < err_col + 3; i++) 4759 output_buf << " "; 4760 4761 output_buf << "^"; 4762 } 4763 4764 output_buf << "\n"; 4765 4766 m_parse_error_msg = output_buf.str (); 4767 } 4768 4769 int 4770 parser::run (void) 4771 { 4772 int status = -1; 4773 4774 yypstate *pstate = static_cast<yypstate *> (m_parser_state); 4775 4776 try 4777 { 4778 status = octave_pull_parse (pstate, *this); 4779 } 4780 catch (const execution_exception&) 4781 { 4782 // FIXME: In previous versions, we emitted a parse error here 4783 // but that is not always correct because the error could have 4784 // happened inside a GUI callback functions executing in the 4785 // readline event_hook loop. Maybe we need a separate exception 4786 // class for parse errors? 4787 4788 throw; 4789 } 4790 catch (const exit_exception&) 4791 { 4792 throw; 4793 } 4794 catch (const interrupt_exception&) 4795 { 4796 throw; 4797 } 4798 catch (...) 4799 { 4800 std::string file = m_lexer.m_fcn_file_full_name; 4801 4802 if (file.empty ()) 4803 error ("unexpected exception while parsing input"); 4804 else 4805 error ("unexpected exception while parsing %s", file.c_str ()); 4806 } 4807 4808 if (status != 0) 4809 parse_error ("%s", m_parse_error_msg.c_str ()); 4810 4811 return status; 4812 } 4813 4814 // Parse input from INPUT. Pass TRUE for EOF if the end of INPUT should 4815 // finish the parse. 4816 4817 int 4818 push_parser::run (const std::string& input, bool eof) 4819 { 4820 int status = -1; 4821 4822 dynamic_cast<push_lexer&> (m_lexer).append_input (input, eof); 4823 4824 do 4825 { 4826 YYSTYPE lval; 4827 4828 int token = octave_lex (&lval, m_lexer.m_scanner); 4829 4830 if (token < 0) 4831 { 4832 // TOKEN == -2 means that the lexer recognized a comment 4833 // and we should be at the end of the buffer but not the 4834 // end of the file so we should return 0 to indicate 4835 // "complete input" instead of -1 to request more input. 4836 4837 status = (token == -2 ? 0 : -1); 4838 4839 if (! eof && m_lexer.at_end_of_buffer ()) 4840 return status; 4841 4842 break; 4843 } 4844 4845 yypstate *pstate = static_cast<yypstate *> (m_parser_state); 4846 4847 try 4848 { 4849 status = octave_push_parse (pstate, token, &lval, *this); 4850 } 4851 catch (execution_exception& e) 4852 { 4853 std::string file = m_lexer.m_fcn_file_full_name; 4854 4855 if (file.empty ()) 4856 error (e, "parse error"); 4857 else 4858 error (e, "parse error in %s", file.c_str ()); 4859 } 4860 catch (const exit_exception&) 4861 { 4862 throw; 4863 } 4864 catch (interrupt_exception &) 4865 { 4866 throw; 4867 } 4868 catch (...) 4869 { 4870 std::string file = m_lexer.m_fcn_file_full_name; 4871 4872 if (file.empty ()) 4873 error ("unexpected exception while parsing input"); 4874 else 4875 error ("unexpected exception while parsing %s", file.c_str ()); 4876 } 4877 } 4878 while (status == YYPUSH_MORE || ! m_lexer.at_end_of_buffer ()); 4879 4880 if (status != 0) 4881 parse_error ("%s", m_parse_error_msg.c_str ()); 4882 4883 return status; 4884 } 4885 4886 int 4887 push_parser::run (void) 4888 { 4889 if (! m_reader) 4890 error ("push_parser::run requires valid input_reader"); 4891 4892 int exit_status = 0; 4893 4894 input_system& input_sys = m_interpreter.get_input_system (); 4895 4896 std::string prompt 4897 = command_editor::decode_prompt_string (input_sys.PS1 ()); 4898 4899 do 4900 { 4901 // Reset status each time through the read loop so that 4902 // it won't be set to -1 and cause us to exit the outer 4903 // loop early if there is an exception while reading 4904 // input or parsing. 4905 4906 exit_status = 0; 4907 4908 bool eof = false; 4909 std::string input_line = m_reader->get_input (prompt, eof); 4910 4911 if (eof) 4912 { 4913 exit_status = EOF; 4914 break; 4915 } 4916 4917 exit_status = run (input_line, false); 4918 4919 prompt = command_editor::decode_prompt_string (input_sys.PS2 ()); 4920 } 4921 while (exit_status < 0); 4922 4923 return exit_status; 4924 } 4925 4926 octave_value 4927 parse_fcn_file (interpreter& interp, const std::string& full_file, 4928 const std::string& file, const std::string& dir_name, 4929 const std::string& dispatch_type, 4930 const std::string& package_name, bool require_file, 4931 bool force_script, bool autoload, bool relative_lookup) 4932 { 4933 octave_value retval; 4934 4935 FILE *ffile = nullptr; 4936 4937 if (! full_file.empty ()) 4938 ffile = sys::fopen (full_file, "rb"); 4939 4940 if (! ffile) 4941 { 4942 if (require_file) 4943 error ("no such file, '%s'", full_file.c_str ()); 4944 4945 return octave_value (); 4946 } 4947 4948 unwind_action act ([ffile] (void) 4949 { 4950 fclose (ffile); 4951 }); 4952 4953 parser parser (ffile, interp); 4954 4955 parser.m_curr_class_name = dispatch_type; 4956 parser.m_curr_package_name = package_name; 4957 parser.m_autoloading = autoload; 4958 parser.m_fcn_file_from_relative_lookup = relative_lookup; 4959 4960 parser.m_lexer.m_force_script = force_script; 4961 parser.m_lexer.prep_for_file (); 4962 parser.m_lexer.m_parsing_class_method = ! dispatch_type.empty (); 4963 4964 parser.m_lexer.m_fcn_file_name = file; 4965 parser.m_lexer.m_fcn_file_full_name = full_file; 4966 parser.m_lexer.m_dir_name = dir_name; 4967 parser.m_lexer.m_package_name = package_name; 4968 4969 int err = parser.run (); 4970 4971 if (err) 4972 error ("parse error while reading file %s", full_file.c_str ()); 4973 4974 octave_value ov_fcn = parser.m_primary_fcn; 4975 4976 if (parser.m_lexer.m_reading_classdef_file 4977 && parser.classdef_object ()) 4978 { 4979 // Convert parse tree for classdef object to 4980 // meta.class info (and stash it in the symbol 4981 // table?). Return pointer to constructor? 4982 4983 if (ov_fcn.is_defined ()) 4984 panic_impossible (); 4985 4986 bool is_at_folder = ! dispatch_type.empty (); 4987 4988 std::shared_ptr<tree_classdef> cdef_obj 4989 = parser.classdef_object(); 4990 4991 return cdef_obj->make_meta_class (interp, is_at_folder); 4992 } 4993 else if (ov_fcn.is_defined ()) 4994 { 4995 octave_function *fcn = ov_fcn.function_value (); 4996 4997 fcn->maybe_relocate_end (); 4998 4999 if (parser.m_parsing_subfunctions) 5000 { 5001 if (! parser.m_endfunction_found) 5002 parser.m_subfunction_names.reverse (); 5003 5004 fcn->stash_subfunction_names (parser.m_subfunction_names); 5005 } 5006 5007 return ov_fcn; 5008 } 5009 5010 return octave_value (); 5011 } 5012 5013 // Maybe print a warning if an assignment expression is used as the 5014 // test in a logical expression. 5015 5016 void 5017 base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr) 5018 { 5019 if (expr->is_assignment_expression () 5020 && expr->paren_count () < 2) 5021 { 5022 if (m_lexer.m_fcn_file_full_name.empty ()) 5023 warning_with_id 5024 ("Octave:assign-as-truth-value", 5025 "suggest parenthesis around assignment used as truth value"); 5026 else 5027 warning_with_id 5028 ("Octave:assign-as-truth-value", 5029 "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'", 5030 expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ()); 5031 } 5032 } 5033 5034 // Maybe print a warning about switch labels that aren't constants. 5035 5036 void 5037 base_parser::maybe_warn_variable_switch_label (tree_expression *expr) 5038 { 5039 if (! expr->is_constant ()) 5040 { 5041 if (m_lexer.m_fcn_file_full_name.empty ()) 5042 warning_with_id ("Octave:variable-switch-label", 5043 "variable switch label"); 5044 else 5045 warning_with_id 5046 ("Octave:variable-switch-label", 5047 "variable switch label near line %d, column %d in file '%s'", 5048 expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ()); 5049 } 5050 } 5051 5052 void 5053 base_parser::maybe_warn_missing_semi (tree_statement_list *t) 5054 { 5055 if (m_curr_fcn_depth >= 0) 5056 { 5057 tree_statement *tmp = t->back (); 5058 5059 if (tmp->is_expression ()) 5060 warning_with_id 5061 ("Octave:missing-semicolon", 5062 "missing semicolon near line %d, column %d in file '%s'", 5063 tmp->line (), tmp->column (), m_lexer.m_fcn_file_full_name.c_str ()); 5064 } 5065 } 5066 5067 std::string 5068 get_help_from_file (const std::string& nm, bool& symbol_found, 5069 std::string& full_file) 5070 { 5071 std::string retval; 5072 5073 full_file = fcn_file_in_path (nm); 5074 5075 std::string file = full_file; 5076 5077 std::size_t file_len = file.length (); 5078 5079 if ((file_len > 4 && file.substr (file_len-4) == ".oct") 5080 || (file_len > 4 && file.substr (file_len-4) == ".mex") 5081 || (file_len > 2 && file.substr (file_len-2) == ".m")) 5082 { 5083 file = sys::env::base_pathname (file); 5084 file = file.substr (0, file.find_last_of ('.')); 5085 5086 std::size_t pos = file.find_last_of (sys::file_ops::dir_sep_str ()); 5087 if (pos != std::string::npos) 5088 file = file.substr (pos+1); 5089 } 5090 5091 if (! file.empty ()) 5092 { 5093 interpreter& interp = __get_interpreter__ ("get_help_from_file"); 5094 5095 symbol_found = true; 5096 5097 octave_value ov_fcn 5098 = parse_fcn_file (interp, full_file, file, "", "", "", true, 5099 false, false, false); 5100 5101 if (ov_fcn.is_defined ()) 5102 { 5103 octave_function *fcn = ov_fcn.function_value (); 5104 5105 if (fcn) 5106 retval = fcn->doc_string (); 5107 } 5108 } 5109 5110 return retval; 5111 } 5112 5113 std::string 5114 get_help_from_file (const std::string& nm, bool& symbol_found) 5115 { 5116 std::string file; 5117 return get_help_from_file (nm, symbol_found, file); 5118 } 5119 5120 octave_value 5121 load_fcn_from_file (const std::string& file_name, 5122 const std::string& dir_name, 5123 const std::string& dispatch_type, 5124 const std::string& package_name, 5125 const std::string& fcn_name, bool autoload) 5126 { 5127 octave_value retval; 5128 5129 unwind_protect frame; 5130 5131 std::string nm = file_name; 5132 5133 std::size_t nm_len = nm.length (); 5134 5135 std::string file; 5136 5137 bool relative_lookup = false; 5138 5139 file = nm; 5140 5141 if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct") 5142 || (nm_len > 4 && nm.substr (nm_len-4) == ".mex") 5143 || (nm_len > 2 && nm.substr (nm_len-2) == ".m")) 5144 { 5145 nm = sys::env::base_pathname (file); 5146 nm = nm.substr (0, nm.find_last_of ('.')); 5147 5148 std::size_t pos = nm.find_last_of (sys::file_ops::dir_sep_str ()); 5149 if (pos != std::string::npos) 5150 nm = nm.substr (pos+1); 5151 } 5152 5153 relative_lookup = ! sys::env::absolute_pathname (file); 5154 5155 file = sys::env::make_absolute (file); 5156 5157 int len = file.length (); 5158 5159 interpreter& interp = __get_interpreter__ ("load_fcn_from_file"); 5160 5161 dynamic_loader& dyn_loader = interp.get_dynamic_loader (); 5162 5163 if (len > 4 && file.substr (len-4, len-1) == ".oct") 5164 { 5165 if (autoload && ! fcn_name.empty ()) 5166 nm = fcn_name; 5167 5168 octave_function *tmpfcn 5169 = dyn_loader.load_oct (nm, file, relative_lookup); 5170 5171 if (tmpfcn) 5172 { 5173 tmpfcn->stash_package_name (package_name); 5174 retval = octave_value (tmpfcn); 5175 } 5176 } 5177 else if (len > 4 && file.substr (len-4, len-1) == ".mex") 5178 { 5179 // Temporarily load m-file version of mex-file, if it exists, 5180 // to get the help-string to use. 5181 5182 std::string doc_string; 5183 5184 octave_value ov_fcn 5185 = parse_fcn_file (interp, file.substr (0, len - 2), nm, dir_name, 5186 dispatch_type, package_name, false, 5187 autoload, autoload, relative_lookup); 5188 5189 if (ov_fcn.is_defined ()) 5190 { 5191 octave_function *tmpfcn = ov_fcn.function_value (); 5192 5193 if (tmpfcn) 5194 doc_string = tmpfcn->doc_string (); 5195 } 5196 5197 octave_function *tmpfcn 5198 = dyn_loader.load_mex (nm, file, relative_lookup); 5199 5200 if (tmpfcn) 5201 { 5202 tmpfcn->document (doc_string); 5203 tmpfcn->stash_package_name (package_name); 5204 5205 retval = octave_value (tmpfcn); 5206 } 5207 } 5208 else if (len > 2) 5209 { 5210 retval = parse_fcn_file (interp, file, nm, dir_name, 5211 dispatch_type, package_name, true, 5212 autoload, autoload, relative_lookup); 5213 } 5214 5215 return retval; 5216 } 5217} 5218 5219DEFMETHOD (autoload, interp, args, , 5220 doc: /* -*- texinfo -*- 5221@deftypefn {} {@var{autoload_map} =} autoload () 5222@deftypefnx {} {} autoload (@var{function}, @var{file}) 5223@deftypefnx {} {} autoload (@dots{}, "remove") 5224Define @var{function} to autoload from @var{file}. 5225 5226The second argument, @var{file}, should be an absolute filename or a file 5227name in the same directory as the function or script from which the autoload 5228command was run. @var{file} @emph{should not} depend on the Octave load 5229path. 5230 5231Normally, calls to @code{autoload} appear in PKG_ADD script files that are 5232evaluated when a directory is added to Octave's load path. To avoid having 5233to hardcode directory names in @var{file}, if @var{file} is in the same 5234directory as the PKG_ADD script then 5235 5236@example 5237autoload ("foo", "bar.oct"); 5238@end example 5239 5240@noindent 5241will load the function @code{foo} from the file @code{bar.oct}. The above 5242usage when @code{bar.oct} is not in the same directory, or usages such as 5243 5244@example 5245autoload ("foo", file_in_loadpath ("bar.oct")) 5246@end example 5247 5248@noindent 5249are strongly discouraged, as their behavior may be unpredictable. 5250 5251With no arguments, return a structure containing the current autoload map. 5252 5253If a third argument @qcode{"remove"} is given, the function is cleared and 5254not loaded anymore during the current Octave session. 5255 5256@seealso{PKG_ADD} 5257@end deftypefn */) 5258{ 5259 int nargin = args.length (); 5260 5261 if (nargin == 1 || nargin > 3) 5262 print_usage (); 5263 5264 octave::tree_evaluator& tw = interp.get_evaluator (); 5265 5266 if (nargin == 0) 5267 return octave_value (tw.get_autoload_map ()); 5268 else 5269 { 5270 string_vector argv = args.make_argv ("autoload"); 5271 5272 if (nargin == 2) 5273 tw.add_autoload (argv[1], argv[2]); 5274 else if (nargin == 3) 5275 { 5276 if (argv[3] != "remove") 5277 error_with_id ("Octave:invalid-input-arg", 5278 "autoload: third argument can only be 'remove'"); 5279 5280 tw.remove_autoload (argv[1], argv[2]); 5281 } 5282 } 5283 5284 return octave_value_list (); 5285} 5286 5287DEFMETHOD (mfilename, interp, args, , 5288 doc: /* -*- texinfo -*- 5289@deftypefn {} {} mfilename () 5290@deftypefnx {} {} mfilename ("fullpath") 5291@deftypefnx {} {} mfilename ("fullpathext") 5292Return the name of the currently executing file. 5293 5294The base name of the currently executing script or function is returned without 5295any extension. If called from outside an m-file, such as the command line, 5296return the empty string. 5297 5298Given the argument @qcode{"fullpath"}, include the directory part of the 5299filename, but not the extension. 5300 5301Given the argument @qcode{"fullpathext"}, include the directory part of 5302the filename and the extension. 5303@seealso{inputname, dbstack} 5304@end deftypefn */) 5305{ 5306 int nargin = args.length (); 5307 5308 if (nargin > 1) 5309 print_usage (); 5310 5311 std::string opt; 5312 5313 if (nargin == 1) 5314 opt = args(0).xstring_value ("mfilename: option argument must be a string"); 5315 5316 return octave_value (interp.mfilename (opt)); 5317} 5318 5319namespace octave 5320{ 5321 // Execute the contents of a script file. For compatibility with 5322 // Matlab, also execute a function file by calling the function it 5323 // defines with no arguments and nargout = 0. 5324 5325 void 5326 source_file (const std::string& file_name, const std::string& context, 5327 bool verbose, bool require_file) 5328 { 5329 interpreter& interp = __get_interpreter__ ("source_file"); 5330 5331 interp.source_file (file_name, context, verbose, require_file); 5332 } 5333} 5334 5335DEFMETHOD (source, interp, args, , 5336 doc: /* -*- texinfo -*- 5337@deftypefn {} {} source (@var{file}) 5338@deftypefnx {} {} source (@var{file}, @var{context}) 5339Parse and execute the contents of @var{file}. 5340 5341Without specifying @var{context}, this is equivalent to executing commands 5342from a script file, but without requiring the file to be named 5343@file{@var{file}.m} or to be on the execution path. 5344 5345Instead of the current context, the script may be executed in either the 5346context of the function that called the present function 5347(@qcode{"caller"}), or the top-level context (@qcode{"base"}). 5348@seealso{run} 5349@end deftypefn */) 5350{ 5351 int nargin = args.length (); 5352 5353 if (nargin < 1 || nargin > 2) 5354 print_usage (); 5355 5356 std::string file_name 5357 = args(0).xstring_value ("source: FILE must be a string"); 5358 5359 std::string context; 5360 if (nargin == 2) 5361 context = args(1).xstring_value ("source: CONTEXT must be a string"); 5362 5363 interp.source_file (file_name, context); 5364 5365 return octave_value_list (); 5366} 5367 5368namespace octave 5369{ 5370 //! Evaluate an Octave function (built-in or interpreted) and return 5371 //! the list of result values. 5372 //! 5373 //! @param name The name of the function to call. 5374 //! @param args The arguments to the function. 5375 //! @param nargout The number of output arguments expected. 5376 //! @return A list of output values. The length of the list is not 5377 //! necessarily the same as @c nargout. 5378 5379 octave_value_list 5380 feval (const char *name, const octave_value_list& args, int nargout) 5381 { 5382 interpreter& interp = __get_interpreter__ ("feval"); 5383 5384 return interp.feval (name, args, nargout); 5385 } 5386 5387 octave_value_list 5388 feval (const std::string& name, const octave_value_list& args, int nargout) 5389 { 5390 interpreter& interp = __get_interpreter__ ("feval"); 5391 5392 return interp.feval (name, args, nargout); 5393 } 5394 5395 octave_value_list 5396 feval (octave_function *fcn, const octave_value_list& args, int nargout) 5397 { 5398 interpreter& interp = __get_interpreter__ ("feval"); 5399 5400 return interp.feval (fcn, args, nargout); 5401 } 5402 5403 octave_value_list 5404 feval (const octave_value& val, const octave_value_list& args, int nargout) 5405 { 5406 interpreter& interp = __get_interpreter__ ("feval"); 5407 5408 return interp.feval (val, args, nargout); 5409 } 5410 5411 octave_value_list 5412 feval (const octave_value_list& args, int nargout) 5413 { 5414 interpreter& interp = __get_interpreter__ ("feval"); 5415 5416 return interp.feval (args, nargout); 5417 } 5418} 5419 5420DEFMETHOD (feval, interp, args, nargout, 5421 doc: /* -*- texinfo -*- 5422@deftypefn {} {} feval (@var{name}, @dots{}) 5423Evaluate the function named @var{name}. 5424 5425Any arguments after the first are passed as inputs to the named function. 5426For example, 5427 5428@example 5429@group 5430feval ("acos", -1) 5431 @result{} 3.1416 5432@end group 5433@end example 5434 5435@noindent 5436calls the function @code{acos} with the argument @samp{-1}. 5437 5438The function @code{feval} can also be used with function handles of any sort 5439(@pxref{Function Handles}). Historically, @code{feval} was the only way to 5440call user-supplied functions in strings, but function handles are now 5441preferred due to the cleaner syntax they offer. For example, 5442 5443@example 5444@group 5445@var{f} = @@exp; 5446feval (@var{f}, 1) 5447 @result{} 2.7183 5448@var{f} (1) 5449 @result{} 2.7183 5450@end group 5451@end example 5452 5453@noindent 5454are equivalent ways to call the function referred to by @var{f}. If it 5455cannot be predicted beforehand whether @var{f} is a function handle, 5456function name in a string, or inline function then @code{feval} can be used 5457instead. 5458@end deftypefn */) 5459{ 5460 if (args.length () == 0) 5461 print_usage (); 5462 5463 return interp.feval (args, nargout); 5464} 5465 5466DEFMETHOD (builtin, interp, args, nargout, 5467 doc: /* -*- texinfo -*- 5468@deftypefn {} {[@dots{}] =} builtin (@var{f}, @dots{}) 5469Call the base function @var{f} even if @var{f} is overloaded to another 5470function for the given type signature. 5471 5472This is normally useful when doing object-oriented programming and there is 5473a requirement to call one of Octave's base functions rather than the 5474overloaded one of a new class. 5475 5476A trivial example which redefines the @code{sin} function to be the 5477@code{cos} function shows how @code{builtin} works. 5478 5479@example 5480@group 5481sin (0) 5482 @result{} 0 5483function y = sin (x), y = cos (x); endfunction 5484sin (0) 5485 @result{} 1 5486builtin ("sin", 0) 5487 @result{} 0 5488@end group 5489@end example 5490@end deftypefn */) 5491{ 5492 octave_value_list retval; 5493 5494 if (args.length () == 0) 5495 print_usage (); 5496 5497 const std::string name (args(0).xstring_value ("builtin: function name (F) must be a string")); 5498 5499 octave::symbol_table& symtab = interp.get_symbol_table (); 5500 5501 octave_value fcn = symtab.builtin_find (name); 5502 5503 if (fcn.is_defined ()) 5504 retval = interp.feval (fcn.function_value (), args.splice (0, 1), nargout); 5505 else 5506 error ("builtin: lookup for symbol '%s' failed", name.c_str ()); 5507 5508 return retval; 5509} 5510 5511namespace octave 5512{ 5513 octave_value_list 5514 eval_string (const std::string& eval_str, bool silent, 5515 int& parse_status, int nargout) 5516 { 5517 interpreter& interp = __get_interpreter__ ("eval_string"); 5518 5519 return interp.eval_string (eval_str, silent, parse_status, nargout); 5520 } 5521 5522 octave_value 5523 eval_string (const std::string& eval_str, bool silent, int& parse_status) 5524 { 5525 interpreter& interp = __get_interpreter__ ("eval_string"); 5526 5527 return interp.eval_string (eval_str, silent, parse_status); 5528 } 5529 5530 void 5531 cleanup_statement_list (tree_statement_list **lst) 5532 { 5533 if (*lst) 5534 { 5535 delete *lst; 5536 *lst = nullptr; 5537 } 5538 } 5539} 5540 5541DEFMETHOD (eval, interp, args, nargout, 5542 doc: /* -*- texinfo -*- 5543@deftypefn {} {} eval (@var{try}) 5544@deftypefnx {} {} eval (@var{try}, @var{catch}) 5545Parse the string @var{try} and evaluate it as if it were an Octave 5546program. 5547 5548If execution fails, evaluate the optional string @var{catch}. 5549 5550The string @var{try} is evaluated in the current context, so any results 5551remain available after @code{eval} returns. 5552 5553The following example creates the variable @var{A} with the approximate 5554value of 3.1416 in the current workspace. 5555 5556@example 5557eval ("A = acos(-1);"); 5558@end example 5559 5560If an error occurs during the evaluation of @var{try} then the @var{catch} 5561string is evaluated, as the following example shows: 5562 5563@example 5564@group 5565eval ('error ("This is a bad example");', 5566 'printf ("This error occurred:\n%s\n", lasterr ());'); 5567 @print{} This error occurred: 5568 This is a bad example 5569@end group 5570@end example 5571 5572Programming Note: if you are only using @code{eval} as an error-capturing 5573mechanism, rather than for the execution of arbitrary code strings, 5574Consider using try/catch blocks or unwind_protect/unwind_protect_cleanup 5575blocks instead. These techniques have higher performance and don't 5576introduce the security considerations that the evaluation of arbitrary code 5577does. 5578@seealso{evalin, evalc, assignin, feval} 5579@end deftypefn */) 5580{ 5581 int nargin = args.length (); 5582 5583 if (nargin < 1 || nargin > 2) 5584 print_usage (); 5585 5586 if (! args(0).is_string () || args(0).rows () > 1 || args(0).ndims () != 2) 5587 error ("eval: TRY must be a string"); 5588 5589 std::string try_code = args(0).string_value (); 5590 5591 if (nargin == 1) 5592 return interp.eval (try_code, nargout); 5593 else 5594 { 5595 if (! args(1).is_string () || args(1).rows () > 1 5596 || args(1).ndims () != 2) 5597 error ("eval: CATCH must be a string"); 5598 5599 std::string catch_code = args(1).string_value (); 5600 5601 return interp.eval (try_code, catch_code, nargout); 5602 } 5603} 5604 5605/* 5606 5607%!shared x 5608%! x = 1; 5609 5610%!assert (eval ("x"), 1) 5611%!assert (eval ("x;")) 5612%!assert (eval ("x;"), 1) 5613 5614%!test 5615%! y = eval ("x"); 5616%! assert (y, 1); 5617 5618%!test 5619%! y = eval ("x;"); 5620%! assert (y, 1); 5621 5622%!test 5623%! eval ("x = 1;"); 5624%! assert (x,1); 5625 5626%!test 5627%! eval ("flipud = 2;"); 5628%! assert (flipud, 2); 5629 5630%!function y = __f () 5631%! eval ("flipud = 2;"); 5632%! y = flipud; 5633%!endfunction 5634%!assert (__f(), 2) 5635 5636%!test <*35645> 5637%! [a,] = gcd (1,2); 5638%! [a,b,] = gcd (1, 2); 5639 5640## Can't assign to a keyword 5641%!error eval ("switch = 13;") 5642 5643%!shared str 5644%! str = "disp ('hello');"; 5645%! str(:,:,2) = str(:,:,1); 5646 5647%!error <TRY must be a string> eval (1) 5648%!error <TRY must be a string> eval (['a';'b']) 5649%!error <TRY must be a string> eval (str) 5650 5651%!error <CATCH must be a string> eval (str(:,:,1), 1) 5652%!error <CATCH must be a string> eval (str(:,:,1), ['a';'b']) 5653%!error <CATCH must be a string> eval (str(:,:,1), str) 5654 5655*/ 5656 5657DEFMETHOD (assignin, interp, args, , 5658 doc: /* -*- texinfo -*- 5659@deftypefn {} {} assignin (@var{context}, @var{varname}, @var{value}) 5660Assign @var{value} to @var{varname} in context @var{context}, which 5661may be either @qcode{"base"} or @qcode{"caller"}. 5662@seealso{evalin} 5663@end deftypefn */) 5664{ 5665 if (args.length () != 3) 5666 print_usage (); 5667 5668 std::string context 5669 = args(0).xstring_value ("assignin: CONTEXT must be a string"); 5670 5671 std::string varname 5672 = args(1).xstring_value ("assignin: VARNAME must be a string"); 5673 5674 interp.assignin (context, varname, args(2)); 5675 5676 return octave_value_list (); 5677} 5678 5679/* 5680 5681%!error assignin ("base", "switch", "13") 5682 5683*/ 5684 5685DEFMETHOD (evalin, interp, args, nargout, 5686 doc: /* -*- texinfo -*- 5687@deftypefn {} {} evalin (@var{context}, @var{try}) 5688@deftypefnx {} {} evalin (@var{context}, @var{try}, @var{catch}) 5689Like @code{eval}, except that the expressions are evaluated in the context 5690@var{context}, which may be either @qcode{"caller"} or @qcode{"base"}. 5691@seealso{eval, assignin} 5692@end deftypefn */) 5693{ 5694 int nargin = args.length (); 5695 5696 if (nargin < 2 || nargin > 3) 5697 print_usage (); 5698 5699 std::string context 5700 = args(0).xstring_value ("evalin: CONTEXT must be a string"); 5701 5702 std::string try_code 5703 = args(1).xstring_value ("evalin: TRY must be a string"); 5704 5705 if (nargin == 3) 5706 { 5707 std::string catch_code 5708 = args(2).xstring_value ("evalin: CATCH must be a string"); 5709 5710 return interp.evalin (context, try_code, catch_code, nargout); 5711 } 5712 5713 return interp.evalin (context, try_code, nargout); 5714} 5715 5716DEFMETHOD (evalc, interp, args, nargout, 5717 doc: /* -*- texinfo -*- 5718@deftypefn {} {@var{s} =} evalc (@var{try}) 5719@deftypefnx {} {@var{s} =} evalc (@var{try}, @var{catch}) 5720Parse and evaluate the string @var{try} as if it were an Octave program, 5721while capturing the output into the return variable @var{s}. 5722 5723If execution fails, evaluate the optional string @var{catch}. 5724 5725This function behaves like @code{eval}, but any output or warning messages 5726which would normally be written to the console are captured and returned in 5727the string @var{s}. 5728 5729The @code{diary} is disabled during the execution of this function. When 5730@code{system} is used, any output produced by external programs is 5731@emph{not} captured, unless their output is captured by the @code{system} 5732function itself. 5733 5734@example 5735@group 5736s = evalc ("t = 42"), t 5737 @result{} s = t = 42 5738 5739 @result{} t = 42 5740@end group 5741@end example 5742@seealso{eval, diary} 5743@end deftypefn */) 5744{ 5745 int nargin = args.length (); 5746 5747 if (nargin == 0 || nargin > 2) 5748 print_usage (); 5749 5750 // Flush pending output and redirect stdout/stderr to capturing 5751 // buffer. 5752 5753 octave_stdout.flush (); 5754 std::cerr.flush (); 5755 5756 std::stringbuf buffer; 5757 5758 std::streambuf *old_out_buf = octave_stdout.rdbuf (&buffer); 5759 std::streambuf *old_err_buf = std::cerr.rdbuf (&buffer); 5760 5761 // Restore previous output buffers no matter how control exits this 5762 // function. There's no need to flush here. That has already 5763 // happened for the normal execution path. If an error happens during 5764 // the eval, then the message is stored in the exception object and we 5765 // will display it later, after the buffers have been restored. 5766 5767 octave::unwind_action act ([old_out_buf, old_err_buf] (void) 5768 { 5769 octave_stdout.rdbuf (old_out_buf); 5770 std::cerr.rdbuf (old_err_buf); 5771 }); 5772 5773 // Call standard eval function. 5774 5775 int eval_nargout = std::max (0, nargout - 1); 5776 5777 octave_value_list retval = Feval (interp, args, eval_nargout); 5778 5779 // Make sure we capture all pending output. 5780 5781 octave_stdout.flush (); 5782 std::cerr.flush (); 5783 5784 retval.prepend (buffer.str ()); 5785 5786 return retval; 5787} 5788 5789/* 5790 5791%!test 5792%! [old_fmt, old_spacing] = format (); 5793%! unwind_protect 5794%! format short; 5795%! str = evalc ("1"); 5796%! assert (str, "ans = 1\n"); 5797%! unwind_protect_cleanup 5798%! format (old_fmt); 5799%! format (old_spacing); 5800%! end_unwind_protect 5801 5802%!assert (evalc ("1;"), "") 5803 5804%!test 5805%! [s, y] = evalc ("1"); 5806%! assert (s, ""); 5807%! assert (y, 1); 5808 5809%!test 5810%! [s, y] = evalc ("1;"); 5811%! assert (s, ""); 5812%! assert (y, 1); 5813 5814%!test 5815%! [old_fmt, old_spacing] = format (); 5816%! unwind_protect 5817%! format short; 5818%! str = evalc ("y = 2"); 5819%! assert (str, "y = 2\n"); 5820%! assert (y, 2); 5821%! unwind_protect_cleanup 5822%! format (old_fmt); 5823%! format (old_spacing); 5824%! end_unwind_protect 5825 5826%!test 5827%! assert (evalc ("y = 3;"), ""); 5828%! assert (y, 3); 5829 5830%!test 5831%! [s, a, b] = evalc ("deal (1, 2)"); 5832%! assert (s, ""); 5833%! assert (a, 1); 5834%! assert (b, 2); 5835 5836%!function [a, b] = __f_evalc () 5837%! printf ("foo"); 5838%! fprintf (stdout, "bar "); 5839%! disp (pi); 5840%! a = 1; 5841%! b = 2; 5842%!endfunction 5843%!test 5844%! [old_fmt, old_spacing] = format (); 5845%! unwind_protect 5846%! format short; 5847%! [s, a, b] = evalc ("__f_evalc ()"); 5848%! assert (s, "foobar 3.1416\n"); 5849%! assert (a, 1); 5850%! assert (b, 2); 5851%! unwind_protect_cleanup 5852%! format (old_fmt); 5853%! format (old_spacing); 5854%! end_unwind_protect 5855 5856%!error <foo> (evalc ("error ('foo')")) 5857%!error <bar> (evalc ("error ('foo')", "error ('bar')")) 5858 5859%!test 5860%! warning ("off", "quiet", "local"); 5861%! str = evalc ("warning ('foo')"); 5862%! assert (str(1:13), "warning: foo\n"); 5863 5864%!test 5865%! warning ("off", "quiet", "local"); 5866%! str = evalc ("error ('foo')", "warning ('bar')"); 5867%! assert (str(1:13), "warning: bar\n"); 5868 5869%!error evalc ("switch = 13;") 5870 5871*/ 5872 5873DEFUN (__parser_debug_flag__, args, nargout, 5874 doc: /* -*- texinfo -*- 5875@deftypefn {} {@var{val} =} __parser_debug_flag__ () 5876@deftypefnx {} {@var{old_val} =} __parser_debug_flag__ (@var{new_val}) 5877Query or set the internal flag that determines whether Octave's parser 5878prints debug information as it processes an expression. 5879@seealso{__lexer_debug_flag__} 5880@end deftypefn */) 5881{ 5882 octave_value retval; 5883 5884 bool debug_flag = octave_debug; 5885 5886 retval = set_internal_variable (debug_flag, args, nargout, 5887 "__parser_debug_flag__"); 5888 5889 octave_debug = debug_flag; 5890 5891 return retval; 5892} 5893 5894DEFMETHOD (__parse_file__, interp, args, , 5895 doc: /* -*- texinfo -*- 5896@deftypefn {} {} __parse_file__ (@var{file}, @var{verbose}) 5897Undocumented internal function. 5898@end deftypefn */) 5899{ 5900 octave_value retval; 5901 5902 int nargin = args.length (); 5903 5904 if (nargin < 1 || nargin > 2) 5905 print_usage (); 5906 5907 std::string file = args(0).xstring_value ("__parse_file__: expecting filename as argument"); 5908 5909 std::string full_file 5910 = octave::sys::file_ops::tilde_expand (file); 5911 5912 full_file = octave::sys::env::make_absolute (full_file); 5913 5914 std::string dir_name; 5915 5916 std::size_t file_len = file.length (); 5917 5918 if ((file_len > 4 && file.substr (file_len-4) == ".oct") 5919 || (file_len > 4 && file.substr (file_len-4) == ".mex") 5920 || (file_len > 2 && file.substr (file_len-2) == ".m")) 5921 { 5922 file = octave::sys::env::base_pathname (file); 5923 file = file.substr (0, file.find_last_of ('.')); 5924 5925 std::size_t pos = file.find_last_of (octave::sys::file_ops::dir_sep_str ()); 5926 if (pos != std::string::npos) 5927 { 5928 dir_name = file.substr (0, pos); 5929 file = file.substr (pos+1); 5930 } 5931 } 5932 5933 if (nargin == 2) 5934 octave_stdout << "parsing " << full_file << std::endl; 5935 5936 octave_value ov_fcn 5937 = parse_fcn_file (interp, full_file, file, dir_name, "", "", true, 5938 false, false, false); 5939 5940 return retval; 5941} 5942