diff src/parse.y @ 143:7849db4b6dbc

[project @ 1993-10-04 02:36:45 by jwe]
author jwe
date Mon, 04 Oct 1993 02:36:58 +0000
parents 27f35bee46f6
children a500c60e8f23
line wrap: on
line diff
--- a/src/parse.y	Mon Oct 04 00:40:57 1993 +0000
+++ b/src/parse.y	Mon Oct 04 02:36:58 1993 +0000
@@ -1,4 +1,4 @@
-/* parse.y                                              -*- text -*-
+/* parse.y						-*- text -*-
 
 Copyright (C) 1992, 1993 John W. Eaton
 
@@ -43,6 +43,7 @@
 #include "octave.h"
 #include "parse.h"
 #include "lex.h"
+#include "token.h"
 
 // Identifier to define if we are reading an M-fie.
 tree_identifier *id_to_define;
@@ -79,7 +80,7 @@
 int input_line_number = 0;
 
 // The column of the current token.
-int current_input_column = 0;
+int current_input_column = 1;
 
 // Buffer for help text snagged from M-files.
 // Probably shouldn't be a fixed size...
@@ -101,25 +102,11 @@
 // Nonzero means we're looking at the style part of a plot command.
 int in_plot_style = 0;
 
-// The type of an END token.  This declaration is repeated in lex.l.
-enum end_tok_type
-  {
-    simple_end,
-    for_end,
-    function_end,
-    if_end,
-    while_end,
-  };
-
-// The type of a PLOT token.  This declaration is repeated in lex.l.
-enum plot_tok_type
-  {
-    two_dee = 2,
-    three_dee = 3,
-  };
+// Check to see that end statements are properly matched.
+static int check_end (token *tok, token::end_tok_type expected);
 
 // Error mesages for mismatched end statements.
-static void end_error (char *type, end_tok_type ettype);
+static void end_error (char *type, token::end_tok_type ettype, int l, int c);
 
 // Generic error messages.
 static void yyerror (char *s);
@@ -147,6 +134,10 @@
  */
 %union
 {
+// The type of the basic tokens returned by the lexer.
+  token *tok_val;
+
+// Types for the nonterminals we generate.
   tree *tree_type;
   tree_constant *tree_constant_type;
   tree_matrix *tree_matrix_type;
@@ -167,91 +158,49 @@
   tree_plot_range *tree_plot_range_type;
   tree_subplot_using *tree_subplot_using_type;
   tree_subplot_style *tree_subplot_style_type;
-  symbol_record *sym_rec;
-  double number;
-  char *string;
-  end_tok_type ettype;
-  plot_tok_type pttype;
 }
 
-/*
- * There are 20 shift/reduce conflicts, ok?
- */
-%expect 20
+// Tokens with line and column information.
+%token <tok_val> '=' ':' '-' '+' '*' '/'
+%token <tok_val> EXPR_AND EXPR_OR EXPR_NOT
+%token <tok_val> EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT
+%token <tok_val> LEFTDIV EMUL EDIV ELEFTDIV QUOTE TRANSPOSE
+%token <tok_val> PLUS_PLUS MINUS_MINUS POW EPOW
+%token <tok_val> NUM IMAG_NUM
+%token <tok_val> NAME SCREW CLEAR
+%token <tok_val> END
+%token <tok_val> PLOT
+%token <tok_val> TEXT STYLE
 
-/*
- * Reserved words.
- */
+// Other tokens.
 %token FOR WHILE IF ELSEIF ELSE FCN BREAK CONTINUE FUNC_RET SCREW_TWO
-%token END_OF_INPUT GLOBAL CLEAR
-
+%token END_OF_INPUT GLOBAL
 %token USING TITLE WITH COLON OPEN_BRACE CLOSE_BRACE
 
-// tree
+// Nonterminals we construct.
 %type <tree_type> input command 
 %type <tree_type> ans_expression expression simple_expr simple_expr1
 %type <tree_type> title
-
-// tree_matrix
 %type <tree_matrix_type> matrix
-
-// tree_identifier
 %type <tree_identifier_type> identifier
-
-// tree_function 
 %type <tree_function_type> func_def func_def1 func_def2 func_def3
-
-// tree_index_expression
 %type <tree_index_expression_type> variable
-
-// tree_colon_expression
 %type <tree_colon_expression_type> colon_expr
-
-// tree_argument_list
 %type <tree_argument_list_type> arg_list arg_list1
-
-// tree_parameter_list
 %type <tree_parameter_list_type> param_list param_list1 func_def1a 
-
-// tree_word_list
 %type <tree_word_list_type> word_list word_list1
-
-// tree_command
 %type <tree_command_type> statement
-
-// tree_if_command
 %type <tree_if_command_type> elseif
-
-// tree_command_list
 %type <tree_command_list_type> simple_list simple_list1 list list1 opt_list
-
-// tree_word_list_command
 %type <tree_word_list_command_type> word_list_cmd
-
-// tree_plot_command
 %type <tree_plot_command_type> plot_command 
-
-// tree_subplot_list
 %type <tree_subplot_list_type> plot_command1 plot_command2 plot_options
-
-// tree_plot_limits
 %type <tree_plot_limits_type> ranges
-
-// tree_plot_range
 %type <tree_plot_range_type> ranges1 
-
-// tree_subplot_using
 %type <tree_subplot_using_type> using using1 
-
-// tree_subplot_style
 %type <tree_subplot_style_type> style
 
-%token <number> NUM IMAG_NUM
-%token <sym_rec> NAME SCREW
-%token <string> TEXT STYLE
-%token <ettype> END
-%token <pttype> PLOT
-
+// Precedence and associativity.
 %left ';' ',' '\n'
 %right '='
 %left EXPR_AND EXPR_OR
@@ -263,6 +212,10 @@
 %left UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT
 %right POW EPOW
 
+// There are 20 shift/reduce conflicts, ok?
+%expect 20
+
+// Where to start.
 %start input
 
 /*
@@ -397,7 +350,7 @@
 plot_command	: PLOT plot_command1
 		  {
 		    tree_subplot_list *tmp = $2->reverse ();
-		    $$ = new tree_plot_command (tmp, $1);
+		    $$ = new tree_plot_command (tmp, $1->pttype ());
 		    plotting = 0;
 		    past_plot_range = 0;
 		    in_plot_range = 0;
@@ -407,7 +360,7 @@
 		| PLOT ranges plot_command1
 		  {
 		    tree_subplot_list *tmp = $3->reverse ();
-		    $$ = new tree_plot_command (tmp, $2, $1);
+		    $$ = new tree_plot_command (tmp, $2, $1->pttype ());
 		    plotting = 0;
 		    past_plot_range = 0;
 		    in_plot_range = 0;
@@ -506,11 +459,11 @@
 		;
 
 style		: WITH STYLE
-		  { $$ = new tree_subplot_style ($2); }
+		  { $$ = new tree_subplot_style ($2->string ()); }
 		| WITH STYLE expression
-		  { $$ = new tree_subplot_style ($2, $3); }
+		  { $$ = new tree_subplot_style ($2->string (), $3); }
 		| WITH STYLE expression bogus_syntax expression
-		  { $$ = new tree_subplot_style ($2, $3, $5); }
+		  { $$ = new tree_subplot_style ($2->string (), $3, $5); }
 		;
 
 bogus_syntax	: // empty
@@ -525,23 +478,27 @@
 		;
 
 global_decl1	: NAME
-		  { force_global ($1->name ()); }
+		  { force_global ($1->sym_rec()->name ()); }
 		| NAME '=' expression
 		  {
-		    symbol_record *sr = force_global ($1->name ());
-		    tree_identifier *id = new tree_identifier (sr);
+		    symbol_record *sr = force_global ($1->sym_rec()->name ());
+		    tree_identifier *id = new tree_identifier
+		      (sr, $1->line (), $1->column ());
 		    tree_simple_assignment_expression *expr =
-		      new tree_simple_assignment_expression (id, $3);
+		      new tree_simple_assignment_expression
+			(id, $3, $2->line () , $2->column ());
 		    expr->eval (0);
 		  }
 		| global_decl1 optcomma NAME
-		  { force_global ($3->name ()); }
+		  { force_global ($3->sym_rec()->name ()); }
 		| global_decl1 optcomma NAME '=' expression
 		  {
-		    symbol_record *sr = force_global ($3->name ());
-		    tree_identifier *id = new tree_identifier (sr);
+		    symbol_record *sr = force_global ($3->sym_rec()->name ());
+		    tree_identifier *id = new tree_identifier
+		      (sr, $3->line (), $3->column ());
 		    tree_simple_assignment_expression *expr =
-		      new tree_simple_assignment_expression (id, $5);
+		      new tree_simple_assignment_expression
+			(id, $5, $4->line (), $4->column ());
 		    expr->eval (0);
 		  }
 		;
@@ -558,47 +515,31 @@
 statement	: WHILE expression optsep opt_list END
 		  {
 		    maybe_warn_assign_as_truth_value ($2);
-		    if ($5 != while_end && $5 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("while", $5);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($5, token::while_end))
+		      ABORT_PARSE;
 		    looping--;
 		    $$ = new tree_while_command ($2, $4);
 		  }
 		| FOR variable '=' expression optsep opt_list END
 		  {
-		    if ($7 != for_end && $7 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("for", $7);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($7, token::for_end))
+		      ABORT_PARSE;
 		    looping--;
 		    $$ = new tree_for_command ($2, $4, $6);
 		  }
 		| IF expression optsep opt_list END
 		  {
 		    maybe_warn_assign_as_truth_value ($2);
-		    if ($5 != if_end && $5 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("if", $5);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($5, token::if_end))
+		      ABORT_PARSE;
 		    iffing--;
 		    $$ = new tree_if_command ($2, $4);
 		  }
 		| IF expression optsep opt_list ELSE optsep opt_list END
 		  {
 		    maybe_warn_assign_as_truth_value ($2);
-		    if ($8 != if_end && $8 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("if", $8);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($8, token::if_end))
+		      ABORT_PARSE;
 		    iffing--;
 		    tree_if_command *t1 = new tree_if_command ($7);
 		    $$ = t1->chain ($2, $4);
@@ -606,12 +547,8 @@
 		| IF expression optsep opt_list elseif END
 		  {
 		    maybe_warn_assign_as_truth_value ($2);
-		    if ($6 != if_end && $6 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("if", $6);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($6, token::if_end))
+		      ABORT_PARSE;
 		    iffing--;
 		    tree_if_command *t1 = $5->reverse ();
 		    // Add the if list to the new head of the elseif
@@ -621,12 +558,8 @@
 		| IF expression optsep opt_list elseif ELSE optsep opt_list END
 		  {
 		    maybe_warn_assign_as_truth_value ($2);
-		    if ($9 != if_end && $9 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("if", $9);
-			ABORT_PARSE;
-		      }
+		    if (check_end ($9, token::if_end))
+		      ABORT_PARSE;
 		    iffing--;
 		    // Add the else list to the head of the elseif list,
 		    // then reverse the list.
@@ -699,12 +632,13 @@
 		;
 
 expression	: variable '=' expression
-		  { $$ = new tree_simple_assignment_expression ($1, $3); }
+		  { $$ = new tree_simple_assignment_expression
+		      ($1, $3, $2->line (), $2->column ()); }
 		| '[' screwed_again matrix_row SCREW_TWO '=' expression
 		  {
 
 // Will need a way to convert the matrix list to a list of
-// identifiers.  If that fails, we can abort here, without losing
+// identifiers.	 If that fails, we can abort here, without losing
 // anything -- no other possible syntax is valid if we've seen the
 // equals sign as the next token after the `]'.
 
@@ -716,12 +650,13 @@
 		    if (id_list == NULL_TREE)
 		      {
 			yyerror ("parse error");
-		        error ("invalid identifier list for assignment");
+			error ("invalid identifier list for assignment");
 			$$ = (tree_multi_assignment_expression *) NULL;
 			ABORT_PARSE;
 		      }
 		    else
-		      $$ = new tree_multi_assignment_expression (id_list, $6);
+		      $$ = new tree_multi_assignment_expression
+			(id_list, $6, $5->line (), $5->column ());
 		  }
 		| NUM '=' expression
 		  {
@@ -737,58 +672,79 @@
 simple_expr	: simple_expr1
 		  { $$ = $1; }
 		| identifier PLUS_PLUS
-		  { $$ = new tree_postfix_expression ($1, tree::increment); }
+		  { $$ = new tree_postfix_expression
+		      ($1, tree::increment, $2->line (), $2->column ()); }
 		| identifier MINUS_MINUS
-		  { $$ = new tree_postfix_expression ($1, tree::decrement); }
+		  { $$ = new tree_postfix_expression
+		      ($1, tree::decrement, $2->line (), $2->column ()); }
 		| simple_expr QUOTE
-		  { $$ = new tree_unary_expression ($1, tree::hermitian); }
+		  { $$ = new tree_unary_expression
+		      ($1, tree::hermitian, $2->line (), $2->column ()); }
 		| simple_expr TRANSPOSE
-		  { $$ = new tree_unary_expression ($1, tree::transpose); }
+		  { $$ = new tree_unary_expression
+		      ($1, tree::transpose, $2->line (), $2->column ()); }
 		| simple_expr POW simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::power); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::power, $2->line (), $2->column ()); }
 		| simple_expr EPOW simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::elem_pow); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::elem_pow, $2->line (), $2->column ()); }
 		| simple_expr '+' simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::add); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::add, $2->line (), $2->column ()); }
 		| simple_expr '-' simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::subtract); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::subtract, $2->line (), $2->column ()); }
 		| simple_expr '*' simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::multiply); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::multiply, $2->line (), $2->column ()); }
 		| simple_expr '/' simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::divide); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::divide, $2->line (), $2->column ()); }
 		| simple_expr EMUL simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::el_mul); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::el_mul, $2->line (), $2->column ()); }
 		| simple_expr EDIV simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::el_div); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::el_div, $2->line (), $2->column ()); }
 		| simple_expr LEFTDIV simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::leftdiv); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::leftdiv, $2->line (), $2->column ()); }
 		| simple_expr ELEFTDIV simple_expr
-		  { $$ = new tree_binary_expression ($1, $3,
-						     tree::el_leftdiv); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::el_leftdiv, $2->line (), $2->column ()); }
 		| simple_expr EXPR_LT simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_lt); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_lt, $2->line (), $2->column ()); }
 		| simple_expr EXPR_LE simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_le); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_le, $2->line (), $2->column ()); }
 		| simple_expr EXPR_EQ simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_eq); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_eq, $2->line (), $2->column ()); }
 		| simple_expr EXPR_GE simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_ge); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_ge, $2->line (), $2->column ()); }
 		| simple_expr EXPR_GT simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_gt); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_gt, $2->line (), $2->column ()); }
 		| simple_expr EXPR_NE simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::cmp_ne); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::cmp_ne, $2->line (), $2->column ()); }
 		| simple_expr EXPR_AND simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::and); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::and, $2->line (), $2->column ()); }
 		| simple_expr EXPR_OR simple_expr
-		  { $$ = new tree_binary_expression ($1, $3, tree::or); }
+		  { $$ = new tree_binary_expression
+		      ($1, $3, tree::or, $2->line (), $2->column ()); }
 		;
 
 simple_expr1	: NUM
-		  { $$ = new tree_constant ($1); }
+		  { $$ = new tree_constant ($1->number ()); }
 		| IMAG_NUM
-		  { $$ = new tree_constant (Complex (0.0, $1)); }
+		  { $$ = new tree_constant (Complex (0.0, $1->number ())); }
 		| TEXT
-		  { $$ = new tree_constant ($1); }
+		  { $$ = new tree_constant ($1->string ()); }
 		| word_list_cmd
 		  { $$ = $1; }
 		| '(' expression ')'
@@ -804,19 +760,24 @@
 		| colon_expr
 		  { $$ = $1; }
 		| PLUS_PLUS identifier %prec UNARY
-		  { $$ = new tree_prefix_expression ($2, tree::increment); }
+		  { $$ = new tree_prefix_expression
+		      ($2, tree::increment, $1->line (), $1->column ()); }
 		| MINUS_MINUS identifier %prec UNARY
-		  { $$ = new tree_prefix_expression ($2, tree::decrement); }
+		  { $$ = new tree_prefix_expression
+		      ($2, tree::decrement, $1->line (), $1->column ()); }
 		| EXPR_NOT simple_expr
-		  { $$ = new tree_unary_expression ($2, tree::not); }
+		  { $$ = new tree_unary_expression
+		      ($2, tree::not, $1->line (), $1->column ()); }
 		| '+' simple_expr %prec UNARY
 		  { $$ = $2; }
 		| '-' simple_expr %prec UNARY
-		  { $$ = new tree_unary_expression ($2, tree::uminus); }
+		  { $$ = new tree_unary_expression
+		      ($2, tree::uminus, $1->line (), $1->column ()); }
 		;
 
 colon_expr	: simple_expr ':' simple_expr
-		  { $$ = new tree_colon_expression ($1, $3); }
+		  { $$ = new tree_colon_expression
+		      ($1, $3, $2->line (), $2->column ()); }
 		| colon_expr ':' simple_expr
 		  {
 		    $$ = $1->chain ($3);
@@ -838,9 +799,8 @@
 			error ("clear: invalid within function body");
 			ABORT_PARSE;
 		      }
-		    symbol_record *sr = global_sym_tab->lookup ("clear", 1, 0);
-		    assert (sr != (symbol_record *) NULL);
-		    tree_identifier *tmp = new tree_identifier (sr);
+		    tree_identifier *tmp = new tree_identifier
+		      ($1->sym_rec (), $1->line (), $1->column ());
 		    $$ = new tree_word_list_command (tmp,
 						     (tree_word_list *) NULL);
 		  }
@@ -852,9 +812,8 @@
 			error ("clear: invalid within function body");
 			ABORT_PARSE;
 		      }
-		    symbol_record *sr = global_sym_tab->lookup ("clear", 1, 0);
-		    assert (sr != (symbol_record *) NULL);
-		    tree_identifier *tmp = new tree_identifier (sr);
+		    tree_identifier *tmp = new tree_identifier
+		      ($1->sym_rec (), $1->line (), $1->column ());
 		    $$ = new tree_word_list_command (tmp, $2);
 		  }
 		;
@@ -864,9 +823,9 @@
 		;
 
 word_list1	: TEXT
-		  { $$ = new tree_word_list ($1); }
+		  { $$ = new tree_word_list ($1->string ()); }
 		| word_list1 TEXT
-		  { $$ = $1->chain ($2); }
+		  { $$ = $1->chain ($2->string ()); }
 		;
 
 // This is truly disgusting.
@@ -903,7 +862,8 @@
 
 func_def1	: SCREW safe g_symtab '=' func_def2
 		  {
-		    tree_identifier *tmp = new tree_identifier ($1);
+		    tree_identifier *tmp = new tree_identifier
+		      ($1->sym_rec (), $1->line (), $1->column ());
 		    tree_parameter_list *tpl = new tree_parameter_list (tmp);
 		    tpl = tpl->reverse ();
 		    tpl->mark_as_formal_parameters ();
@@ -958,6 +918,7 @@
 			top_level_sym_tab->clear (id_name);
 		      }
 
+		    $4->stash_function_name (id_name);
 		    $$ = $4;
 		  }
 		;
@@ -975,12 +936,8 @@
 
 fcn_end_or_eof	: END
 		  {
-		    if ($1 != function_end && $1 != simple_end)
-		      {
-			yyerror ("parse error");
-			end_error ("function", $1);
+		    if (check_end ($1, token::function_end))
 			ABORT_PARSE;
-		      }
 
 		    if (reading_m_file)
 		      check_for_garbage_after_fcn_def ();
@@ -1035,7 +992,8 @@
 		;
 
 identifier	: NAME
-		  { $$ = new tree_identifier ($1); }
+		  { $$ = new tree_identifier
+		      ($1->sym_rec (), $1->line (), $1->column ()); }
 
 arg_list	: arg_list1
 		  { $$ = $1->reverse (); }
@@ -1101,7 +1059,7 @@
 		      {
 			mlnm.pop ();
 			mlnm.push (0);
-		        tree_matrix *tmp = new tree_matrix ($1, tree::md_none);
+			tree_matrix *tmp = new tree_matrix ($1, tree::md_none);
 			ml.push (tmp);
 		      }
 		    else
@@ -1126,7 +1084,7 @@
 yyerror (char *s)
 {
   char *line = current_input_line;
-  int err_col = current_input_column;
+  int err_col = current_input_column - 1;
   if (err_col == 0)
     err_col = strlen (current_input_line) + 1;
 
@@ -1152,25 +1110,62 @@
     fprintf (stderr, ":\n\n  %s\n  %*s\n\n", line, err_col, "^");
 }
 
+static int
+check_end (token *tok, token::end_tok_type expected)
+{
+  token::end_tok_type ettype = tok->ettype ();
+  if (ettype != expected && ettype != token::simple_end)
+    {
+      yyerror ("parse error");
+
+      int l = tok->line ();
+      int c = tok->column ();
+
+      switch (expected)
+	{
+	case token::for_end:
+	  end_error ("for", ettype, l, c);
+	  break;
+	case token::function_end:
+	  end_error ("function", ettype, l, c);
+	  break;
+	case token::if_end:
+	  end_error ("if", ettype, l, c);
+	  break;
+	case token::while_end:
+	  end_error ("while", ettype, l, c);
+	  break;
+	default:
+	  panic_impossible ();
+	  break;
+	}
+      return 1;
+    }
+  else
+    return 0;
+}
+
 static void
-end_error (char *type, end_tok_type ettype)
+end_error (char *type, token::end_tok_type ettype, int l, int c)
 {
+  static char *fmt = "%s command matched by `%s' near line %d column %d";
+
   switch (ettype)
     {
-    case simple_end:
-      error ("%s command matched by `end'", type);
+    case token::simple_end:
+      error (fmt, type, "end", l, c);
       break;
-    case for_end:
-      error ("%s command matched by `endfor'", type);
+    case token::for_end:
+      error (fmt, type, "endfor", l, c);
       break;
-    case function_end:
-      error ("%s command matched by `endfunction'", type);
+    case token::function_end:
+      error (fmt, type, "endfunction", l, c);
       break;
-    case if_end:
-      error ("%s command matched by `endif'", type);
+    case token::if_end:
+      error (fmt, type, "endif", l, c);
       break;
-    case while_end:
-      error ("%s command matched by `endwhile'", type);
+    case token::while_end:
+      error (fmt, type, "endwhile", l, c); 
       break;
     default:
       panic_impossible ();