changeset 1826:b14829582cc4

[project @ 1996-02-02 03:05:07 by jwe]
author jwe
date Fri, 02 Feb 1996 03:07:27 +0000
parents 8219d9b7cb73
children effa9400766f
files src/lex.h src/lex.l src/parse.h src/parse.y
diffstat 4 files changed, 385 insertions(+), 418 deletions(-) [+]
line wrap: on
line diff
--- a/src/lex.h	Fri Feb 02 01:02:02 1996 +0000
+++ b/src/lex.h	Fri Feb 02 03:07:27 1996 +0000
@@ -50,9 +50,9 @@
   do \
     { \
       current_input_column += yyleng; \
-      quote_is_transpose = 0; \
-      cant_be_identifier = 0; \
-      convert_spaces_to_comma = 1; \
+      lexer_flags.quote_is_transpose = 0; \
+      lexer_flags.cant_be_identifier = 0; \
+      lexer_flags.convert_spaces_to_comma = 1; \
       return (tok); \
     } \
   while (0)
@@ -73,13 +73,16 @@
       yylval.tok_val = new token (input_line_number, current_input_column); \
       token_stack.push (yylval.tok_val); \
       current_input_column += yyleng; \
-      quote_is_transpose = 0; \
-      cant_be_identifier = 0; \
-      convert_spaces_to_comma = convert; \
+      lexer_flags.quote_is_transpose = 0; \
+      lexer_flags.cant_be_identifier = 0; \
+      lexer_flags.convert_spaces_to_comma = convert; \
       return (tok); \
     } \
   while (0)
 
+// XXX FIXME XXX -- these input buffer things should be members of an
+// parser input stream class.
+
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
 
 // Associate a buffer with a new file to read.
@@ -101,14 +104,93 @@
 extern void delete_input_buffer (void *buf);
 
 // See if a function file has extra garbage after the end statement.
+// This needs to be defined in lex.l so that it can use yyinput() but
+// it must be called from parse.y.
 extern void check_for_garbage_after_fcn_def (void);
 
-// Return transpose or start a string?
-extern int quote_is_transpose;
+// For communication between the lexer and parser.
+
+class lexical_feedback
+{
+public:
+
+  lexical_feedback (void) { init (); }
+
+  ~lexical_feedback (void) { }
+
+  void init (void);
+
+  // Nonzero means we thing we are looking at the beginning of a
+  // function definition.
+  int beginning_of_function;
+
+  // Brace level count.
+  int braceflag;
+
+  // Another context hack, this time for the plot command's `using',
+  // `title', and `with' keywords.
+  int cant_be_identifier;
+
+  // Nonzero means that we should convert spaces to a comma inside a
+  // matrix definition.
+  int convert_spaces_to_comma;
+
+  // Nonzero means we're in the middle of defining a function.
+  int defining_func;
+
+  // GAG.  Stupid kludge so that [[1,2][3,4]] will work.
+  int do_comma_insert;
+
+  // Nonzero means we think we are looking at a set command.
+  int doing_set;
+
+  // Nonzero means we're in the middle of defining a conditional
+  // expression.
+  int iffing;
 
-// Nonzero means we thing we are looking at the beginning of a
-// function definition.
-extern int beginning_of_function;
+  // Nonzero means we're looking at the range part of a plot command.
+  int in_plot_range;
+
+  // Nonzero means we're looking at the using part of a plot command.
+  int in_plot_using;
+
+  // Nonzero means we're looking at the style part of a plot command.
+  int in_plot_style;
+
+  // Nonzero means we're looking at an indirect reference to a
+  // structure element.
+  int looking_at_indirect_ref;
+
+  // Nonzero means we're in the middle of defining a loop.
+  int looping;
+
+  // Nonzero means we need to do some extra lookahead to avoid being
+  // screwed by bogus function syntax.
+  int maybe_screwed;
+
+  // Nonzero means we need to do some extra lookahead to avoid being
+  // screwed by bogus function syntax.
+  int maybe_screwed_again;
+
+  // Nonzero means we've seen something that means we must be past the
+  // range part of a plot command.
+  int past_plot_range;
+
+  // Nonzero means we're working on a plot command.
+  int plotting;
+
+  // Return transpose or start a string?
+  int quote_is_transpose;
+
+private:
+
+  lexical_feedback (const lexical_feedback&);
+
+  lexical_feedback& operator = (const lexical_feedback&);
+};
+
+// Flags that need to be shared between the lexer and parser.
+extern lexical_feedback lexer_flags;
 
 #endif
 
--- a/src/lex.l	Fri Feb 02 01:02:02 1996 +0000
+++ b/src/lex.l	Fri Feb 02 03:07:27 1996 +0000
@@ -24,8 +24,6 @@
 %s MATRIX
 
 %{
-#define SHORT_CIRCUIT_LOGICALS 1
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -64,51 +62,53 @@
 #include "y.tab.h"
 #include "oct-gperf.h"
 
+// Flags that need to be shared between the lexer and parser.
+lexical_feedback lexer_flags;
+
 // Stack to hold tokens so that we can delete them when the parser is
 // reset and avoid growing forever just because we are stashing some
 // information.  This has to appear before lex.h is included, because
 // one of the macros defined there uses token_stack.
 static SLStack <token*> token_stack;
 
-// Nonzero means we think we are looking at a set command.
-static int doing_set = 0;
-
-// GAG.  Stupid kludge so that [[1,2][3,4]] will work.
-static do_comma_insert = 0;
+// Did eat_whitespace() eat a space or tab, or a newline, or both?
 
-// Brace level count.
-static int braceflag = 0;
-
-// Return transpose or start a string?
-int quote_is_transpose = 0;
+typedef int yum_yum;
 
-// Nonzero means we thing we are looking at the beginning of a
-// function definition.
-int beginning_of_function = 0;
-
-// Nonzero means that we should convert spaces to a comma inside a
-// matrix definition.
-static int convert_spaces_to_comma = 1;
-
-// Another context hack, this time for the plot command's `using',
-// `title', and `with' keywords.
-static int cant_be_identifier = 0;
-
-#define BRACE 1
-#define PAREN 2
-
-// Did eat_whitespace() eat a space or tab, or a newline, or both?
-#define ATE_SPACE_OR_TAB 1
-#define ATE_NEWLINE 2
+const yum_yum ATE_NOTHING = 0;
+const yum_yum ATE_SPACE_OR_TAB = 1;
+const yum_yum ATE_NEWLINE = 2;
 
 // Is the closest nesting level a square brace or a paren?
-//
-//  BRACE -> spaces are important (they can turn into commas)
-//           new lines are important (they can turn into semicolons)
-//
-//  PAREN -> spaces and new lines are not important
+
+class brace_paren_nesting_level : public SLStack <int>
+{
+public:
+
+  brace_paren_nesting_level (void) : SLStack<int> () { }
+
+  ~brace_paren_nesting_level (void) { }
+
+  void brace (void) { push (BRACE); }
+  bool is_brace (void) { return ! empty () && top () == BRACE; }
+
+  void paren (void) { push (PAREN); }
+  bool is_paren (void) { return ! empty () && top () == PAREN; }
 
-static SLStack <int> nesting_level;
+  bool none (void) { return empty (); }
+
+  void remove (void) { if (! empty ()) SLStack<int>::pop (); }
+
+private:
+
+  enum { BRACE = 1, PAREN = 2 };
+
+  brace_paren_nesting_level (const brace_paren_nesting_level&);
+
+  brace_paren_nesting_level& operator = (const brace_paren_nesting_level&);
+};
+
+static brace_paren_nesting_level nesting_level;
 
 // Forward declarations for functions defined at the bottom of this
 // file.
@@ -131,8 +131,8 @@
 static int handle_identifier (const string& tok, int spc_gobbled);
 static int have_continuation (int trailing_comments_ok = 1);
 static int have_ellipsis_continuation (int trailing_comments_ok = 1);
-static int eat_whitespace (void);
-static int eat_continuation (void);
+static yum_yum eat_whitespace (void);
+static yum_yum eat_continuation (void);
 
 %}
 
@@ -165,14 +165,14 @@
 <TEXT_FCN>{NL} {
     BEGIN 0;
     current_input_column = 1;
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
     return '\n';
   }
 
 <TEXT_FCN>[\;\,] {
-    if (doing_set && strcmp (yytext, ",") == 0)
+    if (lexer_flags.doing_set && strcmp (yytext, ",") == 0)
       {
 	TOK_PUSH_AND_RETURN (yytext, TEXT);
       }
@@ -225,9 +225,9 @@
 <MATRIX>{S}*\,{S}* {
     current_input_column += yyleng;
     int tmp = eat_continuation ();
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
     if (user_pref.whitespace_in_literal_matrix != 2
 	&& (tmp & ATE_NEWLINE) == ATE_NEWLINE)
       unput (';');
@@ -249,13 +249,13 @@
 	int bin_op = next_token_is_bin_op (1, yytext);
 	int postfix_un_op = next_token_is_postfix_unary_op (1, yytext);
 
-	if (! (postfix_un_op || bin_op || nesting_level.empty ())
-	    && nesting_level.top () == BRACE
-	    && convert_spaces_to_comma)
+	if (! (postfix_un_op || bin_op)
+	    && nesting_level.is_brace ()
+	    && lexer_flags.convert_spaces_to_comma)
 	  {
-	    quote_is_transpose = 0;
-	    cant_be_identifier = 0;
-	    convert_spaces_to_comma = 1;
+	    lexer_flags.quote_is_transpose = 0;
+	    lexer_flags.cant_be_identifier = 0;
+	    lexer_flags.convert_spaces_to_comma = 1;
 	    if ((tmp & ATE_NEWLINE) == ATE_NEWLINE)
 	      unput (';');
 	    return (',');
@@ -272,9 +272,9 @@
 <MATRIX>{SNLCMT}*;{SNLCMT}* {
     fixup_column_count (yytext);
     eat_whitespace ();
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
     return ';';
   }
 
@@ -289,14 +289,14 @@
     eat_whitespace ();
     if (user_pref.whitespace_in_literal_matrix != 2)
       {
-	quote_is_transpose = 0;
-	cant_be_identifier = 0;
-	convert_spaces_to_comma = 1;
+	lexer_flags.quote_is_transpose = 0;
+	lexer_flags.cant_be_identifier = 0;
+	lexer_flags.convert_spaces_to_comma = 1;
 
-	if (nesting_level.empty ())
+	if (nesting_level.none ())
 	  return LEXICAL_ERROR;
 
-	if (nesting_level.top () == BRACE)
+	if (nesting_level.is_brace ())
 	  return ';';
       }
   }
@@ -308,37 +308,36 @@
 %}
 
 \[{S}* {
-    nesting_level.push (BRACE);
+    nesting_level.brace ();
 
     current_input_column += yyleng;
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
 
     promptflag--;
     eat_whitespace ();
 
-    if (plotting && ! past_plot_range)
+    if (lexer_flags.plotting && ! lexer_flags.past_plot_range)
       {
-	in_plot_range = 1;
+	lexer_flags.in_plot_range = 1;
 	return OPEN_BRACE;
       }
     else
       {
 	mlnm.push (1);
-	braceflag++;
+	lexer_flags.braceflag++;
 	BEGIN MATRIX;
 	return '[';
       }
   }
 
 \] {
-    if (! nesting_level.empty ())
-      nesting_level.pop ();
+    nesting_level.remove ();
 
-    if (plotting && ! past_plot_range)
+    if (lexer_flags.plotting && ! lexer_flags.past_plot_range)
       {
-	in_plot_range = 0;
+	lexer_flags.in_plot_range = 0;
 	TOK_RETURN (CLOSE_BRACE);
       }
     else
@@ -421,15 +420,15 @@
 %}
 
 {NL} {
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
     current_input_column = 1;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
 
-    if (nesting_level.empty ())
+    if (nesting_level.none ())
       return '\n';
 
-    if (nesting_level.top () == BRACE)
+    if (nesting_level.is_brace ())
       return LEXICAL_ERROR;
   }
 
@@ -440,9 +439,9 @@
 
 "'" {
     current_input_column++;
-    convert_spaces_to_comma = 1;
+    lexer_flags.convert_spaces_to_comma = 1;
 
-    if (quote_is_transpose)
+    if (lexer_flags.quote_is_transpose)
       {
 	do_comma_insert_check ();
 	return QUOTE;
@@ -466,7 +465,8 @@
 %}
 
 ":" {
-    if (plotting && (in_plot_range || in_plot_using))
+    if (lexer_flags.plotting
+	&& (lexer_flags.in_plot_range || lexer_flags.in_plot_using))
       BIN_OP_RETURN (COLON, 1);
     else
       BIN_OP_RETURN (':', 0);
@@ -478,10 +478,12 @@
 %} 
 
 {CCHAR} {
-    if (help_buf.empty () && beginning_of_function && nesting_level.empty ())
+    if (help_buf.empty ()
+	&& lexer_flags.beginning_of_function
+	&& nesting_level.none ())
       {
 	grab_help_text ();
-	beginning_of_function = 0;
+	lexer_flags.beginning_of_function = 0;
       }
     else
       {
@@ -490,14 +492,14 @@
 	  ; // Eat comment.
       }
 
-    quote_is_transpose = 0;
-    cant_be_identifier = 0;
     current_input_column = 1;
-    convert_spaces_to_comma = 1;
+    lexer_flags.quote_is_transpose = 0;
+    lexer_flags.cant_be_identifier = 0;
+    lexer_flags.convert_spaces_to_comma = 1;
 
-    if (nesting_level.empty ())
+    if (nesting_level.none ())
       return '\n';
-    else if (nesting_level.top () == BRACE)
+    else if (nesting_level.is_brace ())
       return ';';
   }
 
@@ -529,58 +531,42 @@
 ","		{ BIN_OP_RETURN (',', 1); }
 {POW}		{ BIN_OP_RETURN (POW, 0); }
 "="		{ BIN_OP_RETURN ('=', 1); }
-
-"||" {
-#ifdef SHORT_CIRCUIT_LOGICALS
-    BIN_OP_RETURN (EXPR_OR_OR, 0);
-#else
-    BIN_OP_RETURN (EXPR_OR, 0);
-#endif
-  }
-
-"&&" {
-#ifdef SHORT_CIRCUIT_LOGICALS
-    BIN_OP_RETURN (EXPR_AND_AND, 0);
-#else
-    BIN_OP_RETURN (EXPR_AND, 0);
-#endif
-  }
+"||"		{ BIN_OP_RETURN (EXPR_OR_OR, 0); }
+"&&"		{ BIN_OP_RETURN (EXPR_AND_AND, 0); }
 
 {NOT} {
-    if (plotting && ! in_plot_range)
-      past_plot_range = 1;
+    if (lexer_flags.plotting && ! lexer_flags.in_plot_range)
+      lexer_flags.past_plot_range = 1;
     BIN_OP_RETURN (EXPR_NOT, 0);
   }
 
 "+" { 
-    if (plotting && ! in_plot_range)
-      past_plot_range = 1;
+    if (lexer_flags.plotting && ! lexer_flags.in_plot_range)
+      lexer_flags.past_plot_range = 1;
     BIN_OP_RETURN ('+', 0);
   }
 
 "-" { 
-    if (plotting && ! in_plot_range)
-      past_plot_range = 1;
+    if (lexer_flags.plotting && ! lexer_flags.in_plot_range)
+      lexer_flags.past_plot_range = 1;
     BIN_OP_RETURN ('-', 0);
   }
 
 "(" {
-    if (plotting && ! in_plot_range)
-      past_plot_range = 1;
-    nesting_level.push (PAREN);
+    if (lexer_flags.plotting && ! lexer_flags.in_plot_range)
+      lexer_flags.past_plot_range = 1;
+    nesting_level.paren ();
     promptflag--;
     TOK_RETURN ('(');
   }
 
 ")" {
-    if (! nesting_level.empty ())
-      nesting_level.pop ();
+    nesting_level.remove ();
 
     current_input_column++;
-    cant_be_identifier = 1;
-    quote_is_transpose = 1;
-    convert_spaces_to_comma = (! nesting_level.empty ()
-			       && nesting_level.top () == BRACE);
+    lexer_flags.cant_be_identifier = 1;
+    lexer_flags.quote_is_transpose = 1;
+    lexer_flags.convert_spaces_to_comma = nesting_level.is_brace ();
     do_comma_insert_check ();
     return ')';
   }
@@ -607,7 +593,7 @@
   yyunput (c, yytext);
   if (spc_gobbled)
     yyunput (' ', yytext);
-  do_comma_insert = (braceflag && c == '[');
+  lexer_flags.do_comma_insert = (lexer_flags.braceflag && c == '[');
 }
 
 // Fix things up for errors or interrupts.  The parser is never called
@@ -617,75 +603,42 @@
 void
 reset_parser (void)
 {
-// Start off on the right foot.
+  // Start off on the right foot.
   BEGIN 0;
   error_state = 0;
 
-// We do want a prompt by default.
+  // We do want a prompt by default.
   promptflag = 1;
 
-// Not initially screwed by `function [...] = f (...)' syntax.
-  maybe_screwed = 0;
-  maybe_screwed_again = 0;
-
-// Not initially inside a loop or if statement.
-  looping = 0;
-  iffing = 0;
-
-// Quote marks strings intially.
-  quote_is_transpose = 0;
-
-// Next token can be identifier.
-  cant_be_identifier = 0;
-
-// No need to do comma insert or convert spaces to comma at beginning
-// of input. 
-  do_comma_insert = 0;
-  convert_spaces_to_comma = 1;
-
-// Not initially defining a function.
-  beginning_of_function = 0;
-  defining_func = 0;
-
-// Not initially doing any plotting or setting of plot attributes.
-  plotting = 0;
-  in_plot_range = 0;
-  past_plot_range = 0;
-  in_plot_using = 0;
-  in_plot_style = 0;
-  doing_set = 0;
-
-// Not initially looking at indirect references.
-  looking_at_indirect_ref = 0;
-
-// Error may have occurred inside some parentheses or braces.
+  // Error may have occurred inside some parentheses or braces.
   nesting_level.clear ();
 
-// Not initially defining a matrix list.
-  braceflag = 0;
+  // Not initially defining a matrix list.
   ml.clear ();
   mlnm.clear ();
 
-// Clear out the stack of token info used to track line and column
-// numbers.
+  // Clear out the stack of token info used to track line and column
+  // numbers.
   while (! token_stack.empty ())
     delete token_stack.pop ();
 
-// Can be reset by defining a function.
+  // Can be reset by defining a function.
   if (! (reading_script_file || reading_fcn_file))
     {
       current_input_column = 1;
       input_line_number = current_command_number - 1;
     }
 
-// Only ask for input from stdin if we are expecting interactive
-// input.
+  // Only ask for input from stdin if we are expecting interactive
+  // input.
   if (interactive && ! (reading_fcn_file || get_input_from_eval_string))
     yyrestart (stdin);
 
-// Clear the buffer for help text.
+  // Clear the buffer for help text.
+  help_buf.resize (0);
 
-  help_buf.resize (0);
+  // Reset other flags.
+  lexer_flags.init ();
 }
 
 // Replace backslash escapes in a string with the real values.
@@ -787,29 +740,6 @@
   return 1;
 }
 
-// These are not needed with flex-2.4.6, but may be needed with
-// earlier 2.4.x versions.
-
-#if 0
-static void *
-yy_flex_alloc (int size)
-{
-  return (void *) malloc ((unsigned) size);
-}
-
-static void *
-yy_flex_realloc (void *ptr, int size)
-{
-  return (void *) realloc (ptr, (unsigned) size);
-}
-
-static void
-yy_flex_free (void *ptr)
-{
-  free (ptr);
-}
-#endif
-
 // Tell us all what the current buffer is.
 
 YY_BUFFER_STATE
@@ -910,12 +840,12 @@
     }
   else if (almost_match ("using", t))
     {
-      in_plot_using = 1;
+      lexer_flags.in_plot_using = 1;
       return USING;
     }
   else if (almost_match ("with", t))
     {
-      in_plot_style = 1;
+      lexer_flags.in_plot_style = 1;
       return WITH;
     }
   else if (strcmp ("clear", t) == 0)
@@ -933,13 +863,13 @@
 static int
 is_keyword (const string& s)
 {
-  if (plotting && in_plot_style)
+  if (lexer_flags.plotting && lexer_flags.in_plot_style)
     {
       string sty = plot_style_token (s);
 
       if (! sty.empty ())
 	{
-	  in_plot_style = 0;
+	  lexer_flags.in_plot_style = 0;
 	  yylval.tok_val = new token (sty);
 	  token_stack.push (yylval.tok_val);
 	  return STYLE;
@@ -1001,12 +931,12 @@
 	case for_kw:
 	case while_kw:
 	  promptflag--;
-	  looping++;
+	  lexer_flags.looping++;
 	  break;
 
 	case if_kw:
-	  iffing++;
 	  promptflag--;
+	  lexer_flags.iffing++;
 	  break;
 
 	case try_kw:
@@ -1015,22 +945,22 @@
 	  break;
 
 	case gplot_kw:
-	  plotting = 1;
+	  lexer_flags.plotting = 1;
 	  yylval.tok_val = new token (token::two_dee, l, c);
 	  break;
 
 	case gsplot_kw:
-	  plotting = 1;
+	  lexer_flags.plotting = 1;
 	  yylval.tok_val = new token (token::three_dee, l, c);
 	  break;
 
 	case replot_kw:
-	  plotting = 1;
+	  lexer_flags.plotting = 1;
 	  yylval.tok_val = new token (token::replot, l, c);
 	  break;
 
 	case function_kw:
-	  if (defining_func)
+	  if (lexer_flags.defining_func)
 	    {
 	      error ("function keyword invalid within a function body");
 
@@ -1048,9 +978,9 @@
 	    {
 	      tmp_local_sym_tab = new symbol_table ();
 	      curr_sym_tab = tmp_local_sym_tab;
-	      defining_func = 1;
+	      lexer_flags.defining_func = 1;
 	      promptflag--;
-	      beginning_of_function = 1;
+	      lexer_flags.beginning_of_function = 1;
 	      if (! (reading_fcn_file || reading_script_file))
 		input_line_number = 1;
 	    }
@@ -1152,17 +1082,6 @@
   return ((spc_prev && spc_next) || ! spc_prev);
 }
 
-// Duh.  This seems to no longer be needed.
-#if 0
-static int
-next_char_is_space (void)
-{
-  int c = yyinput ();
-  yyunput (c, yytext);
-  return (c == ' ' || c == '\t');
-}
-#endif
-
 // Try to determine if the next token should be treated as a postfix
 // unary operator.  This is ugly, but it seems to do the right thing.
 
@@ -1276,13 +1195,14 @@
 //
 // Return value is logical OR of the following values:
 //
+//  ATE_NOTHING      : no spaces to eat
 //  ATE_SPACE_OR_TAB : space or tab in input
 //  ATE_NEWLINE      : bare new line in input
 
-static int
+static yum_yum
 eat_whitespace (void)
 {
-  int retval = 0;
+  yum_yum retval = ATE_NOTHING;
   int in_comment = 0;
   int c;
   while ((c = yyinput ()) != EOF)
@@ -1349,16 +1269,16 @@
   double value;
   int nread = sscanf (yytext, "%lf", &value);
 
-// If yytext doesn't contain a valid number, we are in deep doo doo.
+  // If yytext doesn't contain a valid number, we are in deep doo doo.
 
   assert (nread == 1);
 
-  quote_is_transpose = 1;
-  cant_be_identifier = 1;
-  convert_spaces_to_comma = 1;
+  lexer_flags.quote_is_transpose = 1;
+  lexer_flags.cant_be_identifier = 1;
+  lexer_flags.convert_spaces_to_comma = 1;
 
-  if (plotting && ! in_plot_range)
-    past_plot_range = 1;
+  if (lexer_flags.plotting && ! lexer_flags.in_plot_range)
+    lexer_flags.past_plot_range = 1;
 
   yylval.tok_val = new token (value, yytext, input_line_number,
 			      current_input_column);
@@ -1462,10 +1382,10 @@
 //
 // Return value is the same as described for eat_whitespace().
 
-static int
+static yum_yum
 eat_continuation (void)
 {
-  int retval = 0;
+  int retval = ATE_NOTHING;
   int c = yyinput ();
   if ((c == '.' && have_ellipsis_continuation ())
       || (c == '\\' && have_continuation ()))
@@ -1533,7 +1453,7 @@
 		  char *tok = buf.str ();
 		  do_string_escapes (tok);
 
-		  if (text_style && doing_set)
+		  if (text_style && lexer_flags.doing_set)
 		    {
 		      if (tok)
 			{
@@ -1549,9 +1469,9 @@
 		    }
 		  else
 		    {
-		      quote_is_transpose = 1;
-		      cant_be_identifier = 1;
-		      convert_spaces_to_comma = 1;
+		      lexer_flags.quote_is_transpose = 1;
+		      lexer_flags.cant_be_identifier = 1;
+		      lexer_flags.convert_spaces_to_comma = 1;
 		    }
 
 		  yylval.tok_val = new token (tok);
@@ -1575,27 +1495,27 @@
 static int
 handle_close_brace (int spc_gobbled)
 {
-  if (! nesting_level.empty ())
+  if (! nesting_level.none ())
     {
-      nesting_level.pop ();
-      braceflag--;
+      nesting_level.remove ();
+      lexer_flags.braceflag--;
     }
 
-  if (braceflag == 0)
+  if (lexer_flags.braceflag == 0)
     BEGIN 0;
 
   int c1 = yyinput ();
   if (c1 == '=')
     {
-      quote_is_transpose = 0;
-      cant_be_identifier = 0;
-      convert_spaces_to_comma = 1;
+      lexer_flags.quote_is_transpose = 0;
+      lexer_flags.cant_be_identifier = 0;
+      lexer_flags.convert_spaces_to_comma = 1;
 
       int c2 = yyinput ();
       unput (c2);
       unput (c1);
 
-      if (c2 != '=' && maybe_screwed_again)
+      if (c2 != '=' && lexer_flags.maybe_screwed_again)
 	return SCREW_TWO;
       else
 	return ']';
@@ -1604,7 +1524,7 @@
     {
       unput (c1);
 
-      if (braceflag && user_pref.whitespace_in_literal_matrix != 2)
+      if (lexer_flags.braceflag && user_pref.whitespace_in_literal_matrix != 2)
 	{
 	  int bin_op = next_token_is_bin_op (spc_gobbled, yytext);
 	  int postfix_un_op = next_token_is_postfix_unary_op
@@ -1612,10 +1532,9 @@
 
 	  int other_op = match_any (c1, ",;\n]");
 
-	  if (! (postfix_un_op || bin_op || other_op
-		 || nesting_level.empty ())
-	      && nesting_level.top () == BRACE
-	      && convert_spaces_to_comma)
+	  if (! (postfix_un_op || bin_op || other_op)
+	      && nesting_level.is_brace ()
+	      && lexer_flags.convert_spaces_to_comma)
 	    {
 	      unput (',');
 	      return ']';
@@ -1623,9 +1542,9 @@
 	}
     }
 
-  quote_is_transpose = 1;
-  cant_be_identifier = 0;
-  convert_spaces_to_comma = 1;
+  lexer_flags.quote_is_transpose = 1;
+  lexer_flags.cant_be_identifier = 0;
+  lexer_flags.convert_spaces_to_comma = 1;
   return ']';
 }
 
@@ -1633,8 +1552,7 @@
 maybe_unput_comma (int spc_gobbled)
 {
   if (user_pref.whitespace_in_literal_matrix != 2
-      && ! nesting_level.empty ()
-      && nesting_level.top () == BRACE) 
+      && nesting_level.is_brace ())
     {
       int bin_op = next_token_is_bin_op (spc_gobbled, yytext);
 
@@ -1663,23 +1581,25 @@
 static int
 handle_identifier (const string& tok, int spc_gobbled)
 {
-// It is almost always an error for an identifier to be followed
-// directly by another identifier.  Special cases are handled below.
+  // It is almost always an error for an identifier to be followed
+  // directly by another identifier.  Special cases are handled
+  // below.
 
-  cant_be_identifier = 1;
+  lexer_flags.cant_be_identifier = 1;
 
-// If we are expecting a structure element, we just want to return
-// TEXT_ID, which is a string that is also a valid identifier.  But
-// first, we have to decide whether to insert a comma.
+  // If we are expecting a structure element, we just want to return
+  // TEXT_ID, which is a string that is also a valid identifier.  But
+  // first, we have to decide whether to insert a comma.
 
-  if (looking_at_indirect_ref)
+  if (lexer_flags.looking_at_indirect_ref)
     {
       maybe_unput_comma (spc_gobbled);
       TOK_PUSH_AND_RETURN (tok, TEXT_ID);
     }
 
-// If we have a regular keyword, or a plot STYLE, return it.  Keywords
-// can be followed by identifiers (TOK_RETURN handles that).
+  // If we have a regular keyword, or a plot STYLE, return it.
+  // Keywords can be followed by identifiers (TOK_RETURN handles
+  // that).
 
   int kw_token = is_keyword (tok);
   if (kw_token)
@@ -1687,60 +1607,61 @@
       if (kw_token == STYLE)
 	{
 	  current_input_column += yyleng;
-	  quote_is_transpose = 0;
-	  convert_spaces_to_comma = 1;
+	  lexer_flags.quote_is_transpose = 0;
+	  lexer_flags.convert_spaces_to_comma = 1;
 	  return kw_token;
 	}
       else
 	TOK_RETURN (kw_token);
     }
 
-// See if we have a plot keyword (title, using, with, or clear).
+  // See if we have a plot keyword (title, using, with, or clear).
 
-  if (plotting)
+  if (lexer_flags.plotting)
     {
-// Yes, we really do need both of these plot_range variables.  One
-// is used to mark when we are past all possiblity of a plot range,
-// the other is used to mark when we are actually between the square
-// brackets that surround the range.
+      // Yes, we really do need both of these plot_range variables.
+      // One is used to mark when we are past all possiblity of a plot
+      // range, the other is used to mark when we are actually between
+      // the square brackets that surround the range.
 
-      if (! in_plot_range)
-	past_plot_range = 1;
+      if (! lexer_flags.in_plot_range)
+	lexer_flags.past_plot_range = 1;
 
       // Option keywords can't appear in parentheses or braces.
 
       int plot_option_kw = 0;
-      if (nesting_level.empty ())
+      if (nesting_level.none ())
 	plot_option_kw = is_plot_keyword (tok);
 
-      if (cant_be_identifier && plot_option_kw)
+      if (lexer_flags.cant_be_identifier && plot_option_kw)
 	TOK_RETURN (plot_option_kw);
     }
 
-// If we are looking at a text style function, set up to gobble its
-// arguments.  These are also reserved words, but only because it
-// would be very difficult to do anything intelligent with them if
-// they were not reserved.
+  // If we are looking at a text style function, set up to gobble its
+  // arguments.  These are also reserved words, but only because it
+  // would be very difficult to do anything intelligent with them if
+  // they were not reserved.
 
   if (is_text_function_name (tok))
     {
       BEGIN TEXT_FCN;
 
       if (tok == "set")
-	doing_set = 1;
+	lexer_flags.doing_set = 1;
     }
 
   int c = yyinput ();
   yyunput (c, yytext);
   int next_tok_is_eq = (c == '=');
 
-// Make sure we put the return values of a function in the symbol
-// table that is local to the function.
+  // Make sure we put the return values of a function in the symbol
+  // table that is local to the function.
 
-  if (next_tok_is_eq && defining_func && maybe_screwed)
+  if (next_tok_is_eq
+      && lexer_flags.defining_func && lexer_flags.maybe_screwed)
     curr_sym_tab = tmp_local_sym_tab;
 
-// Find the token in the symbol table.
+  // Find the token in the symbol table.
 
   yylval.tok_val = new token (lookup_identifier (tok),
 			      input_line_number,
@@ -1748,35 +1669,35 @@
 
   token_stack.push (yylval.tok_val);
 
-// After seeing an identifer, it is ok to convert spaces to a comma
-// (if needed).
+  // After seeing an identifer, it is ok to convert spaces to a comma
+  // (if needed).
 
-  convert_spaces_to_comma = 1;
+  lexer_flags.convert_spaces_to_comma = 1;
 
-// If we are defining a function and we have not seen the parameter
-// list yet and the next token is `=', return a token that represents
-// the only return value for the function.  For example,
-//
-//   function SCREW = f (args);
-//
-// The variable maybe_screwed is reset in parse.y.
+  // If we are defining a function and we have not seen the parameter
+  // list yet and the next token is `=', return a token that
+  // represents the only return value for the function.  For example,
+  //
+  //   function SCREW = f (args);
+  //
+  // The variable maybe_screwed is reset in parse.y.
 
   if (next_tok_is_eq)
     {
       current_input_column += yyleng;
-      if (defining_func && maybe_screwed)
+      if (lexer_flags.defining_func && lexer_flags.maybe_screwed)
 	return SCREW;
       else
 	return NAME;
     }
 
-// At this point, we are only dealing with identifiers that are not
-// followed by `=' (if the next token is `=', there is no need to
-// check to see if we should insert a comma (invalid syntax), or allow
-// a following `'' to be treated as a transpose (the next token is
-// `=', so it can't be `''.
+  // At this point, we are only dealing with identifiers that are not
+  // followed by `=' (if the next token is `=', there is no need to
+  // check to see if we should insert a comma (invalid syntax), or
+  // allow a following `'' to be treated as a transpose (the next
+  // token is `=', so it can't be `''.
 
-  quote_is_transpose = 1;
+  lexer_flags.quote_is_transpose = 1;
   do_comma_insert_check ();
 
   maybe_unput_comma (spc_gobbled);
@@ -1792,9 +1713,9 @@
 void
 check_for_garbage_after_fcn_def (void)
 {
-// By making a newline be the next character to be read, we will force
-// the parser to return after reading the function.  Calling yyunput
-// with EOF seems not to work...
+  // By making a newline be the next character to be read, we will
+  // force the parser to return after reading the function.  Calling
+  // yyunput with EOF seems not to work...
 
   int in_comment = 0;
   int lineno = input_line_number;
@@ -1835,19 +1756,56 @@
   yyunput ('\n', yytext);
 }
 
-/*
+void
+lexical_feedback::init (void)
+{
+  // Not initially defining a function.
+  beginning_of_function = 0;
+  defining_func = 0;
+
+  // Not initially defining a matrix list.
+  braceflag = 0;
+
+  // Next token can be identifier.
+  cant_be_identifier = 0;
 
-Maybe someday...
+  // No need to do comma insert or convert spaces to comma at
+  // beginning of input. 
+  convert_spaces_to_comma = 1;
+  do_comma_insert = 0;
+
+  // Not initially doing any plotting or setting of plot attributes.
+  doing_set = 0;
+  in_plot_range = 0;
+  in_plot_style = 0;
+  in_plot_using = 0;
+  past_plot_range = 0;
+  plotting = 0;
 
-"+="		return ADD_EQ;
-"-="		return SUB_EQ;
-"*="		return MUL_EQ;
-"/="		return DIV_EQ;
-"\\="		return LEFTDIV_EQ;
-".+="		return ADD_EQ;
-".-="		return SUB_EQ;
-".*="		return EMUL_EQ;
-"./="		return EDIV_EQ;
-".\\="		return ELEFTDIV_EQ;
+  // Not initially inside a loop or if statement.
+  iffing = 0;
+  looping = 0;
+
+  // Not initially looking at indirect references.
+  looking_at_indirect_ref = 0;
+
+  // Not initially screwed by `function [...] = f (...)' syntax.
+  maybe_screwed = 0;
+  maybe_screwed_again = 0;
 
-*/
+  // Quote marks strings intially.
+  quote_is_transpose = 0;
+}
+
+// Maybe someday...
+//
+// "+="		return ADD_EQ;
+// "-="		return SUB_EQ;
+// "*="		return MUL_EQ;
+// "/="		return DIV_EQ;
+// "\\="	return LEFTDIV_EQ;
+// ".+="	return ADD_EQ;
+// ".-="	return SUB_EQ;
+// ".*="	return EMUL_EQ;
+// "./="	return EDIV_EQ;
+// ".\\="	return ELEFTDIV_EQ;
--- a/src/parse.h	Fri Feb 02 01:02:02 1996 +0000
+++ b/src/parse.h	Fri Feb 02 03:07:27 1996 +0000
@@ -37,23 +37,6 @@
 class tree_identifier;
 class symbol_table;
 
-// Nonzero means we're in the middle of defining a function.
-extern int defining_func;
-
-// Nonzero means we're in the middle of defining a loop.
-extern int looping;
-
-// Nonzero means we're in the middle of defining a conditional expression.
-extern int iffing;
-
-// Nonzero means we need to do some extra lookahead to avoid being
-// screwed by bogus function syntax.
-extern int maybe_screwed;
-
-// Nonzero means we need to do some extra lookahead to avoid being
-// screwed by bogus function syntax.
-extern int maybe_screwed_again;
-
 // Temporary symbol table pointer used to cope with bogus function syntax.
 extern symbol_table *tmp_local_sym_tab;
 
@@ -77,26 +60,6 @@
 // Buffer for help text snagged from function files.
 extern string help_buf;
 
-// Nonzero means we're working on a plot command.
-extern int plotting;
-
-// Nonzero means we've seen something that means we must be past the
-// range part of a plot command.
-extern int past_plot_range;
-
-// Nonzero means we're looking at the range part of a plot command.
-extern int in_plot_range;
-
-// Nonzero means we're looking at the using part of a plot command.
-extern int in_plot_using;
-
-// Nonzero means we're looking at the style part of a plot command.
-extern int in_plot_style;
-
-// Nonzero means we're looking at an indirect reference to a structure
-// element.
-extern int looking_at_indirect_ref;
-
 #endif
 
 /*
--- a/src/parse.y	Fri Feb 02 01:02:02 1996 +0000
+++ b/src/parse.y	Fri Feb 02 03:07:27 1996 +0000
@@ -59,23 +59,6 @@
 #include "utils.h"
 #include "variables.h"
 
-// Nonzero means we're in the middle of defining a function.
-int defining_func = 0;
-
-// Nonzero means we're in the middle of defining a loop.
-int looping = 0;
-
-// Nonzero means we're in the middle of defining a conditional expression.
-int iffing = 0;
-
-// Nonzero means we need to do some extra lookahead to avoid being
-// screwed by bogus function syntax.
-int maybe_screwed = 0;
-
-// Nonzero means we need to do some extra lookahead to avoid being
-// screwed by bogus function syntax.
-int maybe_screwed_again = 0;
-
 // Temporary symbol table pointer used to cope with bogus function syntax.
 symbol_table *tmp_local_sym_tab = 0;
 
@@ -96,26 +79,6 @@
 // Buffer for help text snagged from function files.
 string help_buf;
 
-// Nonzero means we're working on a plot command.
-int plotting = 0;
-
-// Nonzero means we've seen something that means we must be past the
-// range part of a plot command.
-int past_plot_range = 0;
-
-// Nonzero means we're looking at the range part of a plot command.
-int in_plot_range = 0;
-
-// Nonzero means we're looking at the using part of a plot command.
-int in_plot_using = 0;
-
-// Nonzero means we're looking at the style part of a plot command.
-int in_plot_style = 0;
-
-// Nonzero means we're looking at an indirect reference to a structure
-// element.
-int looking_at_indirect_ref = 0;
-
 // Forward declarations for some functions defined at the bottom of
 // the file.
 
@@ -491,7 +454,7 @@
 
 list1		: statement
 		  {
-		    beginning_of_function = 0;
+		    lexer_flags.beginning_of_function = 0;
 		    $$ = new tree_statement_list ($1);
 		  }
 		| list1 comma_nl_sep statement
@@ -601,12 +564,12 @@
 
 using		: using1
 		  {
-		    in_plot_using = 0;
+		    lexer_flags.in_plot_using = 0;
 		    $$ = $1;
 		  }
 		| using1 expression
 		  {
-		    in_plot_using = 0;
+		    lexer_flags.in_plot_using = 0;
 		    $$ = $1->set_format ($2);
 		  }
 		;
@@ -679,7 +642,7 @@
 		  { $$ = $1; }
 		| if_command
 		  {
-		    iffing--;
+		    lexer_flags.iffing--;
 		    $$ = $1;
 		  }
 		| UNWIND optsep opt_list CLEANUP optsep opt_list END
@@ -765,7 +728,7 @@
 		;
 
 screwed_again	: // empty
-		  { maybe_screwed_again++; }
+		  { lexer_flags.maybe_screwed_again++; }
 		;
 
 expression	: simple_expr
@@ -930,23 +893,23 @@
 		;
 
 safe		: // empty
-		  { maybe_screwed = 0; }
+		  { lexer_flags.maybe_screwed = 0; }
 		;
 
 are_we_screwed	: // empty
-		  { maybe_screwed = 1; }
+		  { lexer_flags.maybe_screwed = 1; }
 		;
 
 func_def	: FCN g_symtab are_we_screwed func_def1
 		  {
 		    curr_sym_tab = top_level_sym_tab;
-		    defining_func = 0;
+		    lexer_flags.defining_func = 0;
 		    $$ = 0;
 		  }
 		| FCN g_symtab are_we_screwed func_def2
 		  {
 		    curr_sym_tab = top_level_sym_tab;
-		    defining_func = 0;
+		    lexer_flags.defining_func = 0;
 		    $$ = 0;
 		  }
 		;
@@ -1018,7 +981,7 @@
 
 indirect_ref	: indirect_ref1
 		  {
-		    looking_at_indirect_ref = 0;
+		    lexer_flags.looking_at_indirect_ref = 0;
 		    $$ = $1;
 		  }
 
@@ -1027,7 +990,8 @@
 		    $$ = new tree_indirect_ref ($1, $1->line (),
 						$1->column ());
 		  }
-		| indirect_ref1 '.' { looking_at_indirect_ref = 1; } TEXT_ID
+		| indirect_ref1 '.'
+		    { lexer_flags.looking_at_indirect_ref = 1; } TEXT_ID
 		  { $$ = $1->chain ($4->text ()); }
 		;
 
@@ -1048,24 +1012,24 @@
 
 param_list	: '(' ')'
 		  {
-		    quote_is_transpose = 0;
+		    lexer_flags.quote_is_transpose = 0;
 		    $$ = 0;
 		  }
 		| '(' ELLIPSIS ')'
 		  {
-		    quote_is_transpose = 0;
+		    lexer_flags.quote_is_transpose = 0;
 		    tree_parameter_list *tmp = new tree_parameter_list ();
 		    tmp->mark_varargs_only ();
 		    $$ = tmp;
 		  }
 		| param_list1 ')'
 		  {
-		    quote_is_transpose = 0;
+		    lexer_flags.quote_is_transpose = 0;
 		    $1->mark_as_formal_parameters ();
 		  }
 		| param_list1 ',' ELLIPSIS ')'
 		  {
-		    quote_is_transpose = 0;
+		    lexer_flags.quote_is_transpose = 0;
 		    $1->mark_as_formal_parameters ();
 		    $1->mark_varargs ();
 		  }
@@ -1365,11 +1329,11 @@
       return 0;
     }
 
-  plotting = 0;
-  past_plot_range = 0;
-  in_plot_range = 0;
-  in_plot_using = 0;
-  in_plot_style = 0;
+  lexer_flags.plotting = 0;
+  lexer_flags.past_plot_range = 0;
+  lexer_flags.in_plot_range = 0;
+  lexer_flags.in_plot_using = 0;
+  lexer_flags.in_plot_style = 0;
   
   return new tree_plot_command (list, range, tok->pttype ());
 }
@@ -1704,7 +1668,7 @@
 
   if (! check_end (end_tok, token::while_end))
     {
-      looping--;
+      lexer_flags.looping--;
 
       int l = while_tok->line ();
       int c = while_tok->column ();
@@ -1726,7 +1690,7 @@
 
   if (! check_end (end_tok, token::for_end))
     {
-      looping--;
+      lexer_flags.looping--;
 
       int l = for_tok->line ();
       int c = for_tok->column ();
@@ -1747,7 +1711,7 @@
 
   if (! check_end (end_tok, token::for_end))
     {
-      looping--;
+      lexer_flags.looping--;
 
       tree_matrix *tmp = ml.pop ();
       tmp = tmp->reverse ();
@@ -1769,7 +1733,7 @@
 {
   tree_command *retval = 0;
 
-  if (! (looping || defining_func))
+  if (! (lexer_flags.looping || lexer_flags.defining_func))
     yyerror ("break: only meaningful within a loop or function body");
   else
     {
@@ -1789,7 +1753,7 @@
 {
   tree_command *retval = 0;
 
-  if (! looping)
+  if (! lexer_flags.looping)
     yyerror ("continue: only meaningful within a `for' or `while' loop");
   else
     {
@@ -1809,7 +1773,7 @@
 {
   tree_command *retval = 0;
 
-  if (! defining_func)
+  if (! lexer_flags.defining_func)
     yyerror ("return: only meaningful within a function");
   else
     {
@@ -1887,7 +1851,7 @@
 
   tree_expression *retval = 0;
 
-  maybe_screwed_again--;
+  lexer_flags.maybe_screwed_again--;
 
   tree_matrix *tmp = ml.pop ();
 
@@ -2078,7 +2042,7 @@
 
   mlnm.pop ();
 
-  maybe_screwed_again--;
+  lexer_flags.maybe_screwed_again--;
 
   tree_matrix *list = ml.pop ();
 
@@ -2102,7 +2066,7 @@
 static void
 maybe_warn_missing_semi (tree_statement_list *t)
 {
-  if (defining_func && user_pref.warn_missing_semicolon)
+  if (lexer_flags.defining_func && user_pref.warn_missing_semicolon)
     {
       tree_statement *tmp = t->rear();