comparison libinterp/parse-tree/lex.ll @ 16155:0259254a3ccc classdef

maint: periodic merge of default to classdef * lex.h, lex.ll, parse.h, oct-parse.yy: Resolve conflicts by adapting classdef changes to new octave_parser and lexical_feedback classes.
author John W. Eaton <jwe@octave.org>
date Thu, 28 Feb 2013 02:04:24 -0500
parents 6ea536cb7360 aa5e1e8dce66
children a8f9eb92fa6e
comparison
equal deleted inserted replaced
16050:fc3cb570ac46 16155:0259254a3ccc
18 along with Octave; see the file COPYING. If not, see 18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>. 19 <http://www.gnu.org/licenses/>.
20 20
21 */ 21 */
22 22
23 /*
24 We are using the pure parser interface and the reentrant lexer
25 interface but the Octave parser and lexer are NOT properly
26 reentrant because both still use many global variables. It should be
27 safe to create a parser object and call it while anotehr parser
28 object is active (to parse a callback function while the main
29 interactive parser is waiting for input, for example) if you take
30 care to properly save and restore (typically with an unwind_protect
31 object) relevant global values before and after the nested call.
32 */
33
23 %option prefix = "octave_" 34 %option prefix = "octave_"
35 %option noyywrap
36 %option reentrant
37 %option bison-bridge
24 38
25 %top { 39 %top {
26 #ifdef HAVE_CONFIG_H 40 #ifdef HAVE_CONFIG_H
27 #include <config.h> 41 #include <config.h>
28 #endif 42 #endif
52 66
53 #include "cmd-edit.h" 67 #include "cmd-edit.h"
54 #include "quit.h" 68 #include "quit.h"
55 #include "lo-mappers.h" 69 #include "lo-mappers.h"
56 70
57 // These would be alphabetical, but y.tab.h must be included before 71 // These would be alphabetical, but oct-parse.h must be included before
58 // oct-gperf.h and y.tab.h must be included after token.h and the tree 72 // oct-gperf.h and oct-parse.h must be included after token.h and the tree
59 // class declarations. We can't include y.tab.h in oct-gperf.h 73 // class declarations. We can't include oct-parse.h in oct-gperf.h
60 // because it may not be protected to allow it to be included multiple 74 // because it may not be protected to allow it to be included multiple
61 // times. 75 // times.
62 76
63 #include "Cell.h" 77 #include "Cell.h"
64 #include "comment-list.h" 78 #include "comment-list.h"
94 && defined (YY_FLEX_MAJOR_VERSION) && YY_FLEX_MAJOR_VERSION >= 2 \ 108 && defined (YY_FLEX_MAJOR_VERSION) && YY_FLEX_MAJOR_VERSION >= 2 \
95 && defined (YY_FLEX_MINOR_VERSION) && YY_FLEX_MINOR_VERSION >= 5) 109 && defined (YY_FLEX_MINOR_VERSION) && YY_FLEX_MINOR_VERSION >= 5)
96 #error lex.l requires flex version 2.5.4 or later 110 #error lex.l requires flex version 2.5.4 or later
97 #endif 111 #endif
98 112
99 #define yylval octave_lval 113 #define YY_EXTRA_TYPE lexical_feedback *
114 #define curr_lexer yyextra
100 115
101 // Arrange to get input via readline. 116 // Arrange to get input via readline.
102 117
103 #ifdef YY_INPUT 118 #ifdef YY_INPUT
104 #undef YY_INPUT 119 #undef YY_INPUT
105 #endif 120 #endif
106 #define YY_INPUT(buf, result, max_size) \ 121 #define YY_INPUT(buf, result, max_size) \
107 if ((result = octave_read (buf, max_size)) < 0) \ 122 result = curr_lexer->octave_read (buf, max_size)
108 YY_FATAL_ERROR ("octave_read () in flex scanner failed");
109 123
110 // Try to avoid crashing out completely on fatal scanner errors. 124 // Try to avoid crashing out completely on fatal scanner errors.
111 // The call to yy_fatal_error should never happen, but it avoids a
112 // 'static function defined but not used' warning from gcc.
113 125
114 #ifdef YY_FATAL_ERROR 126 #ifdef YY_FATAL_ERROR
115 #undef YY_FATAL_ERROR 127 #undef YY_FATAL_ERROR
116 #endif 128 #endif
117 #define YY_FATAL_ERROR(msg) \ 129 #define YY_FATAL_ERROR(msg) \
118 do \ 130 (yyget_extra (yyscanner))->fatal_error (msg)
119 { \
120 error (msg); \
121 OCTAVE_QUIT; \
122 yy_fatal_error (msg); \
123 } \
124 while (0)
125 131
126 #define DISPLAY_TOK_AND_RETURN(tok) \ 132 #define DISPLAY_TOK_AND_RETURN(tok) \
127 do \ 133 do \
128 { \ 134 { \
129 int tok_val = tok; \ 135 int tok_val = tok; \
130 if (Vdisplay_tokens) \ 136 if (Vdisplay_tokens) \
131 display_token (tok_val); \ 137 curr_lexer->display_token (tok_val); \
132 if (lexer_debug_flag) \ 138 if (lexer_debug_flag) \
133 { \ 139 { \
134 std::cerr << "R: "; \ 140 std::cerr << "R: "; \
135 display_token (tok_val); \ 141 curr_lexer->display_token (tok_val); \
136 std::cerr << std::endl; \ 142 std::cerr << std::endl; \
137 } \ 143 } \
138 return tok_val; \ 144 return tok_val; \
139 } \ 145 } \
140 while (0) 146 while (0)
148 while (0) 154 while (0)
149 155
150 #define TOK_RETURN(tok) \ 156 #define TOK_RETURN(tok) \
151 do \ 157 do \
152 { \ 158 { \
153 current_input_column += yyleng; \ 159 curr_lexer->current_input_column += yyleng; \
154 lexer_flags.quote_is_transpose = false; \ 160 curr_lexer->quote_is_transpose = false; \
155 lexer_flags.convert_spaces_to_comma = true; \ 161 curr_lexer->convert_spaces_to_comma = true; \
156 COUNT_TOK_AND_RETURN (tok); \ 162 COUNT_TOK_AND_RETURN (tok); \
157 } \ 163 } \
158 while (0) 164 while (0)
159 165
160 #define TOK_PUSH_AND_RETURN(name, tok) \ 166 #define TOK_PUSH_AND_RETURN(name, tok) \
161 do \ 167 do \
162 { \ 168 { \
163 yylval.tok_val = new token (name, input_line_number, \ 169 curr_lexer->push_token \
164 current_input_column); \ 170 (new token (name, curr_lexer->input_line_number, \
165 token_stack.push (yylval.tok_val); \ 171 curr_lexer->current_input_column)); \
166 TOK_RETURN (tok); \ 172 TOK_RETURN (tok); \
167 } \ 173 } \
168 while (0) 174 while (0)
169 175
170 #define BIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ 176 #define BIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \
171 do \ 177 do \
172 { \ 178 { \
173 yylval.tok_val = new token (input_line_number, current_input_column); \ 179 curr_lexer->push_token \
174 token_stack.push (yylval.tok_val); \ 180 (new token (curr_lexer->input_line_number, \
175 current_input_column += yyleng; \ 181 curr_lexer->current_input_column)); \
176 lexer_flags.quote_is_transpose = qit; \ 182 curr_lexer->current_input_column += yyleng; \
177 lexer_flags.convert_spaces_to_comma = convert; \ 183 curr_lexer->quote_is_transpose = qit; \
178 lexer_flags.looking_for_object_index = false; \ 184 curr_lexer->convert_spaces_to_comma = convert; \
179 lexer_flags.at_beginning_of_statement = bos; \ 185 curr_lexer->looking_for_object_index = false; \
186 curr_lexer->at_beginning_of_statement = bos; \
180 COUNT_TOK_AND_RETURN (tok); \ 187 COUNT_TOK_AND_RETURN (tok); \
181 } \ 188 } \
182 while (0) 189 while (0)
183 190
184 #define XBIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ 191 #define XBIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \
185 do \ 192 do \
186 { \ 193 { \
187 gripe_matlab_incompatible_operator (yytext); \ 194 curr_lexer->gripe_matlab_incompatible_operator (yytext); \
188 BIN_OP_RETURN_INTERNAL (tok, convert, bos, qit); \ 195 BIN_OP_RETURN_INTERNAL (tok, convert, bos, qit); \
189 } \ 196 } \
190 while (0) 197 while (0)
191 198
192 #define BIN_OP_RETURN(tok, convert, bos) \ 199 #define BIN_OP_RETURN(tok, convert, bos) \
197 while (0) 204 while (0)
198 205
199 #define XBIN_OP_RETURN(tok, convert, bos) \ 206 #define XBIN_OP_RETURN(tok, convert, bos) \
200 do \ 207 do \
201 { \ 208 { \
202 gripe_matlab_incompatible_operator (yytext); \ 209 curr_lexer->gripe_matlab_incompatible_operator (yytext); \
203 BIN_OP_RETURN (tok, convert, bos); \ 210 BIN_OP_RETURN (tok, convert, bos); \
204 } \ 211 } \
205 while (0) 212 while (0)
206 213
207 #define LEXER_DEBUG(pattern) \ 214 #define LEXER_DEBUG(pattern) \
208 do \ 215 do \
209 { \ 216 { \
210 if (lexer_debug_flag) \ 217 if (lexer_debug_flag) \
211 lexer_debug (pattern, yytext); \ 218 curr_lexer->lexer_debug (pattern, yytext); \
212 } \ 219 } \
213 while (0) 220 while (0)
214 221
215 // TRUE means that we have encountered EOF on the input stream.
216 bool parser_end_of_input = false;
217
218 // Flags that need to be shared between the lexer and parser.
219 lexical_feedback lexer_flags;
220
221 // Stack to hold tokens so that we can delete them when the parser is
222 // reset and avoid growing forever just because we are stashing some
223 // information. This has to appear before lex.h is included, because
224 // one of the macros defined there uses token_stack.
225 //
226 // FIXME -- this should really be static, but that causes
227 // problems on some systems.
228 std::stack <token*> token_stack;
229
230 // Did eat_whitespace() eat a space or tab, or a newline, or both?
231
232 typedef int yum_yum;
233
234 const yum_yum ATE_NOTHING = 0;
235 const yum_yum ATE_SPACE_OR_TAB = 1;
236 const yum_yum ATE_NEWLINE = 2;
237
238 // Is the closest nesting level a square bracket, squiggly brace or a paren?
239
240 class bracket_brace_paren_nesting_level
241 {
242 public:
243
244 bracket_brace_paren_nesting_level (void) : context () { }
245
246 ~bracket_brace_paren_nesting_level (void) { }
247
248 void bracket (void) { context.push (BRACKET); }
249 bool is_bracket (void)
250 { return ! context.empty () && context.top () == BRACKET; }
251
252 void brace (void) { context.push (BRACE); }
253 bool is_brace (void)
254 { return ! context.empty () && context.top () == BRACE; }
255
256 void paren (void) { context.push (PAREN); }
257 bool is_paren (void)
258 { return ! context.empty () && context.top () == PAREN; }
259
260 bool is_bracket_or_brace (void)
261 { return (! context.empty ()
262 && (context.top () == BRACKET || context.top () == BRACE)); }
263
264 bool none (void) { return context.empty (); }
265
266 void remove (void) { if (! context.empty ()) context.pop (); }
267
268 void clear (void) { while (! context.empty ()) context.pop (); }
269
270 private:
271
272 std::stack<int> context;
273
274 static const int BRACKET;
275 static const int BRACE;
276 static const int PAREN;
277
278 bracket_brace_paren_nesting_level (const bracket_brace_paren_nesting_level&);
279
280 bracket_brace_paren_nesting_level&
281 operator = (const bracket_brace_paren_nesting_level&);
282 };
283
284 const int bracket_brace_paren_nesting_level::BRACKET = 1;
285 const int bracket_brace_paren_nesting_level::BRACE = 2;
286 const int bracket_brace_paren_nesting_level::PAREN = 3;
287
288 static bracket_brace_paren_nesting_level nesting_level;
289
290 static bool Vdisplay_tokens = false; 222 static bool Vdisplay_tokens = false;
291 223
292 static unsigned int Vtoken_count = 0; 224 static unsigned int Vtoken_count = 0;
293
294 // The start state that was in effect when the beginning of a block
295 // comment was noticed.
296 static int block_comment_nesting_level = 0;
297 225
298 // Internal variable for lexer debugging state. 226 // Internal variable for lexer debugging state.
299 static bool lexer_debug_flag = false; 227 static bool lexer_debug_flag = false;
300 228
301 // Forward declarations for functions defined at the bottom of this 229 // Forward declarations for functions defined at the bottom of this
302 // file. 230 // file that are needed inside the lexer actions.
303 231
304 static int text_yyinput (void);
305 static void xunput (char c, char *buf);
306 static void fixup_column_count (char *s);
307 static void do_comma_insert_check (void);
308 static int is_keyword_token (const std::string& s);
309 static int process_comment (bool start_in_block, bool& eof);
310 static bool match_any (char c, const char *s);
311 static bool next_token_is_sep_op (void);
312 static bool next_token_is_bin_op (bool spc_prev);
313 static bool next_token_is_postfix_unary_op (bool spc_prev);
314 static std::string strip_trailing_whitespace (char *s); 232 static std::string strip_trailing_whitespace (char *s);
315 static void handle_number (void);
316 static int handle_string (char delim);
317 static int handle_close_bracket (bool spc_gobbled, int bracket_type);
318 static int handle_superclass_identifier (void);
319 static int handle_meta_identifier (void);
320 static int handle_identifier (void);
321 static bool have_continuation (bool trailing_comments_ok = true);
322 static bool have_ellipsis_continuation (bool trailing_comments_ok = true);
323 static void scan_for_comments (const char *);
324 static yum_yum eat_whitespace (void);
325 static yum_yum eat_continuation (void);
326 static void maybe_warn_separator_insert (char sep);
327 static void gripe_single_quote_string (void);
328 static void gripe_matlab_incompatible (const std::string& msg);
329 static void maybe_gripe_matlab_incompatible_comment (char c);
330 static void gripe_matlab_incompatible_continuation (void);
331 static void gripe_matlab_incompatible_operator (const std::string& op);
332 static void display_token (int tok);
333 static void lexer_debug (const char *pattern, const char *text);
334 233
335 %} 234 %}
336 235
337 D [0-9] 236 D [0-9]
338 S [ \t] 237 S [ \t]
360 259
361 <SCRIPT_FILE_BEGIN>. { 260 <SCRIPT_FILE_BEGIN>. {
362 LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>."); 261 LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>.");
363 262
364 BEGIN (INITIAL); 263 BEGIN (INITIAL);
365 xunput (yytext[0], yytext); 264 curr_lexer->xunput (yytext[0]);
366 COUNT_TOK_AND_RETURN (SCRIPT_FILE); 265 COUNT_TOK_AND_RETURN (SCRIPT_FILE);
367 } 266 }
368 267
369 <FUNCTION_FILE_BEGIN>. { 268 <FUNCTION_FILE_BEGIN>. {
370 LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>."); 269 LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>.");
371 270
372 BEGIN (INITIAL); 271 BEGIN (INITIAL);
373 xunput (yytext[0], yytext); 272 curr_lexer->xunput (yytext[0]);
374 COUNT_TOK_AND_RETURN (FUNCTION_FILE); 273 COUNT_TOK_AND_RETURN (FUNCTION_FILE);
375 } 274 }
376 275
377 <CLASSDEF_FILE_BEGIN>. { 276 <CLASSDEF_FILE_BEGIN>. {
378 LEXER_DEBUG ("<CLASSDEF_FILE_BEGIN>."); 277 LEXER_DEBUG ("<CLASSDEF_FILE_BEGIN>.");
379 278
380 BEGIN (INITIAL); 279 BEGIN (INITIAL);
381 xunput (yytext[0], yytext); 280 curr_lexer->xunput (yytext[0], yytext);
382 COUNT_TOK_AND_RETURN (CLASSDEF_FILE); 281 COUNT_TOK_AND_RETURN (CLASSDEF_FILE);
383 } 282 }
384 283
385 %{ 284 %{
386 // Help and other command-style functions. 285 // Help and other command-style functions.
388 287
389 <COMMAND_START>{NL} { 288 <COMMAND_START>{NL} {
390 LEXER_DEBUG ("<COMMAND_START>{NL}"); 289 LEXER_DEBUG ("<COMMAND_START>{NL}");
391 290
392 BEGIN (INITIAL); 291 BEGIN (INITIAL);
393 input_line_number++; 292 curr_lexer->input_line_number++;
394 current_input_column = 1; 293 curr_lexer->current_input_column = 1;
395 294
396 lexer_flags.quote_is_transpose = false; 295 curr_lexer->quote_is_transpose = false;
397 lexer_flags.convert_spaces_to_comma = true; 296 curr_lexer->convert_spaces_to_comma = true;
398 lexer_flags.looking_for_object_index = false; 297 curr_lexer->looking_for_object_index = false;
399 lexer_flags.at_beginning_of_statement = true; 298 curr_lexer->at_beginning_of_statement = true;
400 299
401 COUNT_TOK_AND_RETURN ('\n'); 300 COUNT_TOK_AND_RETURN ('\n');
402 } 301 }
403 302
404 <COMMAND_START>[\;\,] { 303 <COMMAND_START>[\;\,] {
405 LEXER_DEBUG ("<COMMAND_START>[\\;\\,]"); 304 LEXER_DEBUG ("<COMMAND_START>[\\;\\,]");
406 305
407 lexer_flags.looking_for_object_index = false; 306 curr_lexer->looking_for_object_index = false;
408 lexer_flags.at_beginning_of_statement = true; 307 curr_lexer->at_beginning_of_statement = true;
409 308
410 BEGIN (INITIAL); 309 BEGIN (INITIAL);
411 310
412 if (strcmp (yytext, ",") == 0) 311 if (strcmp (yytext, ",") == 0)
413 TOK_RETURN (','); 312 TOK_RETURN (',');
416 } 315 }
417 316
418 <COMMAND_START>[\"\'] { 317 <COMMAND_START>[\"\'] {
419 LEXER_DEBUG ("<COMMAND_START>[\\\"\\']"); 318 LEXER_DEBUG ("<COMMAND_START>[\\\"\\']");
420 319
421 lexer_flags.at_beginning_of_statement = false; 320 curr_lexer->at_beginning_of_statement = false;
422 321
423 current_input_column++; 322 curr_lexer->current_input_column++;
424 int tok = handle_string (yytext[0]); 323 int tok = curr_lexer->handle_string (yytext[0]);
425 324
426 COUNT_TOK_AND_RETURN (tok); 325 COUNT_TOK_AND_RETURN (tok);
427 } 326 }
428 327
429 <COMMAND_START>[^#% \t\r\n\;\,\"\'][^ \t\r\n\;\,]*{S}* { 328 <COMMAND_START>[^#% \t\r\n\;\,\"\'][^ \t\r\n\;\,]*{S}* {
430 LEXER_DEBUG ("<COMMAND_START>[^#% \\t\\r\\n\\;\\,\\\"\\'][^ \\t\\r\\n\\;\\,]*{S}*"); 329 LEXER_DEBUG ("<COMMAND_START>[^#% \\t\\r\\n\\;\\,\\\"\\'][^ \\t\\r\\n\\;\\,]*{S}*");
431 330
432 std::string tok = strip_trailing_whitespace (yytext); 331 std::string tok = strip_trailing_whitespace (yytext);
433 332
434 lexer_flags.looking_for_object_index = false; 333 curr_lexer->looking_for_object_index = false;
435 lexer_flags.at_beginning_of_statement = false; 334 curr_lexer->at_beginning_of_statement = false;
436 335
437 TOK_PUSH_AND_RETURN (tok, SQ_STRING); 336 TOK_PUSH_AND_RETURN (tok, SQ_STRING);
438 } 337 }
439 338
440 %{ 339 %{
452 %} 351 %}
453 352
454 <MATRIX_START>{SNLCMT}*\]{S}* { 353 <MATRIX_START>{SNLCMT}*\]{S}* {
455 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\]{S}*"); 354 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\]{S}*");
456 355
457 scan_for_comments (yytext); 356 curr_lexer->scan_for_comments (yytext);
458 fixup_column_count (yytext); 357 curr_lexer->fixup_column_count (yytext);
459 358
460 lexer_flags.looking_at_object_index.pop_front (); 359 curr_lexer->looking_at_object_index.pop_front ();
461 360
462 lexer_flags.looking_for_object_index = true; 361 curr_lexer->looking_for_object_index = true;
463 lexer_flags.at_beginning_of_statement = false; 362 curr_lexer->at_beginning_of_statement = false;
464 363
465 int c = yytext[yyleng-1]; 364 int c = yytext[yyleng-1];
466 int cont_is_spc = eat_continuation (); 365 bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE);
467 bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); 366 bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
468 int tok_to_return = handle_close_bracket (spc_gobbled, ']'); 367 int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, ']');
469 368
470 if (spc_gobbled) 369 if (spc_gobbled)
471 xunput (' ', yytext); 370 curr_lexer->xunput (' ');
472 371
473 COUNT_TOK_AND_RETURN (tok_to_return); 372 COUNT_TOK_AND_RETURN (tok_to_return);
474 } 373 }
475 374
476 %{ 375 %{
478 %} 377 %}
479 378
480 <MATRIX_START>{SNLCMT}*\}{S}* { 379 <MATRIX_START>{SNLCMT}*\}{S}* {
481 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\}{S}*"); 380 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*\\}{S}*");
482 381
483 scan_for_comments (yytext); 382 curr_lexer->scan_for_comments (yytext);
484 fixup_column_count (yytext); 383 curr_lexer->fixup_column_count (yytext);
485 384
486 lexer_flags.looking_at_object_index.pop_front (); 385 curr_lexer->looking_at_object_index.pop_front ();
487 386
488 lexer_flags.looking_for_object_index = true; 387 curr_lexer->looking_for_object_index = true;
489 lexer_flags.at_beginning_of_statement = false; 388 curr_lexer->at_beginning_of_statement = false;
490 389
491 int c = yytext[yyleng-1]; 390 int c = yytext[yyleng-1];
492 int cont_is_spc = eat_continuation (); 391 bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE);
493 bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); 392 bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
494 int tok_to_return = handle_close_bracket (spc_gobbled, '}'); 393 int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, '}');
495 394
496 if (spc_gobbled) 395 if (spc_gobbled)
497 xunput (' ', yytext); 396 curr_lexer->xunput (' ');
498 397
499 COUNT_TOK_AND_RETURN (tok_to_return); 398 COUNT_TOK_AND_RETURN (tok_to_return);
500 } 399 }
501 400
502 %{ 401 %{
506 %} 405 %}
507 406
508 <MATRIX_START>{S}*\,{S}* { 407 <MATRIX_START>{S}*\,{S}* {
509 LEXER_DEBUG ("<MATRIX_START>{S}*\\,{S}*"); 408 LEXER_DEBUG ("<MATRIX_START>{S}*\\,{S}*");
510 409
511 current_input_column += yyleng; 410 curr_lexer->current_input_column += yyleng;
512 411
513 int tmp = eat_continuation (); 412 int tmp = curr_lexer->eat_continuation ();
514 413
515 lexer_flags.quote_is_transpose = false; 414 curr_lexer->quote_is_transpose = false;
516 lexer_flags.convert_spaces_to_comma = true; 415 curr_lexer->convert_spaces_to_comma = true;
517 lexer_flags.looking_for_object_index = false; 416 curr_lexer->looking_for_object_index = false;
518 lexer_flags.at_beginning_of_statement = false; 417 curr_lexer->at_beginning_of_statement = false;
519 418
520 if (! lexer_flags.looking_at_object_index.front ()) 419 if (! curr_lexer->looking_at_object_index.front ())
521 { 420 {
522 if ((tmp & ATE_NEWLINE) == ATE_NEWLINE) 421 if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE)
523 { 422 {
524 maybe_warn_separator_insert (';'); 423 curr_lexer->maybe_warn_separator_insert (';');
525 424
526 xunput (';', yytext); 425 curr_lexer->xunput (';');
527 } 426 }
528 } 427 }
529 428
530 COUNT_TOK_AND_RETURN (','); 429 COUNT_TOK_AND_RETURN (',');
531 } 430 }
538 %} 437 %}
539 438
540 <MATRIX_START>{S}+ { 439 <MATRIX_START>{S}+ {
541 LEXER_DEBUG ("<MATRIX_START>{S}+"); 440 LEXER_DEBUG ("<MATRIX_START>{S}+");
542 441
543 current_input_column += yyleng; 442 curr_lexer->current_input_column += yyleng;
544 443
545 lexer_flags.at_beginning_of_statement = false; 444 curr_lexer->at_beginning_of_statement = false;
546 445
547 int tmp = eat_continuation (); 446 int tmp = curr_lexer->eat_continuation ();
548 447
549 if (! lexer_flags.looking_at_object_index.front ()) 448 if (! curr_lexer->looking_at_object_index.front ())
550 { 449 {
551 bool bin_op = next_token_is_bin_op (true); 450 bool bin_op = curr_lexer->next_token_is_bin_op (true);
552 bool postfix_un_op = next_token_is_postfix_unary_op (true); 451 bool postfix_un_op = curr_lexer->next_token_is_postfix_unary_op (true);
553 bool sep_op = next_token_is_sep_op (); 452 bool sep_op = curr_lexer->next_token_is_sep_op ();
554 453
555 if (! (postfix_un_op || bin_op || sep_op) 454 if (! (postfix_un_op || bin_op || sep_op)
556 && nesting_level.is_bracket_or_brace () 455 && curr_lexer->nesting_level.is_bracket_or_brace ()
557 && lexer_flags.convert_spaces_to_comma) 456 && curr_lexer->convert_spaces_to_comma)
558 { 457 {
559 if ((tmp & ATE_NEWLINE) == ATE_NEWLINE) 458 if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE)
560 { 459 {
561 maybe_warn_separator_insert (';'); 460 curr_lexer->maybe_warn_separator_insert (';');
562 461
563 xunput (';', yytext); 462 curr_lexer->xunput (';');
564 } 463 }
565 464
566 lexer_flags.quote_is_transpose = false; 465 curr_lexer->quote_is_transpose = false;
567 lexer_flags.convert_spaces_to_comma = true; 466 curr_lexer->convert_spaces_to_comma = true;
568 lexer_flags.looking_for_object_index = false; 467 curr_lexer->looking_for_object_index = false;
569 468
570 maybe_warn_separator_insert (','); 469 curr_lexer->maybe_warn_separator_insert (',');
571 470
572 COUNT_TOK_AND_RETURN (','); 471 COUNT_TOK_AND_RETURN (',');
573 } 472 }
574 } 473 }
575 } 474 }
583 %} 482 %}
584 483
585 <MATRIX_START>{SNLCMT}*;{SNLCMT}* { 484 <MATRIX_START>{SNLCMT}*;{SNLCMT}* {
586 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*;{SNLCMT}*"); 485 LEXER_DEBUG ("<MATRIX_START>{SNLCMT}*;{SNLCMT}*");
587 486
588 scan_for_comments (yytext); 487 curr_lexer->scan_for_comments (yytext);
589 fixup_column_count (yytext); 488 curr_lexer->fixup_column_count (yytext);
590 eat_whitespace (); 489 curr_lexer->eat_whitespace ();
591 490
592 lexer_flags.quote_is_transpose = false; 491 curr_lexer->quote_is_transpose = false;
593 lexer_flags.convert_spaces_to_comma = true; 492 curr_lexer->convert_spaces_to_comma = true;
594 lexer_flags.looking_for_object_index = false; 493 curr_lexer->looking_for_object_index = false;
595 lexer_flags.at_beginning_of_statement = false; 494 curr_lexer->at_beginning_of_statement = false;
596 495
597 COUNT_TOK_AND_RETURN (';'); 496 COUNT_TOK_AND_RETURN (';');
598 } 497 }
599 498
600 %{ 499 %{
607 506
608 <MATRIX_START>{S}*{COMMENT}{SNLCMT}* | 507 <MATRIX_START>{S}*{COMMENT}{SNLCMT}* |
609 <MATRIX_START>{S}*{NL}{SNLCMT}* { 508 <MATRIX_START>{S}*{NL}{SNLCMT}* {
610 LEXER_DEBUG ("<MATRIX_START>{S}*{COMMENT}{SNLCMT}*|<MATRIX_START>{S}*{NL}{SNLCMT}*"); 509 LEXER_DEBUG ("<MATRIX_START>{S}*{COMMENT}{SNLCMT}*|<MATRIX_START>{S}*{NL}{SNLCMT}*");
611 510
612 scan_for_comments (yytext); 511 curr_lexer->scan_for_comments (yytext);
613 fixup_column_count (yytext); 512 curr_lexer->fixup_column_count (yytext);
614 eat_whitespace (); 513 curr_lexer->eat_whitespace ();
615 514
616 lexer_flags.quote_is_transpose = false; 515 curr_lexer->quote_is_transpose = false;
617 lexer_flags.convert_spaces_to_comma = true; 516 curr_lexer->convert_spaces_to_comma = true;
618 lexer_flags.at_beginning_of_statement = false; 517 curr_lexer->at_beginning_of_statement = false;
619 518
620 if (nesting_level.none ()) 519 if (curr_lexer->nesting_level.none ())
621 return LEXICAL_ERROR; 520 return LEXICAL_ERROR;
622 521
623 if (! lexer_flags.looking_at_object_index.front () 522 if (! curr_lexer->looking_at_object_index.front ()
624 && nesting_level.is_bracket_or_brace ()) 523 && curr_lexer->nesting_level.is_bracket_or_brace ())
625 { 524 {
626 maybe_warn_separator_insert (';'); 525 curr_lexer->maybe_warn_separator_insert (';');
627 526
628 COUNT_TOK_AND_RETURN (';'); 527 COUNT_TOK_AND_RETURN (';');
629 } 528 }
630 } 529 }
631 530
632 \[{S}* { 531 \[{S}* {
633 LEXER_DEBUG ("\\[{S}*"); 532 LEXER_DEBUG ("\\[{S}*");
634 533
635 nesting_level.bracket (); 534 curr_lexer->nesting_level.bracket ();
636 535
637 lexer_flags.looking_at_object_index.push_front (false); 536 curr_lexer->looking_at_object_index.push_front (false);
638 537
639 current_input_column += yyleng; 538 curr_lexer->current_input_column += yyleng;
640 lexer_flags.quote_is_transpose = false; 539 curr_lexer->quote_is_transpose = false;
641 lexer_flags.convert_spaces_to_comma = true; 540 curr_lexer->convert_spaces_to_comma = true;
642 lexer_flags.looking_for_object_index = false; 541 curr_lexer->looking_for_object_index = false;
643 lexer_flags.at_beginning_of_statement = false; 542 curr_lexer->at_beginning_of_statement = false;
644 543
645 if (lexer_flags.defining_func 544 if (curr_lexer->defining_func
646 && ! lexer_flags.parsed_function_name.top ()) 545 && ! curr_lexer->parsed_function_name.top ())
647 lexer_flags.looking_at_return_list = true; 546 curr_lexer->looking_at_return_list = true;
648 else 547 else
649 lexer_flags.looking_at_matrix_or_assign_lhs = true; 548 curr_lexer->looking_at_matrix_or_assign_lhs = true;
650 549
651 promptflag--; 550 promptflag--;
652 eat_whitespace (); 551 curr_lexer->eat_whitespace ();
653 552
654 lexer_flags.bracketflag++; 553 curr_lexer->bracketflag++;
655 BEGIN (MATRIX_START); 554 BEGIN (MATRIX_START);
656 COUNT_TOK_AND_RETURN ('['); 555 COUNT_TOK_AND_RETURN ('[');
657 } 556 }
658 557
659 \] { 558 \] {
660 LEXER_DEBUG ("\\]"); 559 LEXER_DEBUG ("\\]");
661 560
662 nesting_level.remove (); 561 curr_lexer->nesting_level.remove ();
663 562
664 lexer_flags.looking_at_object_index.pop_front (); 563 curr_lexer->looking_at_object_index.pop_front ();
665 564
666 lexer_flags.looking_for_object_index = true; 565 curr_lexer->looking_for_object_index = true;
667 lexer_flags.at_beginning_of_statement = false; 566 curr_lexer->at_beginning_of_statement = false;
668 567
669 TOK_RETURN (']'); 568 TOK_RETURN (']');
670 } 569 }
671 570
672 %{ 571 %{
674 %} 573 %}
675 574
676 {NUMBER}{Im} { 575 {NUMBER}{Im} {
677 LEXER_DEBUG ("{NUMBER}{Im}"); 576 LEXER_DEBUG ("{NUMBER}{Im}");
678 577
679 handle_number (); 578 curr_lexer->handle_number ();
680 COUNT_TOK_AND_RETURN (IMAG_NUM); 579 COUNT_TOK_AND_RETURN (IMAG_NUM);
681 } 580 }
682 581
683 %{ 582 %{
684 // Real numbers. Don't grab the '.' part of a dot operator as part of 583 // Real numbers. Don't grab the '.' part of a dot operator as part of
686 %} 585 %}
687 586
688 {D}+/\.[\*/\\^\'] | 587 {D}+/\.[\*/\\^\'] |
689 {NUMBER} { 588 {NUMBER} {
690 LEXER_DEBUG ("{D}+/\\.[\\*/\\^\\']|{NUMBER}"); 589 LEXER_DEBUG ("{D}+/\\.[\\*/\\^\\']|{NUMBER}");
691 handle_number (); 590 curr_lexer->handle_number ();
692 COUNT_TOK_AND_RETURN (NUM); 591 COUNT_TOK_AND_RETURN (NUM);
693 } 592 }
694 593
695 %{ 594 %{
696 // Eat whitespace. Whitespace inside matrix constants is handled by 595 // Eat whitespace. Whitespace inside matrix constants is handled by
697 // the <MATRIX_START> start state code above. 596 // the <MATRIX_START> start state code above.
698 %} 597 %}
699 598
700 {S}* { 599 {S}* {
701 current_input_column += yyleng; 600 curr_lexer->current_input_column += yyleng;
702 } 601 }
703 602
704 %{ 603 %{
705 // Continuation lines. Allow comments after continuations. 604 // Continuation lines. Allow comments after continuations.
706 %} 605 %}
708 {CONT}{S}*{NL} | 607 {CONT}{S}*{NL} |
709 {CONT}{S}*{COMMENT} { 608 {CONT}{S}*{COMMENT} {
710 LEXER_DEBUG ("{CONT}{S}*{NL}|{CONT}{S}*{COMMENT}"); 609 LEXER_DEBUG ("{CONT}{S}*{NL}|{CONT}{S}*{COMMENT}");
711 610
712 if (yytext[0] == '\\') 611 if (yytext[0] == '\\')
713 gripe_matlab_incompatible_continuation (); 612 curr_lexer->gripe_matlab_incompatible_continuation ();
714 scan_for_comments (yytext); 613 curr_lexer->scan_for_comments (yytext);
715 promptflag--; 614 promptflag--;
716 input_line_number++; 615 curr_lexer->input_line_number++;
717 current_input_column = 1; 616 curr_lexer->current_input_column = 1;
718 } 617 }
719 618
720 %{ 619 %{
721 // End of file. 620 // End of file.
722 %} 621 %}
723 622
724 <<EOF>> { 623 <<EOF>> {
725 LEXER_DEBUG ("<<EOF>>"); 624 LEXER_DEBUG ("<<EOF>>");
726 625
727 if (block_comment_nesting_level != 0) 626 if (curr_lexer->block_comment_nesting_level != 0)
728 { 627 {
729 warning ("block comment open at end of input"); 628 warning ("block comment open at end of input");
730 629
731 if ((reading_fcn_file || reading_script_file || reading_classdef_file) 630 if ((reading_fcn_file || reading_script_file || reading_classdef_file)
732 && ! curr_fcn_file_name.empty ()) 631 && ! curr_fcn_file_name.empty ())
733 warning ("near line %d of file '%s.m'", 632 warning ("near line %d of file '%s.m'",
734 input_line_number, curr_fcn_file_name.c_str ()); 633 curr_lexer->input_line_number, curr_fcn_file_name.c_str ());
735 } 634 }
736 635
737 TOK_RETURN (END_OF_INPUT); 636 TOK_RETURN (END_OF_INPUT);
738 } 637 }
739 638
743 %} 642 %}
744 643
745 {IDENT}{S}* { 644 {IDENT}{S}* {
746 LEXER_DEBUG ("{IDENT}{S}*"); 645 LEXER_DEBUG ("{IDENT}{S}*");
747 646
748 int id_tok = handle_identifier (); 647 int id_tok = curr_lexer->handle_identifier ();
749 648
750 if (id_tok >= 0) 649 if (id_tok >= 0)
751 COUNT_TOK_AND_RETURN (id_tok); 650 COUNT_TOK_AND_RETURN (id_tok);
752 } 651 }
753 652
757 656
758 {IDENT}@{IDENT}{S}* | 657 {IDENT}@{IDENT}{S}* |
759 {IDENT}@{IDENT}.{IDENT}{S}* { 658 {IDENT}@{IDENT}.{IDENT}{S}* {
760 LEXER_DEBUG ("{IDENT}@{IDENT}{S}*|{IDENT}@{IDENT}.{IDENT}{S}*"); 659 LEXER_DEBUG ("{IDENT}@{IDENT}{S}*|{IDENT}@{IDENT}.{IDENT}{S}*");
761 660
762 int id_tok = handle_superclass_identifier (); 661 int id_tok = curr_lexer->handle_superclass_identifier ();
763 662
764 if (id_tok >= 0) 663 if (id_tok >= 0)
765 { 664 {
766 lexer_flags.looking_for_object_index = true; 665 curr_lexer->looking_for_object_index = true;
767 666
768 COUNT_TOK_AND_RETURN (id_tok); 667 COUNT_TOK_AND_RETURN (id_tok);
769 } 668 }
770 } 669 }
771 670
775 674
776 \?{IDENT}{S}* | 675 \?{IDENT}{S}* |
777 \?{IDENT}\.{IDENT}{S}* { 676 \?{IDENT}\.{IDENT}{S}* {
778 LEXER_DEBUG ("\\?{IDENT}{S}*|\\?{IDENT}\\.{IDENT}{S}*"); 677 LEXER_DEBUG ("\\?{IDENT}{S}*|\\?{IDENT}\\.{IDENT}{S}*");
779 678
780 int id_tok = handle_meta_identifier (); 679 int id_tok = curr_lexer->handle_meta_identifier ();
781 680
782 if (id_tok >= 0) 681 if (id_tok >= 0)
783 { 682 {
784 lexer_flags.looking_for_object_index = true; 683 curr_lexer->looking_for_object_index = true;
785 684
786 COUNT_TOK_AND_RETURN (id_tok); 685 COUNT_TOK_AND_RETURN (id_tok);
787 } 686 }
788 } 687 }
789 688
792 %} 691 %}
793 692
794 "@" { 693 "@" {
795 LEXER_DEBUG ("@"); 694 LEXER_DEBUG ("@");
796 695
797 current_input_column++; 696 curr_lexer->current_input_column++;
798 697
799 lexer_flags.quote_is_transpose = false; 698 curr_lexer->quote_is_transpose = false;
800 lexer_flags.convert_spaces_to_comma = false; 699 curr_lexer->convert_spaces_to_comma = false;
801 lexer_flags.looking_at_function_handle++; 700 curr_lexer->looking_at_function_handle++;
802 lexer_flags.looking_for_object_index = false; 701 curr_lexer->looking_for_object_index = false;
803 lexer_flags.at_beginning_of_statement = false; 702 curr_lexer->at_beginning_of_statement = false;
804 703
805 COUNT_TOK_AND_RETURN ('@'); 704 COUNT_TOK_AND_RETURN ('@');
806 705
807 } 706 }
808 707
813 %} 712 %}
814 713
815 {NL} { 714 {NL} {
816 LEXER_DEBUG ("{NL}"); 715 LEXER_DEBUG ("{NL}");
817 716
818 input_line_number++; 717 curr_lexer->input_line_number++;
819 current_input_column = 1; 718 curr_lexer->current_input_column = 1;
820 719
821 lexer_flags.quote_is_transpose = false; 720 curr_lexer->quote_is_transpose = false;
822 lexer_flags.convert_spaces_to_comma = true; 721 curr_lexer->convert_spaces_to_comma = true;
823 722
824 if (nesting_level.none ()) 723 if (curr_lexer->nesting_level.none ())
825 { 724 {
826 lexer_flags.at_beginning_of_statement = true; 725 curr_lexer->at_beginning_of_statement = true;
827 COUNT_TOK_AND_RETURN ('\n'); 726 COUNT_TOK_AND_RETURN ('\n');
828 } 727 }
829 else if (nesting_level.is_paren ()) 728 else if (curr_lexer->nesting_level.is_paren ())
830 { 729 {
831 lexer_flags.at_beginning_of_statement = false; 730 curr_lexer->at_beginning_of_statement = false;
832 gripe_matlab_incompatible ("bare newline inside parentheses"); 731 curr_lexer->gripe_matlab_incompatible ("bare newline inside parentheses");
833 } 732 }
834 else if (nesting_level.is_bracket_or_brace ()) 733 else if (curr_lexer->nesting_level.is_bracket_or_brace ())
835 return LEXICAL_ERROR; 734 return LEXICAL_ERROR;
836 } 735 }
837 736
838 %{ 737 %{
839 // Single quote can either be the beginning of a string or a transpose 738 // Single quote can either be the beginning of a string or a transpose
841 %} 740 %}
842 741
843 "'" { 742 "'" {
844 LEXER_DEBUG ("'"); 743 LEXER_DEBUG ("'");
845 744
846 current_input_column++; 745 curr_lexer->current_input_column++;
847 lexer_flags.convert_spaces_to_comma = true; 746 curr_lexer->convert_spaces_to_comma = true;
848 747
849 if (lexer_flags.quote_is_transpose) 748 if (curr_lexer->quote_is_transpose)
850 { 749 {
851 do_comma_insert_check (); 750 curr_lexer->do_comma_insert_check ();
852 COUNT_TOK_AND_RETURN (QUOTE); 751 COUNT_TOK_AND_RETURN (QUOTE);
853 } 752 }
854 else 753 else
855 { 754 {
856 int tok = handle_string ('\''); 755 int tok = curr_lexer->handle_string ('\'');
857 COUNT_TOK_AND_RETURN (tok); 756 COUNT_TOK_AND_RETURN (tok);
858 } 757 }
859 } 758 }
860 759
861 %{ 760 %{
863 %} 762 %}
864 763
865 \" { 764 \" {
866 LEXER_DEBUG ("\""); 765 LEXER_DEBUG ("\"");
867 766
868 current_input_column++; 767 curr_lexer->current_input_column++;
869 int tok = handle_string ('"'); 768 int tok = curr_lexer->handle_string ('"');
870 769
871 COUNT_TOK_AND_RETURN (tok); 770 COUNT_TOK_AND_RETURN (tok);
872 } 771 }
873 772
874 %{ 773 %{
876 %} 775 %}
877 776
878 {CCHAR} { 777 {CCHAR} {
879 LEXER_DEBUG ("{CCHAR}"); 778 LEXER_DEBUG ("{CCHAR}");
880 779
881 lexer_flags.looking_for_object_index = false; 780 curr_lexer->looking_for_object_index = false;
882 781
883 xunput (yytext[0], yytext); 782 curr_lexer->xunput (yytext[0]);
884 783
885 bool eof = false; 784 bool eof = false;
886 int tok = process_comment (false, eof); 785 int tok = curr_lexer->process_comment (false, eof);
887 786
888 if (eof) 787 if (eof)
889 TOK_RETURN (END_OF_INPUT); 788 TOK_RETURN (END_OF_INPUT);
890 else if (tok > 0) 789 else if (tok > 0)
891 COUNT_TOK_AND_RETURN (tok); 790 COUNT_TOK_AND_RETURN (tok);
896 %} 795 %}
897 796
898 ^{S}*{CCHAR}\{{S}*{NL} { 797 ^{S}*{CCHAR}\{{S}*{NL} {
899 LEXER_DEBUG ("^{S}*{CCHAR}\\{{S}*{NL}"); 798 LEXER_DEBUG ("^{S}*{CCHAR}\\{{S}*{NL}");
900 799
901 lexer_flags.looking_for_object_index = false; 800 curr_lexer->looking_for_object_index = false;
902 801
903 input_line_number++; 802 curr_lexer->input_line_number++;
904 current_input_column = 1; 803 curr_lexer->current_input_column = 1;
905 block_comment_nesting_level++; 804 curr_lexer->block_comment_nesting_level++;
906 promptflag--; 805 promptflag--;
907 806
908 bool eof = false; 807 bool eof = false;
909 process_comment (true, eof); 808 curr_lexer->process_comment (true, eof);
910 } 809 }
911 810
912 %{ 811 %{
913 // Other operators. 812 // Other operators.
914 %} 813 %}
920 ".*" { LEXER_DEBUG (".*"); BIN_OP_RETURN (EMUL, false, false); } 819 ".*" { LEXER_DEBUG (".*"); BIN_OP_RETURN (EMUL, false, false); }
921 "./" { LEXER_DEBUG ("./"); BIN_OP_RETURN (EDIV, false, false); } 820 "./" { LEXER_DEBUG ("./"); BIN_OP_RETURN (EDIV, false, false); }
922 ".\\" { LEXER_DEBUG (".\\"); BIN_OP_RETURN (ELEFTDIV, false, false); } 821 ".\\" { LEXER_DEBUG (".\\"); BIN_OP_RETURN (ELEFTDIV, false, false); }
923 ".^" { LEXER_DEBUG (".^"); BIN_OP_RETURN (EPOW, false, false); } 822 ".^" { LEXER_DEBUG (".^"); BIN_OP_RETURN (EPOW, false, false); }
924 ".**" { LEXER_DEBUG (".**"); XBIN_OP_RETURN (EPOW, false, false); } 823 ".**" { LEXER_DEBUG (".**"); XBIN_OP_RETURN (EPOW, false, false); }
925 ".'" { LEXER_DEBUG (".'"); do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, true, false); } 824 ".'" { LEXER_DEBUG (".'"); curr_lexer->do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, true, false); }
926 "++" { LEXER_DEBUG ("++"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (PLUS_PLUS, true, false, true); } 825 "++" { LEXER_DEBUG ("++"); curr_lexer->do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (PLUS_PLUS, true, false, true); }
927 "--" { LEXER_DEBUG ("--"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (MINUS_MINUS, true, false, true); } 826 "--" { LEXER_DEBUG ("--"); curr_lexer->do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (MINUS_MINUS, true, false, true); }
928 "<=" { LEXER_DEBUG ("<="); BIN_OP_RETURN (EXPR_LE, false, false); } 827 "<=" { LEXER_DEBUG ("<="); BIN_OP_RETURN (EXPR_LE, false, false); }
929 "==" { LEXER_DEBUG ("=="); BIN_OP_RETURN (EXPR_EQ, false, false); } 828 "==" { LEXER_DEBUG ("=="); BIN_OP_RETURN (EXPR_EQ, false, false); }
930 "~=" { LEXER_DEBUG ("~="); BIN_OP_RETURN (EXPR_NE, false, false); } 829 "~=" { LEXER_DEBUG ("~="); BIN_OP_RETURN (EXPR_NE, false, false); }
931 "!=" { LEXER_DEBUG ("!="); XBIN_OP_RETURN (EXPR_NE, false, false); } 830 "!=" { LEXER_DEBUG ("!="); XBIN_OP_RETURN (EXPR_NE, false, false); }
932 ">=" { LEXER_DEBUG (">="); BIN_OP_RETURN (EXPR_GE, false, false); } 831 ">=" { LEXER_DEBUG (">="); BIN_OP_RETURN (EXPR_GE, false, false); }
938 "-" { LEXER_DEBUG ("-"); BIN_OP_RETURN ('-', false, false); } 837 "-" { LEXER_DEBUG ("-"); BIN_OP_RETURN ('-', false, false); }
939 "*" { LEXER_DEBUG ("*"); BIN_OP_RETURN ('*', false, false); } 838 "*" { LEXER_DEBUG ("*"); BIN_OP_RETURN ('*', false, false); }
940 "/" { LEXER_DEBUG ("/"); BIN_OP_RETURN ('/', false, false); } 839 "/" { LEXER_DEBUG ("/"); BIN_OP_RETURN ('/', false, false); }
941 "\\" { LEXER_DEBUG ("\\"); BIN_OP_RETURN (LEFTDIV, false, false); } 840 "\\" { LEXER_DEBUG ("\\"); BIN_OP_RETURN (LEFTDIV, false, false); }
942 ";" { LEXER_DEBUG (";"); BIN_OP_RETURN (';', true, true); } 841 ";" { LEXER_DEBUG (";"); BIN_OP_RETURN (';', true, true); }
943 "," { LEXER_DEBUG (","); BIN_OP_RETURN (',', true, ! lexer_flags.looking_at_object_index.front ()); } 842 "," { LEXER_DEBUG (","); BIN_OP_RETURN (',', true, ! curr_lexer->looking_at_object_index.front ()); }
944 "^" { LEXER_DEBUG ("^"); BIN_OP_RETURN (POW, false, false); } 843 "^" { LEXER_DEBUG ("^"); BIN_OP_RETURN (POW, false, false); }
945 "**" { LEXER_DEBUG ("**"); XBIN_OP_RETURN (POW, false, false); } 844 "**" { LEXER_DEBUG ("**"); XBIN_OP_RETURN (POW, false, false); }
946 "=" { LEXER_DEBUG ("="); BIN_OP_RETURN ('=', true, false); } 845 "=" { LEXER_DEBUG ("="); BIN_OP_RETURN ('=', true, false); }
947 "&&" { LEXER_DEBUG ("&&"); BIN_OP_RETURN (EXPR_AND_AND, false, false); } 846 "&&" { LEXER_DEBUG ("&&"); BIN_OP_RETURN (EXPR_AND_AND, false, false); }
948 "||" { LEXER_DEBUG ("||"); BIN_OP_RETURN (EXPR_OR_OR, false, false); } 847 "||" { LEXER_DEBUG ("||"); BIN_OP_RETURN (EXPR_OR_OR, false, false); }
964 // If we are looking for an object index, then push TRUE for 863 // If we are looking for an object index, then push TRUE for
965 // looking_at_object_index. Otherwise, just push whatever state 864 // looking_at_object_index. Otherwise, just push whatever state
966 // is current (so that we can pop it off the stack when we find 865 // is current (so that we can pop it off the stack when we find
967 // the matching close paren). 866 // the matching close paren).
968 867
969 lexer_flags.looking_at_object_index.push_front 868 curr_lexer->looking_at_object_index.push_front
970 (lexer_flags.looking_for_object_index); 869 (curr_lexer->looking_for_object_index);
971 870
972 lexer_flags.looking_at_indirect_ref = false; 871 curr_lexer->looking_at_indirect_ref = false;
973 lexer_flags.looking_for_object_index = false; 872 curr_lexer->looking_for_object_index = false;
974 lexer_flags.at_beginning_of_statement = false; 873 curr_lexer->at_beginning_of_statement = false;
975 874
976 nesting_level.paren (); 875 curr_lexer->nesting_level.paren ();
977 promptflag--; 876 promptflag--;
978 877
979 TOK_RETURN ('('); 878 TOK_RETURN ('(');
980 } 879 }
981 880
982 ")" { 881 ")" {
983 LEXER_DEBUG (")"); 882 LEXER_DEBUG (")");
984 883
985 nesting_level.remove (); 884 curr_lexer->nesting_level.remove ();
986 current_input_column++; 885 curr_lexer->current_input_column++;
987 886
988 lexer_flags.looking_at_object_index.pop_front (); 887 curr_lexer->looking_at_object_index.pop_front ();
989 888
990 lexer_flags.quote_is_transpose = true; 889 curr_lexer->quote_is_transpose = true;
991 lexer_flags.convert_spaces_to_comma 890 curr_lexer->convert_spaces_to_comma
992 = (nesting_level.is_bracket_or_brace () 891 = (curr_lexer->nesting_level.is_bracket_or_brace ()
993 && ! lexer_flags.looking_at_anon_fcn_args); 892 && ! curr_lexer->looking_at_anon_fcn_args);
994 lexer_flags.looking_for_object_index = true; 893 curr_lexer->looking_for_object_index = true;
995 lexer_flags.at_beginning_of_statement = false; 894 curr_lexer->at_beginning_of_statement = false;
996 895
997 if (lexer_flags.looking_at_anon_fcn_args) 896 if (curr_lexer->looking_at_anon_fcn_args)
998 lexer_flags.looking_at_anon_fcn_args = false; 897 curr_lexer->looking_at_anon_fcn_args = false;
999 898
1000 do_comma_insert_check (); 899 curr_lexer->do_comma_insert_check ();
1001 900
1002 COUNT_TOK_AND_RETURN (')'); 901 COUNT_TOK_AND_RETURN (')');
1003 } 902 }
1004 903
1005 "." { 904 "." {
1006 LEXER_DEBUG ("."); 905 LEXER_DEBUG (".");
1007 906
1008 lexer_flags.looking_for_object_index = false; 907 curr_lexer->looking_for_object_index = false;
1009 lexer_flags.at_beginning_of_statement = false; 908 curr_lexer->at_beginning_of_statement = false;
1010 909
1011 TOK_RETURN ('.'); 910 TOK_RETURN ('.');
1012 } 911 }
1013 912
1014 "+=" { LEXER_DEBUG ("+="); XBIN_OP_RETURN (ADD_EQ, false, false); } 913 "+=" { LEXER_DEBUG ("+="); XBIN_OP_RETURN (ADD_EQ, false, false); }
1029 ">>=" { LEXER_DEBUG (">>="); XBIN_OP_RETURN (RSHIFT_EQ, false, false); } 928 ">>=" { LEXER_DEBUG (">>="); XBIN_OP_RETURN (RSHIFT_EQ, false, false); }
1030 929
1031 \{{S}* { 930 \{{S}* {
1032 LEXER_DEBUG ("\\{{S}*"); 931 LEXER_DEBUG ("\\{{S}*");
1033 932
1034 nesting_level.brace (); 933 curr_lexer->nesting_level.brace ();
1035 934
1036 lexer_flags.looking_at_object_index.push_front 935 curr_lexer->looking_at_object_index.push_front
1037 (lexer_flags.looking_for_object_index); 936 (curr_lexer->looking_for_object_index);
1038 937
1039 current_input_column += yyleng; 938 curr_lexer->current_input_column += yyleng;
1040 lexer_flags.quote_is_transpose = false; 939 curr_lexer->quote_is_transpose = false;
1041 lexer_flags.convert_spaces_to_comma = true; 940 curr_lexer->convert_spaces_to_comma = true;
1042 lexer_flags.looking_for_object_index = false; 941 curr_lexer->looking_for_object_index = false;
1043 lexer_flags.at_beginning_of_statement = false; 942 curr_lexer->at_beginning_of_statement = false;
1044 943
1045 promptflag--; 944 promptflag--;
1046 eat_whitespace (); 945 curr_lexer->eat_whitespace ();
1047 946
1048 lexer_flags.braceflag++; 947 curr_lexer->braceflag++;
1049 BEGIN (MATRIX_START); 948 BEGIN (MATRIX_START);
1050 COUNT_TOK_AND_RETURN ('{'); 949 COUNT_TOK_AND_RETURN ('{');
1051 } 950 }
1052 951
1053 "}" { 952 "}" {
1054 LEXER_DEBUG ("}"); 953 LEXER_DEBUG ("}");
1055 954
1056 lexer_flags.looking_at_object_index.pop_front (); 955 curr_lexer->looking_at_object_index.pop_front ();
1057 956
1058 lexer_flags.looking_for_object_index = true; 957 curr_lexer->looking_for_object_index = true;
1059 lexer_flags.at_beginning_of_statement = false; 958 curr_lexer->at_beginning_of_statement = false;
1060 959
1061 nesting_level.remove (); 960 curr_lexer->nesting_level.remove ();
1062 961
1063 TOK_RETURN ('}'); 962 TOK_RETURN ('}');
1064 } 963 }
1065 964
1066 %{ 965 %{
1068 %} 967 %}
1069 968
1070 . { 969 . {
1071 LEXER_DEBUG ("."); 970 LEXER_DEBUG (".");
1072 971
1073 xunput (yytext[0], yytext); 972 curr_lexer->xunput (yytext[0]);
1074 973
1075 int c = text_yyinput (); 974 int c = curr_lexer->text_yyinput ();
1076 975
1077 if (c != EOF) 976 if (c != EOF)
1078 { 977 {
1079 current_input_column++; 978 curr_lexer->current_input_column++;
1080 979
1081 error ("invalid character '%s' (ASCII %d) near line %d, column %d", 980 error ("invalid character '%s' (ASCII %d) near line %d, column %d",
1082 undo_string_escape (static_cast<char> (c)), c, 981 undo_string_escape (static_cast<char> (c)), c,
1083 input_line_number, current_input_column); 982 curr_lexer->input_line_number, curr_lexer->current_input_column);
1084 983
1085 return LEXICAL_ERROR; 984 return LEXICAL_ERROR;
1086 } 985 }
1087 else 986 else
1088 TOK_RETURN (END_OF_INPUT); 987 TOK_RETURN (END_OF_INPUT);
1089 } 988 }
1090 989
1091 %% 990 %%
1092
1093 // GAG.
1094 //
1095 // If we're reading a matrix and the next character is '[', make sure
1096 // that we insert a comma ahead of it.
1097
1098 void
1099 do_comma_insert_check (void)
1100 {
1101 int spc_gobbled = eat_continuation ();
1102
1103 int c = text_yyinput ();
1104
1105 xunput (c, yytext);
1106
1107 if (spc_gobbled)
1108 xunput (' ', yytext);
1109
1110 lexer_flags.do_comma_insert = (! lexer_flags.looking_at_object_index.front ()
1111 && lexer_flags.bracketflag && c == '[');
1112 }
1113
1114 // Fix things up for errors or interrupts. The parser is never called
1115 // recursively, so it is always safe to reinitialize its state before
1116 // doing any parsing.
1117
1118 void
1119 reset_parser (void)
1120 {
1121 // Start off on the right foot.
1122 BEGIN (INITIAL);
1123
1124 parser_end_of_input = false;
1125
1126 parser_symtab_context.clear ();
1127
1128 // We do want a prompt by default.
1129 promptflag = 1;
1130
1131 // We are not in a block comment.
1132 block_comment_nesting_level = 0;
1133
1134 // Error may have occurred inside some brackets, braces, or parentheses.
1135 nesting_level.clear ();
1136
1137 // Clear out the stack of token info used to track line and column
1138 // numbers.
1139 while (! token_stack.empty ())
1140 {
1141 delete token_stack.top ();
1142 token_stack.pop ();
1143 }
1144
1145 // Can be reset by defining a function.
1146 if (! (reading_script_file || reading_fcn_file || reading_classdef_file))
1147 {
1148 current_input_column = 1;
1149 input_line_number = command_editor::current_command_number ();
1150 }
1151
1152 // Only ask for input from stdin if we are expecting interactive
1153 // input.
1154
1155 if (! quitting_gracefully
1156 && (interactive || forced_interactive)
1157 && ! (reading_fcn_file
1158 || reading_classdef_file
1159 || reading_script_file
1160 || get_input_from_eval_string
1161 || input_from_startup_file))
1162 yyrestart (stdin);
1163
1164 // Clear the buffer for help text.
1165 while (! help_buf.empty ())
1166 help_buf.pop ();
1167
1168 // Reset other flags.
1169 lexer_flags.init ();
1170 }
1171 991
1172 static void 992 static void
1173 display_character (char c) 993 display_character (char c)
1174 { 994 {
1175 if (isgraph (c)) 995 if (isgraph (c))
1313 std::cerr << "DEL"; 1133 std::cerr << "DEL";
1314 break; 1134 break;
1315 } 1135 }
1316 } 1136 }
1317 1137
1318 static int 1138 void
1319 text_yyinput (void) 1139 cleanup_parser (void)
1320 { 1140 {
1321 int c = yyinput (); 1141 }
1142
1143 // Return 1 if the given character matches any character in the given
1144 // string.
1145
1146 static bool
1147 match_any (char c, const char *s)
1148 {
1149 char tmp;
1150 while ((tmp = *s++) != '\0')
1151 {
1152 if (c == tmp)
1153 return true;
1154 }
1155 return false;
1156 }
1157
1158 // Given information about the spacing surrounding an operator,
1159 // return 1 if it looks like it should be treated as a binary
1160 // operator. For example,
1161 //
1162 // [ 1 + 2 ] or [ 1+ 2] or [ 1+2 ] ==> binary
1163 //
1164 // [ 1 +2 ] ==> unary
1165
1166 static bool
1167 looks_like_bin_op (bool spc_prev, int next_char)
1168 {
1169 bool spc_next = (next_char == ' ' || next_char == '\t');
1170
1171 return ((spc_prev && spc_next) || ! spc_prev);
1172 }
1173
1174 bool
1175 is_keyword (const std::string& s)
1176 {
1177 // Parsing function names like "set.property_name" inside
1178 // classdef-style class definitions is simplified by handling the
1179 // "set" and "get" portions of the names using the same mechanism as
1180 // is used for keywords. However, they are not really keywords in
1181 // the language, so omit them from the list of possible keywords.
1182
1183 return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0
1184 && ! (s == "set" || s == "get"));
1185 }
1186
1187 DEFUN (iskeyword, args, ,
1188 "-*- texinfo -*-\n\
1189 @deftypefn {Built-in Function} {} iskeyword ()\n\
1190 @deftypefnx {Built-in Function} {} iskeyword (@var{name})\n\
1191 Return true if @var{name} is an Octave keyword. If @var{name}\n\
1192 is omitted, return a list of keywords.\n\
1193 @seealso{isvarname, exist}\n\
1194 @end deftypefn")
1195 {
1196 octave_value retval;
1197
1198 int argc = args.length () + 1;
1199
1200 string_vector argv = args.make_argv ("iskeyword");
1201
1202 if (error_state)
1203 return retval;
1204
1205 if (argc == 1)
1206 {
1207 // Neither set and get are keywords. See the note in the
1208 // is_keyword function for additional details.
1209
1210 string_vector lst (TOTAL_KEYWORDS);
1211
1212 int j = 0;
1213
1214 for (int i = 0; i < TOTAL_KEYWORDS; i++)
1215 {
1216 std::string tmp = wordlist[i].name;
1217
1218 if (! (tmp == "set" || tmp == "get"))
1219 lst[j++] = tmp;
1220 }
1221
1222 lst.resize (j);
1223
1224 retval = Cell (lst.sort ());
1225 }
1226 else if (argc == 2)
1227 {
1228 retval = is_keyword (argv[1]);
1229 }
1230 else
1231 print_usage ();
1232
1233 return retval;
1234 }
1235
1236 /*
1237
1238 %!assert (iskeyword ("for"))
1239 %!assert (iskeyword ("fort"), false)
1240 %!assert (iskeyword ("fft"), false)
1241
1242 */
1243
1244 // Used to delete trailing white space from tokens.
1245
1246 static std::string
1247 strip_trailing_whitespace (char *s)
1248 {
1249 std::string retval = s;
1250
1251 size_t pos = retval.find_first_of (" \t");
1252
1253 if (pos != std::string::npos)
1254 retval.resize (pos);
1255
1256 return retval;
1257 }
1258
1259 DEFUN (__display_tokens__, args, nargout,
1260 "-*- texinfo -*-\n\
1261 @deftypefn {Built-in Function} {} __display_tokens__ ()\n\
1262 Query or set the internal variable that determines whether Octave's\n\
1263 lexer displays tokens as they are read.\n\
1264 @end deftypefn")
1265 {
1266 return SET_INTERNAL_VARIABLE (display_tokens);
1267 }
1268
1269 DEFUN (__token_count__, , ,
1270 "-*- texinfo -*-\n\
1271 @deftypefn {Built-in Function} {} __token_count__ ()\n\
1272 Number of language tokens processed since Octave startup.\n\
1273 @end deftypefn")
1274 {
1275 return octave_value (Vtoken_count);
1276 }
1277
1278 DEFUN (__lexer_debug_flag__, args, nargout,
1279 "-*- texinfo -*-\n\
1280 @deftypefn {Built-in Function} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val}))\n\
1281 Undocumented internal function.\n\
1282 @end deftypefn")
1283 {
1284 octave_value retval;
1285
1286 retval = set_internal_variable (lexer_debug_flag, args, nargout,
1287 "__lexer_debug_flag__");
1288
1289 return retval;
1290 }
1291
1292 class
1293 flex_stream_reader : public stream_reader
1294 {
1295 public:
1296 flex_stream_reader (lexical_feedback *l, char *buf_arg)
1297 : stream_reader (), lexer (l), buf (buf_arg)
1298 { }
1299
1300 int getc (void) { return lexer->text_yyinput (); }
1301 int ungetc (int c) { lexer->xunput (c, buf); return 0; }
1302
1303 private:
1304
1305 // No copying!
1306
1307 flex_stream_reader (const flex_stream_reader&);
1308
1309 flex_stream_reader& operator = (const flex_stream_reader&);
1310
1311 lexical_feedback *lexer;
1312
1313 char *buf;
1314 };
1315
1316 lexical_feedback::~lexical_feedback (void)
1317 {
1318 // Clear out the stack of token info used to track line and
1319 // column numbers.
1320
1321 while (! token_stack.empty ())
1322 {
1323 delete token_stack.top ();
1324 token_stack.pop ();
1325 }
1326
1327 yylex_destroy (scanner);
1328 }
1329
1330 void
1331 lexical_feedback::init (void)
1332 {
1333 // The closest paren, brace, or bracket nesting is not an object
1334 // index.
1335 looking_at_object_index.push_front (false);
1336
1337 yylex_init (&scanner);
1338
1339 // Make lexical_feedback object available through yyextra in
1340 // flex-generated lexer.
1341 yyset_extra (this, scanner);
1342 }
1343
1344 // Inside Flex-generated functions, yyg is the scanner cast to its real
1345 // type. The BEGIN macro uses yyg and we want to use that in
1346 // lexical_feedback member functions. If we could set the start state
1347 // by calling a function instead of using the BEGIN macro, we could
1348 // eliminate the OCTAVE_YYG macro.
1349
1350 #define OCTAVE_YYG \
1351 struct yyguts_t *yyg = static_cast<struct yyguts_t*> (scanner)
1352
1353 void
1354 lexical_feedback::reset (void)
1355 {
1356 OCTAVE_YYG;
1357
1358 // Start off on the right foot.
1359 BEGIN (INITIAL);
1360
1361 parser_symtab_context.clear ();
1362
1363 // We do want a prompt by default.
1364 promptflag = 1;
1365
1366 // Only ask for input from stdin if we are expecting interactive
1367 // input.
1368
1369 if (! quitting_gracefully
1370 && (interactive || forced_interactive)
1371 && ! (reading_fcn_file
1372 || reading_classdef_file
1373 || reading_script_file
1374 || get_input_from_eval_string
1375 || input_from_startup_file))
1376 yyrestart (stdin, scanner);
1377
1378 // Clear the buffer for help text.
1379 while (! help_buf.empty ())
1380 help_buf.pop ();
1381 }
1382
1383 void
1384 lexical_feedback::prep_for_script_file (void)
1385 {
1386 OCTAVE_YYG;
1387
1388 BEGIN (SCRIPT_FILE_BEGIN);
1389 }
1390
1391 void
1392 lexical_feedback::prep_for_function_file (void)
1393 {
1394 OCTAVE_YYG;
1395
1396 BEGIN (FUNCTION_FILE_BEGIN);
1397 }
1398
1399 void
1400 lexical_feedback::prep_for_classdef_file (void)
1401 {
1402 OCTAVE_YYG;
1403
1404 BEGIN (CLASSDEF_FILE_BEGIN);
1405 }
1406
1407 int
1408 lexical_feedback::octave_read (char *buf, unsigned max_size)
1409 {
1410 static const char * const eol = "\n";
1411 static std::string input_buf;
1412 static const char *pos = 0;
1413 static size_t chars_left = 0;
1414 static bool eof = false;
1415
1416 int status = 0;
1417
1418 if (chars_left == 0)
1419 {
1420 pos = 0;
1421
1422 input_buf = get_user_input (eof);
1423
1424 chars_left = input_buf.length ();
1425
1426 pos = input_buf.c_str ();
1427 }
1428
1429 if (chars_left > 0)
1430 {
1431 size_t len = max_size > chars_left ? chars_left : max_size;
1432 assert (len > 0);
1433
1434 memcpy (buf, pos, len);
1435
1436 chars_left -= len;
1437 pos += len;
1438
1439 // Make sure input ends with a new line character.
1440 if (chars_left == 0 && buf[len-1] != '\n')
1441 {
1442 if (len < max_size)
1443 {
1444 // There is enough room to plug the newline character in
1445 // the buffer.
1446 buf[len++] = '\n';
1447 }
1448 else
1449 {
1450 // There isn't enough room to plug the newline character
1451 // in the buffer so make sure it is returned on the next
1452 // octave_read call.
1453 pos = eol;
1454 chars_left = 1;
1455 }
1456 }
1457
1458 status = len;
1459 }
1460 else
1461 {
1462 status = YY_NULL;
1463
1464 if (! eof)
1465 fatal_error ("octave_read () in flex scanner failed");
1466 }
1467
1468 return status;
1469 }
1470
1471 char *
1472 lexical_feedback::flex_yytext (void)
1473 {
1474 return yyget_text (scanner);
1475 }
1476
1477 int
1478 lexical_feedback::flex_yyleng (void)
1479 {
1480 return yyget_leng (scanner);
1481 }
1482
1483 // GAG.
1484 //
1485 // If we're reading a matrix and the next character is '[', make sure
1486 // that we insert a comma ahead of it.
1487
1488 void
1489 lexical_feedback::do_comma_insert_check (void)
1490 {
1491 bool spc_gobbled = (eat_continuation () != lexical_feedback::NO_WHITESPACE);
1492
1493 int c = text_yyinput ();
1494
1495 xunput (c);
1496
1497 if (spc_gobbled)
1498 xunput (' ');
1499
1500 do_comma_insert = (! looking_at_object_index.front ()
1501 && bracketflag && c == '[');
1502 }
1503
1504 int
1505 lexical_feedback::text_yyinput (void)
1506 {
1507 int c = yyinput (scanner);
1322 1508
1323 if (lexer_debug_flag) 1509 if (lexer_debug_flag)
1324 { 1510 {
1325 std::cerr << "I: "; 1511 std::cerr << "I: ";
1326 display_character (c); 1512 display_character (c);
1329 1515
1330 // Convert CRLF into just LF and single CR into LF. 1516 // Convert CRLF into just LF and single CR into LF.
1331 1517
1332 if (c == '\r') 1518 if (c == '\r')
1333 { 1519 {
1334 c = yyinput (); 1520 c = yyinput (scanner);
1335 1521
1336 if (lexer_debug_flag) 1522 if (lexer_debug_flag)
1337 { 1523 {
1338 std::cerr << "I: "; 1524 std::cerr << "I: ";
1339 display_character (c); 1525 display_character (c);
1340 std::cerr << std::endl; 1526 std::cerr << std::endl;
1341 } 1527 }
1342 1528
1343 if (c != '\n') 1529 if (c != '\n')
1344 { 1530 {
1345 xunput (c, yytext); 1531 xunput (c);
1346 c = '\n'; 1532 c = '\n';
1347 } 1533 }
1348 } 1534 }
1349 1535
1350 if (c == '\n') 1536 if (c == '\n')
1351 input_line_number++; 1537 input_line_number++;
1352 1538
1353 return c; 1539 return c;
1354 } 1540 }
1355 1541
1356 static void 1542 void
1357 xunput (char c, char *buf) 1543 lexical_feedback::xunput (char c, char *buf)
1358 { 1544 {
1359 if (lexer_debug_flag) 1545 if (lexer_debug_flag)
1360 { 1546 {
1361 std::cerr << "U: "; 1547 std::cerr << "U: ";
1362 display_character (c); 1548 display_character (c);
1364 } 1550 }
1365 1551
1366 if (c == '\n') 1552 if (c == '\n')
1367 input_line_number--; 1553 input_line_number--;
1368 1554
1369 yyunput (c, buf); 1555 yyunput (c, buf, scanner);
1556 }
1557
1558 void
1559 lexical_feedback::xunput (char c)
1560 {
1561 char *yytxt = flex_yytext ();
1562
1563 xunput (c, yytxt);
1370 } 1564 }
1371 1565
1372 // If we read some newlines, we need figure out what column we're 1566 // If we read some newlines, we need figure out what column we're
1373 // really looking at. 1567 // really looking at.
1374 1568
1375 static void 1569 void
1376 fixup_column_count (char *s) 1570 lexical_feedback::fixup_column_count (char *s)
1377 { 1571 {
1378 char c; 1572 char c;
1379 while ((c = *s++) != '\0') 1573 while ((c = *s++) != '\0')
1380 { 1574 {
1381 if (c == '\n') 1575 if (c == '\n')
1386 else 1580 else
1387 current_input_column++; 1581 current_input_column++;
1388 } 1582 }
1389 } 1583 }
1390 1584
1391 // Include these so that we don't have to link to libfl.a. 1585 bool
1392 1586 lexical_feedback::inside_any_object_index (void)
1393 int
1394 yywrap (void)
1395 {
1396 return 1;
1397 }
1398
1399 // Tell us all what the current buffer is.
1400
1401 YY_BUFFER_STATE
1402 current_buffer (void)
1403 {
1404 return YY_CURRENT_BUFFER;
1405 }
1406
1407 // Create a new buffer.
1408
1409 YY_BUFFER_STATE
1410 create_buffer (FILE *f)
1411 {
1412 return yy_create_buffer (f, YY_BUF_SIZE);
1413 }
1414
1415 // Start reading a new buffer.
1416
1417 void
1418 switch_to_buffer (YY_BUFFER_STATE buf)
1419 {
1420 yy_switch_to_buffer (buf);
1421 }
1422
1423 // Delete a buffer.
1424
1425 void
1426 delete_buffer (YY_BUFFER_STATE buf)
1427 {
1428 yy_delete_buffer (buf);
1429
1430 // Prevent invalid yyin from being used by yyrestart.
1431 if (! current_buffer ())
1432 yyin = 0;
1433 }
1434
1435 // Delete all buffers from the stack.
1436 void
1437 clear_all_buffers (void)
1438 {
1439 while (current_buffer ())
1440 octave_pop_buffer_state ();
1441 }
1442
1443 void
1444 cleanup_parser (void)
1445 {
1446 reset_parser ();
1447
1448 clear_all_buffers ();
1449 }
1450
1451 // Restore a buffer (for unwind-prot).
1452
1453 void
1454 restore_input_buffer (void *buf)
1455 {
1456 switch_to_buffer (static_cast<YY_BUFFER_STATE> (buf));
1457 }
1458
1459 // Delete a buffer (for unwind-prot).
1460
1461 void
1462 delete_input_buffer (void *buf)
1463 {
1464 delete_buffer (static_cast<YY_BUFFER_STATE> (buf));
1465 }
1466
1467 static bool
1468 inside_any_object_index (void)
1469 { 1587 {
1470 bool retval = false; 1588 bool retval = false;
1471 1589
1472 for (std::list<bool>::const_iterator i = lexer_flags.looking_at_object_index.begin (); 1590 for (std::list<bool>::const_iterator i = looking_at_object_index.begin ();
1473 i != lexer_flags.looking_at_object_index.end (); i++) 1591 i != looking_at_object_index.end (); i++)
1474 { 1592 {
1475 if (*i) 1593 if (*i)
1476 { 1594 {
1477 retval = true; 1595 retval = true;
1478 break; 1596 break;
1482 return retval; 1600 return retval;
1483 } 1601 }
1484 1602
1485 // Handle keywords. Return -1 if the keyword should be ignored. 1603 // Handle keywords. Return -1 if the keyword should be ignored.
1486 1604
1487 static int 1605 int
1488 is_keyword_token (const std::string& s) 1606 lexical_feedback::is_keyword_token (const std::string& s)
1489 { 1607 {
1490 int l = input_line_number; 1608 int l = input_line_number;
1491 int c = current_input_column; 1609 int c = current_input_column;
1492 1610
1493 int len = s.length (); 1611 int len = s.length ();
1494 1612
1495 const octave_kw *kw = octave_kw_hash::in_word_set (s.c_str (), len); 1613 const octave_kw *kw = octave_kw_hash::in_word_set (s.c_str (), len);
1496 1614
1497 if (kw) 1615 if (kw)
1498 { 1616 {
1499 yylval.tok_val = 0; 1617 token *tok_val = 0;
1500 1618
1501 switch (kw->kw_id) 1619 switch (kw->kw_id)
1502 { 1620 {
1503 case break_kw: 1621 case break_kw:
1504 case catch_kw: 1622 case catch_kw:
1505 case continue_kw: 1623 case continue_kw:
1506 case else_kw: 1624 case else_kw:
1507 case otherwise_kw: 1625 case otherwise_kw:
1508 case return_kw: 1626 case return_kw:
1509 case unwind_protect_cleanup_kw: 1627 case unwind_protect_cleanup_kw:
1510 lexer_flags.at_beginning_of_statement = true; 1628 at_beginning_of_statement = true;
1511 break; 1629 break;
1512 1630
1513 case static_kw: 1631 case static_kw:
1514 if ((reading_fcn_file || reading_script_file 1632 if ((reading_fcn_file || reading_script_file
1515 || reading_classdef_file) 1633 || reading_classdef_file)
1534 break; 1652 break;
1535 1653
1536 case end_kw: 1654 case end_kw:
1537 if (inside_any_object_index () 1655 if (inside_any_object_index ()
1538 || (! reading_classdef_file 1656 || (! reading_classdef_file
1539 && (lexer_flags.defining_func 1657 && (defining_func
1540 && ! (lexer_flags.looking_at_return_list 1658 && ! (looking_at_return_list
1541 || lexer_flags.parsed_function_name.top ())))) 1659 || parsed_function_name.top ()))))
1542 return 0; 1660 return 0;
1543 1661
1544 yylval.tok_val = new token (token::simple_end, l, c); 1662 tok_val = new token (token::simple_end, l, c);
1545 lexer_flags.at_beginning_of_statement = true; 1663 at_beginning_of_statement = true;
1546 break; 1664 break;
1547 1665
1548 case end_try_catch_kw: 1666 case end_try_catch_kw:
1549 yylval.tok_val = new token (token::try_catch_end, l, c); 1667 tok_val = new token (token::try_catch_end, l, c);
1550 lexer_flags.at_beginning_of_statement = true; 1668 at_beginning_of_statement = true;
1551 break; 1669 break;
1552 1670
1553 case end_unwind_protect_kw: 1671 case end_unwind_protect_kw:
1554 yylval.tok_val = new token (token::unwind_protect_end, l, c); 1672 tok_val = new token (token::unwind_protect_end, l, c);
1555 lexer_flags.at_beginning_of_statement = true; 1673 at_beginning_of_statement = true;
1556 break; 1674 break;
1557 1675
1558 case endfor_kw: 1676 case endfor_kw:
1559 yylval.tok_val = new token (token::for_end, l, c); 1677 tok_val = new token (token::for_end, l, c);
1560 lexer_flags.at_beginning_of_statement = true; 1678 at_beginning_of_statement = true;
1561 break; 1679 break;
1562 1680
1563 case endfunction_kw: 1681 case endfunction_kw:
1564 yylval.tok_val = new token (token::function_end, l, c); 1682 tok_val = new token (token::function_end, l, c);
1565 lexer_flags.at_beginning_of_statement = true; 1683 at_beginning_of_statement = true;
1566 break; 1684 break;
1567 1685
1568 case endif_kw: 1686 case endif_kw:
1569 yylval.tok_val = new token (token::if_end, l, c); 1687 tok_val = new token (token::if_end, l, c);
1570 lexer_flags.at_beginning_of_statement = true; 1688 at_beginning_of_statement = true;
1571 break; 1689 break;
1572 1690
1573 case endparfor_kw: 1691 case endparfor_kw:
1574 yylval.tok_val = new token (token::parfor_end, l, c); 1692 tok_val = new token (token::parfor_end, l, c);
1575 lexer_flags.at_beginning_of_statement = true; 1693 at_beginning_of_statement = true;
1576 break; 1694 break;
1577 1695
1578 case endswitch_kw: 1696 case endswitch_kw:
1579 yylval.tok_val = new token (token::switch_end, l, c); 1697 tok_val = new token (token::switch_end, l, c);
1580 lexer_flags.at_beginning_of_statement = true; 1698 at_beginning_of_statement = true;
1581 break; 1699 break;
1582 1700
1583 case endwhile_kw: 1701 case endwhile_kw:
1584 yylval.tok_val = new token (token::while_end, l, c); 1702 tok_val = new token (token::while_end, l, c);
1585 lexer_flags.at_beginning_of_statement = true; 1703 at_beginning_of_statement = true;
1586 break; 1704 break;
1587 1705
1588 case endclassdef_kw: 1706 case endclassdef_kw:
1589 yylval.tok_val = new token (token::classdef_end, l, c); 1707 tok_val = new token (token::classdef_end, l, c);
1590 lexer_flags.at_beginning_of_statement = true; 1708 at_beginning_of_statement = true;
1591 break; 1709 break;
1592 1710
1593 case endenumeration_kw: 1711 case endenumeration_kw:
1594 yylval.tok_val = new token (token::enumeration_end, l, c); 1712 tok_val = new token (token::enumeration_end, l, c);
1595 lexer_flags.at_beginning_of_statement = true; 1713 at_beginning_of_statement = true;
1596 break; 1714 break;
1597 1715
1598 case endevents_kw: 1716 case endevents_kw:
1599 yylval.tok_val = new token (token::events_end, l, c); 1717 tok_val = new token (token::events_end, l, c);
1600 lexer_flags.at_beginning_of_statement = true; 1718 at_beginning_of_statement = true;
1601 break; 1719 break;
1602 1720
1603 case endmethods_kw: 1721 case endmethods_kw:
1604 yylval.tok_val = new token (token::methods_end, l, c); 1722 tok_val = new token (token::methods_end, l, c);
1605 lexer_flags.at_beginning_of_statement = true; 1723 at_beginning_of_statement = true;
1606 break; 1724 break;
1607 1725
1608 case endproperties_kw: 1726 case endproperties_kw:
1609 yylval.tok_val = new token (token::properties_end, l, c); 1727 tok_val = new token (token::properties_end, l, c);
1610 lexer_flags.at_beginning_of_statement = true; 1728 at_beginning_of_statement = true;
1611 break; 1729 break;
1612 1730
1613 1731
1614 case for_kw: 1732 case for_kw:
1615 case parfor_kw: 1733 case parfor_kw:
1616 case while_kw: 1734 case while_kw:
1617 promptflag--; 1735 promptflag--;
1618 lexer_flags.looping++; 1736 looping++;
1619 break; 1737 break;
1620 1738
1621 case do_kw: 1739 case do_kw:
1622 lexer_flags.at_beginning_of_statement = true; 1740 at_beginning_of_statement = true;
1623 promptflag--; 1741 promptflag--;
1624 lexer_flags.looping++; 1742 looping++;
1625 break; 1743 break;
1626 1744
1627 case try_kw: 1745 case try_kw:
1628 case unwind_protect_kw: 1746 case unwind_protect_kw:
1629 lexer_flags.at_beginning_of_statement = true; 1747 at_beginning_of_statement = true;
1630 promptflag--; 1748 promptflag--;
1631 break; 1749 break;
1632 1750
1633 case if_kw: 1751 case if_kw:
1634 case switch_kw: 1752 case switch_kw:
1637 1755
1638 case get_kw: 1756 case get_kw:
1639 case set_kw: 1757 case set_kw:
1640 // 'get' and 'set' are keywords in classdef method 1758 // 'get' and 'set' are keywords in classdef method
1641 // declarations. 1759 // declarations.
1642 if (! lexer_flags.maybe_classdef_get_set_method) 1760 if (! maybe_classdef_get_set_method)
1643 return 0; 1761 return 0;
1644 break; 1762 break;
1645 1763
1646 case enumeration_kw: 1764 case enumeration_kw:
1647 case events_kw: 1765 case events_kw:
1648 case methods_kw: 1766 case methods_kw:
1649 case properties_kw: 1767 case properties_kw:
1650 // 'properties', 'methods' and 'events' are keywords for 1768 // 'properties', 'methods' and 'events' are keywords for
1651 // classdef blocks. 1769 // classdef blocks.
1652 if (! lexer_flags.parsing_classdef) 1770 if (! parsing_classdef)
1653 return 0; 1771 return 0;
1654 // fall through ... 1772 // fall through ...
1655 1773
1656 case classdef_kw: 1774 case classdef_kw:
1657 // 'classdef' is always a keyword. 1775 // 'classdef' is always a keyword.
1659 break; 1777 break;
1660 1778
1661 case function_kw: 1779 case function_kw:
1662 promptflag--; 1780 promptflag--;
1663 1781
1664 lexer_flags.defining_func++; 1782 defining_func++;
1665 lexer_flags.parsed_function_name.push (false); 1783 parsed_function_name.push (false);
1666 1784
1667 if (! (reading_fcn_file || reading_script_file 1785 if (! (reading_fcn_file || reading_script_file
1668 || reading_classdef_file)) 1786 || reading_classdef_file))
1669 input_line_number = 1; 1787 input_line_number = 1;
1670 break; 1788 break;
1672 case magic_file_kw: 1790 case magic_file_kw:
1673 { 1791 {
1674 if ((reading_fcn_file || reading_script_file 1792 if ((reading_fcn_file || reading_script_file
1675 || reading_classdef_file) 1793 || reading_classdef_file)
1676 && ! curr_fcn_file_full_name.empty ()) 1794 && ! curr_fcn_file_full_name.empty ())
1677 yylval.tok_val = new token (curr_fcn_file_full_name, l, c); 1795 tok_val = new token (curr_fcn_file_full_name, l, c);
1678 else 1796 else
1679 yylval.tok_val = new token ("stdin", l, c); 1797 tok_val = new token ("stdin", l, c);
1680 } 1798 }
1681 break; 1799 break;
1682 1800
1683 case magic_line_kw: 1801 case magic_line_kw:
1684 yylval.tok_val = new token (static_cast<double> (l), "", l, c); 1802 tok_val = new token (static_cast<double> (l), "", l, c);
1685 break; 1803 break;
1686 1804
1687 default: 1805 default:
1688 panic_impossible (); 1806 panic_impossible ();
1689 } 1807 }
1690 1808
1691 if (! yylval.tok_val) 1809 if (! tok_val)
1692 yylval.tok_val = new token (l, c); 1810 tok_val = new token (l, c);
1693 1811
1694 token_stack.push (yylval.tok_val); 1812 push_token (tok_val);
1695 1813
1696 return kw->tok; 1814 return kw->tok;
1697 } 1815 }
1698 1816
1699 return 0; 1817 return 0;
1700 } 1818 }
1701 1819
1702 static bool 1820 bool
1703 is_variable (const std::string& name) 1821 lexical_feedback::is_variable (const std::string& name)
1704 { 1822 {
1705 return (symbol_table::is_variable (name) 1823 return (symbol_table::is_variable (name)
1706 || (lexer_flags.pending_local_variables.find (name) 1824 || (pending_local_variables.find (name)
1707 != lexer_flags.pending_local_variables.end ())); 1825 != pending_local_variables.end ()));
1708 } 1826 }
1709 1827
1710 static std::string 1828 std::string
1711 grab_block_comment (stream_reader& reader, bool& eof) 1829 lexical_feedback::grab_block_comment (stream_reader& reader, bool& eof)
1712 { 1830 {
1713 std::string buf; 1831 std::string buf;
1714 1832
1715 bool at_bol = true; 1833 bool at_bol = true;
1716 bool look_for_marker = false; 1834 bool look_for_marker = false;
1812 1930
1813 return buf; 1931 return buf;
1814 } 1932 }
1815 1933
1816 std::string 1934 std::string
1817 grab_comment_block (stream_reader& reader, bool at_bol, 1935 lexical_feedback::grab_comment_block (stream_reader& reader, bool at_bol,
1818 bool& eof) 1936 bool& eof)
1819 { 1937 {
1820 std::string buf; 1938 std::string buf;
1821 1939
1822 // TRUE means we are at the beginning of a comment block. 1940 // TRUE means we are at the beginning of a comment block.
1823 bool begin_comment = false; 1941 bool begin_comment = false;
1951 eof = true; 2069 eof = true;
1952 2070
1953 return buf; 2071 return buf;
1954 } 2072 }
1955 2073
1956 class 2074 int
1957 flex_stream_reader : public stream_reader 2075 lexical_feedback::process_comment (bool start_in_block, bool& eof)
1958 { 2076 {
1959 public: 2077 OCTAVE_YYG;
1960 flex_stream_reader (char *buf_arg) : stream_reader (), buf (buf_arg) { } 2078
1961
1962 int getc (void) { return ::text_yyinput (); }
1963 int ungetc (int c) { ::xunput (c, buf); return 0; }
1964
1965 private:
1966
1967 // No copying!
1968
1969 flex_stream_reader (const flex_stream_reader&);
1970
1971 flex_stream_reader& operator = (const flex_stream_reader&);
1972
1973 char *buf;
1974 };
1975
1976 static int
1977 process_comment (bool start_in_block, bool& eof)
1978 {
1979 eof = false; 2079 eof = false;
1980 2080
1981 std::string help_txt; 2081 std::string help_txt;
1982 2082
1983 if (! help_buf.empty ()) 2083 if (! help_buf.empty ())
1984 help_txt = help_buf.top (); 2084 help_txt = help_buf.top ();
1985 2085
1986 flex_stream_reader flex_reader (yytext); 2086 char *yytxt = flex_yytext ();
2087 flex_stream_reader flex_reader (this, yytxt);
1987 2088
1988 // process_comment is only supposed to be called when we are not 2089 // process_comment is only supposed to be called when we are not
1989 // initially looking at a block comment. 2090 // initially looking at a block comment.
1990 2091
1991 std::string txt = start_in_block 2092 std::string txt = start_in_block
2004 } 2105 }
2005 2106
2006 octave_comment_buffer::append (txt); 2107 octave_comment_buffer::append (txt);
2007 2108
2008 current_input_column = 1; 2109 current_input_column = 1;
2009 lexer_flags.quote_is_transpose = false; 2110 quote_is_transpose = false;
2010 lexer_flags.convert_spaces_to_comma = true; 2111 convert_spaces_to_comma = true;
2011 lexer_flags.at_beginning_of_statement = true; 2112 at_beginning_of_statement = true;
2012 2113
2013 if (YY_START == COMMAND_START) 2114 if (YY_START == COMMAND_START)
2014 BEGIN (INITIAL); 2115 BEGIN (INITIAL);
2015 2116
2016 if (nesting_level.none ()) 2117 if (nesting_level.none ())
2019 return ';'; 2120 return ';';
2020 else 2121 else
2021 return 0; 2122 return 0;
2022 } 2123 }
2023 2124
2024 // Return 1 if the given character matches any character in the given
2025 // string.
2026
2027 static bool
2028 match_any (char c, const char *s)
2029 {
2030 char tmp;
2031 while ((tmp = *s++) != '\0')
2032 {
2033 if (c == tmp)
2034 return true;
2035 }
2036 return false;
2037 }
2038
2039 // Given information about the spacing surrounding an operator,
2040 // return 1 if it looks like it should be treated as a binary
2041 // operator. For example,
2042 //
2043 // [ 1 + 2 ] or [ 1+ 2] or [ 1+2 ] ==> binary
2044 //
2045 // [ 1 +2 ] ==> unary
2046
2047 static bool
2048 looks_like_bin_op (bool spc_prev, int next_char)
2049 {
2050 bool spc_next = (next_char == ' ' || next_char == '\t');
2051
2052 return ((spc_prev && spc_next) || ! spc_prev);
2053 }
2054
2055 // Recognize separators. If the separator is a CRLF pair, it is 2125 // Recognize separators. If the separator is a CRLF pair, it is
2056 // replaced by a single LF. 2126 // replaced by a single LF.
2057 2127
2058 static bool 2128 bool
2059 next_token_is_sep_op (void) 2129 lexical_feedback::next_token_is_sep_op (void)
2060 { 2130 {
2061 bool retval = false; 2131 bool retval = false;
2062 2132
2063 int c = text_yyinput (); 2133 int c = text_yyinput ();
2064 2134
2065 retval = match_any (c, ",;\n]"); 2135 retval = match_any (c, ",;\n]");
2066 2136
2067 xunput (c, yytext); 2137 xunput (c);
2068 2138
2069 return retval; 2139 return retval;
2070 } 2140 }
2071 2141
2072 // Try to determine if the next token should be treated as a postfix 2142 // Try to determine if the next token should be treated as a postfix
2073 // unary operator. This is ugly, but it seems to do the right thing. 2143 // unary operator. This is ugly, but it seems to do the right thing.
2074 2144
2075 static bool 2145 bool
2076 next_token_is_postfix_unary_op (bool spc_prev) 2146 lexical_feedback::next_token_is_postfix_unary_op (bool spc_prev)
2077 { 2147 {
2078 bool un_op = false; 2148 bool un_op = false;
2079 2149
2080 int c0 = text_yyinput (); 2150 int c0 = text_yyinput ();
2081 2151
2085 } 2155 }
2086 else if (c0 == '.') 2156 else if (c0 == '.')
2087 { 2157 {
2088 int c1 = text_yyinput (); 2158 int c1 = text_yyinput ();
2089 un_op = (c1 == '\''); 2159 un_op = (c1 == '\'');
2090 xunput (c1, yytext); 2160 xunput (c1);
2091 } 2161 }
2092 else if (c0 == '+') 2162 else if (c0 == '+')
2093 { 2163 {
2094 int c1 = text_yyinput (); 2164 int c1 = text_yyinput ();
2095 un_op = (c1 == '+'); 2165 un_op = (c1 == '+');
2096 xunput (c1, yytext); 2166 xunput (c1);
2097 } 2167 }
2098 else if (c0 == '-') 2168 else if (c0 == '-')
2099 { 2169 {
2100 int c1 = text_yyinput (); 2170 int c1 = text_yyinput ();
2101 un_op = (c1 == '-'); 2171 un_op = (c1 == '-');
2102 xunput (c1, yytext); 2172 xunput (c1);
2103 } 2173 }
2104 2174
2105 xunput (c0, yytext); 2175 xunput (c0);
2106 2176
2107 return un_op; 2177 return un_op;
2108 } 2178 }
2109 2179
2110 // Try to determine if the next token should be treated as a binary 2180 // Try to determine if the next token should be treated as a binary
2117 // 2187 //
2118 // Note that a line continuation directly following a + or - operator 2188 // Note that a line continuation directly following a + or - operator
2119 // (e.g., the characters '[' 'a' ' ' '+' '\' LFD 'b' ']') will be 2189 // (e.g., the characters '[' 'a' ' ' '+' '\' LFD 'b' ']') will be
2120 // parsed as a binary operator. 2190 // parsed as a binary operator.
2121 2191
2122 static bool 2192 bool
2123 next_token_is_bin_op (bool spc_prev) 2193 lexical_feedback::next_token_is_bin_op (bool spc_prev)
2124 { 2194 {
2125 bool bin_op = false; 2195 bool bin_op = false;
2126 2196
2127 int c0 = text_yyinput (); 2197 int c0 = text_yyinput ();
2128 2198
2149 // Could be either, spacing matters. 2219 // Could be either, spacing matters.
2150 bin_op = looks_like_bin_op (spc_prev, c1); 2220 bin_op = looks_like_bin_op (spc_prev, c1);
2151 break; 2221 break;
2152 } 2222 }
2153 2223
2154 xunput (c1, yytext); 2224 xunput (c1);
2155 } 2225 }
2156 break; 2226 break;
2157 2227
2158 case ':': 2228 case ':':
2159 case '/': 2229 case '/':
2173 bin_op = true; 2243 bin_op = true;
2174 else if (! isdigit (c1) && c1 != ' ' && c1 != '\t' && c1 != '.') 2244 else if (! isdigit (c1) && c1 != ' ' && c1 != '\t' && c1 != '.')
2175 // A structure element reference is a binary op. 2245 // A structure element reference is a binary op.
2176 bin_op = true; 2246 bin_op = true;
2177 2247
2178 xunput (c1, yytext); 2248 xunput (c1);
2179 } 2249 }
2180 break; 2250 break;
2181 2251
2182 // = == & && | || * ** 2252 // = == & && | || * **
2183 case '=': 2253 case '=':
2203 2273
2204 // ~ and ! can be unary ops, so require following =. 2274 // ~ and ! can be unary ops, so require following =.
2205 if (c1 == '=') 2275 if (c1 == '=')
2206 bin_op = true; 2276 bin_op = true;
2207 2277
2208 xunput (c1, yytext); 2278 xunput (c1);
2209 } 2279 }
2210 break; 2280 break;
2211 2281
2212 default: 2282 default:
2213 break; 2283 break;
2214 } 2284 }
2215 2285
2216 xunput (c0, yytext); 2286 xunput (c0);
2217 2287
2218 return bin_op; 2288 return bin_op;
2219 } 2289 }
2220 2290
2221 // Used to delete trailing white space from tokens.
2222
2223 static std::string
2224 strip_trailing_whitespace (char *s)
2225 {
2226 std::string retval = s;
2227
2228 size_t pos = retval.find_first_of (" \t");
2229
2230 if (pos != std::string::npos)
2231 retval.resize (pos);
2232
2233 return retval;
2234 }
2235
2236 // FIXME -- we need to handle block comments here. 2291 // FIXME -- we need to handle block comments here.
2237 2292
2238 static void 2293 void
2239 scan_for_comments (const char *text) 2294 lexical_feedback::scan_for_comments (const char *text)
2240 { 2295 {
2241 std::string comment_buf; 2296 std::string comment_buf;
2242 2297
2243 bool in_comment = false; 2298 bool in_comment = false;
2244 bool beginning_of_comment = false; 2299 bool beginning_of_comment = false;
2291 if (! comment_buf.empty ()) 2346 if (! comment_buf.empty ())
2292 octave_comment_buffer::append (comment_buf); 2347 octave_comment_buffer::append (comment_buf);
2293 } 2348 }
2294 2349
2295 // Discard whitespace, including comments and continuations. 2350 // Discard whitespace, including comments and continuations.
2296 //
2297 // Return value is logical OR of the following values:
2298 //
2299 // ATE_NOTHING : no spaces to eat
2300 // ATE_SPACE_OR_TAB : space or tab in input
2301 // ATE_NEWLINE : bare new line in input
2302 2351
2303 // FIXME -- we need to handle block comments here. 2352 // FIXME -- we need to handle block comments here.
2304 2353
2305 static yum_yum 2354 int
2306 eat_whitespace (void) 2355 lexical_feedback::eat_whitespace (void)
2307 { 2356 {
2308 yum_yum retval = ATE_NOTHING; 2357 int retval = lexical_feedback::NO_WHITESPACE;
2309 2358
2310 std::string comment_buf; 2359 std::string comment_buf;
2311 2360
2312 bool in_comment = false; 2361 bool in_comment = false;
2313 bool beginning_of_comment = false; 2362 bool beginning_of_comment = false;
2325 if (in_comment) 2374 if (in_comment)
2326 { 2375 {
2327 comment_buf += static_cast<char> (c); 2376 comment_buf += static_cast<char> (c);
2328 beginning_of_comment = false; 2377 beginning_of_comment = false;
2329 } 2378 }
2330 retval |= ATE_SPACE_OR_TAB; 2379 retval |= lexical_feedback::SPACE_OR_TAB;
2331 break; 2380 break;
2332 2381
2333 case '\n': 2382 case '\n':
2334 retval |= ATE_NEWLINE; 2383 retval |= lexical_feedback::NEWLINE;
2335 if (in_comment) 2384 if (in_comment)
2336 { 2385 {
2337 comment_buf += static_cast<char> (c); 2386 comment_buf += static_cast<char> (c);
2338 octave_comment_buffer::append (comment_buf); 2387 octave_comment_buffer::append (comment_buf);
2339 comment_buf.resize (0); 2388 comment_buf.resize (0);
2402 2451
2403 if (! comment_buf.empty ()) 2452 if (! comment_buf.empty ())
2404 octave_comment_buffer::append (comment_buf); 2453 octave_comment_buffer::append (comment_buf);
2405 2454
2406 done: 2455 done:
2407 xunput (c, yytext); 2456 xunput (c);
2408 current_input_column--; 2457 current_input_column--;
2409 return retval; 2458 return retval;
2410 } 2459 }
2411 2460
2412 static inline bool 2461 static inline bool
2413 looks_like_hex (const char *s, int len) 2462 looks_like_hex (const char *s, int len)
2414 { 2463 {
2415 return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')); 2464 return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
2416 } 2465 }
2417 2466
2418 static void 2467 void
2419 handle_number (void) 2468 lexical_feedback::handle_number (void)
2420 { 2469 {
2421 double value = 0.0; 2470 double value = 0.0;
2422 int nread = 0; 2471 int nread = 0;
2423 2472
2424 if (looks_like_hex (yytext, strlen (yytext))) 2473 char *yytxt = flex_yytext ();
2474
2475 if (looks_like_hex (yytxt, strlen (yytxt)))
2425 { 2476 {
2426 unsigned long ival; 2477 unsigned long ival;
2427 2478
2428 nread = sscanf (yytext, "%lx", &ival); 2479 nread = sscanf (yytxt, "%lx", &ival);
2429 2480
2430 value = static_cast<double> (ival); 2481 value = static_cast<double> (ival);
2431 } 2482 }
2432 else 2483 else
2433 { 2484 {
2434 char *tmp = strsave (yytext); 2485 char *tmp = strsave (yytxt);
2435 2486
2436 char *idx = strpbrk (tmp, "Dd"); 2487 char *idx = strpbrk (tmp, "Dd");
2437 2488
2438 if (idx) 2489 if (idx)
2439 *idx = 'e'; 2490 *idx = 'e';
2445 2496
2446 // If yytext doesn't contain a valid number, we are in deep doo doo. 2497 // If yytext doesn't contain a valid number, we are in deep doo doo.
2447 2498
2448 assert (nread == 1); 2499 assert (nread == 1);
2449 2500
2450 lexer_flags.quote_is_transpose = true; 2501 quote_is_transpose = true;
2451 lexer_flags.convert_spaces_to_comma = true; 2502 convert_spaces_to_comma = true;
2452 lexer_flags.looking_for_object_index = false; 2503 looking_for_object_index = false;
2453 lexer_flags.at_beginning_of_statement = false; 2504 at_beginning_of_statement = false;
2454 2505
2455 yylval.tok_val = new token (value, yytext, input_line_number, 2506 push_token (new token (value, yytxt, input_line_number,
2456 current_input_column); 2507 current_input_column));
2457 2508
2458 token_stack.push (yylval.tok_val); 2509 current_input_column += flex_yyleng ();
2459
2460 current_input_column += yyleng;
2461 2510
2462 do_comma_insert_check (); 2511 do_comma_insert_check ();
2463 } 2512 }
2464 2513
2465 // We have seen a backslash and need to find out if it should be 2514 // We have seen a backslash and need to find out if it should be
2471 // If non-whitespace characters are found before comment 2520 // If non-whitespace characters are found before comment
2472 // characters, return 0. Otherwise, return 1. 2521 // characters, return 0. Otherwise, return 1.
2473 2522
2474 // FIXME -- we need to handle block comments here. 2523 // FIXME -- we need to handle block comments here.
2475 2524
2476 static bool 2525 bool
2477 have_continuation (bool trailing_comments_ok) 2526 lexical_feedback::have_continuation (bool trailing_comments_ok)
2478 { 2527 {
2479 std::ostringstream buf; 2528 std::ostringstream buf;
2480 2529
2481 std::string comment_buf; 2530 std::string comment_buf;
2482 2531
2541 goto cleanup; 2590 goto cleanup;
2542 break; 2591 break;
2543 } 2592 }
2544 } 2593 }
2545 2594
2546 xunput (c, yytext); 2595 xunput (c);
2547 return false; 2596 return false;
2548 2597
2549 cleanup: 2598 cleanup:
2550 2599
2551 std::string s = buf.str (); 2600 std::string s = buf.str ();
2552 2601
2553 int len = s.length (); 2602 int len = s.length ();
2554 while (len--) 2603 while (len--)
2555 xunput (s[len], yytext); 2604 xunput (s[len]);
2556 2605
2557 return false; 2606 return false;
2558 } 2607 }
2559 2608
2560 // We have seen a '.' and need to see if it is the start of a 2609 // We have seen a '.' and need to see if it is the start of a
2561 // continuation. If so, this eats it, up to and including the new 2610 // continuation. If so, this eats it, up to and including the new
2562 // line character. 2611 // line character.
2563 2612
2564 static bool 2613 bool
2565 have_ellipsis_continuation (bool trailing_comments_ok) 2614 lexical_feedback::have_ellipsis_continuation (bool trailing_comments_ok)
2566 { 2615 {
2567 char c1 = text_yyinput (); 2616 char c1 = text_yyinput ();
2568 if (c1 == '.') 2617 if (c1 == '.')
2569 { 2618 {
2570 char c2 = text_yyinput (); 2619 char c2 = text_yyinput ();
2571 if (c2 == '.' && have_continuation (trailing_comments_ok)) 2620 if (c2 == '.' && have_continuation (trailing_comments_ok))
2572 return true; 2621 return true;
2573 else 2622 else
2574 { 2623 {
2575 xunput (c2, yytext); 2624 xunput (c2);
2576 xunput (c1, yytext); 2625 xunput (c1);
2577 } 2626 }
2578 } 2627 }
2579 else 2628 else
2580 xunput (c1, yytext); 2629 xunput (c1);
2581 2630
2582 return false; 2631 return false;
2583 } 2632 }
2584 2633
2585 // See if we have a continuation line. If so, eat it and the leading 2634 // See if we have a continuation line. If so, eat it and the leading
2586 // whitespace on the next line. 2635 // whitespace on the next line.
2587 // 2636
2588 // Return value is the same as described for eat_whitespace(). 2637 int
2589 2638 lexical_feedback::eat_continuation (void)
2590 static yum_yum 2639 {
2591 eat_continuation (void) 2640 int retval = lexical_feedback::NO_WHITESPACE;
2592 {
2593 int retval = ATE_NOTHING;
2594 2641
2595 int c = text_yyinput (); 2642 int c = text_yyinput ();
2596 2643
2597 if ((c == '.' && have_ellipsis_continuation ()) 2644 if ((c == '.' && have_ellipsis_continuation ())
2598 || (c == '\\' && have_continuation ())) 2645 || (c == '\\' && have_continuation ()))
2599 retval = eat_whitespace (); 2646 retval = eat_whitespace ();
2600 else 2647 else
2601 xunput (c, yytext); 2648 xunput (c);
2602 2649
2603 return retval; 2650 return retval;
2604 } 2651 }
2605 2652
2606 static int 2653 int
2607 handle_string (char delim) 2654 lexical_feedback::handle_string (char delim)
2608 { 2655 {
2609 std::ostringstream buf; 2656 std::ostringstream buf;
2610 2657
2611 int bos_line = input_line_number; 2658 int bos_line = input_line_number;
2612 int bos_col = current_input_column; 2659 int bos_col = current_input_column;
2659 buf << static_cast<char> (c); 2706 buf << static_cast<char> (c);
2660 } 2707 }
2661 else 2708 else
2662 { 2709 {
2663 std::string s; 2710 std::string s;
2664 xunput (c, yytext); 2711 xunput (c);
2665 2712
2666 if (delim == '\'') 2713 if (delim == '\'')
2667 s = buf.str (); 2714 s = buf.str ();
2668 else 2715 else
2669 s = do_string_escapes (buf.str ()); 2716 s = do_string_escapes (buf.str ());
2670 2717
2671 lexer_flags.quote_is_transpose = true; 2718 quote_is_transpose = true;
2672 lexer_flags.convert_spaces_to_comma = true; 2719 convert_spaces_to_comma = true;
2673 2720
2674 yylval.tok_val = new token (s, bos_line, bos_col); 2721 push_token (new token (s, bos_line, bos_col));
2675 token_stack.push (yylval.tok_val);
2676 2722
2677 if (delim == '"') 2723 if (delim == '"')
2678 gripe_matlab_incompatible ("\" used as string delimiter"); 2724 gripe_matlab_incompatible ("\" used as string delimiter");
2679 else if (delim == '\'') 2725 else if (delim == '\'')
2680 gripe_single_quote_string (); 2726 gripe_single_quote_string ();
2681 2727
2682 lexer_flags.looking_for_object_index = true; 2728 looking_for_object_index = true;
2683 lexer_flags.at_beginning_of_statement = false; 2729 at_beginning_of_statement = false;
2684 2730
2685 return delim == '"' ? DQ_STRING : SQ_STRING; 2731 return delim == '"' ? DQ_STRING : SQ_STRING;
2686 } 2732 }
2687 } 2733 }
2688 } 2734 }
2695 } 2741 }
2696 2742
2697 return LEXICAL_ERROR; 2743 return LEXICAL_ERROR;
2698 } 2744 }
2699 2745
2700 static bool 2746 bool
2701 next_token_is_assign_op (void) 2747 lexical_feedback::next_token_is_assign_op (void)
2702 { 2748 {
2703 bool retval = false; 2749 bool retval = false;
2704 2750
2705 int c0 = text_yyinput (); 2751 int c0 = text_yyinput ();
2706 2752
2707 switch (c0) 2753 switch (c0)
2708 { 2754 {
2709 case '=': 2755 case '=':
2710 { 2756 {
2711 int c1 = text_yyinput (); 2757 int c1 = text_yyinput ();
2712 xunput (c1, yytext); 2758 xunput (c1);
2713 if (c1 != '=') 2759 if (c1 != '=')
2714 retval = true; 2760 retval = true;
2715 } 2761 }
2716 break; 2762 break;
2717 2763
2722 case '\\': 2768 case '\\':
2723 case '&': 2769 case '&':
2724 case '|': 2770 case '|':
2725 { 2771 {
2726 int c1 = text_yyinput (); 2772 int c1 = text_yyinput ();
2727 xunput (c1, yytext); 2773 xunput (c1);
2728 if (c1 == '=') 2774 if (c1 == '=')
2729 retval = true; 2775 retval = true;
2730 } 2776 }
2731 break; 2777 break;
2732 2778
2734 { 2780 {
2735 int c1 = text_yyinput (); 2781 int c1 = text_yyinput ();
2736 if (match_any (c1, "+-*/\\")) 2782 if (match_any (c1, "+-*/\\"))
2737 { 2783 {
2738 int c2 = text_yyinput (); 2784 int c2 = text_yyinput ();
2739 xunput (c2, yytext); 2785 xunput (c2);
2740 if (c2 == '=') 2786 if (c2 == '=')
2741 retval = true; 2787 retval = true;
2742 } 2788 }
2743 xunput (c1, yytext); 2789 xunput (c1);
2744 } 2790 }
2745 break; 2791 break;
2746 2792
2747 case '>': 2793 case '>':
2748 { 2794 {
2749 int c1 = text_yyinput (); 2795 int c1 = text_yyinput ();
2750 if (c1 == '>') 2796 if (c1 == '>')
2751 { 2797 {
2752 int c2 = text_yyinput (); 2798 int c2 = text_yyinput ();
2753 xunput (c2, yytext); 2799 xunput (c2);
2754 if (c2 == '=') 2800 if (c2 == '=')
2755 retval = true; 2801 retval = true;
2756 } 2802 }
2757 xunput (c1, yytext); 2803 xunput (c1);
2758 } 2804 }
2759 break; 2805 break;
2760 2806
2761 case '<': 2807 case '<':
2762 { 2808 {
2763 int c1 = text_yyinput (); 2809 int c1 = text_yyinput ();
2764 if (c1 == '<') 2810 if (c1 == '<')
2765 { 2811 {
2766 int c2 = text_yyinput (); 2812 int c2 = text_yyinput ();
2767 xunput (c2, yytext); 2813 xunput (c2);
2768 if (c2 == '=') 2814 if (c2 == '=')
2769 retval = true; 2815 retval = true;
2770 } 2816 }
2771 xunput (c1, yytext); 2817 xunput (c1);
2772 } 2818 }
2773 break; 2819 break;
2774 2820
2775 default: 2821 default:
2776 break; 2822 break;
2777 } 2823 }
2778 2824
2779 xunput (c0, yytext); 2825 xunput (c0);
2780 2826
2781 return retval; 2827 return retval;
2782 } 2828 }
2783 2829
2784 static bool 2830 bool
2785 next_token_is_index_op (void) 2831 lexical_feedback::next_token_is_index_op (void)
2786 { 2832 {
2787 int c = text_yyinput (); 2833 int c = text_yyinput ();
2788 xunput (c, yytext); 2834 xunput (c);
2789 return c == '(' || c == '{'; 2835 return c == '(' || c == '{';
2790 } 2836 }
2791 2837
2792 static int 2838 int
2793 handle_close_bracket (bool spc_gobbled, int bracket_type) 2839 lexical_feedback::handle_close_bracket (bool spc_gobbled, int bracket_type)
2794 { 2840 {
2841 OCTAVE_YYG;
2842
2795 int retval = bracket_type; 2843 int retval = bracket_type;
2796 2844
2797 if (! nesting_level.none ()) 2845 if (! nesting_level.none ())
2798 { 2846 {
2799 nesting_level.remove (); 2847 nesting_level.remove ();
2800 2848
2801 if (bracket_type == ']') 2849 if (bracket_type == ']')
2802 lexer_flags.bracketflag--; 2850 bracketflag--;
2803 else if (bracket_type == '}') 2851 else if (bracket_type == '}')
2804 lexer_flags.braceflag--; 2852 braceflag--;
2805 else 2853 else
2806 panic_impossible (); 2854 panic_impossible ();
2807 } 2855 }
2808 2856
2809 if (lexer_flags.bracketflag == 0 && lexer_flags.braceflag == 0) 2857 if (bracketflag == 0 && braceflag == 0)
2810 BEGIN (INITIAL); 2858 BEGIN (INITIAL);
2811 2859
2812 if (bracket_type == ']' 2860 if (bracket_type == ']'
2813 && next_token_is_assign_op () 2861 && next_token_is_assign_op ()
2814 && ! lexer_flags.looking_at_return_list) 2862 && ! looking_at_return_list)
2815 { 2863 {
2816 retval = CLOSE_BRACE; 2864 retval = CLOSE_BRACE;
2817 } 2865 }
2818 else if ((lexer_flags.bracketflag || lexer_flags.braceflag) 2866 else if ((bracketflag || braceflag)
2819 && lexer_flags.convert_spaces_to_comma 2867 && convert_spaces_to_comma
2820 && (nesting_level.is_bracket () 2868 && (nesting_level.is_bracket ()
2821 || (nesting_level.is_brace () 2869 || (nesting_level.is_brace ()
2822 && ! lexer_flags.looking_at_object_index.front ()))) 2870 && ! looking_at_object_index.front ())))
2823 { 2871 {
2824 bool index_op = next_token_is_index_op (); 2872 bool index_op = next_token_is_index_op ();
2825 2873
2826 // Don't insert comma if we are looking at something like 2874 // Don't insert comma if we are looking at something like
2827 // 2875 //
2841 2889
2842 if (! (postfix_un_op || bin_op || sep_op)) 2890 if (! (postfix_un_op || bin_op || sep_op))
2843 { 2891 {
2844 maybe_warn_separator_insert (','); 2892 maybe_warn_separator_insert (',');
2845 2893
2846 xunput (',', yytext); 2894 xunput (',');
2847 return retval; 2895 return retval;
2848 } 2896 }
2849 } 2897 }
2850 } 2898 }
2851 2899
2852 lexer_flags.quote_is_transpose = true; 2900 quote_is_transpose = true;
2853 lexer_flags.convert_spaces_to_comma = true; 2901 convert_spaces_to_comma = true;
2854 2902
2855 return retval; 2903 return retval;
2856 } 2904 }
2857 2905
2858 static void 2906 void
2859 maybe_unput_comma (int spc_gobbled) 2907 lexical_feedback::maybe_unput_comma (int spc_gobbled)
2860 { 2908 {
2861 if (nesting_level.is_bracket () 2909 if (nesting_level.is_bracket ()
2862 || (nesting_level.is_brace () 2910 || (nesting_level.is_brace ()
2863 && ! lexer_flags.looking_at_object_index.front ())) 2911 && ! looking_at_object_index.front ()))
2864 { 2912 {
2865 int bin_op = next_token_is_bin_op (spc_gobbled); 2913 int bin_op = next_token_is_bin_op (spc_gobbled);
2866 2914
2867 int postfix_un_op = next_token_is_postfix_unary_op (spc_gobbled); 2915 int postfix_un_op = next_token_is_postfix_unary_op (spc_gobbled);
2868 2916
2869 int c1 = text_yyinput (); 2917 int c1 = text_yyinput ();
2870 int c2 = text_yyinput (); 2918 int c2 = text_yyinput ();
2871 2919
2872 xunput (c2, yytext); 2920 xunput (c2);
2873 xunput (c1, yytext); 2921 xunput (c1);
2874 2922
2875 int sep_op = next_token_is_sep_op (); 2923 int sep_op = next_token_is_sep_op ();
2876 2924
2877 int dot_op = (c1 == '.' 2925 int dot_op = (c1 == '.'
2878 && (isalpha (c2) || isspace (c2) || c2 == '_')); 2926 && (isalpha (c2) || isspace (c2) || c2 == '_'));
2888 if (index_op && ! spc_gobbled) 2936 if (index_op && ! spc_gobbled)
2889 return; 2937 return;
2890 2938
2891 maybe_warn_separator_insert (','); 2939 maybe_warn_separator_insert (',');
2892 2940
2893 xunput (',', yytext); 2941 xunput (',');
2894 } 2942 }
2895 } 2943 }
2896 2944
2897 static bool 2945 bool
2898 next_token_can_follow_bin_op (void) 2946 lexical_feedback::next_token_can_follow_bin_op (void)
2899 { 2947 {
2900 std::stack<char> buf; 2948 std::stack<char> buf;
2901 2949
2902 int c = EOF; 2950 int c = EOF;
2903 2951
2913 } 2961 }
2914 2962
2915 // Restore input. 2963 // Restore input.
2916 while (! buf.empty ()) 2964 while (! buf.empty ())
2917 { 2965 {
2918 xunput (buf.top (), yytext); 2966 xunput (buf.top ());
2919 2967
2920 buf.pop (); 2968 buf.pop ();
2921 } 2969 }
2922 2970
2923 return (isalnum (c) || match_any (c, "!\"'(-[_{~")); 2971 return (isalnum (c) || match_any (c, "!\"'(-[_{~"));
2934 || tok == "J" || tok == "j" 2982 || tok == "J" || tok == "j"
2935 || tok == "Inf" || tok == "inf" 2983 || tok == "Inf" || tok == "inf"
2936 || tok == "NaN" || tok == "nan"); 2984 || tok == "NaN" || tok == "nan");
2937 } 2985 }
2938 2986
2939 static bool 2987 bool
2940 looks_like_command_arg (void) 2988 lexical_feedback::looks_like_command_arg (void)
2941 { 2989 {
2942 bool retval = true; 2990 bool retval = true;
2943 2991
2944 int c0 = text_yyinput (); 2992 int c0 = text_yyinput ();
2945 2993
2956 3004
2957 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3005 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
2958 && next_token_can_follow_bin_op ()) 3006 && next_token_can_follow_bin_op ())
2959 retval = false; 3007 retval = false;
2960 3008
2961 xunput (c2, yytext); 3009 xunput (c2);
2962 } 3010 }
2963 else 3011 else
2964 retval = false; 3012 retval = false;
2965 3013
2966 xunput (c1, yytext); 3014 xunput (c1);
2967 } 3015 }
2968 break; 3016 break;
2969 3017
2970 case '(': 3018 case '(':
2971 case '{': 3019 case '{':
3011 3059
3012 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3060 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
3013 && next_token_can_follow_bin_op ()) 3061 && next_token_can_follow_bin_op ())
3014 retval = false; 3062 retval = false;
3015 3063
3016 xunput (c2, yytext); 3064 xunput (c2);
3017 } 3065 }
3018 break; 3066 break;
3019 } 3067 }
3020 3068
3021 xunput (c1, yytext); 3069 xunput (c1);
3022 } 3070 }
3023 break; 3071 break;
3024 3072
3025 case ':': 3073 case ':':
3026 case '/': 3074 case '/':
3031 3079
3032 if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') 3080 if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t')
3033 && next_token_can_follow_bin_op ()) 3081 && next_token_can_follow_bin_op ())
3034 retval = false; 3082 retval = false;
3035 3083
3036 xunput (c1, yytext); 3084 xunput (c1);
3037 } 3085 }
3038 break; 3086 break;
3039 3087
3040 // .+ .- ./ .\ .^ .* .** 3088 // .+ .- ./ .\ .^ .* .**
3041 case '.': 3089 case '.':
3052 3100
3053 if (! match_any (c3, ",;\n") && (c3 == ' ' || c3 == '\t') 3101 if (! match_any (c3, ",;\n") && (c3 == ' ' || c3 == '\t')
3054 && next_token_can_follow_bin_op ()) 3102 && next_token_can_follow_bin_op ())
3055 retval = false; 3103 retval = false;
3056 3104
3057 xunput (c3, yytext); 3105 xunput (c3);
3058 } 3106 }
3059 else if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3107 else if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
3060 && next_token_can_follow_bin_op ()) 3108 && next_token_can_follow_bin_op ())
3061 retval = false; 3109 retval = false;
3062 3110
3063 xunput (c2, yytext); 3111 xunput (c2);
3064 } 3112 }
3065 else if (! match_any (c1, ",;\n") 3113 else if (! match_any (c1, ",;\n")
3066 && (! isdigit (c1) && c1 != ' ' && c1 != '\t' 3114 && (! isdigit (c1) && c1 != ' ' && c1 != '\t'
3067 && c1 != '.')) 3115 && c1 != '.'))
3068 { 3116 {
3069 // Structure reference. FIXME -- is this a complete check? 3117 // Structure reference. FIXME -- is this a complete check?
3070 3118
3071 retval = false; 3119 retval = false;
3072 } 3120 }
3073 3121
3074 xunput (c1, yytext); 3122 xunput (c1);
3075 } 3123 }
3076 break; 3124 break;
3077 3125
3078 // & && | || * ** 3126 // & && | || * **
3079 case '&': 3127 case '&':
3088 3136
3089 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3137 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
3090 && next_token_can_follow_bin_op ()) 3138 && next_token_can_follow_bin_op ())
3091 retval = false; 3139 retval = false;
3092 3140
3093 xunput (c2, yytext); 3141 xunput (c2);
3094 } 3142 }
3095 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') 3143 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t')
3096 && next_token_can_follow_bin_op ()) 3144 && next_token_can_follow_bin_op ())
3097 retval = false; 3145 retval = false;
3098 3146
3099 xunput (c1, yytext); 3147 xunput (c1);
3100 } 3148 }
3101 break; 3149 break;
3102 3150
3103 // < <= > >= 3151 // < <= > >=
3104 case '<': 3152 case '<':
3112 3160
3113 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3161 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
3114 && next_token_can_follow_bin_op ()) 3162 && next_token_can_follow_bin_op ())
3115 retval = false; 3163 retval = false;
3116 3164
3117 xunput (c2, yytext); 3165 xunput (c2);
3118 } 3166 }
3119 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') 3167 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t')
3120 && next_token_can_follow_bin_op ()) 3168 && next_token_can_follow_bin_op ())
3121 retval = false; 3169 retval = false;
3122 3170
3123 xunput (c1, yytext); 3171 xunput (c1);
3124 } 3172 }
3125 break; 3173 break;
3126 3174
3127 // ~= != 3175 // ~= !=
3128 case '~': 3176 case '~':
3137 3185
3138 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t') 3186 if (! match_any (c2, ",;\n") && (c2 == ' ' || c2 == '\t')
3139 && next_token_can_follow_bin_op ()) 3187 && next_token_can_follow_bin_op ())
3140 retval = false; 3188 retval = false;
3141 3189
3142 xunput (c2, yytext); 3190 xunput (c2);
3143 } 3191 }
3144 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t') 3192 else if (! match_any (c1, ",;\n") && (c1 == ' ' || c1 == '\t')
3145 && next_token_can_follow_bin_op ()) 3193 && next_token_can_follow_bin_op ())
3146 retval = false; 3194 retval = false;
3147 3195
3148 xunput (c1, yytext); 3196 xunput (c1);
3149 } 3197 }
3150 break; 3198 break;
3151 3199
3152 default: 3200 default:
3153 break; 3201 break;
3154 } 3202 }
3155 3203
3156 xunput (c0, yytext); 3204 xunput (c0);
3157 3205
3158 return retval; 3206 return retval;
3159 } 3207 }
3160 3208
3161 static int 3209 int
3162 handle_superclass_identifier (void) 3210 lexical_feedback::handle_superclass_identifier (void)
3163 { 3211 {
3164 int c = yytext[yyleng-1]; 3212 char *yytxt = flex_yytext ();
3165 3213 int c = yytxt[flex_yyleng()-1];
3166 std::string meth = strip_trailing_whitespace (yytext); 3214
3215 std::string meth = strip_trailing_whitespace (yytxt);
3167 3216
3168 int cont_is_spc = eat_continuation (); 3217 int cont_is_spc = eat_continuation ();
3169 3218
3170 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); 3219 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
3171 3220
3187 { 3236 {
3188 error ("method, class, and package names may not be keywords"); 3237 error ("method, class, and package names may not be keywords");
3189 return LEXICAL_ERROR; 3238 return LEXICAL_ERROR;
3190 } 3239 }
3191 3240
3192 yylval.tok_val = new token (meth, pkg, cls, input_line_number, 3241 push_token (new token (meth, pkg, cls, input_line_number,
3193 current_input_column); 3242 current_input_column));
3194 token_stack.push (yylval.tok_val);
3195 3243
3196 do_comma_insert_check (); 3244 do_comma_insert_check ();
3197 maybe_unput_comma (spc_gobbled); 3245 maybe_unput_comma (spc_gobbled);
3198 current_input_column += yyleng; 3246 current_input_column += flex_yyleng ();
3199 3247
3200 return SUPERCLASSREF; 3248 return SUPERCLASSREF;
3201 } 3249 }
3202 3250
3203 static int 3251 int
3204 handle_meta_identifier (void) 3252 lexical_feedback::handle_meta_identifier (void)
3205 { 3253 {
3206 int c = yytext[yyleng-1]; 3254 char *yytxt = flex_yytext ();
3207 3255 int c = yytxt[flex_yyleng()-1];
3208 std::string cls = strip_trailing_whitespace (yytext).substr (1); 3256
3257 std::string cls = strip_trailing_whitespace (yytxt).substr (1);
3209 3258
3210 int cont_is_spc = eat_continuation (); 3259 int cont_is_spc = eat_continuation ();
3211 3260
3212 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); 3261 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
3213 3262
3224 { 3273 {
3225 error ("class and package names may not be keywords"); 3274 error ("class and package names may not be keywords");
3226 return LEXICAL_ERROR; 3275 return LEXICAL_ERROR;
3227 } 3276 }
3228 3277
3229 yylval.tok_val = new token (pkg, cls, input_line_number, 3278 push_token (new token (pkg, cls, input_line_number,
3230 current_input_column); 3279 current_input_column));
3231 token_stack.push (yylval.tok_val);
3232 3280
3233 do_comma_insert_check (); 3281 do_comma_insert_check ();
3234 maybe_unput_comma (spc_gobbled); 3282 maybe_unput_comma (spc_gobbled);
3235 current_input_column += yyleng; 3283 current_input_column += flex_yyleng ();
3236 3284
3237 return METAQUERY; 3285 return METAQUERY;
3238 } 3286 }
3239 3287
3240 // Figure out exactly what kind of token to return when we have seen 3288 // Figure out exactly what kind of token to return when we have seen
3241 // an identifier. Handles keywords. Return -1 if the identifier 3289 // an identifier. Handles keywords. Return -1 if the identifier
3242 // should be ignored. 3290 // should be ignored.
3243 3291
3244 static int 3292 int
3245 handle_identifier (void) 3293 lexical_feedback::handle_identifier (void)
3246 { 3294 {
3247 bool at_bos = lexer_flags.at_beginning_of_statement; 3295 OCTAVE_YYG;
3248 3296
3249 std::string tok = strip_trailing_whitespace (yytext); 3297 bool at_bos = at_beginning_of_statement;
3250 3298
3251 int c = yytext[yyleng-1]; 3299 char *yytxt = flex_yytext ();
3252 3300
3253 int cont_is_spc = eat_continuation (); 3301 std::string tok = strip_trailing_whitespace (yytxt);
3302
3303 int c = yytxt[flex_yyleng()-1];
3304
3305 bool cont_is_spc = (eat_continuation () != lexical_feedback::NO_WHITESPACE);
3254 3306
3255 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); 3307 int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
3256 3308
3257 // If we are expecting a structure element, avoid recognizing 3309 // If we are expecting a structure element, avoid recognizing
3258 // keywords and other special names and return STRUCT_ELT, which is 3310 // keywords and other special names and return STRUCT_ELT, which is
3259 // a string that is also a valid identifier. But first, we have to 3311 // a string that is also a valid identifier. But first, we have to
3260 // decide whether to insert a comma. 3312 // decide whether to insert a comma.
3261 3313
3262 if (lexer_flags.looking_at_indirect_ref) 3314 if (looking_at_indirect_ref)
3263 { 3315 {
3264 do_comma_insert_check (); 3316 do_comma_insert_check ();
3265 3317
3266 maybe_unput_comma (spc_gobbled); 3318 maybe_unput_comma (spc_gobbled);
3267 3319
3268 yylval.tok_val = new token (tok, input_line_number, 3320 push_token (new token (tok, input_line_number,
3269 current_input_column); 3321 current_input_column));
3270 3322
3271 token_stack.push (yylval.tok_val); 3323 quote_is_transpose = true;
3272 3324 convert_spaces_to_comma = true;
3273 lexer_flags.quote_is_transpose = true; 3325 looking_for_object_index = true;
3274 lexer_flags.convert_spaces_to_comma = true; 3326
3275 lexer_flags.looking_for_object_index = true; 3327 current_input_column += flex_yyleng ();
3276
3277 current_input_column += yyleng;
3278 3328
3279 return STRUCT_ELT; 3329 return STRUCT_ELT;
3280 } 3330 }
3281 3331
3282 lexer_flags.at_beginning_of_statement = false; 3332 at_beginning_of_statement = false;
3283 3333
3284 // The is_keyword_token may reset 3334 // The is_keyword_token may reset
3285 // lexer_flags.at_beginning_of_statement. For example, if it sees 3335 // at_beginning_of_statement. For example, if it sees
3286 // an else token, then the next token is at the beginning of a 3336 // an else token, then the next token is at the beginning of a
3287 // statement. 3337 // statement.
3288 3338
3289 int kw_token = is_keyword_token (tok); 3339 int kw_token = is_keyword_token (tok);
3290 3340
3291 // If we found a keyword token, then the beginning_of_statement flag 3341 // If we found a keyword token, then the beginning_of_statement flag
3292 // is already set. Otherwise, we won't be at the beginning of a 3342 // is already set. Otherwise, we won't be at the beginning of a
3293 // statement. 3343 // statement.
3294 3344
3295 if (lexer_flags.looking_at_function_handle) 3345 if (looking_at_function_handle)
3296 { 3346 {
3297 if (kw_token) 3347 if (kw_token)
3298 { 3348 {
3299 error ("function handles may not refer to keywords"); 3349 error ("function handles may not refer to keywords");
3300 3350
3301 return LEXICAL_ERROR; 3351 return LEXICAL_ERROR;
3302 } 3352 }
3303 else 3353 else
3304 { 3354 {
3305 yylval.tok_val = new token (tok, input_line_number, 3355 push_token (new token (tok, input_line_number,
3306 current_input_column); 3356 current_input_column));
3307 3357
3308 token_stack.push (yylval.tok_val); 3358 current_input_column += flex_yyleng ();
3309 3359 quote_is_transpose = false;
3310 current_input_column += yyleng; 3360 convert_spaces_to_comma = true;
3311 lexer_flags.quote_is_transpose = false; 3361 looking_for_object_index = true;
3312 lexer_flags.convert_spaces_to_comma = true;
3313 lexer_flags.looking_for_object_index = true;
3314 3362
3315 return FCN_HANDLE; 3363 return FCN_HANDLE;
3316 } 3364 }
3317 } 3365 }
3318 3366
3321 3369
3322 if (kw_token) 3370 if (kw_token)
3323 { 3371 {
3324 if (kw_token >= 0) 3372 if (kw_token >= 0)
3325 { 3373 {
3326 current_input_column += yyleng; 3374 current_input_column += flex_yyleng ();
3327 lexer_flags.quote_is_transpose = false; 3375 quote_is_transpose = false;
3328 lexer_flags.convert_spaces_to_comma = true; 3376 convert_spaces_to_comma = true;
3329 lexer_flags.looking_for_object_index = false; 3377 looking_for_object_index = false;
3330 } 3378 }
3331 3379
3332 return kw_token; 3380 return kw_token;
3333 } 3381 }
3334 3382
3338 3386
3339 bool next_tok_is_eq = false; 3387 bool next_tok_is_eq = false;
3340 if (c1 == '=') 3388 if (c1 == '=')
3341 { 3389 {
3342 int c2 = text_yyinput (); 3390 int c2 = text_yyinput ();
3343 xunput (c2, yytext); 3391 xunput (c2);
3344 3392
3345 if (c2 != '=') 3393 if (c2 != '=')
3346 next_tok_is_eq = true; 3394 next_tok_is_eq = true;
3347 } 3395 }
3348 3396
3349 xunput (c1, yytext); 3397 xunput (c1);
3350 3398
3351 // Kluge alert. 3399 // Kluge alert.
3352 // 3400 //
3353 // If we are looking at a text style function, set up to gobble its 3401 // If we are looking at a text style function, set up to gobble its
3354 // arguments. 3402 // arguments.
3364 && looks_like_command_arg ()) 3412 && looks_like_command_arg ())
3365 { 3413 {
3366 BEGIN (COMMAND_START); 3414 BEGIN (COMMAND_START);
3367 } 3415 }
3368 else if (next_tok_is_eq 3416 else if (next_tok_is_eq
3369 || lexer_flags.looking_at_decl_list 3417 || looking_at_decl_list
3370 || lexer_flags.looking_at_return_list 3418 || looking_at_return_list
3371 || (lexer_flags.looking_at_parameter_list 3419 || (looking_at_parameter_list
3372 && ! lexer_flags.looking_at_initializer_expression)) 3420 && ! looking_at_initializer_expression))
3373 { 3421 {
3374 symbol_table::force_variable (tok); 3422 symbol_table::force_variable (tok);
3375 } 3423 }
3376 else if (lexer_flags.looking_at_matrix_or_assign_lhs) 3424 else if (looking_at_matrix_or_assign_lhs)
3377 { 3425 {
3378 lexer_flags.pending_local_variables.insert (tok); 3426 pending_local_variables.insert (tok);
3379 } 3427 }
3380 } 3428 }
3381 3429
3382 // Find the token in the symbol table. Beware the magic 3430 // Find the token in the symbol table. Beware the magic
3383 // transformation of the end keyword... 3431 // transformation of the end keyword...
3384 3432
3385 if (tok == "end") 3433 if (tok == "end")
3386 tok = "__end__"; 3434 tok = "__end__";
3387 3435
3388 yylval.tok_val = new token (&(symbol_table::insert (tok)), 3436 push_token (new token (&(symbol_table::insert (tok)),
3389 input_line_number, current_input_column); 3437 input_line_number, current_input_column));
3390
3391 token_stack.push (yylval.tok_val);
3392 3438
3393 // After seeing an identifer, it is ok to convert spaces to a comma 3439 // After seeing an identifer, it is ok to convert spaces to a comma
3394 // (if needed). 3440 // (if needed).
3395 3441
3396 lexer_flags.convert_spaces_to_comma = true; 3442 convert_spaces_to_comma = true;
3397 3443
3398 if (! (next_tok_is_eq || YY_START == COMMAND_START)) 3444 if (! (next_tok_is_eq || YY_START == COMMAND_START))
3399 { 3445 {
3400 lexer_flags.quote_is_transpose = true; 3446 quote_is_transpose = true;
3401 3447
3402 do_comma_insert_check (); 3448 do_comma_insert_check ();
3403 3449
3404 maybe_unput_comma (spc_gobbled); 3450 maybe_unput_comma (spc_gobbled);
3405 } 3451 }
3406 3452
3407 current_input_column += yyleng; 3453 current_input_column += flex_yyleng ();
3408 3454
3409 if (tok != "__end__") 3455 if (tok != "__end__")
3410 lexer_flags.looking_for_object_index = true; 3456 looking_for_object_index = true;
3411 3457
3412 return NAME; 3458 return NAME;
3413 } 3459 }
3414 3460
3415 void 3461 void
3416 lexical_feedback::init (void) 3462 lexical_feedback::maybe_warn_separator_insert (char sep)
3417 {
3418 // Not initially defining a matrix list.
3419 bracketflag = 0;
3420
3421 // Not initially defining a cell array list.
3422 braceflag = 0;
3423
3424 // Not initially inside a loop or if statement.
3425 looping = 0;
3426
3427 // Not initially defining a function.
3428 defining_func = 0;
3429
3430 // Not parsing an object index.
3431 while (! parsed_function_name.empty ())
3432 parsed_function_name.pop ();
3433
3434 parsing_class_method = false;
3435
3436 // Not initially defining a class with classdef.
3437 maybe_classdef_get_set_method = false;
3438 parsing_classdef = false;
3439 parsing_classdef_get_method = false;
3440 parsing_classdef_set_method = false;
3441
3442 // Not initiallly looking at a function handle.
3443 looking_at_function_handle = 0;
3444
3445 // Not initiallly looking at an anonymous function argument list.
3446 looking_at_anon_fcn_args = 0;
3447
3448 // Not parsing a function return, parameter, or declaration list.
3449 looking_at_return_list = false;
3450 looking_at_parameter_list = false;
3451 looking_at_decl_list = false;
3452
3453 // Not looking at an argument list initializer expression.
3454 looking_at_initializer_expression = false;
3455
3456 // Not parsing a matrix or the left hand side of multi-value
3457 // assignment statement.
3458 looking_at_matrix_or_assign_lhs = false;
3459
3460 // Not parsing an object index.
3461 while (! looking_at_object_index.empty ())
3462 looking_at_object_index.pop_front ();
3463
3464 looking_at_object_index.push_front (false);
3465
3466 // Object index not possible until we've seen something.
3467 looking_for_object_index = false;
3468
3469 // Yes, we are at the beginning of a statement.
3470 at_beginning_of_statement = true;
3471
3472 // No need to do comma insert or convert spaces to comma at
3473 // beginning of input.
3474 convert_spaces_to_comma = true;
3475 do_comma_insert = false;
3476
3477 // Not initially looking at indirect references.
3478 looking_at_indirect_ref = false;
3479
3480 // Quote marks strings intially.
3481 quote_is_transpose = false;
3482
3483 // Set of identifiers that might be local variable names is empty.
3484 pending_local_variables.clear ();
3485 }
3486
3487 bool
3488 is_keyword (const std::string& s)
3489 {
3490 // Parsing function names like "set.property_name" inside
3491 // classdef-style class definitions is simplified by handling the
3492 // "set" and "get" portions of the names using the same mechanism as
3493 // is used for keywords. However, they are not really keywords in
3494 // the language, so omit them from the list of possible keywords.
3495
3496 return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0
3497 && ! (s == "set" || s == "get"));
3498 }
3499
3500 DEFUN (iskeyword, args, ,
3501 "-*- texinfo -*-\n\
3502 @deftypefn {Built-in Function} {} iskeyword ()\n\
3503 @deftypefnx {Built-in Function} {} iskeyword (@var{name})\n\
3504 Return true if @var{name} is an Octave keyword. If @var{name}\n\
3505 is omitted, return a list of keywords.\n\
3506 @seealso{isvarname, exist}\n\
3507 @end deftypefn")
3508 {
3509 octave_value retval;
3510
3511 int argc = args.length () + 1;
3512
3513 string_vector argv = args.make_argv ("iskeyword");
3514
3515 if (error_state)
3516 return retval;
3517
3518 if (argc == 1)
3519 {
3520 // Neither set and get are keywords. See the note in the
3521 // is_keyword function for additional details.
3522
3523 string_vector lst (TOTAL_KEYWORDS);
3524
3525 int j = 0;
3526
3527 for (int i = 0; i < TOTAL_KEYWORDS; i++)
3528 {
3529 std::string tmp = wordlist[i].name;
3530
3531 if (! (tmp == "set" || tmp == "get"))
3532 lst[j++] = tmp;
3533 }
3534
3535 lst.resize (j);
3536
3537 retval = Cell (lst.sort ());
3538 }
3539 else if (argc == 2)
3540 {
3541 retval = is_keyword (argv[1]);
3542 }
3543 else
3544 print_usage ();
3545
3546 return retval;
3547 }
3548
3549 /*
3550
3551 %!assert (iskeyword ("for"))
3552 %!assert (iskeyword ("fort"), false)
3553 %!assert (iskeyword ("fft"), false)
3554
3555 */
3556
3557 void
3558 prep_lexer_for_script_file (void)
3559 {
3560 BEGIN (SCRIPT_FILE_BEGIN);
3561 }
3562
3563 void
3564 prep_lexer_for_function_file (void)
3565 {
3566 BEGIN (FUNCTION_FILE_BEGIN);
3567 }
3568
3569 void
3570 prep_lexer_for_classdef_file (void)
3571 {
3572 BEGIN (CLASSDEF_FILE_BEGIN);
3573 }
3574
3575 static void
3576 maybe_warn_separator_insert (char sep)
3577 { 3463 {
3578 std::string nm = curr_fcn_file_full_name; 3464 std::string nm = curr_fcn_file_full_name;
3579 3465
3580 if (nm.empty ()) 3466 if (nm.empty ())
3581 warning_with_id ("Octave:separator-insert", 3467 warning_with_id ("Octave:separator-insert",
3585 warning_with_id ("Octave:separator-insert", 3471 warning_with_id ("Octave:separator-insert",
3586 "potential auto-insertion of '%c' near line %d of file %s", 3472 "potential auto-insertion of '%c' near line %d of file %s",
3587 sep, input_line_number, nm.c_str ()); 3473 sep, input_line_number, nm.c_str ());
3588 } 3474 }
3589 3475
3590 static void 3476 void
3591 gripe_single_quote_string (void) 3477 lexical_feedback::gripe_single_quote_string (void)
3592 { 3478 {
3593 std::string nm = curr_fcn_file_full_name; 3479 std::string nm = curr_fcn_file_full_name;
3594 3480
3595 if (nm.empty ()) 3481 if (nm.empty ())
3596 warning_with_id ("Octave:single-quote-string", 3482 warning_with_id ("Octave:single-quote-string",
3600 warning_with_id ("Octave:single-quote-string", 3486 warning_with_id ("Octave:single-quote-string",
3601 "single quote delimited string near line %d of file %s", 3487 "single quote delimited string near line %d of file %s",
3602 input_line_number, nm.c_str ()); 3488 input_line_number, nm.c_str ());
3603 } 3489 }
3604 3490
3605 static void 3491 void
3606 gripe_matlab_incompatible (const std::string& msg) 3492 lexical_feedback::gripe_matlab_incompatible (const std::string& msg)
3607 { 3493 {
3608 std::string nm = curr_fcn_file_full_name; 3494 std::string nm = curr_fcn_file_full_name;
3609 3495
3610 if (nm.empty ()) 3496 if (nm.empty ())
3611 warning_with_id ("Octave:matlab-incompatible", 3497 warning_with_id ("Octave:matlab-incompatible",
3615 warning_with_id ("Octave:matlab-incompatible", 3501 warning_with_id ("Octave:matlab-incompatible",
3616 "potential Matlab compatibility problem: %s near line %d offile %s", 3502 "potential Matlab compatibility problem: %s near line %d offile %s",
3617 msg.c_str (), input_line_number, nm.c_str ()); 3503 msg.c_str (), input_line_number, nm.c_str ());
3618 } 3504 }
3619 3505
3620 static void 3506 void
3621 maybe_gripe_matlab_incompatible_comment (char c) 3507 lexical_feedback::maybe_gripe_matlab_incompatible_comment (char c)
3622 { 3508 {
3623 if (c == '#') 3509 if (c == '#')
3624 gripe_matlab_incompatible ("# used as comment character"); 3510 gripe_matlab_incompatible ("# used as comment character");
3625 } 3511 }
3626 3512
3627 static void 3513 void
3628 gripe_matlab_incompatible_continuation (void) 3514 lexical_feedback::gripe_matlab_incompatible_continuation (void)
3629 { 3515 {
3630 gripe_matlab_incompatible ("\\ used as line continuation marker"); 3516 gripe_matlab_incompatible ("\\ used as line continuation marker");
3631 } 3517 }
3632 3518
3633 static void 3519 void
3634 gripe_matlab_incompatible_operator (const std::string& op) 3520 lexical_feedback::gripe_matlab_incompatible_operator (const std::string& op)
3635 { 3521 {
3636 std::string t = op; 3522 std::string t = op;
3637 int n = t.length (); 3523 int n = t.length ();
3638 if (t[n-1] == '\n') 3524 if (t[n-1] == '\n')
3639 t.resize (n-1); 3525 t.resize (n-1);
3640 gripe_matlab_incompatible (t + " used as operator"); 3526 gripe_matlab_incompatible (t + " used as operator");
3641 } 3527 }
3642 3528
3643 static void 3529 void
3644 display_token (int tok) 3530 lexical_feedback::push_token (token *tok)
3531 {
3532 YYSTYPE *lval = yyget_lval (scanner);
3533 lval->tok_val = tok;
3534 token_stack.push (tok);
3535 }
3536
3537 token *
3538 lexical_feedback::current_token (void)
3539 {
3540 YYSTYPE *lval = yyget_lval (scanner);
3541 return lval->tok_val;
3542 }
3543
3544 void
3545 lexical_feedback::display_token (int tok)
3645 { 3546 {
3646 switch (tok) 3547 switch (tok)
3647 { 3548 {
3648 case '=': std::cerr << "'='\n"; break; 3549 case '=': std::cerr << "'='\n"; break;
3649 case ':': std::cerr << "':'\n"; break; 3550 case ':': std::cerr << "':'\n"; break;
3691 case POW: std::cerr << "POW\n"; break; 3592 case POW: std::cerr << "POW\n"; break;
3692 case EPOW: std::cerr << "EPOW\n"; break; 3593 case EPOW: std::cerr << "EPOW\n"; break;
3693 3594
3694 case NUM: 3595 case NUM:
3695 case IMAG_NUM: 3596 case IMAG_NUM:
3696 std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM") 3597 {
3697 << " [" << yylval.tok_val->number () << "]\n"; 3598 token *tok_val = current_token ();
3599 std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM")
3600 << " [" << tok_val->number () << "]\n";
3601 }
3698 break; 3602 break;
3699 3603
3700 case STRUCT_ELT: 3604 case STRUCT_ELT:
3701 std::cerr << "STRUCT_ELT [" << yylval.tok_val->text () << "]\n"; break; 3605 {
3606 token *tok_val = current_token ();
3607 std::cerr << "STRUCT_ELT [" << tok_val->text () << "]\n";
3608 }
3609 break;
3702 3610
3703 case NAME: 3611 case NAME:
3704 { 3612 {
3705 symbol_table::symbol_record *sr = yylval.tok_val->sym_rec (); 3613 token *tok_val = current_token ();
3614 symbol_table::symbol_record *sr = tok_val->sym_rec ();
3706 std::cerr << "NAME"; 3615 std::cerr << "NAME";
3707 if (sr) 3616 if (sr)
3708 std::cerr << " [" << sr->name () << "]"; 3617 std::cerr << " [" << sr->name () << "]";
3709 std::cerr << "\n"; 3618 std::cerr << "\n";
3710 } 3619 }
3712 3621
3713 case END: std::cerr << "END\n"; break; 3622 case END: std::cerr << "END\n"; break;
3714 3623
3715 case DQ_STRING: 3624 case DQ_STRING:
3716 case SQ_STRING: 3625 case SQ_STRING:
3717 std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING") 3626 {
3718 << " [" << yylval.tok_val->text () << "]\n"; 3627 token *tok_val = current_token ();
3628
3629 std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING")
3630 << " [" << tok_val->text () << "]\n";
3631 }
3719 break; 3632 break;
3720 3633
3721 case FOR: std::cerr << "FOR\n"; break; 3634 case FOR: std::cerr << "FOR\n"; break;
3722 case WHILE: std::cerr << "WHILE\n"; break; 3635 case WHILE: std::cerr << "WHILE\n"; break;
3723 case DO: std::cerr << "DO\n"; break; 3636 case DO: std::cerr << "DO\n"; break;
3766 break; 3679 break;
3767 } 3680 }
3768 } 3681 }
3769 3682
3770 static void 3683 static void
3771 display_state (void) 3684 display_state (int state)
3772 { 3685 {
3773 std::cerr << "S: "; 3686 std::cerr << "S: ";
3774 3687
3775 switch (YY_START) 3688 switch (state)
3776 { 3689 {
3777 case INITIAL: 3690 case INITIAL:
3778 std::cerr << "INITIAL" << std::endl; 3691 std::cerr << "INITIAL" << std::endl;
3779 break; 3692 break;
3780 3693
3802 std::cerr << "UNKNOWN START STATE!" << std::endl; 3715 std::cerr << "UNKNOWN START STATE!" << std::endl;
3803 break; 3716 break;
3804 } 3717 }
3805 } 3718 }
3806 3719
3807 static void 3720 void
3808 lexer_debug (const char *pattern, const char *text) 3721 lexical_feedback::fatal_error (const char *msg)
3809 { 3722 {
3723 error (msg);
3724
3725 OCTAVE_QUIT;
3726
3727 yy_fatal_error (msg, scanner);
3728 }
3729
3730 void
3731 lexical_feedback::lexer_debug (const char *pattern, const char *text)
3732 {
3733 OCTAVE_YYG;
3734
3810 std::cerr << std::endl; 3735 std::cerr << std::endl;
3811 3736
3812 display_state (); 3737 display_state (YY_START);
3813 3738
3814 std::cerr << "P: " << pattern << std::endl; 3739 std::cerr << "P: " << pattern << std::endl;
3815 std::cerr << "T: " << text << std::endl; 3740 std::cerr << "T: " << text << std::endl;
3816 } 3741 }
3817
3818 DEFUN (__display_tokens__, args, nargout,
3819 "-*- texinfo -*-\n\
3820 @deftypefn {Built-in Function} {} __display_tokens__ ()\n\
3821 Query or set the internal variable that determines whether Octave's\n\
3822 lexer displays tokens as they are read.\n\
3823 @end deftypefn")
3824 {
3825 return SET_INTERNAL_VARIABLE (display_tokens);
3826 }
3827
3828 DEFUN (__token_count__, , ,
3829 "-*- texinfo -*-\n\
3830 @deftypefn {Built-in Function} {} __token_count__ ()\n\
3831 Number of language tokens processed since Octave startup.\n\
3832 @end deftypefn")
3833 {
3834 return octave_value (Vtoken_count);
3835 }
3836
3837 DEFUN (__lexer_debug_flag__, args, nargout,
3838 "-*- texinfo -*-\n\
3839 @deftypefn {Built-in Function} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val}))\n\
3840 Undocumented internal function.\n\
3841 @end deftypefn")
3842 {
3843 octave_value retval;
3844
3845 retval = set_internal_variable (lexer_debug_flag, args, nargout,
3846 "__lexer_debug_flag__");
3847
3848 return retval;
3849 }