Mercurial > hg > octave-lyh
comparison src/oct-parse.yy @ 9794:0d4613a736e9
convert build system to use automake and libtool
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 10 Nov 2009 15:02:25 -0500 |
parents | src/parse.y@5f8971be8e12 |
children | 6f79338c269b |
comparison
equal
deleted
inserted
replaced
9793:7161e9b41cf6 | 9794:0d4613a736e9 |
---|---|
1 /* | |
2 | |
3 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, | |
4 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton | |
5 Copyright (C) 2009 David Grundberg | |
6 | |
7 This file is part of Octave. | |
8 | |
9 Octave is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 3 of the License, or (at your | |
12 option) any later version. | |
13 | |
14 Octave is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with Octave; see the file COPYING. If not, see | |
21 <http://www.gnu.org/licenses/>. | |
22 | |
23 */ | |
24 | |
25 // Parser for Octave. | |
26 | |
27 // C decarations. | |
28 | |
29 %{ | |
30 #define YYDEBUG 1 | |
31 | |
32 #ifdef HAVE_CONFIG_H | |
33 #include <config.h> | |
34 #endif | |
35 | |
36 #include <cassert> | |
37 #include <cstdio> | |
38 | |
39 #ifdef YYBYACC | |
40 #include <cstdlib> | |
41 #endif | |
42 | |
43 #include <iostream> | |
44 #include <map> | |
45 #include <sstream> | |
46 | |
47 #include "Cell.h" | |
48 #include "Matrix.h" | |
49 #include "cmd-edit.h" | |
50 #include "cmd-hist.h" | |
51 #include "file-ops.h" | |
52 #include "file-stat.h" | |
53 #include "oct-env.h" | |
54 #include "oct-time.h" | |
55 #include "quit.h" | |
56 | |
57 #include "comment-list.h" | |
58 #include "defaults.h" | |
59 #include "defun.h" | |
60 #include "dirfns.h" | |
61 #include "dynamic-ld.h" | |
62 #include "error.h" | |
63 #include "input.h" | |
64 #include "lex.h" | |
65 #include "load-path.h" | |
66 #include "oct-hist.h" | |
67 #include "oct-map.h" | |
68 #include "ov-fcn-handle.h" | |
69 #include "ov-usr-fcn.h" | |
70 #include "ov-null-mat.h" | |
71 #include "toplev.h" | |
72 #include "pager.h" | |
73 #include "parse.h" | |
74 #include "pt-all.h" | |
75 #include "pt-eval.h" | |
76 #include "symtab.h" | |
77 #include "token.h" | |
78 #include "unwind-prot.h" | |
79 #include "utils.h" | |
80 #include "variables.h" | |
81 | |
82 // The current input line number. | |
83 int input_line_number = 1; | |
84 | |
85 // The column of the current token. | |
86 int current_input_column = 1; | |
87 | |
88 // Buffer for help text snagged from function files. | |
89 std::stack<std::string> help_buf; | |
90 | |
91 // Buffer for comments appearing before a function statement. | |
92 static std::string fcn_comment_header; | |
93 | |
94 // TRUE means we are using readline. | |
95 // (--no-line-editing) | |
96 bool line_editing = true; | |
97 | |
98 // TRUE means we printed messages about reading startup files. | |
99 bool reading_startup_message_printed = false; | |
100 | |
101 // TRUE means input is coming from startup file. | |
102 bool input_from_startup_file = false; | |
103 | |
104 // = 0 currently outside any function. | |
105 // = 1 inside the primary function or a subfunction. | |
106 // > 1 means we are looking at a function definition that seems to be | |
107 // inside a function. Note that the function still might not be a | |
108 // nested function. | |
109 static int current_function_depth = 0; | |
110 | |
111 // Maximum function depth detected. Just here to determine whether | |
112 // we have nested functions or just implicitly ended subfunctions. | |
113 static int max_function_depth = 0; | |
114 | |
115 // FALSE if we are still at the primary function. Subfunctions can | |
116 // only be declared inside function files. | |
117 static int parsing_subfunctions = false; | |
118 | |
119 // Have we found an explicit end to a function? | |
120 static bool endfunction_found = false; | |
121 | |
122 // Keep track of symbol table information when parsing functions. | |
123 std::stack<symbol_table::scope_id> symtab_context; | |
124 | |
125 // Name of the current class when we are parsing class methods or | |
126 // constructors. | |
127 std::string current_class_name; | |
128 | |
129 // TRUE means we are in the process of autoloading a function. | |
130 static bool autoloading = false; | |
131 | |
132 // TRUE means the current function file was found in a relative path | |
133 // element. | |
134 static bool fcn_file_from_relative_lookup = false; | |
135 | |
136 // Pointer to the primary user function or user script function. | |
137 static octave_function *primary_fcn_ptr = 0; | |
138 | |
139 // Scope where we install all subfunctions and nested functions. Only | |
140 // used while reading function files. | |
141 static symbol_table::scope_id primary_fcn_scope; | |
142 | |
143 // List of autoloads (function -> file mapping). | |
144 static std::map<std::string, std::string> autoload_map; | |
145 | |
146 // Forward declarations for some functions defined at the bottom of | |
147 // the file. | |
148 | |
149 // Generic error messages. | |
150 static void | |
151 yyerror (const char *s); | |
152 | |
153 // Error mesages for mismatched end tokens. | |
154 static void | |
155 end_error (const char *type, token::end_tok_type ettype, int l, int c); | |
156 | |
157 // Check to see that end tokens are properly matched. | |
158 static bool | |
159 end_token_ok (token *tok, token::end_tok_type expected); | |
160 | |
161 // Maybe print a warning if an assignment expression is used as the | |
162 // test in a logical expression. | |
163 static void | |
164 maybe_warn_assign_as_truth_value (tree_expression *expr); | |
165 | |
166 // Maybe print a warning about switch labels that aren't constants. | |
167 static void | |
168 maybe_warn_variable_switch_label (tree_expression *expr); | |
169 | |
170 // Finish building a range. | |
171 static tree_expression * | |
172 finish_colon_expression (tree_colon_expression *e); | |
173 | |
174 // Build a constant. | |
175 static tree_constant * | |
176 make_constant (int op, token *tok_val); | |
177 | |
178 // Build a function handle. | |
179 static tree_fcn_handle * | |
180 make_fcn_handle (token *tok_val); | |
181 | |
182 // Build an anonymous function handle. | |
183 static tree_anon_fcn_handle * | |
184 make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt); | |
185 | |
186 // Build a binary expression. | |
187 static tree_expression * | |
188 make_binary_op (int op, tree_expression *op1, token *tok_val, | |
189 tree_expression *op2); | |
190 | |
191 // Build a boolean expression. | |
192 static tree_expression * | |
193 make_boolean_op (int op, tree_expression *op1, token *tok_val, | |
194 tree_expression *op2); | |
195 | |
196 // Build a prefix expression. | |
197 static tree_expression * | |
198 make_prefix_op (int op, tree_expression *op1, token *tok_val); | |
199 | |
200 // Build a postfix expression. | |
201 static tree_expression * | |
202 make_postfix_op (int op, tree_expression *op1, token *tok_val); | |
203 | |
204 // Build an unwind-protect command. | |
205 static tree_command * | |
206 make_unwind_command (token *unwind_tok, tree_statement_list *body, | |
207 tree_statement_list *cleanup, token *end_tok, | |
208 octave_comment_list *lc, octave_comment_list *mc); | |
209 | |
210 // Build a try-catch command. | |
211 static tree_command * | |
212 make_try_command (token *try_tok, tree_statement_list *body, | |
213 tree_statement_list *cleanup, token *end_tok, | |
214 octave_comment_list *lc, octave_comment_list *mc); | |
215 | |
216 // Build a while command. | |
217 static tree_command * | |
218 make_while_command (token *while_tok, tree_expression *expr, | |
219 tree_statement_list *body, token *end_tok, | |
220 octave_comment_list *lc); | |
221 | |
222 // Build a do-until command. | |
223 static tree_command * | |
224 make_do_until_command (token *until_tok, tree_statement_list *body, | |
225 tree_expression *expr, octave_comment_list *lc); | |
226 | |
227 // Build a for command. | |
228 static tree_command * | |
229 make_for_command (token *for_tok, tree_argument_list *lhs, | |
230 tree_expression *expr, tree_statement_list *body, | |
231 token *end_tok, octave_comment_list *lc); | |
232 | |
233 // Build a break command. | |
234 static tree_command * | |
235 make_break_command (token *break_tok); | |
236 | |
237 // Build a continue command. | |
238 static tree_command * | |
239 make_continue_command (token *continue_tok); | |
240 | |
241 // Build a return command. | |
242 static tree_command * | |
243 make_return_command (token *return_tok); | |
244 | |
245 // Start an if command. | |
246 static tree_if_command_list * | |
247 start_if_command (tree_expression *expr, tree_statement_list *list); | |
248 | |
249 // Finish an if command. | |
250 static tree_if_command * | |
251 finish_if_command (token *if_tok, tree_if_command_list *list, | |
252 token *end_tok, octave_comment_list *lc); | |
253 | |
254 // Build an elseif clause. | |
255 static tree_if_clause * | |
256 make_elseif_clause (token *elseif_tok, tree_expression *expr, | |
257 tree_statement_list *list, octave_comment_list *lc); | |
258 | |
259 // Finish a switch command. | |
260 static tree_switch_command * | |
261 finish_switch_command (token *switch_tok, tree_expression *expr, | |
262 tree_switch_case_list *list, token *end_tok, | |
263 octave_comment_list *lc); | |
264 | |
265 // Build a switch case. | |
266 static tree_switch_case * | |
267 make_switch_case (token *case_tok, tree_expression *expr, | |
268 tree_statement_list *list, octave_comment_list *lc); | |
269 | |
270 // Build an assignment to a variable. | |
271 static tree_expression * | |
272 make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, | |
273 tree_expression *rhs); | |
274 | |
275 // Define a script. | |
276 static void | |
277 make_script (tree_statement_list *cmds, tree_statement *end_script); | |
278 | |
279 // Begin defining a function. | |
280 static octave_user_function * | |
281 start_function (tree_parameter_list *param_list, tree_statement_list *body, | |
282 tree_statement *end_function); | |
283 | |
284 // Create a no-op statement for end_function. | |
285 static tree_statement * | |
286 make_end (const std::string& type, int l, int c); | |
287 | |
288 // Do most of the work for defining a function. | |
289 static octave_user_function * | |
290 frob_function (const std::string& fname, octave_user_function *fcn); | |
291 | |
292 // Finish defining a function. | |
293 static tree_function_def * | |
294 finish_function (tree_parameter_list *ret_list, | |
295 octave_user_function *fcn, octave_comment_list *lc); | |
296 | |
297 // Reset state after parsing function. | |
298 static void | |
299 recover_from_parsing_function (void); | |
300 | |
301 // Make an index expression. | |
302 static tree_index_expression * | |
303 make_index_expression (tree_expression *expr, | |
304 tree_argument_list *args, char type); | |
305 | |
306 // Make an indirect reference expression. | |
307 static tree_index_expression * | |
308 make_indirect_ref (tree_expression *expr, const std::string&); | |
309 | |
310 // Make an indirect reference expression with dynamic field name. | |
311 static tree_index_expression * | |
312 make_indirect_ref (tree_expression *expr, tree_expression *field); | |
313 | |
314 // Make a declaration command. | |
315 static tree_decl_command * | |
316 make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst); | |
317 | |
318 // Finish building a matrix list. | |
319 static tree_expression * | |
320 finish_matrix (tree_matrix *m); | |
321 | |
322 // Finish building a cell list. | |
323 static tree_expression * | |
324 finish_cell (tree_cell *c); | |
325 | |
326 // Maybe print a warning. Duh. | |
327 static void | |
328 maybe_warn_missing_semi (tree_statement_list *); | |
329 | |
330 // Set the print flag for a statement based on the separator type. | |
331 static tree_statement_list * | |
332 set_stmt_print_flag (tree_statement_list *, char, bool); | |
333 | |
334 // Create a statement list. | |
335 static tree_statement_list *make_statement_list (tree_statement *stmt); | |
336 | |
337 // Append a statement to an existing statement list. | |
338 static tree_statement_list * | |
339 append_statement_list (tree_statement_list *list, char sep, | |
340 tree_statement *stmt, bool warn_missing_semi); | |
341 | |
342 // Finish building a statement. | |
343 template <class T> | |
344 static tree_statement * | |
345 make_statement (T *arg) | |
346 { | |
347 octave_comment_list *comment = octave_comment_buffer::get_comment (); | |
348 | |
349 return new tree_statement (arg, comment); | |
350 } | |
351 | |
352 #define ABORT_PARSE \ | |
353 do \ | |
354 { \ | |
355 global_command = 0; \ | |
356 yyerrok; \ | |
357 if (! symtab_context.empty ()) \ | |
358 { \ | |
359 symbol_table::set_scope (symtab_context.top ()); \ | |
360 symtab_context.pop (); \ | |
361 } \ | |
362 if (interactive || forced_interactive) \ | |
363 YYACCEPT; \ | |
364 else \ | |
365 YYABORT; \ | |
366 } \ | |
367 while (0) | |
368 | |
369 %} | |
370 | |
371 // Bison declarations. | |
372 | |
373 // Don't add spaces around the = here; it causes some versions of | |
374 // bison to fail to properly recognize the directive. | |
375 | |
376 %name-prefix="octave_" | |
377 | |
378 %union | |
379 { | |
380 // The type of the basic tokens returned by the lexer. | |
381 token *tok_val; | |
382 | |
383 // Comment strings that we need to deal with mid-rule. | |
384 octave_comment_list *comment_type; | |
385 | |
386 // Types for the nonterminals we generate. | |
387 char sep_type; | |
388 tree *tree_type; | |
389 tree_matrix *tree_matrix_type; | |
390 tree_cell *tree_cell_type; | |
391 tree_expression *tree_expression_type; | |
392 tree_constant *tree_constant_type; | |
393 tree_fcn_handle *tree_fcn_handle_type; | |
394 tree_anon_fcn_handle *tree_anon_fcn_handle_type; | |
395 tree_identifier *tree_identifier_type; | |
396 tree_index_expression *tree_index_expression_type; | |
397 tree_colon_expression *tree_colon_expression_type; | |
398 tree_argument_list *tree_argument_list_type; | |
399 tree_parameter_list *tree_parameter_list_type; | |
400 tree_command *tree_command_type; | |
401 tree_if_command *tree_if_command_type; | |
402 tree_if_clause *tree_if_clause_type; | |
403 tree_if_command_list *tree_if_command_list_type; | |
404 tree_switch_command *tree_switch_command_type; | |
405 tree_switch_case *tree_switch_case_type; | |
406 tree_switch_case_list *tree_switch_case_list_type; | |
407 tree_decl_elt *tree_decl_elt_type; | |
408 tree_decl_init_list *tree_decl_init_list_type; | |
409 tree_decl_command *tree_decl_command_type; | |
410 tree_statement *tree_statement_type; | |
411 tree_statement_list *tree_statement_list_type; | |
412 octave_user_function *octave_user_function_type; | |
413 void *dummy_type; | |
414 } | |
415 | |
416 // Tokens with line and column information. | |
417 %token <tok_val> '=' ':' '-' '+' '*' '/' | |
418 %token <tok_val> ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ | |
419 %token <tok_val> EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ AND_EQ OR_EQ | |
420 %token <tok_val> LSHIFT_EQ RSHIFT_EQ LSHIFT RSHIFT | |
421 %token <tok_val> EXPR_AND_AND EXPR_OR_OR | |
422 %token <tok_val> EXPR_AND EXPR_OR EXPR_NOT | |
423 %token <tok_val> EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT | |
424 %token <tok_val> LEFTDIV EMUL EDIV ELEFTDIV EPLUS EMINUS | |
425 %token <tok_val> QUOTE TRANSPOSE | |
426 %token <tok_val> PLUS_PLUS MINUS_MINUS POW EPOW | |
427 %token <tok_val> NUM IMAG_NUM | |
428 %token <tok_val> STRUCT_ELT | |
429 %token <tok_val> NAME | |
430 %token <tok_val> END | |
431 %token <tok_val> DQ_STRING SQ_STRING | |
432 %token <tok_val> FOR WHILE DO UNTIL | |
433 %token <tok_val> IF ELSEIF ELSE | |
434 %token <tok_val> SWITCH CASE OTHERWISE | |
435 %token <tok_val> BREAK CONTINUE FUNC_RET | |
436 %token <tok_val> UNWIND CLEANUP | |
437 %token <tok_val> TRY CATCH | |
438 %token <tok_val> GLOBAL STATIC | |
439 %token <tok_val> FCN_HANDLE | |
440 %token <tok_val> PROPERTIES | |
441 %token <tok_val> METHODS | |
442 %token <tok_val> EVENTS | |
443 %token <tok_val> METAQUERY | |
444 %token <tok_val> SUPERCLASSREF | |
445 %token <tok_val> GET SET | |
446 | |
447 // Other tokens. | |
448 %token END_OF_INPUT LEXICAL_ERROR | |
449 %token FCN SCRIPT_FILE FUNCTION_FILE CLASSDEF | |
450 // %token VARARGIN VARARGOUT | |
451 %token CLOSE_BRACE | |
452 | |
453 // Nonterminals we construct. | |
454 %type <comment_type> stash_comment function_beg classdef_beg | |
455 %type <comment_type> properties_beg methods_beg events_beg | |
456 %type <sep_type> sep_no_nl opt_sep_no_nl sep opt_sep | |
457 %type <tree_type> input | |
458 %type <tree_constant_type> string constant magic_colon | |
459 %type <tree_anon_fcn_handle_type> anon_fcn_handle | |
460 %type <tree_fcn_handle_type> fcn_handle | |
461 %type <tree_matrix_type> matrix_rows matrix_rows1 | |
462 %type <tree_cell_type> cell_rows cell_rows1 | |
463 %type <tree_expression_type> matrix cell | |
464 %type <tree_expression_type> primary_expr postfix_expr prefix_expr binary_expr | |
465 %type <tree_expression_type> simple_expr colon_expr assign_expr expression | |
466 %type <tree_identifier_type> identifier fcn_name | |
467 %type <tree_identifier_type> superclass_identifier meta_identifier | |
468 %type <octave_user_function_type> function1 function2 classdef1 | |
469 %type <tree_index_expression_type> word_list_cmd | |
470 %type <tree_colon_expression_type> colon_expr1 | |
471 %type <tree_argument_list_type> arg_list word_list assign_lhs | |
472 %type <tree_argument_list_type> cell_or_matrix_row | |
473 %type <tree_parameter_list_type> param_list param_list1 param_list2 | |
474 %type <tree_parameter_list_type> return_list return_list1 | |
475 %type <tree_parameter_list_type> superclasses opt_superclasses | |
476 %type <tree_command_type> command select_command loop_command | |
477 %type <tree_command_type> jump_command except_command function | |
478 %type <tree_command_type> script_file classdef | |
479 %type <tree_command_type> function_file function_list | |
480 %type <tree_if_command_type> if_command | |
481 %type <tree_if_clause_type> elseif_clause else_clause | |
482 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list | |
483 %type <tree_switch_command_type> switch_command | |
484 %type <tree_switch_case_type> switch_case default_case | |
485 %type <tree_switch_case_list_type> case_list1 case_list | |
486 %type <tree_decl_elt_type> decl2 | |
487 %type <tree_decl_init_list_type> decl1 | |
488 %type <tree_decl_command_type> declaration | |
489 %type <tree_statement_type> statement function_end classdef_end | |
490 %type <tree_statement_list_type> simple_list simple_list1 list list1 | |
491 %type <tree_statement_list_type> opt_list input1 | |
492 // These types need to be specified. | |
493 %type <dummy_type> attr | |
494 %type <dummy_type> class_event | |
495 %type <dummy_type> class_property | |
496 %type <dummy_type> properties_list | |
497 %type <dummy_type> properties_block | |
498 %type <dummy_type> methods_list | |
499 %type <dummy_type> methods_block | |
500 %type <dummy_type> opt_attr_list | |
501 %type <dummy_type> attr_list | |
502 %type <dummy_type> events_list | |
503 %type <dummy_type> events_block | |
504 %type <dummy_type> class_body | |
505 | |
506 // Precedence and associativity. | |
507 %left ';' ',' '\n' | |
508 %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 LSHIFT_EQ RSHIFT_EQ | |
509 %left EXPR_OR_OR | |
510 %left EXPR_AND_AND | |
511 %left EXPR_OR | |
512 %left EXPR_AND | |
513 %left EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT | |
514 %left LSHIFT RSHIFT | |
515 %left ':' | |
516 %left '-' '+' EPLUS EMINUS | |
517 %left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV | |
518 %left UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT | |
519 %left POW EPOW QUOTE TRANSPOSE | |
520 %left '(' '.' '{' | |
521 | |
522 // Where to start. | |
523 %start input | |
524 | |
525 %% | |
526 | |
527 // ============================== | |
528 // Statements and statement lists | |
529 // ============================== | |
530 | |
531 input : input1 | |
532 { | |
533 global_command = $1; | |
534 promptflag = 1; | |
535 YYACCEPT; | |
536 } | |
537 | function_file | |
538 { | |
539 YYACCEPT; | |
540 } | |
541 | simple_list parse_error | |
542 { ABORT_PARSE; } | |
543 | parse_error | |
544 { ABORT_PARSE; } | |
545 ; | |
546 | |
547 input1 : '\n' | |
548 { $$ = 0; } | |
549 | END_OF_INPUT | |
550 { | |
551 parser_end_of_input = 1; | |
552 $$ = 0; | |
553 } | |
554 | simple_list | |
555 { $$ = $1; } | |
556 | simple_list '\n' | |
557 { $$ = $1; } | |
558 | simple_list END_OF_INPUT | |
559 { $$ = $1; } | |
560 ; | |
561 | |
562 simple_list : simple_list1 opt_sep_no_nl | |
563 { $$ = set_stmt_print_flag ($1, $2, false); } | |
564 ; | |
565 | |
566 simple_list1 : statement | |
567 { $$ = make_statement_list ($1); } | |
568 | simple_list1 sep_no_nl statement | |
569 { $$ = append_statement_list ($1, $2, $3, false); } | |
570 ; | |
571 | |
572 opt_list : // empty | |
573 { $$ = new tree_statement_list (); } | |
574 | list | |
575 { $$ = $1; } | |
576 ; | |
577 | |
578 list : list1 opt_sep | |
579 { $$ = set_stmt_print_flag ($1, $2, true); } | |
580 ; | |
581 | |
582 list1 : statement | |
583 { $$ = make_statement_list ($1); } | |
584 | list1 sep statement | |
585 { $$ = append_statement_list ($1, $2, $3, true); } | |
586 ; | |
587 | |
588 statement : expression | |
589 { $$ = make_statement ($1); } | |
590 | command | |
591 { $$ = make_statement ($1); } | |
592 | word_list_cmd | |
593 { $$ = make_statement ($1); } | |
594 ; | |
595 | |
596 // ================= | |
597 // Word-list command | |
598 // ================= | |
599 | |
600 // These are not really like expressions since they can't appear on | |
601 // the RHS of an assignment. But they are also not like commands (IF, | |
602 // WHILE, etc. | |
603 | |
604 word_list_cmd : identifier word_list | |
605 { $$ = make_index_expression ($1, $2, '('); } | |
606 ; | |
607 | |
608 word_list : string | |
609 { $$ = new tree_argument_list ($1); } | |
610 | word_list string | |
611 { | |
612 $1->append ($2); | |
613 $$ = $1; | |
614 } | |
615 ; | |
616 | |
617 // =========== | |
618 // Expressions | |
619 // =========== | |
620 | |
621 identifier : NAME | |
622 { | |
623 symbol_table::symbol_record *sr = $1->sym_rec (); | |
624 $$ = new tree_identifier (*sr, $1->line (), $1->column ()); | |
625 } | |
626 ; | |
627 | |
628 superclass_identifier | |
629 : SUPERCLASSREF | |
630 { $$ = new tree_identifier ($1->line (), $1->column ()); } | |
631 ; | |
632 | |
633 meta_identifier : METAQUERY | |
634 { $$ = new tree_identifier ($1->line (), $1->column ()); } | |
635 ; | |
636 | |
637 string : DQ_STRING | |
638 { $$ = make_constant (DQ_STRING, $1); } | |
639 | SQ_STRING | |
640 { $$ = make_constant (SQ_STRING, $1); } | |
641 ; | |
642 | |
643 constant : NUM | |
644 { $$ = make_constant (NUM, $1); } | |
645 | IMAG_NUM | |
646 { $$ = make_constant (IMAG_NUM, $1); } | |
647 | string | |
648 { $$ = $1; } | |
649 ; | |
650 | |
651 matrix : '[' ']' | |
652 { | |
653 $$ = new tree_constant (octave_null_matrix::instance); | |
654 lexer_flags.looking_at_matrix_or_assign_lhs = false; | |
655 lexer_flags.pending_local_variables.clear (); | |
656 } | |
657 | '[' ';' ']' | |
658 { | |
659 $$ = new tree_constant (octave_null_matrix::instance); | |
660 lexer_flags.looking_at_matrix_or_assign_lhs = false; | |
661 lexer_flags.pending_local_variables.clear (); | |
662 } | |
663 | '[' ',' ']' | |
664 { | |
665 $$ = new tree_constant (octave_null_matrix::instance); | |
666 lexer_flags.looking_at_matrix_or_assign_lhs = false; | |
667 lexer_flags.pending_local_variables.clear (); | |
668 } | |
669 | '[' matrix_rows ']' | |
670 { | |
671 $$ = finish_matrix ($2); | |
672 lexer_flags.looking_at_matrix_or_assign_lhs = false; | |
673 lexer_flags.pending_local_variables.clear (); | |
674 } | |
675 ; | |
676 | |
677 matrix_rows : matrix_rows1 | |
678 { $$ = $1; } | |
679 | matrix_rows1 ';' // Ignore trailing semicolon. | |
680 { $$ = $1; } | |
681 ; | |
682 | |
683 matrix_rows1 : cell_or_matrix_row | |
684 { $$ = new tree_matrix ($1); } | |
685 | matrix_rows1 ';' cell_or_matrix_row | |
686 { | |
687 $1->append ($3); | |
688 $$ = $1; | |
689 } | |
690 ; | |
691 | |
692 cell : '{' '}' | |
693 { $$ = new tree_constant (octave_value (Cell ())); } | |
694 | '{' ';' '}' | |
695 { $$ = new tree_constant (octave_value (Cell ())); } | |
696 | '{' cell_rows '}' | |
697 { $$ = finish_cell ($2); } | |
698 ; | |
699 | |
700 cell_rows : cell_rows1 | |
701 { $$ = $1; } | |
702 | cell_rows1 ';' // Ignore trailing semicolon. | |
703 { $$ = $1; } | |
704 ; | |
705 | |
706 cell_rows1 : cell_or_matrix_row | |
707 { $$ = new tree_cell ($1); } | |
708 | cell_rows1 ';' cell_or_matrix_row | |
709 { | |
710 $1->append ($3); | |
711 $$ = $1; | |
712 } | |
713 ; | |
714 | |
715 cell_or_matrix_row | |
716 : arg_list | |
717 { $$ = $1; } | |
718 | arg_list ',' // Ignore trailing comma. | |
719 { $$ = $1; } | |
720 ; | |
721 | |
722 fcn_handle : '@' FCN_HANDLE | |
723 { | |
724 $$ = make_fcn_handle ($2); | |
725 lexer_flags.looking_at_function_handle--; | |
726 } | |
727 ; | |
728 | |
729 anon_fcn_handle : '@' param_list statement | |
730 { $$ = make_anon_fcn_handle ($2, $3); } | |
731 ; | |
732 | |
733 primary_expr : identifier | |
734 { $$ = $1; } | |
735 | constant | |
736 { $$ = $1; } | |
737 | fcn_handle | |
738 { $$ = $1; } | |
739 | matrix | |
740 { $$ = $1; } | |
741 | cell | |
742 { $$ = $1; } | |
743 | meta_identifier | |
744 { $$ = $1; } | |
745 | superclass_identifier | |
746 { $$ = $1; } | |
747 | '(' expression ')' | |
748 { $$ = $2->mark_in_parens (); } | |
749 ; | |
750 | |
751 magic_colon : ':' | |
752 { | |
753 octave_value tmp (octave_value::magic_colon_t); | |
754 $$ = new tree_constant (tmp); | |
755 } | |
756 ; | |
757 | |
758 arg_list : expression | |
759 { $$ = new tree_argument_list ($1); } | |
760 | magic_colon | |
761 { $$ = new tree_argument_list ($1); } | |
762 | arg_list ',' magic_colon | |
763 { | |
764 $1->append ($3); | |
765 $$ = $1; | |
766 } | |
767 | arg_list ',' expression | |
768 { | |
769 $1->append ($3); | |
770 $$ = $1; | |
771 } | |
772 ; | |
773 | |
774 indirect_ref_op : '.' | |
775 { lexer_flags.looking_at_indirect_ref = true; } | |
776 ; | |
777 | |
778 postfix_expr : primary_expr | |
779 { $$ = $1; } | |
780 | postfix_expr '(' ')' | |
781 { $$ = make_index_expression ($1, 0, '('); } | |
782 | postfix_expr '(' arg_list ')' | |
783 { $$ = make_index_expression ($1, $3, '('); } | |
784 | postfix_expr '{' '}' | |
785 { $$ = make_index_expression ($1, 0, '{'); } | |
786 | postfix_expr '{' arg_list '}' | |
787 { $$ = make_index_expression ($1, $3, '{'); } | |
788 | postfix_expr PLUS_PLUS | |
789 { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } | |
790 | postfix_expr MINUS_MINUS | |
791 { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } | |
792 | postfix_expr QUOTE | |
793 { $$ = make_postfix_op (QUOTE, $1, $2); } | |
794 | postfix_expr TRANSPOSE | |
795 { $$ = make_postfix_op (TRANSPOSE, $1, $2); } | |
796 | postfix_expr indirect_ref_op STRUCT_ELT | |
797 { $$ = make_indirect_ref ($1, $3->text ()); } | |
798 | postfix_expr indirect_ref_op '(' expression ')' | |
799 { $$ = make_indirect_ref ($1, $4); } | |
800 ; | |
801 | |
802 prefix_expr : postfix_expr | |
803 { $$ = $1; } | |
804 | binary_expr | |
805 { $$ = $1; } | |
806 | PLUS_PLUS prefix_expr %prec UNARY | |
807 { $$ = make_prefix_op (PLUS_PLUS, $2, $1); } | |
808 | MINUS_MINUS prefix_expr %prec UNARY | |
809 { $$ = make_prefix_op (MINUS_MINUS, $2, $1); } | |
810 | EXPR_NOT prefix_expr %prec UNARY | |
811 { $$ = make_prefix_op (EXPR_NOT, $2, $1); } | |
812 | '+' prefix_expr %prec UNARY | |
813 { $$ = make_prefix_op ('+', $2, $1); } | |
814 | '-' prefix_expr %prec UNARY | |
815 { $$ = make_prefix_op ('-', $2, $1); } | |
816 ; | |
817 | |
818 binary_expr : prefix_expr POW prefix_expr | |
819 { $$ = make_binary_op (POW, $1, $2, $3); } | |
820 | prefix_expr EPOW prefix_expr | |
821 { $$ = make_binary_op (EPOW, $1, $2, $3); } | |
822 | prefix_expr '+' prefix_expr | |
823 { $$ = make_binary_op ('+', $1, $2, $3); } | |
824 | prefix_expr '-' prefix_expr | |
825 { $$ = make_binary_op ('-', $1, $2, $3); } | |
826 | prefix_expr '*' prefix_expr | |
827 { $$ = make_binary_op ('*', $1, $2, $3); } | |
828 | prefix_expr '/' prefix_expr | |
829 { $$ = make_binary_op ('/', $1, $2, $3); } | |
830 | prefix_expr EPLUS prefix_expr | |
831 { $$ = make_binary_op ('+', $1, $2, $3); } | |
832 | prefix_expr EMINUS prefix_expr | |
833 { $$ = make_binary_op ('-', $1, $2, $3); } | |
834 | prefix_expr EMUL prefix_expr | |
835 { $$ = make_binary_op (EMUL, $1, $2, $3); } | |
836 | prefix_expr EDIV prefix_expr | |
837 { $$ = make_binary_op (EDIV, $1, $2, $3); } | |
838 | prefix_expr LEFTDIV prefix_expr | |
839 { $$ = make_binary_op (LEFTDIV, $1, $2, $3); } | |
840 | prefix_expr ELEFTDIV prefix_expr | |
841 { $$ = make_binary_op (ELEFTDIV, $1, $2, $3); } | |
842 ; | |
843 | |
844 colon_expr : colon_expr1 | |
845 { $$ = finish_colon_expression ($1); } | |
846 ; | |
847 | |
848 colon_expr1 : prefix_expr | |
849 { $$ = new tree_colon_expression ($1); } | |
850 | colon_expr1 ':' prefix_expr | |
851 { | |
852 if (! ($$ = $1->append ($3))) | |
853 ABORT_PARSE; | |
854 } | |
855 ; | |
856 | |
857 simple_expr : colon_expr | |
858 { $$ = $1; } | |
859 | simple_expr LSHIFT simple_expr | |
860 { $$ = make_binary_op (LSHIFT, $1, $2, $3); } | |
861 | simple_expr RSHIFT simple_expr | |
862 { $$ = make_binary_op (RSHIFT, $1, $2, $3); } | |
863 | simple_expr EXPR_LT simple_expr | |
864 { $$ = make_binary_op (EXPR_LT, $1, $2, $3); } | |
865 | simple_expr EXPR_LE simple_expr | |
866 { $$ = make_binary_op (EXPR_LE, $1, $2, $3); } | |
867 | simple_expr EXPR_EQ simple_expr | |
868 { $$ = make_binary_op (EXPR_EQ, $1, $2, $3); } | |
869 | simple_expr EXPR_GE simple_expr | |
870 { $$ = make_binary_op (EXPR_GE, $1, $2, $3); } | |
871 | simple_expr EXPR_GT simple_expr | |
872 { $$ = make_binary_op (EXPR_GT, $1, $2, $3); } | |
873 | simple_expr EXPR_NE simple_expr | |
874 { $$ = make_binary_op (EXPR_NE, $1, $2, $3); } | |
875 | simple_expr EXPR_AND simple_expr | |
876 { $$ = make_binary_op (EXPR_AND, $1, $2, $3); } | |
877 | simple_expr EXPR_OR simple_expr | |
878 { $$ = make_binary_op (EXPR_OR, $1, $2, $3); } | |
879 | simple_expr EXPR_AND_AND simple_expr | |
880 { $$ = make_boolean_op (EXPR_AND_AND, $1, $2, $3); } | |
881 | simple_expr EXPR_OR_OR simple_expr | |
882 { $$ = make_boolean_op (EXPR_OR_OR, $1, $2, $3); } | |
883 ; | |
884 | |
885 // Arrange for the lexer to return CLOSE_BRACE for `]' by looking ahead | |
886 // one token for an assignment op. | |
887 | |
888 assign_lhs : simple_expr | |
889 { | |
890 $$ = new tree_argument_list ($1); | |
891 $$->mark_as_simple_assign_lhs (); | |
892 } | |
893 | '[' arg_list CLOSE_BRACE | |
894 { | |
895 $$ = $2; | |
896 lexer_flags.looking_at_matrix_or_assign_lhs = false; | |
897 for (std::set<std::string>::const_iterator p = lexer_flags.pending_local_variables.begin (); | |
898 p != lexer_flags.pending_local_variables.end (); | |
899 p++) | |
900 { | |
901 symbol_table::force_variable (*p); | |
902 } | |
903 lexer_flags.pending_local_variables.clear (); | |
904 } | |
905 ; | |
906 | |
907 assign_expr : assign_lhs '=' expression | |
908 { $$ = make_assign_op ('=', $1, $2, $3); } | |
909 | assign_lhs ADD_EQ expression | |
910 { $$ = make_assign_op (ADD_EQ, $1, $2, $3); } | |
911 | assign_lhs SUB_EQ expression | |
912 { $$ = make_assign_op (SUB_EQ, $1, $2, $3); } | |
913 | assign_lhs MUL_EQ expression | |
914 { $$ = make_assign_op (MUL_EQ, $1, $2, $3); } | |
915 | assign_lhs DIV_EQ expression | |
916 { $$ = make_assign_op (DIV_EQ, $1, $2, $3); } | |
917 | assign_lhs LEFTDIV_EQ expression | |
918 { $$ = make_assign_op (LEFTDIV_EQ, $1, $2, $3); } | |
919 | assign_lhs POW_EQ expression | |
920 { $$ = make_assign_op (POW_EQ, $1, $2, $3); } | |
921 | assign_lhs LSHIFT_EQ expression | |
922 { $$ = make_assign_op (LSHIFT_EQ, $1, $2, $3); } | |
923 | assign_lhs RSHIFT_EQ expression | |
924 { $$ = make_assign_op (RSHIFT_EQ, $1, $2, $3); } | |
925 | assign_lhs EMUL_EQ expression | |
926 { $$ = make_assign_op (EMUL_EQ, $1, $2, $3); } | |
927 | assign_lhs EDIV_EQ expression | |
928 { $$ = make_assign_op (EDIV_EQ, $1, $2, $3); } | |
929 | assign_lhs ELEFTDIV_EQ expression | |
930 { $$ = make_assign_op (ELEFTDIV_EQ, $1, $2, $3); } | |
931 | assign_lhs EPOW_EQ expression | |
932 { $$ = make_assign_op (EPOW_EQ, $1, $2, $3); } | |
933 | assign_lhs AND_EQ expression | |
934 { $$ = make_assign_op (AND_EQ, $1, $2, $3); } | |
935 | assign_lhs OR_EQ expression | |
936 { $$ = make_assign_op (OR_EQ, $1, $2, $3); } | |
937 ; | |
938 | |
939 expression : simple_expr | |
940 { $$ = $1; } | |
941 | assign_expr | |
942 { $$ = $1; } | |
943 | anon_fcn_handle | |
944 { $$ = $1; } | |
945 ; | |
946 | |
947 // ================================================ | |
948 // Commands, declarations, and function definitions | |
949 // ================================================ | |
950 | |
951 command : declaration | |
952 { $$ = $1; } | |
953 | select_command | |
954 { $$ = $1; } | |
955 | loop_command | |
956 { $$ = $1; } | |
957 | jump_command | |
958 { $$ = $1; } | |
959 | except_command | |
960 { $$ = $1; } | |
961 | function | |
962 { $$ = $1; } | |
963 | script_file | |
964 { $$ = $1; } | |
965 | classdef | |
966 { $$ = $1; } | |
967 ; | |
968 | |
969 // ===================== | |
970 // Declaration statemnts | |
971 // ===================== | |
972 | |
973 parsing_decl_list | |
974 : // empty | |
975 { lexer_flags.looking_at_decl_list = true; } | |
976 | |
977 declaration : GLOBAL parsing_decl_list decl1 | |
978 { | |
979 $$ = make_decl_command (GLOBAL, $1, $3); | |
980 lexer_flags.looking_at_decl_list = false; | |
981 } | |
982 | STATIC parsing_decl_list decl1 | |
983 { | |
984 $$ = make_decl_command (STATIC, $1, $3); | |
985 lexer_flags.looking_at_decl_list = false; | |
986 } | |
987 ; | |
988 | |
989 decl1 : decl2 | |
990 { $$ = new tree_decl_init_list ($1); } | |
991 | decl1 decl2 | |
992 { | |
993 $1->append ($2); | |
994 $$ = $1; | |
995 } | |
996 ; | |
997 | |
998 decl_param_init : // empty | |
999 { lexer_flags.looking_at_initializer_expression = true; } | |
1000 | |
1001 decl2 : identifier | |
1002 { $$ = new tree_decl_elt ($1); } | |
1003 | identifier '=' decl_param_init expression | |
1004 { | |
1005 lexer_flags.looking_at_initializer_expression = false; | |
1006 $$ = new tree_decl_elt ($1, $4); | |
1007 } | |
1008 ; | |
1009 | |
1010 // ==================== | |
1011 // Selection statements | |
1012 // ==================== | |
1013 | |
1014 select_command : if_command | |
1015 { $$ = $1; } | |
1016 | switch_command | |
1017 { $$ = $1; } | |
1018 ; | |
1019 | |
1020 // ============ | |
1021 // If statement | |
1022 // ============ | |
1023 | |
1024 if_command : IF stash_comment if_cmd_list END | |
1025 { | |
1026 if (! ($$ = finish_if_command ($1, $3, $4, $2))) | |
1027 ABORT_PARSE; | |
1028 } | |
1029 ; | |
1030 | |
1031 if_cmd_list : if_cmd_list1 | |
1032 { $$ = $1; } | |
1033 | if_cmd_list1 else_clause | |
1034 { | |
1035 $1->append ($2); | |
1036 $$ = $1; | |
1037 } | |
1038 ; | |
1039 | |
1040 if_cmd_list1 : expression opt_sep opt_list | |
1041 { $$ = start_if_command ($1, $3); } | |
1042 | if_cmd_list1 elseif_clause | |
1043 { | |
1044 $1->append ($2); | |
1045 $$ = $1; | |
1046 } | |
1047 ; | |
1048 | |
1049 elseif_clause : ELSEIF stash_comment opt_sep expression opt_sep opt_list | |
1050 { $$ = make_elseif_clause ($1, $4, $6, $2); } | |
1051 ; | |
1052 | |
1053 else_clause : ELSE stash_comment opt_sep opt_list | |
1054 { $$ = new tree_if_clause ($4, $2); } | |
1055 ; | |
1056 | |
1057 // ================ | |
1058 // Switch statement | |
1059 // ================ | |
1060 | |
1061 switch_command : SWITCH stash_comment expression opt_sep case_list END | |
1062 { | |
1063 if (! ($$ = finish_switch_command ($1, $3, $5, $6, $2))) | |
1064 ABORT_PARSE; | |
1065 } | |
1066 ; | |
1067 | |
1068 case_list : // empty | |
1069 { $$ = new tree_switch_case_list (); } | |
1070 | case_list1 | |
1071 { $$ = $1; } | |
1072 | case_list1 default_case | |
1073 { | |
1074 $1->append ($2); | |
1075 $$ = $1; | |
1076 } | |
1077 ; | |
1078 | |
1079 case_list1 : switch_case | |
1080 { $$ = new tree_switch_case_list ($1); } | |
1081 | case_list1 switch_case | |
1082 { | |
1083 $1->append ($2); | |
1084 $$ = $1; | |
1085 } | |
1086 ; | |
1087 | |
1088 switch_case : CASE stash_comment opt_sep expression opt_sep opt_list | |
1089 { $$ = make_switch_case ($1, $4, $6, $2); } | |
1090 ; | |
1091 | |
1092 default_case : OTHERWISE stash_comment opt_sep opt_list | |
1093 { | |
1094 $$ = new tree_switch_case ($4, $2); | |
1095 } | |
1096 ; | |
1097 | |
1098 // ======= | |
1099 // Looping | |
1100 // ======= | |
1101 | |
1102 loop_command : WHILE stash_comment expression opt_sep opt_list END | |
1103 { | |
1104 if (! ($$ = make_while_command ($1, $3, $5, $6, $2))) | |
1105 ABORT_PARSE; | |
1106 } | |
1107 | DO stash_comment opt_sep opt_list UNTIL expression | |
1108 { | |
1109 if (! ($$ = make_do_until_command ($5, $4, $6, $2))) | |
1110 ABORT_PARSE; | |
1111 } | |
1112 | FOR stash_comment assign_lhs '=' expression opt_sep opt_list END | |
1113 { | |
1114 if (! ($$ = make_for_command ($1, $3, $5, $7, $8, $2))) | |
1115 ABORT_PARSE; | |
1116 } | |
1117 | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END | |
1118 { | |
1119 if (! ($$ = make_for_command ($1, $4, $6, $9, $10, $2))) | |
1120 ABORT_PARSE; | |
1121 } | |
1122 ; | |
1123 | |
1124 // ======= | |
1125 // Jumping | |
1126 // ======= | |
1127 | |
1128 jump_command : BREAK | |
1129 { | |
1130 if (! ($$ = make_break_command ($1))) | |
1131 ABORT_PARSE; | |
1132 } | |
1133 | CONTINUE | |
1134 { | |
1135 if (! ($$ = make_continue_command ($1))) | |
1136 ABORT_PARSE; | |
1137 } | |
1138 | FUNC_RET | |
1139 { | |
1140 if (! ($$ = make_return_command ($1))) | |
1141 ABORT_PARSE; | |
1142 } | |
1143 ; | |
1144 | |
1145 // ========== | |
1146 // Exceptions | |
1147 // ========== | |
1148 | |
1149 except_command : UNWIND stash_comment opt_sep opt_list CLEANUP | |
1150 stash_comment opt_sep opt_list END | |
1151 { | |
1152 if (! ($$ = make_unwind_command ($1, $4, $8, $9, $2, $6))) | |
1153 ABORT_PARSE; | |
1154 } | |
1155 | TRY stash_comment opt_sep opt_list CATCH | |
1156 stash_comment opt_sep opt_list END | |
1157 { | |
1158 if (! ($$ = make_try_command ($1, $4, $8, $9, $2, $6))) | |
1159 ABORT_PARSE; | |
1160 } | |
1161 | TRY stash_comment opt_sep opt_list END | |
1162 { | |
1163 if (! ($$ = make_try_command ($1, $4, 0, $5, $2, 0))) | |
1164 ABORT_PARSE; | |
1165 } | |
1166 ; | |
1167 | |
1168 // =========================================== | |
1169 // Some `subroutines' for function definitions | |
1170 // =========================================== | |
1171 | |
1172 push_fcn_symtab : // empty | |
1173 { | |
1174 current_function_depth++; | |
1175 | |
1176 if (max_function_depth < current_function_depth) | |
1177 max_function_depth = current_function_depth; | |
1178 | |
1179 symtab_context.push (symbol_table::current_scope ()); | |
1180 symbol_table::set_scope (symbol_table::alloc_scope ()); | |
1181 | |
1182 if (! reading_script_file && current_function_depth == 1 | |
1183 && ! parsing_subfunctions) | |
1184 primary_fcn_scope = symbol_table::current_scope (); | |
1185 | |
1186 if (reading_script_file && current_function_depth > 1) | |
1187 yyerror ("nested functions not implemented in this context"); | |
1188 } | |
1189 ; | |
1190 | |
1191 // =========================== | |
1192 // List of function parameters | |
1193 // =========================== | |
1194 | |
1195 param_list_beg : '(' | |
1196 { | |
1197 lexer_flags.looking_at_parameter_list = true; | |
1198 | |
1199 if (lexer_flags.looking_at_function_handle) | |
1200 { | |
1201 symtab_context.push (symbol_table::current_scope ()); | |
1202 symbol_table::set_scope (symbol_table::alloc_scope ()); | |
1203 lexer_flags.looking_at_function_handle--; | |
1204 } | |
1205 } | |
1206 ; | |
1207 | |
1208 param_list_end : ')' | |
1209 { | |
1210 lexer_flags.looking_at_parameter_list = false; | |
1211 lexer_flags.looking_for_object_index = false; | |
1212 } | |
1213 ; | |
1214 | |
1215 param_list : param_list_beg param_list1 param_list_end | |
1216 { | |
1217 lexer_flags.quote_is_transpose = false; | |
1218 $$ = $2; | |
1219 } | |
1220 | param_list_beg error | |
1221 { | |
1222 yyerror ("invalid parameter list"); | |
1223 $$ = 0; | |
1224 ABORT_PARSE; | |
1225 } | |
1226 ; | |
1227 | |
1228 param_list1 : // empty | |
1229 { $$ = 0; } | |
1230 | param_list2 | |
1231 { | |
1232 $1->mark_as_formal_parameters (); | |
1233 if ($1->validate (tree_parameter_list::in)) | |
1234 $$ = $1; | |
1235 else | |
1236 ABORT_PARSE; | |
1237 } | |
1238 ; | |
1239 | |
1240 param_list2 : decl2 | |
1241 { $$ = new tree_parameter_list ($1); } | |
1242 | param_list2 ',' decl2 | |
1243 { | |
1244 $1->append ($3); | |
1245 $$ = $1; | |
1246 } | |
1247 ; | |
1248 | |
1249 // =================================== | |
1250 // List of function return value names | |
1251 // =================================== | |
1252 | |
1253 return_list : '[' ']' | |
1254 { | |
1255 lexer_flags.looking_at_return_list = false; | |
1256 $$ = new tree_parameter_list (); | |
1257 } | |
1258 | return_list1 | |
1259 { | |
1260 lexer_flags.looking_at_return_list = false; | |
1261 if ($1->validate (tree_parameter_list::out)) | |
1262 $$ = $1; | |
1263 else | |
1264 ABORT_PARSE; | |
1265 } | |
1266 | '[' return_list1 ']' | |
1267 { | |
1268 lexer_flags.looking_at_return_list = false; | |
1269 if ($2->validate (tree_parameter_list::out)) | |
1270 $$ = $2; | |
1271 else | |
1272 ABORT_PARSE; | |
1273 } | |
1274 ; | |
1275 | |
1276 return_list1 : identifier | |
1277 { $$ = new tree_parameter_list (new tree_decl_elt ($1)); } | |
1278 | return_list1 ',' identifier | |
1279 { | |
1280 $1->append (new tree_decl_elt ($3)); | |
1281 $$ = $1; | |
1282 } | |
1283 ; | |
1284 | |
1285 // =========== | |
1286 // Script file | |
1287 // =========== | |
1288 | |
1289 script_file : SCRIPT_FILE opt_list END_OF_INPUT | |
1290 { | |
1291 tree_statement *end_of_script | |
1292 = make_end ("endscript", input_line_number, | |
1293 current_input_column); | |
1294 | |
1295 make_script ($2, end_of_script); | |
1296 | |
1297 $$ = 0; | |
1298 } | |
1299 ; | |
1300 | |
1301 // ============= | |
1302 // Function file | |
1303 // ============= | |
1304 | |
1305 function_file : FUNCTION_FILE function_list opt_sep END_OF_INPUT | |
1306 { $$ = 0; } | |
1307 ; | |
1308 | |
1309 function_list : function | |
1310 | function_list sep function | |
1311 ; | |
1312 | |
1313 // =================== | |
1314 // Function definition | |
1315 // =================== | |
1316 | |
1317 function_beg : push_fcn_symtab FCN stash_comment | |
1318 { | |
1319 $$ = $3; | |
1320 | |
1321 if (reading_classdef_file || lexer_flags.parsing_classdef) | |
1322 lexer_flags.maybe_classdef_get_set_method = true; | |
1323 } | |
1324 ; | |
1325 | |
1326 function : function_beg function1 | |
1327 { | |
1328 $$ = finish_function (0, $2, $1); | |
1329 recover_from_parsing_function (); | |
1330 } | |
1331 | function_beg return_list '=' function1 | |
1332 { | |
1333 $$ = finish_function ($2, $4, $1); | |
1334 recover_from_parsing_function (); | |
1335 } | |
1336 ; | |
1337 | |
1338 fcn_name : identifier | |
1339 { | |
1340 std::string id_name = $1->name (); | |
1341 | |
1342 lexer_flags.parsed_function_name = true; | |
1343 lexer_flags.defining_func = false; | |
1344 lexer_flags.maybe_classdef_get_set_method = false; | |
1345 | |
1346 $$ = $1; | |
1347 } | |
1348 | GET '.' identifier | |
1349 { | |
1350 lexer_flags.maybe_classdef_get_set_method = false; | |
1351 $$ = $3; | |
1352 } | |
1353 | SET '.' identifier | |
1354 { | |
1355 lexer_flags.maybe_classdef_get_set_method = false; | |
1356 $$ = $3; | |
1357 } | |
1358 ; | |
1359 | |
1360 function1 : fcn_name function2 | |
1361 { | |
1362 std::string fname = $1->name (); | |
1363 | |
1364 delete $1; | |
1365 | |
1366 if (! ($$ = frob_function (fname, $2))) | |
1367 ABORT_PARSE; | |
1368 } | |
1369 ; | |
1370 | |
1371 function2 : param_list opt_sep opt_list function_end | |
1372 { $$ = start_function ($1, $3, $4); } | |
1373 | opt_sep opt_list function_end | |
1374 { $$ = start_function (0, $2, $3); } | |
1375 ; | |
1376 | |
1377 function_end : END | |
1378 { | |
1379 endfunction_found = true; | |
1380 if (end_token_ok ($1, token::function_end)) | |
1381 $$ = make_end ("endfunction", $1->line (), $1->column ()); | |
1382 else | |
1383 ABORT_PARSE; | |
1384 } | |
1385 | END_OF_INPUT | |
1386 { | |
1387 // A lot of tests are based on the assumption that this is OK | |
1388 // if (reading_script_file) | |
1389 // { | |
1390 // yyerror ("function body open at end of script"); | |
1391 // YYABORT; | |
1392 // } | |
1393 | |
1394 if (endfunction_found) | |
1395 { | |
1396 yyerror ("inconsistent function endings -- " | |
1397 "if one function is explicitly ended, " | |
1398 "so must all the others"); | |
1399 YYABORT; | |
1400 } | |
1401 | |
1402 if (! reading_fcn_file && ! reading_script_file) | |
1403 { | |
1404 yyerror ("function body open at end of input"); | |
1405 YYABORT; | |
1406 } | |
1407 | |
1408 if (reading_classdef_file) | |
1409 { | |
1410 yyerror ("classdef body open at end of input"); | |
1411 YYABORT; | |
1412 } | |
1413 | |
1414 $$ = make_end ("endfunction", input_line_number, | |
1415 current_input_column); | |
1416 } | |
1417 ; | |
1418 | |
1419 // ======== | |
1420 // Classdef | |
1421 // ======== | |
1422 | |
1423 classdef_beg : CLASSDEF stash_comment | |
1424 { | |
1425 $$ = 0; | |
1426 lexer_flags.parsing_classdef = true; | |
1427 } | |
1428 ; | |
1429 | |
1430 classdef_end : END | |
1431 { | |
1432 lexer_flags.parsing_classdef = false; | |
1433 | |
1434 if (end_token_ok ($1, token::classdef_end)) | |
1435 $$ = make_end ("endclassdef", $1->line (), $1->column ()); | |
1436 else | |
1437 ABORT_PARSE; | |
1438 } | |
1439 ; | |
1440 | |
1441 classdef1 : classdef_beg opt_attr_list identifier opt_superclasses | |
1442 { $$ = 0; } | |
1443 ; | |
1444 | |
1445 classdef : classdef1 '\n' class_body '\n' stash_comment classdef_end | |
1446 { $$ = 0; } | |
1447 ; | |
1448 | |
1449 opt_attr_list : // empty | |
1450 { $$ = 0; } | |
1451 | '(' attr_list ')' | |
1452 { $$ = 0; } | |
1453 ; | |
1454 | |
1455 attr_list : attr | |
1456 { $$ = 0; } | |
1457 | attr_list ',' attr | |
1458 { $$ = 0; } | |
1459 ; | |
1460 | |
1461 attr : identifier | |
1462 { $$ = 0; } | |
1463 | identifier '=' decl_param_init expression | |
1464 { $$ = 0; } | |
1465 | EXPR_NOT identifier | |
1466 { $$ = 0; } | |
1467 ; | |
1468 | |
1469 opt_superclasses | |
1470 : // empty | |
1471 { $$ = 0; } | |
1472 | superclasses | |
1473 { $$ = 0; } | |
1474 ; | |
1475 | |
1476 superclasses : EXPR_LT identifier '.' identifier | |
1477 { $$ = 0; } | |
1478 | EXPR_LT identifier | |
1479 { $$ = 0; } | |
1480 | superclasses EXPR_AND identifier '.' identifier | |
1481 { $$ = 0; } | |
1482 | superclasses EXPR_AND identifier | |
1483 { $$ = 0; } | |
1484 ; | |
1485 | |
1486 class_body : properties_block | |
1487 { $$ = 0; } | |
1488 | methods_block | |
1489 { $$ = 0; } | |
1490 | events_block | |
1491 { $$ = 0; } | |
1492 | class_body '\n' properties_block | |
1493 { $$ = 0; } | |
1494 | class_body '\n' methods_block | |
1495 { $$ = 0; } | |
1496 | class_body '\n' events_block | |
1497 { $$ = 0; } | |
1498 ; | |
1499 | |
1500 properties_beg : PROPERTIES stash_comment | |
1501 { $$ = 0; } | |
1502 ; | |
1503 | |
1504 properties_block | |
1505 : properties_beg opt_attr_list '\n' properties_list '\n' END | |
1506 { $$ = 0; } | |
1507 ; | |
1508 | |
1509 properties_list | |
1510 : class_property | |
1511 { $$ = 0; } | |
1512 | properties_list '\n' class_property | |
1513 { $$ = 0; } | |
1514 ; | |
1515 | |
1516 class_property : identifier | |
1517 { $$ = 0; } | |
1518 | identifier '=' decl_param_init expression ';' | |
1519 { $$ = 0; } | |
1520 ; | |
1521 | |
1522 methods_beg : METHODS stash_comment | |
1523 { $$ = 0; } | |
1524 ; | |
1525 | |
1526 methods_block : methods_beg opt_attr_list '\n' methods_list '\n' END | |
1527 { $$ = 0; } | |
1528 ; | |
1529 | |
1530 methods_list : function | |
1531 { $$ = 0; } | |
1532 | methods_list '\n' function | |
1533 { $$ = 0; } | |
1534 ; | |
1535 | |
1536 events_beg : EVENTS stash_comment | |
1537 { $$ = 0; } | |
1538 ; | |
1539 | |
1540 events_block : events_beg opt_attr_list '\n' events_list '\n' END | |
1541 { $$ = 0; } | |
1542 ; | |
1543 | |
1544 events_list : class_event | |
1545 { $$ = 0; } | |
1546 | events_list '\n' class_event | |
1547 { $$ = 0; } | |
1548 ; | |
1549 | |
1550 class_event : identifier | |
1551 { $$ = 0; } | |
1552 ; | |
1553 | |
1554 // ============= | |
1555 // Miscellaneous | |
1556 // ============= | |
1557 | |
1558 stash_comment : // empty | |
1559 { $$ = octave_comment_buffer::get_comment (); } | |
1560 ; | |
1561 | |
1562 parse_error : LEXICAL_ERROR | |
1563 { yyerror ("parse error"); } | |
1564 | error | |
1565 ; | |
1566 | |
1567 sep_no_nl : ',' | |
1568 { $$ = ','; } | |
1569 | ';' | |
1570 { $$ = ';'; } | |
1571 | sep_no_nl ',' | |
1572 { $$ = $1; } | |
1573 | sep_no_nl ';' | |
1574 { $$ = $1; } | |
1575 ; | |
1576 | |
1577 opt_sep_no_nl : // empty | |
1578 { $$ = 0; } | |
1579 | sep_no_nl | |
1580 { $$ = $1; } | |
1581 ; | |
1582 | |
1583 sep : ',' | |
1584 { $$ = ','; } | |
1585 | ';' | |
1586 { $$ = ';'; } | |
1587 | '\n' | |
1588 { $$ = '\n'; } | |
1589 | sep ',' | |
1590 { $$ = $1; } | |
1591 | sep ';' | |
1592 { $$ = $1; } | |
1593 | sep '\n' | |
1594 { $$ = $1; } | |
1595 ; | |
1596 | |
1597 opt_sep : // empty | |
1598 { $$ = 0; } | |
1599 | sep | |
1600 { $$ = $1; } | |
1601 ; | |
1602 | |
1603 %% | |
1604 | |
1605 // Generic error messages. | |
1606 | |
1607 static void | |
1608 yyerror (const char *s) | |
1609 { | |
1610 int err_col = current_input_column - 1; | |
1611 | |
1612 std::ostringstream output_buf; | |
1613 | |
1614 if (reading_fcn_file || reading_script_file || reading_classdef_file) | |
1615 output_buf << "parse error near line " << input_line_number | |
1616 << " of file " << curr_fcn_file_full_name; | |
1617 else | |
1618 output_buf << "parse error:"; | |
1619 | |
1620 if (s && strcmp (s, "parse error") != 0) | |
1621 output_buf << "\n\n " << s; | |
1622 | |
1623 output_buf << "\n\n"; | |
1624 | |
1625 if (! current_input_line.empty ()) | |
1626 { | |
1627 size_t len = current_input_line.length (); | |
1628 | |
1629 if (current_input_line[len-1] == '\n') | |
1630 current_input_line.resize (len-1); | |
1631 | |
1632 // Print the line, maybe with a pointer near the error token. | |
1633 | |
1634 output_buf << ">>> " << current_input_line << "\n"; | |
1635 | |
1636 if (err_col == 0) | |
1637 err_col = len; | |
1638 | |
1639 for (int i = 0; i < err_col + 3; i++) | |
1640 output_buf << " "; | |
1641 | |
1642 output_buf << "^"; | |
1643 } | |
1644 | |
1645 output_buf << "\n"; | |
1646 | |
1647 std::string msg = output_buf.str (); | |
1648 | |
1649 parse_error ("%s", msg.c_str ()); | |
1650 } | |
1651 | |
1652 // Error mesages for mismatched end tokens. | |
1653 | |
1654 static void | |
1655 end_error (const char *type, token::end_tok_type ettype, int l, int c) | |
1656 { | |
1657 static const char *fmt | |
1658 = "`%s' command matched by `%s' near line %d column %d"; | |
1659 | |
1660 switch (ettype) | |
1661 { | |
1662 case token::simple_end: | |
1663 error (fmt, type, "end", l, c); | |
1664 break; | |
1665 | |
1666 case token::for_end: | |
1667 error (fmt, type, "endfor", l, c); | |
1668 break; | |
1669 | |
1670 case token::function_end: | |
1671 error (fmt, type, "endfunction", l, c); | |
1672 break; | |
1673 | |
1674 case token::classdef_end: | |
1675 error (fmt, type, "endclassdef", l, c); | |
1676 break; | |
1677 | |
1678 case token::if_end: | |
1679 error (fmt, type, "endif", l, c); | |
1680 break; | |
1681 | |
1682 case token::switch_end: | |
1683 error (fmt, type, "endswitch", l, c); | |
1684 break; | |
1685 | |
1686 case token::while_end: | |
1687 error (fmt, type, "endwhile", l, c); | |
1688 break; | |
1689 | |
1690 case token::try_catch_end: | |
1691 error (fmt, type, "end_try_catch", l, c); | |
1692 break; | |
1693 | |
1694 case token::unwind_protect_end: | |
1695 error (fmt, type, "end_unwind_protect", l, c); | |
1696 break; | |
1697 | |
1698 default: | |
1699 panic_impossible (); | |
1700 break; | |
1701 } | |
1702 } | |
1703 | |
1704 // Check to see that end tokens are properly matched. | |
1705 | |
1706 static bool | |
1707 end_token_ok (token *tok, token::end_tok_type expected) | |
1708 { | |
1709 bool retval = true; | |
1710 | |
1711 token::end_tok_type ettype = tok->ettype (); | |
1712 | |
1713 if (ettype != expected && ettype != token::simple_end) | |
1714 { | |
1715 retval = false; | |
1716 | |
1717 yyerror ("parse error"); | |
1718 | |
1719 int l = tok->line (); | |
1720 int c = tok->column (); | |
1721 | |
1722 switch (expected) | |
1723 { | |
1724 case token::classdef_end: | |
1725 end_error ("classdef", ettype, l, c); | |
1726 break; | |
1727 | |
1728 case token::for_end: | |
1729 end_error ("for", ettype, l, c); | |
1730 break; | |
1731 | |
1732 case token::function_end: | |
1733 end_error ("function", ettype, l, c); | |
1734 break; | |
1735 | |
1736 case token::if_end: | |
1737 end_error ("if", ettype, l, c); | |
1738 break; | |
1739 | |
1740 case token::try_catch_end: | |
1741 end_error ("try", ettype, l, c); | |
1742 break; | |
1743 | |
1744 case token::switch_end: | |
1745 end_error ("switch", ettype, l, c); | |
1746 break; | |
1747 | |
1748 case token::unwind_protect_end: | |
1749 end_error ("unwind_protect", ettype, l, c); | |
1750 break; | |
1751 | |
1752 case token::while_end: | |
1753 end_error ("while", ettype, l, c); | |
1754 break; | |
1755 | |
1756 default: | |
1757 panic_impossible (); | |
1758 break; | |
1759 } | |
1760 } | |
1761 | |
1762 return retval; | |
1763 } | |
1764 | |
1765 // Maybe print a warning if an assignment expression is used as the | |
1766 // test in a logical expression. | |
1767 | |
1768 static void | |
1769 maybe_warn_assign_as_truth_value (tree_expression *expr) | |
1770 { | |
1771 if (expr->is_assignment_expression () | |
1772 && expr->paren_count () < 2) | |
1773 { | |
1774 if (curr_fcn_file_full_name.empty ()) | |
1775 warning_with_id | |
1776 ("Octave:assign-as-truth-value", | |
1777 "suggest parenthesis around assignment used as truth value"); | |
1778 else | |
1779 warning_with_id | |
1780 ("Octave:assign-as-truth-value", | |
1781 "suggest parenthesis around assignment used as truth value near line %d, column %d in file `%s'", | |
1782 expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); | |
1783 } | |
1784 } | |
1785 | |
1786 // Maybe print a warning about switch labels that aren't constants. | |
1787 | |
1788 static void | |
1789 maybe_warn_variable_switch_label (tree_expression *expr) | |
1790 { | |
1791 if (! expr->is_constant ()) | |
1792 { | |
1793 if (curr_fcn_file_full_name.empty ()) | |
1794 warning_with_id ("Octave:variable-switch-label", | |
1795 "variable switch label"); | |
1796 else | |
1797 warning_with_id | |
1798 ("Octave:variable-switch-label", | |
1799 "variable switch label near line %d, column %d in file `%s'", | |
1800 expr->line (), expr->column (), curr_fcn_file_full_name.c_str ()); | |
1801 } | |
1802 } | |
1803 | |
1804 static tree_expression * | |
1805 fold (tree_binary_expression *e) | |
1806 { | |
1807 tree_expression *retval = e; | |
1808 | |
1809 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
1810 | |
1811 unwind_protect::protect_var (error_state); | |
1812 unwind_protect::protect_var (warning_state); | |
1813 | |
1814 unwind_protect::protect_var (discard_error_messages); | |
1815 unwind_protect::protect_var (discard_warning_messages); | |
1816 | |
1817 discard_error_messages = true; | |
1818 discard_warning_messages = true; | |
1819 | |
1820 tree_expression *op1 = e->lhs (); | |
1821 tree_expression *op2 = e->rhs (); | |
1822 | |
1823 octave_value::binary_op op_type = e->op_type (); | |
1824 | |
1825 if (op1->is_constant () && op2->is_constant () | |
1826 && (! ((warning_enabled ("Octave:associativity-change") | |
1827 && (op_type == POW || op_type == EPOW)) | |
1828 || (warning_enabled ("Octave:precedence-change") | |
1829 && (op_type == EXPR_OR || op_type == EXPR_OR_OR))))) | |
1830 { | |
1831 octave_value tmp = e->rvalue1 (); | |
1832 | |
1833 if (! (error_state || warning_state)) | |
1834 { | |
1835 tree_constant *tc_retval | |
1836 = new tree_constant (tmp, op1->line (), op1->column ()); | |
1837 | |
1838 std::ostringstream buf; | |
1839 | |
1840 tree_print_code tpc (buf); | |
1841 | |
1842 e->accept (tpc); | |
1843 | |
1844 tc_retval->stash_original_text (buf.str ()); | |
1845 | |
1846 delete e; | |
1847 | |
1848 retval = tc_retval; | |
1849 } | |
1850 } | |
1851 | |
1852 unwind_protect::run_frame (uwp_frame); | |
1853 | |
1854 return retval; | |
1855 } | |
1856 | |
1857 static tree_expression * | |
1858 fold (tree_unary_expression *e) | |
1859 { | |
1860 tree_expression *retval = e; | |
1861 | |
1862 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
1863 | |
1864 unwind_protect::protect_var (error_state); | |
1865 unwind_protect::protect_var (warning_state); | |
1866 | |
1867 unwind_protect::protect_var (discard_error_messages); | |
1868 unwind_protect::protect_var (discard_warning_messages); | |
1869 | |
1870 discard_error_messages = true; | |
1871 discard_warning_messages = true; | |
1872 | |
1873 tree_expression *op = e->operand (); | |
1874 | |
1875 if (op->is_constant ()) | |
1876 { | |
1877 octave_value tmp = e->rvalue1 (); | |
1878 | |
1879 if (! (error_state || warning_state)) | |
1880 { | |
1881 tree_constant *tc_retval | |
1882 = new tree_constant (tmp, op->line (), op->column ()); | |
1883 | |
1884 std::ostringstream buf; | |
1885 | |
1886 tree_print_code tpc (buf); | |
1887 | |
1888 e->accept (tpc); | |
1889 | |
1890 tc_retval->stash_original_text (buf.str ()); | |
1891 | |
1892 delete e; | |
1893 | |
1894 retval = tc_retval; | |
1895 } | |
1896 } | |
1897 | |
1898 unwind_protect::run_frame (uwp_frame); | |
1899 | |
1900 return retval; | |
1901 } | |
1902 | |
1903 // Finish building a range. | |
1904 | |
1905 static tree_expression * | |
1906 finish_colon_expression (tree_colon_expression *e) | |
1907 { | |
1908 tree_expression *retval = e; | |
1909 | |
1910 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
1911 | |
1912 unwind_protect::protect_var (error_state); | |
1913 unwind_protect::protect_var (warning_state); | |
1914 | |
1915 unwind_protect::protect_var (discard_error_messages); | |
1916 unwind_protect::protect_var (discard_warning_messages); | |
1917 | |
1918 discard_error_messages = true; | |
1919 discard_warning_messages = true; | |
1920 | |
1921 tree_expression *base = e->base (); | |
1922 tree_expression *limit = e->limit (); | |
1923 tree_expression *incr = e->increment (); | |
1924 | |
1925 if (base) | |
1926 { | |
1927 if (limit) | |
1928 { | |
1929 if (base->is_constant () && limit->is_constant () | |
1930 && (! incr || (incr && incr->is_constant ()))) | |
1931 { | |
1932 octave_value tmp = e->rvalue1 (); | |
1933 | |
1934 if (! (error_state || warning_state)) | |
1935 { | |
1936 tree_constant *tc_retval | |
1937 = new tree_constant (tmp, base->line (), base->column ()); | |
1938 | |
1939 std::ostringstream buf; | |
1940 | |
1941 tree_print_code tpc (buf); | |
1942 | |
1943 e->accept (tpc); | |
1944 | |
1945 tc_retval->stash_original_text (buf.str ()); | |
1946 | |
1947 delete e; | |
1948 | |
1949 retval = tc_retval; | |
1950 } | |
1951 } | |
1952 } | |
1953 else | |
1954 { | |
1955 e->preserve_base (); | |
1956 delete e; | |
1957 | |
1958 // FIXME -- need to attempt constant folding here | |
1959 // too (we need a generic way to do that). | |
1960 retval = base; | |
1961 } | |
1962 } | |
1963 | |
1964 unwind_protect::run_frame (uwp_frame); | |
1965 | |
1966 return retval; | |
1967 } | |
1968 | |
1969 // Make a constant. | |
1970 | |
1971 static tree_constant * | |
1972 make_constant (int op, token *tok_val) | |
1973 { | |
1974 int l = tok_val->line (); | |
1975 int c = tok_val->column (); | |
1976 | |
1977 tree_constant *retval = 0; | |
1978 | |
1979 switch (op) | |
1980 { | |
1981 case NUM: | |
1982 { | |
1983 octave_value tmp (tok_val->number ()); | |
1984 retval = new tree_constant (tmp, l, c); | |
1985 retval->stash_original_text (tok_val->text_rep ()); | |
1986 } | |
1987 break; | |
1988 | |
1989 case IMAG_NUM: | |
1990 { | |
1991 octave_value tmp (Complex (0.0, tok_val->number ())); | |
1992 retval = new tree_constant (tmp, l, c); | |
1993 retval->stash_original_text (tok_val->text_rep ()); | |
1994 } | |
1995 break; | |
1996 | |
1997 case DQ_STRING: | |
1998 case SQ_STRING: | |
1999 { | |
2000 std::string txt = tok_val->text (); | |
2001 | |
2002 char delim = op == DQ_STRING ? '"' : '\''; | |
2003 octave_value tmp (txt, delim); | |
2004 | |
2005 if (txt.empty ()) | |
2006 { | |
2007 if (op == DQ_STRING) | |
2008 tmp = octave_null_str::instance; | |
2009 else | |
2010 tmp = octave_null_sq_str::instance; | |
2011 } | |
2012 | |
2013 retval = new tree_constant (tmp, l, c); | |
2014 | |
2015 if (op == DQ_STRING) | |
2016 txt = undo_string_escapes (txt); | |
2017 | |
2018 // FIXME -- maybe this should also be handled by | |
2019 // tok_val->text_rep () for character strings? | |
2020 retval->stash_original_text (delim + txt + delim); | |
2021 } | |
2022 break; | |
2023 | |
2024 default: | |
2025 panic_impossible (); | |
2026 break; | |
2027 } | |
2028 | |
2029 return retval; | |
2030 } | |
2031 | |
2032 // Make a function handle. | |
2033 | |
2034 static tree_fcn_handle * | |
2035 make_fcn_handle (token *tok_val) | |
2036 { | |
2037 int l = tok_val->line (); | |
2038 int c = tok_val->column (); | |
2039 | |
2040 tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c); | |
2041 | |
2042 return retval; | |
2043 } | |
2044 | |
2045 // Make an anonymous function handle. | |
2046 | |
2047 static tree_anon_fcn_handle * | |
2048 make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt) | |
2049 { | |
2050 // FIXME -- need to get these from the location of the @ symbol. | |
2051 | |
2052 int l = -1; | |
2053 int c = -1; | |
2054 | |
2055 tree_parameter_list *ret_list = 0; | |
2056 | |
2057 symbol_table::scope_id fcn_scope = symbol_table::current_scope (); | |
2058 | |
2059 if (symtab_context.empty ()) | |
2060 panic_impossible (); | |
2061 | |
2062 symbol_table::set_scope (symtab_context.top ()); | |
2063 | |
2064 symtab_context.pop (); | |
2065 | |
2066 stmt->set_print_flag (false); | |
2067 | |
2068 tree_statement_list *body = new tree_statement_list (stmt); | |
2069 | |
2070 body->mark_as_anon_function_body (); | |
2071 | |
2072 tree_anon_fcn_handle *retval | |
2073 = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); | |
2074 | |
2075 return retval; | |
2076 } | |
2077 | |
2078 static void | |
2079 maybe_warn_associativity_change (tree_expression *op) | |
2080 { | |
2081 if (op->paren_count () == 0 && op->is_binary_expression ()) | |
2082 { | |
2083 tree_binary_expression *e | |
2084 = dynamic_cast<tree_binary_expression *> (op); | |
2085 | |
2086 octave_value::binary_op op_type = e->op_type (); | |
2087 | |
2088 if (op_type == octave_value::op_pow | |
2089 || op_type == octave_value::op_el_pow) | |
2090 { | |
2091 std::string op_str = octave_value::binary_op_as_string (op_type); | |
2092 | |
2093 if (curr_fcn_file_full_name.empty ()) | |
2094 warning_with_id | |
2095 ("Octave:associativity-change", | |
2096 "meaning may have changed due to change in associativity for %s operator", | |
2097 op_str.c_str ()); | |
2098 else | |
2099 warning_with_id | |
2100 ("Octave:associativity-change", | |
2101 "meaning may have changed due to change in associativity for %s operator near line %d, column %d in file `%s'", | |
2102 op_str.c_str (), op->line (), op->column (), | |
2103 curr_fcn_file_full_name.c_str ()); | |
2104 } | |
2105 } | |
2106 } | |
2107 | |
2108 // Build a binary expression. | |
2109 | |
2110 static tree_expression * | |
2111 make_binary_op (int op, tree_expression *op1, token *tok_val, | |
2112 tree_expression *op2) | |
2113 { | |
2114 octave_value::binary_op t = octave_value::unknown_binary_op; | |
2115 | |
2116 switch (op) | |
2117 { | |
2118 case POW: | |
2119 t = octave_value::op_pow; | |
2120 maybe_warn_associativity_change (op1); | |
2121 break; | |
2122 | |
2123 case EPOW: | |
2124 t = octave_value::op_el_pow; | |
2125 maybe_warn_associativity_change (op1); | |
2126 break; | |
2127 | |
2128 case '+': | |
2129 t = octave_value::op_add; | |
2130 break; | |
2131 | |
2132 case '-': | |
2133 t = octave_value::op_sub; | |
2134 break; | |
2135 | |
2136 case '*': | |
2137 t = octave_value::op_mul; | |
2138 break; | |
2139 | |
2140 case '/': | |
2141 t = octave_value::op_div; | |
2142 break; | |
2143 | |
2144 case EMUL: | |
2145 t = octave_value::op_el_mul; | |
2146 break; | |
2147 | |
2148 case EDIV: | |
2149 t = octave_value::op_el_div; | |
2150 break; | |
2151 | |
2152 case LEFTDIV: | |
2153 t = octave_value::op_ldiv; | |
2154 break; | |
2155 | |
2156 case ELEFTDIV: | |
2157 t = octave_value::op_el_ldiv; | |
2158 break; | |
2159 | |
2160 case LSHIFT: | |
2161 t = octave_value::op_lshift; | |
2162 break; | |
2163 | |
2164 case RSHIFT: | |
2165 t = octave_value::op_rshift; | |
2166 break; | |
2167 | |
2168 case EXPR_LT: | |
2169 t = octave_value::op_lt; | |
2170 break; | |
2171 | |
2172 case EXPR_LE: | |
2173 t = octave_value::op_le; | |
2174 break; | |
2175 | |
2176 case EXPR_EQ: | |
2177 t = octave_value::op_eq; | |
2178 break; | |
2179 | |
2180 case EXPR_GE: | |
2181 t = octave_value::op_ge; | |
2182 break; | |
2183 | |
2184 case EXPR_GT: | |
2185 t = octave_value::op_gt; | |
2186 break; | |
2187 | |
2188 case EXPR_NE: | |
2189 t = octave_value::op_ne; | |
2190 break; | |
2191 | |
2192 case EXPR_AND: | |
2193 t = octave_value::op_el_and; | |
2194 break; | |
2195 | |
2196 case EXPR_OR: | |
2197 t = octave_value::op_el_or; | |
2198 if (op2->paren_count () == 0 && op2->is_binary_expression ()) | |
2199 { | |
2200 tree_binary_expression *e | |
2201 = dynamic_cast<tree_binary_expression *> (op2); | |
2202 | |
2203 if (e->op_type () == octave_value::op_el_and) | |
2204 { | |
2205 if (curr_fcn_file_full_name.empty ()) | |
2206 warning_with_id | |
2207 ("Octave:precedence-change", | |
2208 "meaning may have changed due to change in precedence for & and | operators"); | |
2209 else | |
2210 warning_with_id | |
2211 ("Octave:precedence-change", | |
2212 "meaning may have changed due to change in precedence for & and | operators near line %d, column %d in file `%s'", | |
2213 op2->line (), op2->column (), | |
2214 curr_fcn_file_full_name.c_str ()); | |
2215 } | |
2216 } | |
2217 break; | |
2218 | |
2219 default: | |
2220 panic_impossible (); | |
2221 break; | |
2222 } | |
2223 | |
2224 int l = tok_val->line (); | |
2225 int c = tok_val->column (); | |
2226 | |
2227 tree_binary_expression *e | |
2228 = maybe_compound_binary_expression (op1, op2, l, c, t); | |
2229 | |
2230 return fold (e); | |
2231 } | |
2232 | |
2233 // Build a boolean expression. | |
2234 | |
2235 static tree_expression * | |
2236 make_boolean_op (int op, tree_expression *op1, token *tok_val, | |
2237 tree_expression *op2) | |
2238 { | |
2239 tree_boolean_expression::type t; | |
2240 | |
2241 switch (op) | |
2242 { | |
2243 case EXPR_AND_AND: | |
2244 t = tree_boolean_expression::bool_and; | |
2245 break; | |
2246 | |
2247 case EXPR_OR_OR: | |
2248 t = tree_boolean_expression::bool_or; | |
2249 if (op2->paren_count () == 0 && op2->is_boolean_expression ()) | |
2250 { | |
2251 tree_boolean_expression *e | |
2252 = dynamic_cast<tree_boolean_expression *> (op2); | |
2253 | |
2254 if (e->op_type () == tree_boolean_expression::bool_and) | |
2255 warning_with_id | |
2256 ("Octave:precedence-change", | |
2257 "meaning may have changed due to change in precedence for && and || operators"); | |
2258 } | |
2259 break; | |
2260 | |
2261 default: | |
2262 panic_impossible (); | |
2263 break; | |
2264 } | |
2265 | |
2266 int l = tok_val->line (); | |
2267 int c = tok_val->column (); | |
2268 | |
2269 tree_boolean_expression *e | |
2270 = new tree_boolean_expression (op1, op2, l, c, t); | |
2271 | |
2272 return fold (e); | |
2273 } | |
2274 | |
2275 // Build a prefix expression. | |
2276 | |
2277 static tree_expression * | |
2278 make_prefix_op (int op, tree_expression *op1, token *tok_val) | |
2279 { | |
2280 octave_value::unary_op t = octave_value::unknown_unary_op; | |
2281 | |
2282 switch (op) | |
2283 { | |
2284 case EXPR_NOT: | |
2285 t = octave_value::op_not; | |
2286 break; | |
2287 | |
2288 case '+': | |
2289 t = octave_value::op_uplus; | |
2290 break; | |
2291 | |
2292 case '-': | |
2293 t = octave_value::op_uminus; | |
2294 break; | |
2295 | |
2296 case PLUS_PLUS: | |
2297 t = octave_value::op_incr; | |
2298 break; | |
2299 | |
2300 case MINUS_MINUS: | |
2301 t = octave_value::op_decr; | |
2302 break; | |
2303 | |
2304 default: | |
2305 panic_impossible (); | |
2306 break; | |
2307 } | |
2308 | |
2309 int l = tok_val->line (); | |
2310 int c = tok_val->column (); | |
2311 | |
2312 tree_prefix_expression *e | |
2313 = new tree_prefix_expression (op1, l, c, t); | |
2314 | |
2315 return fold (e); | |
2316 } | |
2317 | |
2318 // Build a postfix expression. | |
2319 | |
2320 static tree_expression * | |
2321 make_postfix_op (int op, tree_expression *op1, token *tok_val) | |
2322 { | |
2323 octave_value::unary_op t = octave_value::unknown_unary_op; | |
2324 | |
2325 switch (op) | |
2326 { | |
2327 case QUOTE: | |
2328 t = octave_value::op_hermitian; | |
2329 break; | |
2330 | |
2331 case TRANSPOSE: | |
2332 t = octave_value::op_transpose; | |
2333 break; | |
2334 | |
2335 case PLUS_PLUS: | |
2336 t = octave_value::op_incr; | |
2337 break; | |
2338 | |
2339 case MINUS_MINUS: | |
2340 t = octave_value::op_decr; | |
2341 break; | |
2342 | |
2343 default: | |
2344 panic_impossible (); | |
2345 break; | |
2346 } | |
2347 | |
2348 int l = tok_val->line (); | |
2349 int c = tok_val->column (); | |
2350 | |
2351 tree_postfix_expression *e | |
2352 = new tree_postfix_expression (op1, l, c, t); | |
2353 | |
2354 return fold (e); | |
2355 } | |
2356 | |
2357 // Build an unwind-protect command. | |
2358 | |
2359 static tree_command * | |
2360 make_unwind_command (token *unwind_tok, tree_statement_list *body, | |
2361 tree_statement_list *cleanup, token *end_tok, | |
2362 octave_comment_list *lc, octave_comment_list *mc) | |
2363 { | |
2364 tree_command *retval = 0; | |
2365 | |
2366 if (end_token_ok (end_tok, token::unwind_protect_end)) | |
2367 { | |
2368 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2369 | |
2370 int l = unwind_tok->line (); | |
2371 int c = unwind_tok->column (); | |
2372 | |
2373 retval = new tree_unwind_protect_command (body, cleanup, | |
2374 lc, mc, tc, l, c); | |
2375 } | |
2376 | |
2377 return retval; | |
2378 } | |
2379 | |
2380 // Build a try-catch command. | |
2381 | |
2382 static tree_command * | |
2383 make_try_command (token *try_tok, tree_statement_list *body, | |
2384 tree_statement_list *cleanup, token *end_tok, | |
2385 octave_comment_list *lc, octave_comment_list *mc) | |
2386 { | |
2387 tree_command *retval = 0; | |
2388 | |
2389 if (end_token_ok (end_tok, token::try_catch_end)) | |
2390 { | |
2391 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2392 | |
2393 int l = try_tok->line (); | |
2394 int c = try_tok->column (); | |
2395 | |
2396 retval = new tree_try_catch_command (body, cleanup, | |
2397 lc, mc, tc, l, c); | |
2398 } | |
2399 | |
2400 return retval; | |
2401 } | |
2402 | |
2403 // Build a while command. | |
2404 | |
2405 static tree_command * | |
2406 make_while_command (token *while_tok, tree_expression *expr, | |
2407 tree_statement_list *body, token *end_tok, | |
2408 octave_comment_list *lc) | |
2409 { | |
2410 tree_command *retval = 0; | |
2411 | |
2412 maybe_warn_assign_as_truth_value (expr); | |
2413 | |
2414 if (end_token_ok (end_tok, token::while_end)) | |
2415 { | |
2416 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2417 | |
2418 lexer_flags.looping--; | |
2419 | |
2420 int l = while_tok->line (); | |
2421 int c = while_tok->column (); | |
2422 | |
2423 retval = new tree_while_command (expr, body, lc, tc, l, c); | |
2424 } | |
2425 | |
2426 return retval; | |
2427 } | |
2428 | |
2429 // Build a do-until command. | |
2430 | |
2431 static tree_command * | |
2432 make_do_until_command (token *until_tok, tree_statement_list *body, | |
2433 tree_expression *expr, octave_comment_list *lc) | |
2434 { | |
2435 tree_command *retval = 0; | |
2436 | |
2437 maybe_warn_assign_as_truth_value (expr); | |
2438 | |
2439 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2440 | |
2441 lexer_flags.looping--; | |
2442 | |
2443 int l = until_tok->line (); | |
2444 int c = until_tok->column (); | |
2445 | |
2446 retval = new tree_do_until_command (expr, body, lc, tc, l, c); | |
2447 | |
2448 return retval; | |
2449 } | |
2450 | |
2451 // Build a for command. | |
2452 | |
2453 static tree_command * | |
2454 make_for_command (token *for_tok, tree_argument_list *lhs, | |
2455 tree_expression *expr, tree_statement_list *body, | |
2456 token *end_tok, octave_comment_list *lc) | |
2457 { | |
2458 tree_command *retval = 0; | |
2459 | |
2460 if (end_token_ok (end_tok, token::for_end)) | |
2461 { | |
2462 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2463 | |
2464 lexer_flags.looping--; | |
2465 | |
2466 int l = for_tok->line (); | |
2467 int c = for_tok->column (); | |
2468 | |
2469 if (lhs->length () == 1) | |
2470 { | |
2471 tree_expression *tmp = lhs->remove_front (); | |
2472 | |
2473 retval = new tree_simple_for_command (tmp, expr, body, | |
2474 lc, tc, l, c); | |
2475 | |
2476 delete lhs; | |
2477 } | |
2478 else | |
2479 retval = new tree_complex_for_command (lhs, expr, body, | |
2480 lc, tc, l, c); | |
2481 } | |
2482 | |
2483 return retval; | |
2484 } | |
2485 | |
2486 // Build a break command. | |
2487 | |
2488 static tree_command * | |
2489 make_break_command (token *break_tok) | |
2490 { | |
2491 tree_command *retval = 0; | |
2492 | |
2493 int l = break_tok->line (); | |
2494 int c = break_tok->column (); | |
2495 | |
2496 // We check to see if we are evaluating a function, script, or loop | |
2497 // so that we don't turn eval ("break;") inside a function, script, | |
2498 // or loop into a no-op command. | |
2499 | |
2500 if (lexer_flags.looping || current_function_depth > 0 | |
2501 || reading_script_file || tree_evaluator::in_fcn_or_script_body | |
2502 || tree_evaluator::in_loop_command) | |
2503 retval = new tree_break_command (l, c); | |
2504 else | |
2505 retval = new tree_no_op_command ("break", l, c); | |
2506 | |
2507 return retval; | |
2508 } | |
2509 | |
2510 // Build a continue command. | |
2511 | |
2512 static tree_command * | |
2513 make_continue_command (token *continue_tok) | |
2514 { | |
2515 tree_command *retval = 0; | |
2516 | |
2517 int l = continue_tok->line (); | |
2518 int c = continue_tok->column (); | |
2519 | |
2520 // We check to see if we are evaluating a loop so that we don't turn | |
2521 // eval ("continue;") into a no-op command inside a loop. | |
2522 | |
2523 if (lexer_flags.looping || tree_evaluator::in_loop_command) | |
2524 retval = new tree_continue_command (l, c); | |
2525 else | |
2526 retval = new tree_no_op_command ("continue", l, c); | |
2527 | |
2528 return retval; | |
2529 } | |
2530 | |
2531 // Build a return command. | |
2532 | |
2533 static tree_command * | |
2534 make_return_command (token *return_tok) | |
2535 { | |
2536 tree_command *retval = 0; | |
2537 | |
2538 int l = return_tok->line (); | |
2539 int c = return_tok->column (); | |
2540 | |
2541 if (Vdebugging) | |
2542 { | |
2543 Vdebugging = false; | |
2544 | |
2545 retval = new tree_no_op_command ("return", l, c); | |
2546 } | |
2547 else | |
2548 { | |
2549 // We check to see if we are evaluating a function or script so | |
2550 // that we don't turn eval ("return;") inside a function, script, | |
2551 // or loop into a no-op command. | |
2552 | |
2553 if (current_function_depth > 0 || reading_script_file | |
2554 || tree_evaluator::in_fcn_or_script_body) | |
2555 retval = new tree_return_command (l, c); | |
2556 else | |
2557 retval = new tree_no_op_command ("return", l, c); | |
2558 } | |
2559 | |
2560 return retval; | |
2561 } | |
2562 | |
2563 // Start an if command. | |
2564 | |
2565 static tree_if_command_list * | |
2566 start_if_command (tree_expression *expr, tree_statement_list *list) | |
2567 { | |
2568 maybe_warn_assign_as_truth_value (expr); | |
2569 | |
2570 tree_if_clause *t = new tree_if_clause (expr, list); | |
2571 | |
2572 return new tree_if_command_list (t); | |
2573 } | |
2574 | |
2575 // Finish an if command. | |
2576 | |
2577 static tree_if_command * | |
2578 finish_if_command (token *if_tok, tree_if_command_list *list, | |
2579 token *end_tok, octave_comment_list *lc) | |
2580 { | |
2581 tree_if_command *retval = 0; | |
2582 | |
2583 if (end_token_ok (end_tok, token::if_end)) | |
2584 { | |
2585 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2586 | |
2587 int l = if_tok->line (); | |
2588 int c = if_tok->column (); | |
2589 | |
2590 if (list && ! list->empty ()) | |
2591 { | |
2592 tree_if_clause *elt = list->front (); | |
2593 | |
2594 if (elt) | |
2595 { | |
2596 elt->line (l); | |
2597 elt->column (c); | |
2598 } | |
2599 } | |
2600 | |
2601 retval = new tree_if_command (list, lc, tc, l, c); | |
2602 } | |
2603 | |
2604 return retval; | |
2605 } | |
2606 | |
2607 // Build an elseif clause. | |
2608 | |
2609 static tree_if_clause * | |
2610 make_elseif_clause (token *elseif_tok, tree_expression *expr, | |
2611 tree_statement_list *list, octave_comment_list *lc) | |
2612 { | |
2613 maybe_warn_assign_as_truth_value (expr); | |
2614 | |
2615 int l = elseif_tok->line (); | |
2616 int c = elseif_tok->column (); | |
2617 | |
2618 return new tree_if_clause (expr, list, lc, l, c); | |
2619 } | |
2620 | |
2621 // Finish a switch command. | |
2622 | |
2623 static tree_switch_command * | |
2624 finish_switch_command (token *switch_tok, tree_expression *expr, | |
2625 tree_switch_case_list *list, token *end_tok, | |
2626 octave_comment_list *lc) | |
2627 { | |
2628 tree_switch_command *retval = 0; | |
2629 | |
2630 if (end_token_ok (end_tok, token::switch_end)) | |
2631 { | |
2632 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2633 | |
2634 int l = switch_tok->line (); | |
2635 int c = switch_tok->column (); | |
2636 | |
2637 if (list && ! list->empty ()) | |
2638 { | |
2639 tree_switch_case *elt = list->front (); | |
2640 | |
2641 if (elt) | |
2642 { | |
2643 elt->line (l); | |
2644 elt->column (c); | |
2645 } | |
2646 } | |
2647 | |
2648 retval = new tree_switch_command (expr, list, lc, tc, l, c); | |
2649 } | |
2650 | |
2651 return retval; | |
2652 } | |
2653 | |
2654 // Build a switch case. | |
2655 | |
2656 static tree_switch_case * | |
2657 make_switch_case (token *case_tok, tree_expression *expr, | |
2658 tree_statement_list *list, octave_comment_list *lc) | |
2659 { | |
2660 maybe_warn_variable_switch_label (expr); | |
2661 | |
2662 int l = case_tok->line (); | |
2663 int c = case_tok->column (); | |
2664 | |
2665 return new tree_switch_case (expr, list, lc, l, c); | |
2666 } | |
2667 | |
2668 // Build an assignment to a variable. | |
2669 | |
2670 static tree_expression * | |
2671 make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, | |
2672 tree_expression *rhs) | |
2673 { | |
2674 tree_expression *retval = 0; | |
2675 | |
2676 octave_value::assign_op t = octave_value::unknown_assign_op; | |
2677 | |
2678 switch (op) | |
2679 { | |
2680 case '=': | |
2681 t = octave_value::op_asn_eq; | |
2682 break; | |
2683 | |
2684 case ADD_EQ: | |
2685 t = octave_value::op_add_eq; | |
2686 break; | |
2687 | |
2688 case SUB_EQ: | |
2689 t = octave_value::op_sub_eq; | |
2690 break; | |
2691 | |
2692 case MUL_EQ: | |
2693 t = octave_value::op_mul_eq; | |
2694 break; | |
2695 | |
2696 case DIV_EQ: | |
2697 t = octave_value::op_div_eq; | |
2698 break; | |
2699 | |
2700 case LEFTDIV_EQ: | |
2701 t = octave_value::op_ldiv_eq; | |
2702 break; | |
2703 | |
2704 case POW_EQ: | |
2705 t = octave_value::op_pow_eq; | |
2706 break; | |
2707 | |
2708 case LSHIFT_EQ: | |
2709 t = octave_value::op_lshift_eq; | |
2710 break; | |
2711 | |
2712 case RSHIFT_EQ: | |
2713 t = octave_value::op_rshift_eq; | |
2714 break; | |
2715 | |
2716 case EMUL_EQ: | |
2717 t = octave_value::op_el_mul_eq; | |
2718 break; | |
2719 | |
2720 case EDIV_EQ: | |
2721 t = octave_value::op_el_div_eq; | |
2722 break; | |
2723 | |
2724 case ELEFTDIV_EQ: | |
2725 t = octave_value::op_el_ldiv_eq; | |
2726 break; | |
2727 | |
2728 case EPOW_EQ: | |
2729 t = octave_value::op_el_pow_eq; | |
2730 break; | |
2731 | |
2732 case AND_EQ: | |
2733 t = octave_value::op_el_and_eq; | |
2734 break; | |
2735 | |
2736 case OR_EQ: | |
2737 t = octave_value::op_el_or_eq; | |
2738 break; | |
2739 | |
2740 default: | |
2741 panic_impossible (); | |
2742 break; | |
2743 } | |
2744 | |
2745 int l = eq_tok->line (); | |
2746 int c = eq_tok->column (); | |
2747 | |
2748 if (lhs->is_simple_assign_lhs ()) | |
2749 { | |
2750 tree_expression *tmp = lhs->remove_front (); | |
2751 | |
2752 retval = new tree_simple_assignment (tmp, rhs, false, l, c, t); | |
2753 | |
2754 delete lhs; | |
2755 } | |
2756 else | |
2757 return new tree_multi_assignment (lhs, rhs, false, l, c, t); | |
2758 | |
2759 return retval; | |
2760 } | |
2761 | |
2762 // Define a script. | |
2763 | |
2764 static void | |
2765 make_script (tree_statement_list *cmds, tree_statement *end_script) | |
2766 { | |
2767 std::string doc_string; | |
2768 | |
2769 if (! help_buf.empty ()) | |
2770 { | |
2771 doc_string = help_buf.top (); | |
2772 help_buf.pop (); | |
2773 } | |
2774 | |
2775 if (! cmds) | |
2776 cmds = new tree_statement_list (); | |
2777 | |
2778 cmds->append (end_script); | |
2779 | |
2780 octave_user_script *script | |
2781 = new octave_user_script (curr_fcn_file_full_name, curr_fcn_file_name, | |
2782 cmds, doc_string); | |
2783 | |
2784 octave_time now; | |
2785 | |
2786 script->stash_fcn_file_time (now); | |
2787 | |
2788 primary_fcn_ptr = script; | |
2789 | |
2790 // Unmark any symbols that may have been tagged as local variables | |
2791 // while parsing (for example, by force_local_variable in lex.l). | |
2792 | |
2793 symbol_table::unmark_forced_variables (); | |
2794 } | |
2795 | |
2796 // Begin defining a function. | |
2797 | |
2798 static octave_user_function * | |
2799 start_function (tree_parameter_list *param_list, tree_statement_list *body, | |
2800 tree_statement *end_fcn_stmt) | |
2801 { | |
2802 // We'll fill in the return list later. | |
2803 | |
2804 if (! body) | |
2805 body = new tree_statement_list (); | |
2806 | |
2807 body->append (end_fcn_stmt); | |
2808 | |
2809 octave_user_function *fcn | |
2810 = new octave_user_function (symbol_table::current_scope (), | |
2811 param_list, 0, body); | |
2812 | |
2813 if (fcn) | |
2814 { | |
2815 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
2816 | |
2817 fcn->stash_trailing_comment (tc); | |
2818 } | |
2819 | |
2820 return fcn; | |
2821 } | |
2822 | |
2823 static tree_statement * | |
2824 make_end (const std::string& type, int l, int c) | |
2825 { | |
2826 return make_statement (new tree_no_op_command (type, l, c)); | |
2827 } | |
2828 | |
2829 // Do most of the work for defining a function. | |
2830 | |
2831 static octave_user_function * | |
2832 frob_function (const std::string& fname, octave_user_function *fcn) | |
2833 { | |
2834 std::string id_name = fname; | |
2835 | |
2836 // If input is coming from a file, issue a warning if the name of | |
2837 // the file does not match the name of the function stated in the | |
2838 // file. Matlab doesn't provide a diagnostic (it ignores the stated | |
2839 // name). | |
2840 if (! autoloading && reading_fcn_file | |
2841 && (current_function_depth == 1 | |
2842 && ! (parsing_subfunctions || lexer_flags.parsing_class_method))) | |
2843 { | |
2844 // FIXME -- should curr_fcn_file_name already be | |
2845 // preprocessed when we get here? It seems to only be a | |
2846 // problem with relative file names. | |
2847 | |
2848 std::string nm = curr_fcn_file_name; | |
2849 | |
2850 size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); | |
2851 | |
2852 if (pos != std::string::npos) | |
2853 nm = curr_fcn_file_name.substr (pos+1); | |
2854 | |
2855 if (nm != id_name) | |
2856 { | |
2857 warning_with_id | |
2858 ("Octave:function-name-clash", | |
2859 "function name `%s' does not agree with function file name `%s'", | |
2860 id_name.c_str (), curr_fcn_file_full_name.c_str ()); | |
2861 | |
2862 id_name = nm; | |
2863 } | |
2864 } | |
2865 | |
2866 if (reading_fcn_file || reading_classdef_file || autoloading) | |
2867 { | |
2868 octave_time now; | |
2869 | |
2870 fcn->stash_fcn_file_name (curr_fcn_file_full_name); | |
2871 fcn->stash_fcn_file_time (now); | |
2872 fcn->mark_as_system_fcn_file (); | |
2873 | |
2874 if (fcn_file_from_relative_lookup) | |
2875 fcn->mark_relative (); | |
2876 | |
2877 if (current_function_depth > 1 || parsing_subfunctions) | |
2878 { | |
2879 fcn->stash_parent_fcn_name (curr_fcn_file_name); | |
2880 fcn->stash_parent_fcn_scope (primary_fcn_scope); | |
2881 } | |
2882 | |
2883 if (lexer_flags.parsing_class_method) | |
2884 { | |
2885 if (current_class_name == id_name) | |
2886 fcn->mark_as_class_constructor (); | |
2887 else | |
2888 fcn->mark_as_class_method (); | |
2889 | |
2890 fcn->stash_dispatch_class (current_class_name); | |
2891 } | |
2892 | |
2893 std::string nm = fcn->fcn_file_name (); | |
2894 | |
2895 file_stat fs (nm); | |
2896 | |
2897 if (fs && fs.is_newer (now)) | |
2898 warning_with_id ("Octave:future-time-stamp", | |
2899 "time stamp for `%s' is in the future", nm.c_str ()); | |
2900 } | |
2901 else if (! (input_from_tmp_history_file || input_from_startup_file) | |
2902 && reading_script_file | |
2903 && curr_fcn_file_name == id_name) | |
2904 { | |
2905 warning ("function `%s' defined within script file `%s'", | |
2906 id_name.c_str (), curr_fcn_file_full_name.c_str ()); | |
2907 } | |
2908 | |
2909 fcn->stash_function_name (id_name); | |
2910 | |
2911 if (! help_buf.empty () && current_function_depth == 1 | |
2912 && ! parsing_subfunctions) | |
2913 { | |
2914 fcn->document (help_buf.top ()); | |
2915 | |
2916 help_buf.pop (); | |
2917 } | |
2918 | |
2919 if (reading_fcn_file && current_function_depth == 1 | |
2920 && ! parsing_subfunctions) | |
2921 primary_fcn_ptr = fcn; | |
2922 | |
2923 return fcn; | |
2924 } | |
2925 | |
2926 static tree_function_def * | |
2927 finish_function (tree_parameter_list *ret_list, | |
2928 octave_user_function *fcn, octave_comment_list *lc) | |
2929 { | |
2930 tree_function_def *retval = 0; | |
2931 | |
2932 if (ret_list) | |
2933 ret_list->mark_as_formal_parameters (); | |
2934 | |
2935 if (fcn) | |
2936 { | |
2937 std::string nm = fcn->name (); | |
2938 std::string file = fcn->fcn_file_name (); | |
2939 | |
2940 std::string tmp = nm; | |
2941 if (! file.empty ()) | |
2942 tmp += ": " + file; | |
2943 | |
2944 symbol_table::cache_name (fcn->scope (), tmp); | |
2945 | |
2946 if (lc) | |
2947 fcn->stash_leading_comment (lc); | |
2948 | |
2949 fcn->define_ret_list (ret_list); | |
2950 | |
2951 if (current_function_depth > 1 || parsing_subfunctions) | |
2952 { | |
2953 // FIXME -- is this flag used to determine if the function is a | |
2954 // _subfunction_ somewhere? | |
2955 fcn->mark_as_nested_function (); | |
2956 | |
2957 symbol_table::install_subfunction (nm, octave_value (fcn), | |
2958 primary_fcn_scope); | |
2959 } | |
2960 | |
2961 if (! reading_fcn_file) | |
2962 { | |
2963 // We are either reading a script file or defining a function | |
2964 // at the command line, so this definition creates a | |
2965 // tree_function object that is placed in the parse tree. | |
2966 // Otherwise, it is just inserted in the symbol table, | |
2967 // either as a subfunction (see above), or as the primary | |
2968 // function for the file, via primary_fcn_ptr (see also | |
2969 // load_fcn_from_file,, parse_fcn_file, and | |
2970 // symbol_table::fcn_info::fcn_info_rep::find_user_function). | |
2971 | |
2972 retval = new tree_function_def (fcn); | |
2973 } | |
2974 | |
2975 // Unmark any symbols that may have been tagged as local | |
2976 // variables while parsing (for example, by force_local_variable | |
2977 // in lex.l). | |
2978 | |
2979 symbol_table::unmark_forced_variables (fcn->scope ()); | |
2980 } | |
2981 | |
2982 return retval; | |
2983 } | |
2984 | |
2985 static void | |
2986 recover_from_parsing_function (void) | |
2987 { | |
2988 if (symtab_context.empty ()) | |
2989 panic_impossible (); | |
2990 | |
2991 symbol_table::set_scope (symtab_context.top ()); | |
2992 symtab_context.pop (); | |
2993 | |
2994 if (reading_fcn_file && current_function_depth == 1 | |
2995 && ! parsing_subfunctions) | |
2996 parsing_subfunctions = true; | |
2997 | |
2998 current_function_depth--; | |
2999 | |
3000 lexer_flags.parsed_function_name = false; | |
3001 lexer_flags.looking_at_return_list = false; | |
3002 lexer_flags.looking_at_parameter_list = false; | |
3003 } | |
3004 | |
3005 // Make an index expression. | |
3006 | |
3007 static tree_index_expression * | |
3008 make_index_expression (tree_expression *expr, tree_argument_list *args, | |
3009 char type) | |
3010 { | |
3011 tree_index_expression *retval = 0; | |
3012 | |
3013 int l = expr->line (); | |
3014 int c = expr->column (); | |
3015 | |
3016 expr->mark_postfix_indexed (); | |
3017 | |
3018 if (expr->is_index_expression ()) | |
3019 { | |
3020 tree_index_expression *tmp = static_cast<tree_index_expression *> (expr); | |
3021 | |
3022 tmp->append (args, type); | |
3023 | |
3024 retval = tmp; | |
3025 } | |
3026 else | |
3027 retval = new tree_index_expression (expr, args, l, c, type); | |
3028 | |
3029 return retval; | |
3030 } | |
3031 | |
3032 // Make an indirect reference expression. | |
3033 | |
3034 static tree_index_expression * | |
3035 make_indirect_ref (tree_expression *expr, const std::string& elt) | |
3036 { | |
3037 tree_index_expression *retval = 0; | |
3038 | |
3039 int l = expr->line (); | |
3040 int c = expr->column (); | |
3041 | |
3042 if (expr->is_index_expression ()) | |
3043 { | |
3044 tree_index_expression *tmp = static_cast<tree_index_expression *> (expr); | |
3045 | |
3046 tmp->append (elt); | |
3047 | |
3048 retval = tmp; | |
3049 } | |
3050 else | |
3051 retval = new tree_index_expression (expr, elt, l, c); | |
3052 | |
3053 lexer_flags.looking_at_indirect_ref = false; | |
3054 | |
3055 return retval; | |
3056 } | |
3057 | |
3058 // Make an indirect reference expression with dynamic field name. | |
3059 | |
3060 static tree_index_expression * | |
3061 make_indirect_ref (tree_expression *expr, tree_expression *elt) | |
3062 { | |
3063 tree_index_expression *retval = 0; | |
3064 | |
3065 int l = expr->line (); | |
3066 int c = expr->column (); | |
3067 | |
3068 if (expr->is_index_expression ()) | |
3069 { | |
3070 tree_index_expression *tmp = static_cast<tree_index_expression *> (expr); | |
3071 | |
3072 tmp->append (elt); | |
3073 | |
3074 retval = tmp; | |
3075 } | |
3076 else | |
3077 retval = new tree_index_expression (expr, elt, l, c); | |
3078 | |
3079 lexer_flags.looking_at_indirect_ref = false; | |
3080 | |
3081 return retval; | |
3082 } | |
3083 | |
3084 // Make a declaration command. | |
3085 | |
3086 static tree_decl_command * | |
3087 make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst) | |
3088 { | |
3089 tree_decl_command *retval = 0; | |
3090 | |
3091 int l = tok_val->line (); | |
3092 int c = tok_val->column (); | |
3093 | |
3094 switch (tok) | |
3095 { | |
3096 case GLOBAL: | |
3097 retval = new tree_global_command (lst, l, c); | |
3098 break; | |
3099 | |
3100 case STATIC: | |
3101 if (current_function_depth > 0) | |
3102 retval = new tree_static_command (lst, l, c); | |
3103 else | |
3104 { | |
3105 if (reading_script_file) | |
3106 warning ("ignoring persistent declaration near line %d of file `%s'", | |
3107 l, curr_fcn_file_full_name.c_str ()); | |
3108 else | |
3109 warning ("ignoring persistent declaration near line %d", l); | |
3110 } | |
3111 break; | |
3112 | |
3113 default: | |
3114 panic_impossible (); | |
3115 break; | |
3116 } | |
3117 | |
3118 return retval; | |
3119 } | |
3120 | |
3121 // Finish building a matrix list. | |
3122 | |
3123 static tree_expression * | |
3124 finish_matrix (tree_matrix *m) | |
3125 { | |
3126 tree_expression *retval = m; | |
3127 | |
3128 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
3129 | |
3130 unwind_protect::protect_var (error_state); | |
3131 unwind_protect::protect_var (warning_state); | |
3132 | |
3133 unwind_protect::protect_var (discard_error_messages); | |
3134 unwind_protect::protect_var (discard_warning_messages); | |
3135 | |
3136 discard_error_messages = true; | |
3137 discard_warning_messages = true; | |
3138 | |
3139 if (m->all_elements_are_constant ()) | |
3140 { | |
3141 octave_value tmp = m->rvalue1 (); | |
3142 | |
3143 if (! (error_state || warning_state)) | |
3144 { | |
3145 tree_constant *tc_retval | |
3146 = new tree_constant (tmp, m->line (), m->column ()); | |
3147 | |
3148 std::ostringstream buf; | |
3149 | |
3150 tree_print_code tpc (buf); | |
3151 | |
3152 m->accept (tpc); | |
3153 | |
3154 tc_retval->stash_original_text (buf.str ()); | |
3155 | |
3156 delete m; | |
3157 | |
3158 retval = tc_retval; | |
3159 } | |
3160 } | |
3161 | |
3162 unwind_protect::run_frame (uwp_frame); | |
3163 | |
3164 return retval; | |
3165 } | |
3166 | |
3167 // Finish building a cell list. | |
3168 | |
3169 static tree_expression * | |
3170 finish_cell (tree_cell *c) | |
3171 { | |
3172 return finish_matrix (c); | |
3173 } | |
3174 | |
3175 static void | |
3176 maybe_warn_missing_semi (tree_statement_list *t) | |
3177 { | |
3178 if (current_function_depth > 0) | |
3179 { | |
3180 tree_statement *tmp = t->back(); | |
3181 | |
3182 if (tmp->is_expression ()) | |
3183 warning_with_id | |
3184 ("Octave:missing-semicolon", | |
3185 "missing semicolon near line %d, column %d in file `%s'", | |
3186 tmp->line (), tmp->column (), curr_fcn_file_full_name.c_str ()); | |
3187 } | |
3188 } | |
3189 | |
3190 static tree_statement_list * | |
3191 set_stmt_print_flag (tree_statement_list *list, char sep, | |
3192 bool warn_missing_semi) | |
3193 { | |
3194 tree_statement *tmp = list->back (); | |
3195 | |
3196 switch (sep) | |
3197 { | |
3198 case ';': | |
3199 tmp->set_print_flag (false); | |
3200 break; | |
3201 | |
3202 case 0: | |
3203 case ',': | |
3204 case '\n': | |
3205 tmp->set_print_flag (true); | |
3206 if (warn_missing_semi) | |
3207 maybe_warn_missing_semi (list); | |
3208 break; | |
3209 | |
3210 default: | |
3211 warning ("unrecognized separator type!"); | |
3212 break; | |
3213 } | |
3214 | |
3215 // Even if a statement is null, we add it to the list then remove it | |
3216 // here so that the print flag is applied to the correct statement. | |
3217 | |
3218 if (tmp->is_null_statement ()) | |
3219 { | |
3220 list->pop_back (); | |
3221 delete tmp; | |
3222 } | |
3223 | |
3224 return list; | |
3225 } | |
3226 | |
3227 static tree_statement_list * | |
3228 make_statement_list (tree_statement *stmt) | |
3229 { | |
3230 return new tree_statement_list (stmt); | |
3231 } | |
3232 | |
3233 static tree_statement_list * | |
3234 append_statement_list (tree_statement_list *list, char sep, | |
3235 tree_statement *stmt, bool warn_missing_semi) | |
3236 { | |
3237 set_stmt_print_flag (list, sep, warn_missing_semi); | |
3238 | |
3239 list->append (stmt); | |
3240 | |
3241 return list; | |
3242 } | |
3243 | |
3244 static void | |
3245 safe_fclose (void *f) | |
3246 { | |
3247 // FIXME -- comments at the end of an input file are | |
3248 // discarded (otherwise, they would be appended to the next | |
3249 // statement, possibly from the command line or another file, which | |
3250 // can be quite confusing). | |
3251 | |
3252 octave_comment_list *tc = octave_comment_buffer::get_comment (); | |
3253 | |
3254 delete tc; | |
3255 | |
3256 if (f) | |
3257 fclose (static_cast<FILE *> (f)); | |
3258 } | |
3259 | |
3260 static bool | |
3261 looks_like_copyright (const std::string& s) | |
3262 { | |
3263 bool retval = false; | |
3264 | |
3265 if (! s.empty ()) | |
3266 { | |
3267 size_t offset = s.find_first_not_of (" \t"); | |
3268 | |
3269 retval = (s.substr (offset, 9) == "Copyright"); | |
3270 } | |
3271 | |
3272 return retval; | |
3273 } | |
3274 | |
3275 static int | |
3276 text_getc (FILE *f) | |
3277 { | |
3278 int c = getc (f); | |
3279 | |
3280 // Convert CRLF into just LF and single CR into LF. | |
3281 | |
3282 if (c == '\r') | |
3283 { | |
3284 c = getc (f); | |
3285 | |
3286 if (c != '\n') | |
3287 { | |
3288 ungetc (c, f); | |
3289 c = '\n'; | |
3290 } | |
3291 } | |
3292 | |
3293 if (c == '\n') | |
3294 input_line_number++; | |
3295 | |
3296 return c; | |
3297 } | |
3298 | |
3299 class | |
3300 stdio_stream_reader : public stream_reader | |
3301 { | |
3302 public: | |
3303 stdio_stream_reader (FILE *f_arg) : stream_reader (), f (f_arg) { } | |
3304 | |
3305 int getc (void) { return ::text_getc (f); } | |
3306 int ungetc (int c) | |
3307 { | |
3308 if (c == '\n') | |
3309 input_line_number--; | |
3310 | |
3311 return ::ungetc (c, f); | |
3312 } | |
3313 | |
3314 private: | |
3315 FILE *f; | |
3316 }; | |
3317 | |
3318 static bool | |
3319 skip_white_space (stream_reader& reader) | |
3320 { | |
3321 int c = 0; | |
3322 | |
3323 while ((c = reader.getc ()) != EOF) | |
3324 { | |
3325 switch (c) | |
3326 { | |
3327 case ' ': | |
3328 case '\t': | |
3329 current_input_column++; | |
3330 break; | |
3331 | |
3332 case '\n': | |
3333 current_input_column = 0; | |
3334 break; | |
3335 | |
3336 default: | |
3337 current_input_column--; | |
3338 reader.ungetc (c); | |
3339 goto done; | |
3340 } | |
3341 } | |
3342 | |
3343 done: | |
3344 | |
3345 return (c == EOF); | |
3346 } | |
3347 | |
3348 static bool | |
3349 looking_at_classdef_keyword (FILE *ffile) | |
3350 { | |
3351 bool status = false; | |
3352 | |
3353 long pos = ftell (ffile); | |
3354 | |
3355 char buf [10]; | |
3356 fgets (buf, 10, ffile); | |
3357 size_t len = strlen (buf); | |
3358 if (len > 8 && strncmp (buf, "classdef", 8) == 0 | |
3359 && ! (isalnum (buf[8]) || buf[8] == '_')) | |
3360 status = true; | |
3361 | |
3362 fseek (ffile, pos, SEEK_SET); | |
3363 | |
3364 return status; | |
3365 } | |
3366 | |
3367 static std::string | |
3368 gobble_leading_white_space (FILE *ffile, bool& eof) | |
3369 { | |
3370 std::string help_txt; | |
3371 | |
3372 eof = false; | |
3373 | |
3374 // TRUE means we have already cached the help text. | |
3375 bool have_help_text = false; | |
3376 | |
3377 std::string txt; | |
3378 | |
3379 stdio_stream_reader stdio_reader (ffile); | |
3380 | |
3381 while (true) | |
3382 { | |
3383 eof = skip_white_space (stdio_reader); | |
3384 | |
3385 if (eof) | |
3386 break; | |
3387 | |
3388 txt = grab_comment_block (stdio_reader, true, eof); | |
3389 | |
3390 if (txt.empty ()) | |
3391 break; | |
3392 | |
3393 if (! (have_help_text || looks_like_copyright (txt))) | |
3394 { | |
3395 help_txt = txt; | |
3396 have_help_text = true; | |
3397 } | |
3398 | |
3399 octave_comment_buffer::append (txt); | |
3400 | |
3401 if (eof) | |
3402 break; | |
3403 } | |
3404 | |
3405 return help_txt; | |
3406 } | |
3407 | |
3408 static bool | |
3409 looking_at_function_keyword (FILE *ffile) | |
3410 { | |
3411 bool status = false; | |
3412 | |
3413 long pos = ftell (ffile); | |
3414 | |
3415 char buf [10]; | |
3416 fgets (buf, 10, ffile); | |
3417 size_t len = strlen (buf); | |
3418 if (len > 8 && strncmp (buf, "function", 8) == 0 | |
3419 && ! (isalnum (buf[8]) || buf[8] == '_')) | |
3420 status = true; | |
3421 | |
3422 fseek (ffile, pos, SEEK_SET); | |
3423 | |
3424 return status; | |
3425 } | |
3426 | |
3427 static octave_function * | |
3428 parse_fcn_file (const std::string& ff, const std::string& dispatch_type, | |
3429 bool force_script = false, bool require_file = true, | |
3430 const std::string& warn_for = std::string ()) | |
3431 { | |
3432 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
3433 | |
3434 octave_function *fcn_ptr = 0; | |
3435 | |
3436 // Open function file and parse. | |
3437 | |
3438 FILE *in_stream = command_editor::get_input_stream (); | |
3439 | |
3440 unwind_protect::add_fcn (command_editor::set_input_stream, | |
3441 in_stream); | |
3442 | |
3443 unwind_protect::protect_var (ff_instream); | |
3444 | |
3445 unwind_protect::protect_var (input_line_number); | |
3446 unwind_protect::protect_var (current_input_column); | |
3447 unwind_protect::protect_var (reading_fcn_file); | |
3448 unwind_protect::protect_var (line_editing); | |
3449 unwind_protect::protect_var (current_class_name); | |
3450 unwind_protect::protect_var (current_function_depth); | |
3451 unwind_protect::protect_var (max_function_depth); | |
3452 unwind_protect::protect_var (parsing_subfunctions); | |
3453 unwind_protect::protect_var (endfunction_found); | |
3454 | |
3455 input_line_number = 1; | |
3456 current_input_column = 1; | |
3457 reading_fcn_file = true; | |
3458 line_editing = false; | |
3459 current_class_name = dispatch_type; | |
3460 current_function_depth = 0; | |
3461 max_function_depth = 0; | |
3462 parsing_subfunctions = false; | |
3463 endfunction_found = false; | |
3464 | |
3465 // The next four lines must be in this order. | |
3466 unwind_protect::add_fcn (command_history::ignore_entries, ! Vsaving_history); | |
3467 | |
3468 // FIXME -- we shouldn't need both the | |
3469 // command_history object and the | |
3470 // Vsaving_history variable... | |
3471 command_history::ignore_entries (); | |
3472 | |
3473 unwind_protect::protect_var (Vsaving_history); | |
3474 | |
3475 Vsaving_history = false; | |
3476 | |
3477 FILE *ffile = get_input_from_file (ff, 0); | |
3478 | |
3479 unwind_protect::add (safe_fclose, ffile); | |
3480 | |
3481 if (ffile) | |
3482 { | |
3483 bool eof; | |
3484 | |
3485 std::string help_txt = gobble_leading_white_space (ffile, eof); | |
3486 | |
3487 if (! eof) | |
3488 { | |
3489 std::string file_type; | |
3490 | |
3491 unwind_protect::protect_var (get_input_from_eval_string); | |
3492 unwind_protect::protect_var (parser_end_of_input); | |
3493 unwind_protect::protect_var (reading_fcn_file); | |
3494 unwind_protect::protect_var (reading_script_file); | |
3495 unwind_protect::protect_var (reading_classdef_file); | |
3496 unwind_protect::protect_var (Vecho_executing_commands); | |
3497 | |
3498 | |
3499 get_input_from_eval_string = false; | |
3500 parser_end_of_input = false; | |
3501 | |
3502 if (! force_script && looking_at_function_keyword (ffile)) | |
3503 { | |
3504 file_type = "function"; | |
3505 | |
3506 Vecho_executing_commands = ECHO_OFF; | |
3507 | |
3508 reading_classdef_file = false; | |
3509 reading_fcn_file = true; | |
3510 reading_script_file = false; | |
3511 } | |
3512 else if (! force_script && looking_at_classdef_keyword (ffile)) | |
3513 { | |
3514 file_type = "classdef"; | |
3515 | |
3516 Vecho_executing_commands = ECHO_OFF; | |
3517 | |
3518 reading_classdef_file = true; | |
3519 reading_fcn_file = false; | |
3520 reading_script_file = false; | |
3521 } | |
3522 else | |
3523 { | |
3524 file_type = "script"; | |
3525 | |
3526 Vecho_executing_commands = ECHO_OFF; | |
3527 | |
3528 reading_classdef_file = false; | |
3529 reading_fcn_file = false; | |
3530 reading_script_file = true; | |
3531 } | |
3532 | |
3533 YY_BUFFER_STATE old_buf = current_buffer (); | |
3534 YY_BUFFER_STATE new_buf = create_buffer (ffile); | |
3535 | |
3536 unwind_protect::add_fcn (switch_to_buffer, old_buf); | |
3537 unwind_protect::add_fcn (delete_buffer, new_buf); | |
3538 | |
3539 switch_to_buffer (new_buf); | |
3540 | |
3541 unwind_protect::protect_var (primary_fcn_ptr); | |
3542 primary_fcn_ptr = 0; | |
3543 | |
3544 reset_parser (); | |
3545 | |
3546 // Do this with an unwind-protect cleanup function so that | |
3547 // the forced variables will be unmarked in the event of an | |
3548 // interrupt. | |
3549 symbol_table::scope_id scope = symbol_table::top_scope (); | |
3550 unwind_protect::add_fcn (symbol_table::unmark_forced_variables, scope); | |
3551 | |
3552 if (! help_txt.empty ()) | |
3553 help_buf.push (help_txt); | |
3554 | |
3555 if (reading_script_file) | |
3556 prep_lexer_for_script_file (); | |
3557 else | |
3558 prep_lexer_for_function_file (); | |
3559 | |
3560 lexer_flags.parsing_class_method = ! dispatch_type.empty (); | |
3561 | |
3562 int status = yyparse (); | |
3563 | |
3564 fcn_ptr = primary_fcn_ptr; | |
3565 | |
3566 if (reading_fcn_file && endfunction_found && max_function_depth > 1) | |
3567 warning_with_id ("Octave:nested-functions-coerced", | |
3568 "nested functions are coerced into subfunctions " | |
3569 "in file %s", ff.c_str ()); | |
3570 | |
3571 if (status != 0) | |
3572 error ("parse error while reading %s file %s", | |
3573 file_type.c_str(), ff.c_str ()); | |
3574 } | |
3575 } | |
3576 else if (require_file) | |
3577 error ("no such file, `%s'", ff.c_str ()); | |
3578 else if (! warn_for.empty ()) | |
3579 error ("%s: unable to open file `%s'", warn_for.c_str (), ff.c_str ()); | |
3580 | |
3581 unwind_protect::run_frame (uwp_frame); | |
3582 | |
3583 return fcn_ptr; | |
3584 } | |
3585 | |
3586 std::string | |
3587 get_help_from_file (const std::string& nm, bool& symbol_found, | |
3588 std::string& file) | |
3589 { | |
3590 std::string retval; | |
3591 | |
3592 file = fcn_file_in_path (nm); | |
3593 | |
3594 if (! file.empty ()) | |
3595 { | |
3596 symbol_found = true; | |
3597 | |
3598 FILE *fptr = fopen (file.c_str (), "r"); | |
3599 | |
3600 if (fptr) | |
3601 { | |
3602 unwind_protect::add (safe_fclose, fptr); | |
3603 | |
3604 bool eof; | |
3605 retval = gobble_leading_white_space (fptr, eof); | |
3606 | |
3607 if (retval.empty ()) | |
3608 { | |
3609 octave_function *fcn = parse_fcn_file (file, ""); | |
3610 | |
3611 if (fcn) | |
3612 { | |
3613 retval = fcn->doc_string (); | |
3614 | |
3615 delete fcn; | |
3616 } | |
3617 } | |
3618 | |
3619 unwind_protect::run (); | |
3620 } | |
3621 } | |
3622 | |
3623 return retval; | |
3624 } | |
3625 | |
3626 std::string | |
3627 get_help_from_file (const std::string& nm, bool& symbol_found) | |
3628 { | |
3629 std::string file; | |
3630 return get_help_from_file (nm, symbol_found, file); | |
3631 } | |
3632 | |
3633 std::string | |
3634 lookup_autoload (const std::string& nm) | |
3635 { | |
3636 std::string retval; | |
3637 | |
3638 typedef std::map<std::string, std::string>::const_iterator am_iter; | |
3639 | |
3640 am_iter p = autoload_map.find (nm); | |
3641 | |
3642 if (p != autoload_map.end ()) | |
3643 retval = load_path::find_file (p->second); | |
3644 | |
3645 return retval; | |
3646 } | |
3647 | |
3648 string_vector | |
3649 autoloaded_functions (void) | |
3650 { | |
3651 string_vector names (autoload_map.size()); | |
3652 | |
3653 octave_idx_type i = 0; | |
3654 typedef std::map<std::string, std::string>::const_iterator am_iter; | |
3655 for (am_iter p = autoload_map.begin (); p != autoload_map.end (); p++) | |
3656 names[i++] = p->first; | |
3657 | |
3658 return names; | |
3659 } | |
3660 | |
3661 string_vector | |
3662 reverse_lookup_autoload (const std::string& nm) | |
3663 { | |
3664 string_vector names; | |
3665 | |
3666 typedef std::map<std::string, std::string>::const_iterator am_iter; | |
3667 for (am_iter p = autoload_map.begin (); p != autoload_map.end (); p++) | |
3668 if (nm == p->second) | |
3669 names.append (p->first); | |
3670 | |
3671 return names; | |
3672 } | |
3673 | |
3674 octave_function * | |
3675 load_fcn_from_file (const std::string& file_name, const std::string& dir_name, | |
3676 const std::string& dispatch_type, | |
3677 const std::string& fcn_name, bool autoload) | |
3678 { | |
3679 octave_function *retval = 0; | |
3680 | |
3681 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
3682 | |
3683 std::string nm = file_name; | |
3684 | |
3685 size_t nm_len = nm.length (); | |
3686 | |
3687 std::string file; | |
3688 | |
3689 unwind_protect::protect_var (fcn_file_from_relative_lookup); | |
3690 | |
3691 fcn_file_from_relative_lookup = false; | |
3692 | |
3693 file = nm; | |
3694 | |
3695 if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct") | |
3696 || (nm_len > 4 && nm.substr (nm_len-4) == ".mex") | |
3697 || (nm_len > 2 && nm.substr (nm_len-2) == ".m")) | |
3698 { | |
3699 nm = octave_env::base_pathname (file); | |
3700 nm = nm.substr (0, nm.find_last_of ('.')); | |
3701 } | |
3702 | |
3703 if (autoload) | |
3704 { | |
3705 unwind_protect::protect_var (autoloading); | |
3706 autoloading = true; | |
3707 } | |
3708 | |
3709 fcn_file_from_relative_lookup = ! octave_env::absolute_pathname (file); | |
3710 | |
3711 file = octave_env::make_absolute (file, octave_env::getcwd ()); | |
3712 | |
3713 int len = file.length (); | |
3714 | |
3715 if (len > 4 && file.substr (len-4, len-1) == ".oct") | |
3716 { | |
3717 if (autoload && ! fcn_name.empty ()) | |
3718 nm = fcn_name; | |
3719 | |
3720 retval = octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup); | |
3721 } | |
3722 else if (len > 4 && file.substr (len-4, len-1) == ".mex") | |
3723 retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup); | |
3724 else if (len > 2) | |
3725 { | |
3726 // These are needed by yyparse. | |
3727 | |
3728 unwind_protect::protect_var (curr_fcn_file_name); | |
3729 unwind_protect::protect_var (curr_fcn_file_full_name); | |
3730 | |
3731 curr_fcn_file_name = nm; | |
3732 curr_fcn_file_full_name = file; | |
3733 | |
3734 retval = parse_fcn_file (file, dispatch_type, autoloading); | |
3735 } | |
3736 | |
3737 if (retval) | |
3738 { | |
3739 retval->stash_dir_name (dir_name); | |
3740 | |
3741 if (retval->is_user_function ()) | |
3742 { | |
3743 symbol_table::scope_id id = retval->scope (); | |
3744 | |
3745 symbol_table::stash_dir_name_for_subfunctions (id, dir_name); | |
3746 } | |
3747 } | |
3748 | |
3749 unwind_protect::run_frame (uwp_frame); | |
3750 | |
3751 return retval; | |
3752 } | |
3753 | |
3754 DEFUN (autoload, args, , | |
3755 "-*- texinfo -*-\n\ | |
3756 @deftypefn {Built-in Function} {} autoload (@var{function}, @var{file})\n\ | |
3757 Define @var{function} to autoload from @var{file}.\n\ | |
3758 \n\ | |
3759 The second argument, @var{file}, should be an absolute file name or\n\ | |
3760 a file name in the same directory as the function or script from which\n\ | |
3761 the autoload command was run. @var{file} should not depend on the\n\ | |
3762 Octave load path.\n\ | |
3763 \n\ | |
3764 Normally, calls to @code{autoload} appear in PKG_ADD script files that\n\ | |
3765 are evaluated when a directory is added to the Octave's load path. To\n\ | |
3766 avoid having to hardcode directory names in @var{file}, if @var{file}\n\ | |
3767 is in the same directory as the PKG_ADD script then\n\ | |
3768 \n\ | |
3769 @example\n\ | |
3770 autoload (\"foo\", \"bar.oct\");\n\ | |
3771 @end example\n\ | |
3772 \n\ | |
3773 will load the function @code{foo} from the file @code{bar.oct}. The above\n\ | |
3774 when @code{bar.oct} is not in the same directory or uses like\n\ | |
3775 \n\ | |
3776 @example\n\ | |
3777 autoload (\"foo\", file_in_loadpath (\"bar.oct\"))\n\ | |
3778 @end example\n\ | |
3779 \n\ | |
3780 @noindent\n\ | |
3781 are strongly discouraged, as their behavior might be unpredictable.\n\ | |
3782 \n\ | |
3783 With no arguments, return a structure containing the current autoload map.\n\ | |
3784 @seealso{PKG_ADD}\n\ | |
3785 @end deftypefn") | |
3786 { | |
3787 octave_value retval; | |
3788 | |
3789 int nargin = args.length (); | |
3790 | |
3791 if (nargin == 0) | |
3792 { | |
3793 Cell func_names (dim_vector (autoload_map.size ()), 1); | |
3794 Cell file_names (dim_vector (autoload_map.size ()), 1); | |
3795 | |
3796 octave_idx_type i = 0; | |
3797 typedef std::map<std::string, std::string>::const_iterator am_iter; | |
3798 for (am_iter p = autoload_map.begin (); p != autoload_map.end (); p++) | |
3799 { | |
3800 func_names(i) = p->first; | |
3801 file_names(i) = p->second; | |
3802 | |
3803 i++; | |
3804 } | |
3805 | |
3806 Octave_map m; | |
3807 | |
3808 m.assign ("function", func_names); | |
3809 m.assign ("file", file_names); | |
3810 | |
3811 retval = m; | |
3812 } | |
3813 else if (nargin == 2) | |
3814 { | |
3815 string_vector argv = args.make_argv ("autoload"); | |
3816 | |
3817 if (! error_state) | |
3818 { | |
3819 std::string nm = argv[2]; | |
3820 | |
3821 if (! octave_env::absolute_pathname (nm)) | |
3822 { | |
3823 octave_user_code *fcn = octave_call_stack::caller_user_code (); | |
3824 | |
3825 bool found = false; | |
3826 | |
3827 if (fcn) | |
3828 { | |
3829 std::string fname = fcn->fcn_file_name (); | |
3830 | |
3831 if (! fname.empty ()) | |
3832 { | |
3833 fname = octave_env::make_absolute (fname, octave_env::getcwd ()); | |
3834 fname = fname.substr (0, fname.find_last_of (file_ops::dir_sep_str ()) + 1); | |
3835 | |
3836 file_stat fs (fname + nm); | |
3837 | |
3838 if (fs.exists ()) | |
3839 { | |
3840 nm = fname + nm; | |
3841 found = true; | |
3842 } | |
3843 } | |
3844 } | |
3845 if (! found) | |
3846 warning_with_id ("Octave:autoload-relative-file-name", | |
3847 "autoload: `%s' is not an absolute file name", | |
3848 nm.c_str ()); | |
3849 } | |
3850 autoload_map[argv[1]] = nm; | |
3851 } | |
3852 } | |
3853 else | |
3854 print_usage (); | |
3855 | |
3856 return retval; | |
3857 } | |
3858 | |
3859 void | |
3860 source_file (const std::string& file_name, const std::string& context, | |
3861 bool verbose, bool require_file, const std::string& warn_for) | |
3862 { | |
3863 std::string file_full_name = file_ops::tilde_expand (file_name); | |
3864 | |
3865 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
3866 | |
3867 unwind_protect::protect_var (curr_fcn_file_name); | |
3868 unwind_protect::protect_var (curr_fcn_file_full_name); | |
3869 | |
3870 curr_fcn_file_name = file_name; | |
3871 curr_fcn_file_full_name = file_full_name; | |
3872 | |
3873 if (! context.empty ()) | |
3874 { | |
3875 if (context == "caller") | |
3876 octave_call_stack::goto_caller_frame (); | |
3877 else if (context == "base") | |
3878 octave_call_stack::goto_base_frame (); | |
3879 else | |
3880 error ("source: context must be \"caller\" or \"base\""); | |
3881 | |
3882 if (! error_state) | |
3883 unwind_protect::add_fcn (octave_call_stack::pop); | |
3884 } | |
3885 | |
3886 if (! error_state) | |
3887 { | |
3888 octave_function *fcn = parse_fcn_file (file_full_name, "", true, | |
3889 require_file, warn_for); | |
3890 | |
3891 if (! error_state) | |
3892 { | |
3893 if (fcn && fcn->is_user_script ()) | |
3894 { | |
3895 octave_value_list args; | |
3896 | |
3897 if (verbose) | |
3898 { | |
3899 std::cout << "executing commands from " << file_full_name << " ... "; | |
3900 reading_startup_message_printed = true; | |
3901 std::cout.flush (); | |
3902 } | |
3903 | |
3904 fcn->do_multi_index_op (0, args); | |
3905 | |
3906 if (verbose) | |
3907 std::cout << "done." << std::endl; | |
3908 | |
3909 delete fcn; | |
3910 } | |
3911 } | |
3912 else | |
3913 error ("source: error sourcing file `%s'", | |
3914 file_full_name.c_str ()); | |
3915 } | |
3916 | |
3917 unwind_protect::run_frame (uwp_frame); | |
3918 } | |
3919 | |
3920 DEFUN (mfilename, args, , | |
3921 "-*- texinfo -*-\n\ | |
3922 @deftypefn {Built-in Function} {} mfilename ()\n\ | |
3923 @deftypefnx {Built-in Function} {} mfilename (@code{\"fullpath\"})\n\ | |
3924 @deftypefnx {Built-in Function} {} mfilename (@code{\"fullpathext\"})\n\ | |
3925 Return the name of the currently executing file. At the top-level,\n\ | |
3926 return the empty string. Given the argument @code{\"fullpath\"},\n\ | |
3927 include the directory part of the file name, but not the extension.\n\ | |
3928 Given the argument @code{\"fullpathext\"}, include the directory part\n\ | |
3929 of the file name and the extension.\n\ | |
3930 @end deftypefn") | |
3931 { | |
3932 octave_value retval; | |
3933 | |
3934 int nargin = args.length (); | |
3935 | |
3936 if (nargin > 1) | |
3937 { | |
3938 print_usage (); | |
3939 return retval; | |
3940 } | |
3941 | |
3942 std::string arg; | |
3943 | |
3944 if (nargin == 1) | |
3945 { | |
3946 arg = args(0).string_value (); | |
3947 | |
3948 if (error_state) | |
3949 { | |
3950 error ("mfilename: expecting argument to be a character string"); | |
3951 return retval; | |
3952 } | |
3953 } | |
3954 | |
3955 std::string fname; | |
3956 | |
3957 octave_user_code *fcn = octave_call_stack::caller_user_code (); | |
3958 | |
3959 if (fcn) | |
3960 { | |
3961 fname = fcn->fcn_file_name (); | |
3962 | |
3963 if (fname.empty ()) | |
3964 fname = fcn->name (); | |
3965 } | |
3966 | |
3967 if (arg == "fullpathext") | |
3968 retval = fname; | |
3969 else | |
3970 { | |
3971 size_t dpos = fname.rfind (file_ops::dir_sep_char ()); | |
3972 size_t epos = fname.rfind ('.'); | |
3973 | |
3974 if (epos <= dpos) | |
3975 epos = std::string::npos; | |
3976 | |
3977 fname = (epos != std::string::npos) ? fname.substr (0, epos) : fname; | |
3978 | |
3979 if (arg == "fullpath") | |
3980 retval = fname; | |
3981 else | |
3982 retval = (dpos != std::string::npos) ? fname.substr (dpos+1) : fname; | |
3983 } | |
3984 | |
3985 return retval; | |
3986 } | |
3987 | |
3988 | |
3989 DEFUN (source, args, , | |
3990 "-*- texinfo -*-\n\ | |
3991 @deftypefn {Built-in Function} {} source (@var{file})\n\ | |
3992 Parse and execute the contents of @var{file}. This is equivalent to\n\ | |
3993 executing commands from a script file, but without requiring the file to\n\ | |
3994 be named @file{@var{file}.m}.\n\ | |
3995 @end deftypefn") | |
3996 { | |
3997 octave_value_list retval; | |
3998 | |
3999 int nargin = args.length (); | |
4000 | |
4001 if (nargin == 1 || nargin == 2) | |
4002 { | |
4003 std::string file_name = args(0).string_value (); | |
4004 | |
4005 if (! error_state) | |
4006 { | |
4007 std::string context; | |
4008 | |
4009 if (nargin == 2) | |
4010 context = args(1).string_value (); | |
4011 | |
4012 if (! error_state) | |
4013 source_file (file_name, context); | |
4014 else | |
4015 error ("source: expecting context to be character string"); | |
4016 } | |
4017 else | |
4018 error ("source: expecting file name as argument"); | |
4019 } | |
4020 else | |
4021 print_usage (); | |
4022 | |
4023 return retval; | |
4024 } | |
4025 | |
4026 // Evaluate an Octave function (built-in or interpreted) and return | |
4027 // the list of result values. NAME is the name of the function to | |
4028 // call. ARGS are the arguments to the function. NARGOUT is the | |
4029 // number of output arguments expected. | |
4030 | |
4031 octave_value_list | |
4032 feval (const std::string& name, const octave_value_list& args, int nargout) | |
4033 { | |
4034 octave_value_list retval; | |
4035 | |
4036 octave_value fcn = symbol_table::find_function (name, args); | |
4037 | |
4038 if (fcn.is_defined ()) | |
4039 retval = fcn.do_multi_index_op (nargout, args); | |
4040 else | |
4041 error ("feval: function `%s' not found", name.c_str ()); | |
4042 | |
4043 return retval; | |
4044 } | |
4045 | |
4046 octave_value_list | |
4047 feval (octave_function *fcn, const octave_value_list& args, int nargout) | |
4048 { | |
4049 octave_value_list retval; | |
4050 | |
4051 if (fcn) | |
4052 retval = fcn->do_multi_index_op (nargout, args); | |
4053 | |
4054 return retval; | |
4055 } | |
4056 | |
4057 static octave_value_list | |
4058 get_feval_args (const octave_value_list& args) | |
4059 { | |
4060 int tmp_nargin = args.length () - 1; | |
4061 | |
4062 octave_value_list retval (tmp_nargin, octave_value ()); | |
4063 | |
4064 for (int i = 0; i < tmp_nargin; i++) | |
4065 retval(i) = args(i+1); | |
4066 | |
4067 string_vector arg_names = args.name_tags (); | |
4068 | |
4069 if (! arg_names.empty ()) | |
4070 { | |
4071 // tmp_nargin and arg_names.length () - 1 may differ if | |
4072 // we are passed all_va_args. | |
4073 | |
4074 int n = arg_names.length () - 1; | |
4075 | |
4076 int len = n > tmp_nargin ? tmp_nargin : n; | |
4077 | |
4078 string_vector tmp_arg_names (len); | |
4079 | |
4080 for (int i = 0; i < len; i++) | |
4081 tmp_arg_names(i) = arg_names(i+1); | |
4082 | |
4083 retval.stash_name_tags (tmp_arg_names); | |
4084 } | |
4085 | |
4086 return retval; | |
4087 } | |
4088 | |
4089 | |
4090 // Evaluate an Octave function (built-in or interpreted) and return | |
4091 // the list of result values. The first element of ARGS should be a | |
4092 // string containing the name of the function to call, then the rest | |
4093 // are the actual arguments to the function. NARGOUT is the number of | |
4094 // output arguments expected. | |
4095 | |
4096 octave_value_list | |
4097 feval (const octave_value_list& args, int nargout) | |
4098 { | |
4099 octave_value_list retval; | |
4100 | |
4101 int nargin = args.length (); | |
4102 | |
4103 if (nargin > 0) | |
4104 { | |
4105 octave_value f_arg = args(0); | |
4106 | |
4107 if (f_arg.is_string ()) | |
4108 { | |
4109 std::string name = f_arg.string_value (); | |
4110 | |
4111 if (! error_state) | |
4112 { | |
4113 octave_value_list tmp_args = get_feval_args (args); | |
4114 | |
4115 retval = feval (name, tmp_args, nargout); | |
4116 } | |
4117 } | |
4118 else | |
4119 { | |
4120 octave_function *fcn = f_arg.function_value (); | |
4121 | |
4122 if (fcn) | |
4123 { | |
4124 octave_value_list tmp_args = get_feval_args (args); | |
4125 | |
4126 retval = feval (fcn, tmp_args, nargout); | |
4127 } | |
4128 } | |
4129 } | |
4130 | |
4131 return retval; | |
4132 } | |
4133 | |
4134 DEFUN (feval, args, nargout, | |
4135 "-*- texinfo -*-\n\ | |
4136 @deftypefn {Built-in Function} {} feval (@var{name}, @dots{})\n\ | |
4137 Evaluate the function named @var{name}. Any arguments after the first\n\ | |
4138 are passed on to the named function. For example,\n\ | |
4139 \n\ | |
4140 @example\n\ | |
4141 feval (\"acos\", -1)\n\ | |
4142 @result{} 3.1416\n\ | |
4143 @end example\n\ | |
4144 \n\ | |
4145 @noindent\n\ | |
4146 calls the function @code{acos} with the argument @samp{-1}.\n\ | |
4147 \n\ | |
4148 The function @code{feval} is necessary in order to be able to write\n\ | |
4149 functions that call user-supplied functions, because Octave does not\n\ | |
4150 have a way to declare a pointer to a function (like C) or to declare a\n\ | |
4151 special kind of variable that can be used to hold the name of a function\n\ | |
4152 (like @code{EXTERNAL} in Fortran). Instead, you must refer to functions\n\ | |
4153 by name, and use @code{feval} to call them.\n\ | |
4154 @end deftypefn") | |
4155 { | |
4156 octave_value_list retval; | |
4157 | |
4158 int nargin = args.length (); | |
4159 | |
4160 if (nargin > 0) | |
4161 retval = feval (args, nargout); | |
4162 else | |
4163 print_usage (); | |
4164 | |
4165 return retval; | |
4166 } | |
4167 | |
4168 octave_value_list | |
4169 eval_string (const std::string& s, bool silent, int& parse_status, int nargout) | |
4170 { | |
4171 octave_value_list retval; | |
4172 | |
4173 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
4174 | |
4175 unwind_protect::protect_var (input_line_number); | |
4176 unwind_protect::protect_var (current_input_column); | |
4177 unwind_protect::protect_var (get_input_from_eval_string); | |
4178 unwind_protect::protect_var (input_from_eval_string_pending); | |
4179 unwind_protect::protect_var (parser_end_of_input); | |
4180 unwind_protect::protect_var (line_editing); | |
4181 unwind_protect::protect_var (current_eval_string); | |
4182 unwind_protect::protect_var (current_function_depth); | |
4183 unwind_protect::protect_var (max_function_depth); | |
4184 unwind_protect::protect_var (parsing_subfunctions); | |
4185 unwind_protect::protect_var (endfunction_found); | |
4186 | |
4187 input_line_number = 1; | |
4188 current_input_column = 1; | |
4189 get_input_from_eval_string = true; | |
4190 input_from_eval_string_pending = true; | |
4191 parser_end_of_input = false; | |
4192 line_editing = false; | |
4193 current_function_depth = 0; | |
4194 max_function_depth = 0; | |
4195 parsing_subfunctions = false; | |
4196 endfunction_found = false; | |
4197 | |
4198 current_eval_string = s; | |
4199 | |
4200 YY_BUFFER_STATE old_buf = current_buffer (); | |
4201 YY_BUFFER_STATE new_buf = create_buffer (0); | |
4202 | |
4203 unwind_protect::add_fcn (switch_to_buffer, old_buf); | |
4204 unwind_protect::add_fcn (delete_buffer, new_buf); | |
4205 | |
4206 switch_to_buffer (new_buf); | |
4207 | |
4208 do | |
4209 { | |
4210 reset_parser (); | |
4211 | |
4212 unwind_protect::protect_var (global_command); | |
4213 | |
4214 // Do this with an unwind-protect cleanup function so that the | |
4215 // forced variables will be unmarked in the event of an | |
4216 // interrupt. | |
4217 symbol_table::scope_id scope = symbol_table::top_scope (); | |
4218 unwind_protect::add_fcn (symbol_table::unmark_forced_variables, scope); | |
4219 | |
4220 parse_status = yyparse (); | |
4221 | |
4222 tree_statement_list *command_list = global_command; | |
4223 | |
4224 // Unmark forced variables. | |
4225 unwind_protect::run (); | |
4226 | |
4227 // Restore previous value of global_command. | |
4228 unwind_protect::run (); | |
4229 | |
4230 if (parse_status == 0) | |
4231 { | |
4232 if (command_list) | |
4233 { | |
4234 tree_statement *stmt = 0; | |
4235 | |
4236 if (command_list->length () == 1 | |
4237 && (stmt = command_list->front ()) | |
4238 && stmt->is_expression ()) | |
4239 { | |
4240 tree_expression *expr = stmt->expression (); | |
4241 | |
4242 if (silent) | |
4243 expr->set_print_flag (false); | |
4244 | |
4245 bool do_bind_ans = false; | |
4246 | |
4247 if (expr->is_identifier ()) | |
4248 { | |
4249 tree_identifier *id | |
4250 = dynamic_cast<tree_identifier *> (expr); | |
4251 | |
4252 do_bind_ans = (! id->is_variable ()); | |
4253 } | |
4254 else | |
4255 do_bind_ans = (! expr->is_assignment_expression ()); | |
4256 | |
4257 retval = expr->rvalue (nargout); | |
4258 | |
4259 if (do_bind_ans && ! (error_state || retval.empty ())) | |
4260 bind_ans (retval(0), expr->print_result ()); | |
4261 | |
4262 if (nargout == 0) | |
4263 retval = octave_value_list (); | |
4264 } | |
4265 else if (nargout == 0) | |
4266 command_list->accept (*current_evaluator); | |
4267 else | |
4268 error ("eval: invalid use of statement list"); | |
4269 | |
4270 delete command_list; | |
4271 | |
4272 command_list = 0; | |
4273 | |
4274 if (error_state | |
4275 || tree_return_command::returning | |
4276 || tree_break_command::breaking | |
4277 || tree_continue_command::continuing) | |
4278 break; | |
4279 } | |
4280 else if (parser_end_of_input) | |
4281 break; | |
4282 } | |
4283 } | |
4284 while (parse_status == 0); | |
4285 | |
4286 unwind_protect::run_frame (uwp_frame); | |
4287 | |
4288 return retval; | |
4289 } | |
4290 | |
4291 octave_value | |
4292 eval_string (const std::string& s, bool silent, int& parse_status) | |
4293 { | |
4294 octave_value retval; | |
4295 | |
4296 octave_value_list tmp = eval_string (s, silent, parse_status, 1); | |
4297 | |
4298 if (! tmp.empty ()) | |
4299 retval = tmp(0); | |
4300 | |
4301 return retval; | |
4302 } | |
4303 | |
4304 static octave_value_list | |
4305 eval_string (const octave_value& arg, bool silent, int& parse_status, | |
4306 int nargout) | |
4307 { | |
4308 std::string s = arg.string_value (); | |
4309 | |
4310 if (error_state) | |
4311 { | |
4312 error ("eval: expecting std::string argument"); | |
4313 return octave_value (-1); | |
4314 } | |
4315 | |
4316 return eval_string (s, silent, parse_status, nargout); | |
4317 } | |
4318 | |
4319 DEFUN (eval, args, nargout, | |
4320 "-*- texinfo -*-\n\ | |
4321 @deftypefn {Built-in Function} {} eval (@var{try}, @var{catch})\n\ | |
4322 Parse the string @var{try} and evaluate it as if it were an Octave\n\ | |
4323 program. If that fails, evaluate the optional string @var{catch}.\n\ | |
4324 The string @var{try} is evaluated in the current context,\n\ | |
4325 so any results remain available after @code{eval} returns.\n\ | |
4326 \n\ | |
4327 The following example makes the variable @var{a} with the approximate\n\ | |
4328 value 3.1416 available.\n\ | |
4329 \n\ | |
4330 @example\n\ | |
4331 eval(\"a = acos(-1);\");\n\ | |
4332 @end example\n\ | |
4333 \n\ | |
4334 If an error occurs during the evaluation of @var{try} the @var{catch}\n\ | |
4335 string is evaluated, as the following example shows:\n\ | |
4336 \n\ | |
4337 @example\n\ | |
4338 eval ('error (\"This is a bad example\");',\n\ | |
4339 'printf (\"This error occurred:\\n%s\\n\", lasterr ());');\n\ | |
4340 @print{} This error occurred:\n\ | |
4341 This is a bad example\n\ | |
4342 @end example\n\ | |
4343 @end deftypefn") | |
4344 { | |
4345 octave_value_list retval; | |
4346 | |
4347 int nargin = args.length (); | |
4348 | |
4349 if (nargin > 0) | |
4350 { | |
4351 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
4352 | |
4353 if (nargin > 1) | |
4354 { | |
4355 unwind_protect::protect_var (buffer_error_messages); | |
4356 buffer_error_messages++; | |
4357 } | |
4358 | |
4359 int parse_status = 0; | |
4360 | |
4361 octave_value_list tmp = eval_string (args(0), nargout > 0, | |
4362 parse_status, nargout); | |
4363 | |
4364 if (nargin > 1 && (parse_status != 0 || error_state)) | |
4365 { | |
4366 error_state = 0; | |
4367 | |
4368 // Set up for letting the user print any messages from | |
4369 // errors that occurred in the first part of this eval(). | |
4370 | |
4371 buffer_error_messages--; | |
4372 | |
4373 tmp = eval_string (args(1), nargout > 0, parse_status, nargout); | |
4374 | |
4375 if (nargout > 0) | |
4376 retval = tmp; | |
4377 } | |
4378 else if (nargout > 0) | |
4379 retval = tmp; | |
4380 | |
4381 unwind_protect::run_frame (uwp_frame); | |
4382 } | |
4383 else | |
4384 print_usage (); | |
4385 | |
4386 return retval; | |
4387 } | |
4388 | |
4389 /* | |
4390 | |
4391 %% test/octave.test/eval/eval-1.m | |
4392 %!#test | |
4393 %! x = 1; | |
4394 %! assert(eval ("x"),1); | |
4395 | |
4396 %% test/octave.test/eval/eval-2.m | |
4397 %!test | |
4398 %! x = 1; | |
4399 %! assert(eval ("x;")); | |
4400 | |
4401 %% test/octave.test/eval/eval-3.m | |
4402 %!test | |
4403 %! x = 1; | |
4404 %! assert(eval ("x;"),1); | |
4405 | |
4406 %% FIXME | |
4407 %% Disable this test as adding the ";" is redundant with eval-1 and | |
4408 %% in any case is a syntax error with assert | |
4409 %% test/octave.test/eval/eval-4.m | |
4410 %!#test | |
4411 %! x = 1; | |
4412 %! assert(eval ("x");,1); | |
4413 | |
4414 %% test/octave.test/eval/eval-5.m | |
4415 %!test | |
4416 %! eval ("flipud = 2;"); | |
4417 %! assert(flipud,2); | |
4418 | |
4419 %% test/octave.test/eval/eval-6.m | |
4420 %!function y = f () | |
4421 %! eval ("flipud = 2;"); | |
4422 %! y = flipud; | |
4423 %!test | |
4424 %! assert(f,2); | |
4425 | |
4426 %% test/octave.test/eval/eval-7.m | |
4427 %!#test | |
4428 %! eval ("x = 1"); | |
4429 %! assert(x,1); | |
4430 | |
4431 %% test/octave.test/eval/eval-8.m | |
4432 %!test | |
4433 %! eval ("x = 1;") | |
4434 %! assert(x,1); | |
4435 | |
4436 %% test/octave.test/eval/eval-9.m | |
4437 %!test | |
4438 %! eval ("x = 1;"); | |
4439 %! assert(x,1); | |
4440 | |
4441 %% test/octave.test/eval/eval-10.m | |
4442 %!#test | |
4443 %! eval ("x = 1") | |
4444 %! assert(x,1); | |
4445 | |
4446 %% test/octave.test/eval/eval-11.m | |
4447 %!test | |
4448 %! x = 1; | |
4449 %! y = eval ("x"); | |
4450 %! assert(y,1); | |
4451 | |
4452 %% test/octave.test/eval/eval-12.m | |
4453 %!test | |
4454 %! x = 1; | |
4455 %! y = eval ("x;"); | |
4456 %! assert(y,1); | |
4457 | |
4458 %% test/octave.test/eval/eval-13.m | |
4459 %!test | |
4460 %! x = 1; | |
4461 %! y = eval ("x;"); | |
4462 %! assert(y,1); | |
4463 | |
4464 %% test/octave.test/eval/eval-14.m | |
4465 %!test | |
4466 %! x = 1; | |
4467 %! y = eval ("x"); | |
4468 %! assert(y,1); | |
4469 | |
4470 */ | |
4471 | |
4472 DEFUN (assignin, args, , | |
4473 "-*- texinfo -*-\n\ | |
4474 @deftypefn {Built-in Function} {} assignin (@var{context}, @var{varname}, @var{value})\n\ | |
4475 Assign @var{value} to @var{varname} in context @var{context}, which\n\ | |
4476 may be either @code{\"base\"} or @code{\"caller\"}.\n\ | |
4477 @end deftypefn") | |
4478 { | |
4479 octave_value_list retval; | |
4480 | |
4481 int nargin = args.length (); | |
4482 | |
4483 if (nargin == 3) | |
4484 { | |
4485 std::string context = args(0).string_value (); | |
4486 | |
4487 if (! error_state) | |
4488 { | |
4489 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
4490 | |
4491 if (context == "caller") | |
4492 octave_call_stack::goto_caller_frame (); | |
4493 else if (context == "base") | |
4494 octave_call_stack::goto_base_frame (); | |
4495 else | |
4496 error ("assignin: context must be \"caller\" or \"base\""); | |
4497 | |
4498 if (! error_state) | |
4499 { | |
4500 unwind_protect::add_fcn (octave_call_stack::pop); | |
4501 | |
4502 std::string nm = args(1).string_value (); | |
4503 | |
4504 if (! error_state) | |
4505 { | |
4506 if (valid_identifier (nm)) | |
4507 symbol_table::varref (nm) = args(2); | |
4508 else | |
4509 error ("assignin: invalid variable name"); | |
4510 } | |
4511 else | |
4512 error ("assignin: expecting variable name as second argument"); | |
4513 } | |
4514 | |
4515 unwind_protect::run_frame (uwp_frame); | |
4516 } | |
4517 else | |
4518 error ("assignin: expecting string as first argument"); | |
4519 } | |
4520 else | |
4521 print_usage (); | |
4522 | |
4523 return retval; | |
4524 } | |
4525 | |
4526 DEFUN (evalin, args, nargout, | |
4527 "-*- texinfo -*-\n\ | |
4528 @deftypefn {Built-in Function} {} evalin (@var{context}, @var{try}, @var{catch})\n\ | |
4529 Like @code{eval}, except that the expressions are evaluated in the\n\ | |
4530 context @var{context}, which may be either @code{\"caller\"} or\n\ | |
4531 @code{\"base\"}.\n\ | |
4532 @end deftypefn") | |
4533 { | |
4534 octave_value_list retval; | |
4535 | |
4536 int nargin = args.length (); | |
4537 | |
4538 if (nargin > 1) | |
4539 { | |
4540 std::string context = args(0).string_value (); | |
4541 | |
4542 if (! error_state) | |
4543 { | |
4544 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); | |
4545 | |
4546 if (context == "caller") | |
4547 octave_call_stack::goto_caller_frame (); | |
4548 else if (context == "base") | |
4549 octave_call_stack::goto_base_frame (); | |
4550 else | |
4551 error ("evalin: context must be \"caller\" or \"base\""); | |
4552 | |
4553 if (! error_state) | |
4554 { | |
4555 unwind_protect::add_fcn (octave_call_stack::pop); | |
4556 | |
4557 if (nargin > 2) | |
4558 { | |
4559 unwind_protect::protect_var (buffer_error_messages); | |
4560 buffer_error_messages++; | |
4561 } | |
4562 | |
4563 int parse_status = 0; | |
4564 | |
4565 octave_value_list tmp = eval_string (args(1), nargout > 0, | |
4566 parse_status, nargout); | |
4567 | |
4568 if (nargout > 0) | |
4569 retval = tmp; | |
4570 | |
4571 if (nargin > 2 && (parse_status != 0 || error_state)) | |
4572 { | |
4573 error_state = 0; | |
4574 | |
4575 // Set up for letting the user print any messages from | |
4576 // errors that occurred in the first part of this eval(). | |
4577 | |
4578 buffer_error_messages--; | |
4579 | |
4580 tmp = eval_string (args(2), nargout > 0, | |
4581 parse_status, nargout); | |
4582 | |
4583 retval = (nargout > 0) ? tmp : octave_value_list (); | |
4584 } | |
4585 } | |
4586 | |
4587 unwind_protect::run_frame (uwp_frame); | |
4588 } | |
4589 else | |
4590 error ("evalin: expecting string as first argument"); | |
4591 } | |
4592 else | |
4593 print_usage (); | |
4594 | |
4595 return retval; | |
4596 } | |
4597 | |
4598 DEFUN (__parser_debug_flag__, args, nargout, | |
4599 "-*- texinfo -*-\n\ | |
4600 @deftypefn {Built-in Function} {@var{old_val} =} __parser_debug_flag__ (@var{new_val}))\n\ | |
4601 Undocumented internal function.\n\ | |
4602 @end deftypefn") | |
4603 { | |
4604 octave_value retval; | |
4605 | |
4606 bool debug_flag = octave_debug; | |
4607 | |
4608 retval = set_internal_variable (debug_flag, args, nargout, | |
4609 "__parser_debug_flag__"); | |
4610 | |
4611 octave_debug = debug_flag; | |
4612 | |
4613 return retval; | |
4614 } | |
4615 | |
4616 /* | |
4617 ;;; Local Variables: *** | |
4618 ;;; mode: text *** | |
4619 ;;; End: *** | |
4620 */ |