changeset 2323:626d9ac52bc9

(YACC): flag added to c_ext. (c_ext): no more a synonim for c_ext&C_PLPL because of YACC. (find_entries): consistently use streq when reasonable. (find_entries): a .y file is a yacc file. (get_C_stab): c_ext becomes c_ext&C_PLPL. (C_entries): logical cplpl means c_ext&C_PLPL. (C_entries): logical yacc_rules means we are after the first %%. (C_entries): added logic for yacc files. (C_entries): ':' case moved to the second switch. (C_entries): do not examine token if structdef==scolonseen. (consider_token): structtag set to null string for enum. (GET_COOKIE): and related macros removed. (logical): is now int, no more a char. (reg): define deleted. (isgood, _gd, notgd): deleted. (gotone): deleted. (TOKEN): member linestart removed. (linepos, prev_linepos, lb1): deleted. (main): call initbuffer on lbs array instead of lb1. (init): removed the initialisation of the logical _gd array; (find_entries): a .sa suffix means assembler file. (C_create_stab): "auto", "void", "extern", "static" are st_C_typespec. All C state machines rewritten. (C_entries): complete rewrite. (condider_token): complete rewrite. (getline): deleted. (C_entries): Added the quotednl logical variable. Used for parsing of #define's spanning multiple lines. (C_entries): Save the definedef status even when a newline is met inside a string.
author Richard M. Stallman <rms@gnu.org>
date Mon, 22 Mar 1993 23:13:10 +0000
parents a7ea7887481f
children 24cd3df6f184
files lib-src/etags.c
diffstat 1 files changed, 423 insertions(+), 466 deletions(-) [+]
line wrap: on
line diff
--- a/lib-src/etags.c	Mon Mar 22 23:00:48 1993 +0000
+++ b/lib-src/etags.c	Mon Mar 22 23:13:10 1993 +0000
@@ -1,5 +1,5 @@
 /* Tags file maker to go with GNU Emacs
-   Copyright (C) 1984, 1987, 1988, 1989, 1992 Free Software Foundation, Inc. and Ken Arnold
+   Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
 
 This file is part of GNU Emacs.
 
@@ -86,8 +86,6 @@
  *
  *	long GET_CHARNO (pos)
  *				returns absolute char number.
- *	long GET_COOKIE (pos)
- *				returns ftell () cookie.
  *	void SET_FILEPOS (pos, fp, charno)
  *	    FILE *fp; long charno;
  *				sets `pos' from the current file
@@ -105,44 +103,29 @@
  *
  * Implementation notes: the `+ 0' is to enforce rvalue-ness.
  */
-#ifdef VMS
-typedef struct
-{
-  long cookie;
-  long charno;
-} FILEPOS;
 
-#define GET_CHARNO(pos)	((pos).charno + 0)
-#define GET_COOKIE(pos)	((pos).cookie + 0)
-#define SET_FILEPOS(pos, fp, cno) \
-    ((void) ((pos).cookie = ftell (fp), (pos).charno = (cno)))
-#else
 #ifndef DEBUG
- /* UNIX real implementation */
+ /* real implementation */
 typedef long FILEPOS;
 #define GET_CHARNO(pos)	((pos) + 0)
-#define GET_COOKIE(pos)	GET_CHARNO (pos)
 #define SET_FILEPOS(pos, fp, cno)	((void) ((pos) = (cno)))
 #else
- /* UNIX debugging implementation */
+ /* debugging implementation */
 typedef struct
 {
   long charno;
 } FILEPOS;
 
 #define GET_CHARNO(pos)	((pos).charno + 0)
-#define GET_COOKIE(pos)	GET_CHARNO (pos)
 #define SET_FILEPOS(pos, fp, cno)					\
     ((void) ((pos).charno = (cno),					\
 	     (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
 	     			 : 0))
 #endif
-#endif
 
 #define streq(s, t)	(strcmp (s, t) == 0)
 #define strneq(s, t, n)	(strncmp (s, t, n) == 0)
-#define	reg	register
-#define	logical	char
+#define	logical		int
 
 #define	TRUE	1
 #define	FALSE	0
@@ -151,7 +134,6 @@
 #define	begtoken(arg)	(_btk[arg])	/* T if char can start token	*/
 #define	intoken(arg)	(_itk[arg])	/* T if char can be in token	*/
 #define	endtoken(arg)	(_etk[arg])	/* T if char ends tokens	*/
-#define	isgood(arg)	(_gd[arg])	/* T if char can be after ')'	*/
 
 #define	max(I1,I2)	((I1) > (I2) ? (I1) : (I2))
 
@@ -171,10 +153,9 @@
 long ftell ();
 typedef struct nd_st NODE;
 
-logical gotone,			/* found a func already on line	*/
- /* boolean "func" (see init)	*/
-  header_file,			/* TRUE if .h file, FALSE o.w.  */
-  _wht[0177], _etk[0177], _itk[0177], _btk[0177], _gd[0177];
+logical header_file;		/* TRUE if .h file, FALSE o.w.  */
+/* boolean "functions" (see init)	*/
+logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
 
 
 char *concat ();
@@ -348,87 +329,20 @@
 {
   char *p;
   int len;
-  FILEPOS linestart;
   LINENO lineno;
   logical rewritten;
 } TOKEN;
-
 
- /* typedefs are recognized using a simple finite automaton.
-  * tydef is its state variable.
-  */
-typedef enum
-{
-  none, begin, middle, end
-} TYST;
-
-TYST tydef = none;
-
-
- /* struct tags for C++ are recognized using another simple
-  * finite automaton.  `structdef' is its state variable.
-  * This machinery is only invoked for C++; otherwise structdef
-  * should remain snone.  However, this machinery can easily be
-  * adapted to find structure tags in normal C code.
-  */
-typedef enum
-{
-  snone,			/* nothing seen yet */
-  skeyseen,			/* struct-like keyword seen */
-  stagseen,			/* struct-like tag seen */
-  scolonseen,			/* colon seen after struct-like tag */
-  sinbody			/* in a class body: recognize member func defs */
-} STRUCTST;
-STRUCTST structdef = snone;
-/*
- * When structdef is stagseen, scolonseen, or sinbody, structtag is the
- * struct tag, and structkey is the preceding struct-like keyword.
+/* C extensions.
  */
-char structtag[512];
-Stab_entry *structkey;
-
-/*
- * Yet another little state machine to deal with preprocessor lines.
- */
-typedef enum
-{
-  dnone,			/* nothing seen */
-  dsharpseen,			/* '#' seen as first char on line */
-  ddefineseen,			/* '#' and 'define' seen */
-  dignorerest			/* ignore rest of line */
-} DEFINEST;
-DEFINEST definedef;
-
-/*
- * LEVEL_OK_FOR_FUNCDEF allows C++ function definition within class body.
- * Currently tydef and structdef stuff (typedefs and struct definitions) are
- * only noticed when level==0, but that may change.
- *
- * Note that this macro may only be evaluated inside C_entries().  It is
- * for self-documentation only.
- */
-#define LEVEL_OK_FOR_FUNCDEF()					\
-	(level==0 || (c_ext && level==1 && structdef==sinbody))
-
-/*
- * next_token_is_func
- *	set this to TRUE, and the next token considered is called a function.
- */
-logical next_token_is_func;
-
-/* C extensions.  Currently all listed extensions are C++ dialects, so
- * `c_ext' is used as an abbreviation for `c_ext&C_PLPL'.  If a non-C++
- * dialect is added, this must change.
- */
-#define C_PLPL	0x1		/* C++ */
-#define C_STAR	0x3		/* C* */
+#define C_PLPL	0x00001		/* C++ */
+#define C_STAR	0x00003		/* C* */
+#define YACC	0x10000		/* yacc file */
 
 char searchar = '/';		/* use /.../ searches 		*/
 
 LINENO lineno;			/* line number of current line */
 long charno;			/* current character number */
-FILEPOS linepos;		/* start of line (C only) */
-FILEPOS prev_linepos;		/* start of previous line (C only) */
 
 long linecharno;		/* charno of start of line; not used by C, but
 				 * by every other language.
@@ -437,10 +351,11 @@
 char *curfile,			/* current input file name		*/
  *outfile,			/* output file				*/
  *white = " \f\t\n",		/* white chars				*/
- *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",	/* token ending chars			*/
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",	/* token starting chars			*/
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",	/* valid in-token chars			*/
- *notgd = ",;";			/* non-valid after-function chars	*/
+ *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",	/* token ending chars	*/
+				/* token starting chars			*/
+ *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
+				  /* valid in-token chars		*/
+ *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
 
 int append_to_tagfile;		/* -a: append to tags */
 int emacs_tags_format;		/* emacs style output (no -e option any more) */
@@ -502,10 +417,13 @@
 };
 
 struct linebuffer lb;		/* the current line */
-struct linebuffer lb1;		/* sometimes, a previous line in which a token lies */
 struct linebuffer filename_lb;	/* used to read in filenames */
+struct
+{
+  FILEPOS linepos;
+  struct linebuffer lb;		/* used by C_entries instead of lb */
+} lbs[2];
 
-
 void
 print_version ()
 {
@@ -758,7 +676,8 @@
   init ();			/* set up boolean "functions"		*/
 
   initbuffer (&lb);
-  initbuffer (&lb1);
+  initbuffer (&lbs[0].lb);
+  initbuffer (&lbs[1].lb);
   initbuffer (&filename_lb);
   /*
    * loop through files finding functions
@@ -791,7 +710,7 @@
 	  this_file = massage_name (this_file);
 #if 0
 	}
-    }				/* solely to balance out the ifdef'd parens above */
+    }			/* solely to balance out the ifdef'd parens above */
 #endif
 #else
   for (; optind < argc; optind++)
@@ -915,14 +834,11 @@
 void
 init ()
 {
-  reg char *sp;
-  reg int i;
+  register char *sp;
+  register int i;
 
   for (i = 0; i < 0177; i++)
-    {
-      _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
-      _gd[i] = TRUE;
-    }
+    _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
   for (sp = white; *sp; sp++)
     _wht[*sp] = TRUE;
   for (sp = endtk; *sp; sp++)
@@ -931,13 +847,10 @@
     _itk[*sp] = TRUE;
   for (sp = begtk; *sp; sp++)
     _btk[*sp] = TRUE;
-  for (sp = notgd; *sp; sp++)
-    _gd[*sp] = FALSE;
   _wht[0] = _wht['\n'];
   _etk[0] = _etk['\n'];
   _btk[0] = _btk['\n'];
   _itk[0] = _itk['\n'];
-  _gd[0] = _gd['\n'];
 }
 
 /*
@@ -998,8 +911,11 @@
       fclose (inf);
       return;
     }
-  /* Assume that ".s" or ".a" is assembly code. -wolfgang.  */
-  if (cp && (cp[1] == 's' || cp[1] == 'a') && cp[2] == '\0')
+  /* Assume that ".s" or ".a" is assembly code. -wolfgang.
+     Or even ".sa". */
+  if (cp && (streq (cp + 1, "s")
+	     || streq (cp + 1, "a")
+	     || streq (cp + 1, "sa")))
     {
       Asm_funcs (inf);
       fclose (inf);
@@ -1016,13 +932,20 @@
       goto close_and_return;
     }
   /* .cs or .hs: a C* file */
-  if (cp && (cp[1] == 'c' || cp[1] == 'h') && cp[2] == 's' && cp[3] == '\0')
+  if (cp && (streq (cp + 1, "cs")
+	     || streq (cp + 1, "hs")))
     {
       C_entries (C_STAR);
       goto close_and_return;
     }
+  /* .y: a yacc file */
+  if (cp && (streq (cp + 1, "y")))
+    {
+      C_entries (YACC);
+      goto close_and_return;
+    }
   /* .pl implies prolog source code */
-  if (cp && !strcmp (cp + 1, "pl"))
+  if (cp && streq (cp + 1, "pl"))
     {
       prolog_funcs (inf);
       goto close_and_return;
@@ -1035,7 +958,8 @@
       goto close_and_return;
     }
   /* If .f or .for, assume it is fortran or nothing.  */
-  if (cp && (streq (cp + 1, "f") || streq (cp + 1, "for")))
+  if (cp && (streq (cp + 1, "f")
+	     || streq (cp + 1, "for")))
     {
       PF_funcs (inf);
       goto close_and_return;
@@ -1072,7 +996,6 @@
 
 /* Record a tag. */
 /* Should take a TOKEN* instead!! */
-
 void
 pfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
      char *name;		/* tag name */
@@ -1238,9 +1161,9 @@
 
 void
 put_entries (node)
-     reg NODE *node;
+     register NODE *node;
 {
-  reg char *sp;
+  register char *sp;
 
   if (node == NULL)
     return;
@@ -1319,9 +1242,9 @@
  */
 int
 total_size_of_entries (node)
-     reg NODE *node;
+     register NODE *node;
 {
-  reg int total;
+  register int total;
 
   if (node == NULL)
     return 0;
@@ -1352,8 +1275,8 @@
  * SYNOPSIS
  *	Stab *get_C_stab (int c_ext);
  */
-#define get_C_stab(c_ext) ((c_ext&C_STAR) ? C_STAR_stab :		\
-			   c_ext ? C_PLPL_stab :			\
+#define get_C_stab(c_ext) ((c_ext & C_STAR) ? C_STAR_stab :		\
+			   (c_ext & C_PLPL) ? C_PLPL_stab :		\
 			   C_stab)
 
 void
@@ -1391,6 +1314,10 @@
   add_keyword (stab, "double", st_C_typespec);
   add_keyword (stab, "signed", st_C_typespec);
   add_keyword (stab, "unsigned", st_C_typespec);
+  add_keyword (stab, "auto", st_C_typespec);
+  add_keyword (stab, "void", st_C_typespec);
+  add_keyword (stab, "extern", st_C_typespec);
+  add_keyword (stab, "static", st_C_typespec);
   add_keyword (stab, "const", st_C_typespec);
   add_keyword (stab, "volatile", st_C_typespec);
 
@@ -1405,50 +1332,142 @@
   C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
 }
 
+ /*
+  *	etags.c 4.2 1993/03/22 12:13:40 pot Exp
+  * C functions are recognized using a simple finite automaton.
+  * funcdef is its state variable.
+  */
+typedef enum
+{
+  fnone, ftagseen, finlist, flistseen
+} FUNCST;
+FUNCST funcdef;
+
+
+ /* typedefs are recognized using a simple finite automaton.
+  * typeddef is its state variable.
+  */
+typedef enum
+{
+  tnone, ttypedseen, tinbody, tend
+} TYPEDST;
+TYPEDST typdef;
+
+
+ /* struct tags for C++ are recognized using another simple
+  * finite automaton.  `structdef' is its state variable.
+  * This machinery is only invoked for C++; otherwise structdef
+  * should remain snone.  However, this machinery can easily be
+  * adapted to find structure tags in normal C code.
+  */
+typedef enum
+{
+  snone,			/* nothing seen yet */
+  skeyseen,			/* struct-like keyword seen */
+  stagseen,			/* struct-like tag seen */
+  scolonseen,			/* colon seen after struct-like tag */
+  sinbody			/* in class body: recognize member func defs */
+} STRUCTST;
+STRUCTST structdef;
+/*
+ * When structdef is stagseen, scolonseen, or sinbody, structtag is the
+ * struct tag, and structkey is the preceding struct-like keyword.
+ */
+char structtag[BUFSIZ];
+Stab_entry *structkey;
+
+/*
+ * Yet another little state machine to deal with preprocessor lines.
+ */
+typedef enum
+{
+  dnone,			/* nothing seen */
+  dsharpseen,			/* '#' seen as first char on line */
+  ddefineseen,			/* '#' and 'define' seen */
+  dignorerest			/* ignore rest of line */
+} DEFINEST;
+DEFINEST definedef;
+
+/*
+ * Set this to TRUE, and the next token considered is called a function.
+ * Used only for GNUmacs's function-defining macros.
+ */
+logical next_token_is_func;
+
+/*
+ * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
+ */
+logical yacc_rules;
+
 /*
  * C_entries ()
- *	This routine finds functions and typedefs in C syntax and adds them
+ *	This routine finds functions, typedefs, #define's and
+ * 	struct/union/enum definitions in C syntax and adds them
  *	to the list.
  */
 
+/*
+ * LEVEL_OK_FOR_FUNCDEF allows C++ function definition within class body.
+ * Currently typdef and structdef stuff (typedefs and struct
+ * definitions) are only noticed when level==0, but that may change.
+ */
+#define LEVEL_OK_FOR_FUNCDEF()					\
+	(level==0 || (cplpl && level==1 && structdef==sinbody))
+
+#define curlb (lbs[curndx].lb)
+#define othlb (lbs[1-curndx].lb)
+#define newlb (lbs[newndx].lb)
+#define curlinepos (lbs[curndx].linepos)
+#define othlinepos (lbs[1-curndx].linepos)
+#define newlinepos (lbs[newndx].linepos)
+
 #define CNL_SAVE_DEFINEDEF						\
-{									\
+do {									\
+  SET_FILEPOS (curlinepos, inf, charno);				\
+  lineno++;								\
+  charno += readline (&curlb, inf);					\
+  lp = curlb.buffer;							\
   quotednl = FALSE;							\
-  prev_linepos = linepos;						\
-  SET_FILEPOS (linepos, inf, charno);					\
-  lineno++;								\
-  charno += readline (&lb, inf);					\
-  lp = lb.buffer;							\
-}
+  newndx = curndx;							\
+} while (FALSE)
 
 #define CNL								\
-{									\
+do {									\
   CNL_SAVE_DEFINEDEF;							\
   definedef = dnone;							\
-}
+} while (FALSE)
+
+#define MAKE_TAG_FROM_NEW_LB(isfun)  pfnote (tokb, isfun, tok.rewritten, \
+  newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
+#define MAKE_TAG_FROM_OTH_LB(isfun)  pfnote (tokb, isfun, tok.rewritten, \
+  othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
 
 void
 C_entries (c_ext)
      int c_ext;			/* extension of C? */
 {
-  register int c;		/* latest char read; '\0' for end of line */
-  register int tokoff;		/* offset in line of start of latest token*/
-  register int toklen;		/* length of latest token */
+  register char c;		/* latest char read; '\0' for end of line */
   register char *lp;		/* pointer one beyond the character `c' */
-  logical incomm, inquote, inchar, quotednl, midtoken;
+  int curndx, newndx;		/* indices for current and new lb */
+  TOKEN tok;			/* latest token read for funcdef & structdef */
+  char tokb[BUFSIZ];		/* latest token name for funcdef & structdef */
+  register int tokoff;		/* offset in line of start of latest token */
+  register int toklen;		/* length of latest token */
   int level;			/* current curly brace level */
-  char tokb[BUFSIZ];
+  logical incomm, inquote, inchar, quotednl, midtoken;
+  logical cplpl;
 
+  curndx = newndx = 0;
   lineno = 0;
   charno = 0;
-  lp = lb.buffer;
+  lp = curlb.buffer;
   *lp = 0;
 
-  definedef = dnone;
-  gotone = midtoken = inquote = inchar = incomm = quotednl = FALSE;
+  definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
+  next_token_is_func = yacc_rules = FALSE;
+  midtoken = inquote = inchar = incomm = quotednl = FALSE;
   level = 0;
-  tydef = none;
-  next_token_is_func = 0;
+  cplpl = c_ext & C_PLPL;
 
   C_create_stabs ();
 
@@ -1460,9 +1479,9 @@
 	  /* If we're at the end of the line, the next character is a
 	     '\0'; don't skip it, because it's the thing that tells us
 	     to read the next line.  */
-	  if (*lp == 0)
+	  if (*lp == '\0')
 	    {
-	      quotednl =TRUE;
+	      quotednl = TRUE;
 	      continue;
 	    }
 	  lp++;
@@ -1470,18 +1489,38 @@
 	}
       else if (incomm)
 	{
-	  if (c == '*' && *lp == '/')
+	  switch (c)
 	    {
-	      c = *lp++;
-	      incomm = FALSE;
+	    case '*':
+	      if (*lp == '/')
+		{
+		  c = *lp++;
+		  incomm = FALSE;
+		}
+	      break;
+	    case '\0':
+	      /* Newlines inside comments do not end macro definitions in
+		 traditional cpp. */
+	      CNL_SAVE_DEFINEDEF;
+	      break;
 	    }
+	  continue;
 	}
       else if (inquote)
 	{
-	  if (c == '"')
-	    inquote = FALSE;
-	  else if (c == '\\')
-	    c = *lp++;
+	  switch (c)
+	    {
+	    case '"':
+	      inquote = FALSE;
+	      break;
+	    case '\0':
+	      /* Newlines inside strings, do not end macro definitions
+		 in traditional cpp, even though compilers don't
+		 usually accept them. */
+	      CNL_SAVE_DEFINEDEF;
+	      break;
+	    }
+	  continue;
 	}
       else if (inchar)
 	{
@@ -1489,7 +1528,7 @@
 	    inchar = FALSE;
 	  continue;
 	}
-      else
+      else 
 	switch (c)
 	  {
 	  case '"':
@@ -1503,77 +1542,44 @@
 	      {
 		lp++;
 		incomm = TRUE;
+		continue;
 	      }
-	    else if (c_ext && *lp == '/')
+	    else if (cplpl && *lp == '/')
 	      {
 		c = 0;
 		break;
 	      }
 	    continue;
+	  case '%':
+	    if ((c_ext & YACC) && *lp == '%')
+	      {
+		/* entering or exiting rules section in yacc file */
+		lp++;
+		definedef = dnone; funcdef = fnone;
+		typdef= tnone; structdef= snone;
+		next_token_is_func = FALSE;
+		midtoken = inquote = inchar = incomm = quotednl = FALSE;
+		level = 0;
+		yacc_rules = !yacc_rules;
+		continue;
+	      }
 	  case '#':
-	    if (lp == lb.buffer + 1 && definedef == dnone)
+	    if (lp == newlb.buffer + 1 && definedef == dnone)
 	      definedef = dsharpseen;
 	    continue;
+	  } /* switch (c) */
 
-	    /*
-	     * The next two are to help the strucdef state machine.
-	     * They break when they are finished, so they don't interfere
-	     * with anything else that is going on.
-	     */
-	  case ':':
-	    if (structdef == stagseen)
-	      structdef = scolonseen;
-	    break;
-	    /* Not a struct definition when semicolon seen
-	       in non-sinbody context. */
-	  case ';':
-	    if (structdef != snone && structdef != sinbody)
-	      {
-		structdef = snone;
-		(void) strcpy (structtag, "<error 1>");
-	      }
-	    break;
 
-	  case '{':
-	    if (tydef == begin)
-	      {
-		tydef = middle;
-	      }
-	    switch (structdef)
-	      {
-	      case skeyseen:	/* unnamed struct */
-		structtag[0] = '\0';
-		/* FALLTHRU */
-	      case stagseen:
-	      case scolonseen:	/* named struct */
-		structdef = sinbody;
-		break;
-	      }
-	    level++;
-	    continue;
-	  case '}':
-	    if (!noindentypedefs && lp == lb.buffer + 1)
-	      level = 0;	/* reset level if first column */
-	    else if (level > 0)
-	      level--;
-	    if (level == 0 && tydef == middle)
-	      {
-		tydef = end;
-	      }
-	    if (level == 0)
-	      {
-		structdef = snone;
-		(void) strcpy (structtag, "<error 2>");
-	      }
-	    continue;
-	  }
-      if (LEVEL_OK_FOR_FUNCDEF () && !inquote && !incomm && gotone == FALSE)
+      if (LEVEL_OK_FOR_FUNCDEF ()
+	  && definedef != dignorerest
+	  && structdef != scolonseen
+	  && funcdef != finlist)
 	{
 	  if (midtoken)
 	    {
 	      if (endtoken (c))
 		{
-		  if (c_ext && c == ':' && *lp == ':' && intoken (*(lp + 1)))
+		  if (cplpl && c == ':' && *lp == ':' && intoken (*(lp + 1)))
 		    {
 		      /*
 		       * This handles :: in the middle, but not at beginning
@@ -1584,72 +1590,22 @@
 		    }
 		  else
 		    {
-		      /* The following is no longer true,
-			 now that we advance to the next line
-			 at the end of processing the character.  */
-		      /*
-		       * We've just finished lexing an identifier.
-		       * Note that if `c' is '\0', `lb' is the NEXT
-		       * line, `lp' points to the beginning of it, and
-		       * old pointers into `lb.buffer' may no longer be
-		       * valid, since `lb.buffer' may have been
-		       * reallocated.  In this case (which corresponds
-		       * to an identifier followed immediately by a
-		       * newline), we re-read the line into lb1.
-		       *
-		       * This would be faster if the previous line's
-		       * buffer were always saved.
-		       */
 		      logical is_func;
-		      char *tok_linebuf;
-		      TOKEN tok;
-		      logical bingo, tok_at_end_of_line;
-		      char *lp_tmp;	/* addressable */
 
-#if 0
-		      if (c == '\0')
-			{
-			  getline (GET_COOKIE (prev_linepos));
-			  tok_linebuf = lb1.buffer;
-			  tok_at_end_of_line = TRUE;
-			  tok.linestart = prev_linepos;
-			  tok.lineno = lineno - 1;
-			}
-		      else
-#endif
-			{
-			  tok_linebuf = lb.buffer;
-			  tok_at_end_of_line = FALSE;
-			  tok.linestart = linepos;
-			  tok.lineno = lineno;
-			}
-		      tok.p = tok_linebuf + tokoff;
+		      tok.lineno = lineno;
+		      tok.p = newlb.buffer + tokoff;
 		      tok.len = toklen;
 		      tok.rewritten = FALSE;
-		      lp_tmp = lp;
-		      bingo = consider_token (c, &lp_tmp, &tok,
-					      &is_func, c_ext, level);
-		      lp = lp_tmp;
-		      if (bingo)
+		      if (yacc_rules
+			  || consider_token (c, lp, &tok,
+					     c_ext, level, &is_func))
 			{
-			  if (GET_CHARNO (tok.linestart) != GET_CHARNO(linepos)
-			      && !tok_at_end_of_line)
-			    {
-			      /*
-			       * Resynchronize tok.p to point into the right
-			       * linebuffer.
-			       */
-			      getline (GET_COOKIE (tok.linestart));
-			      if (!tok.rewritten)
-				tok.p = lb1.buffer + (tok.p - tok_linebuf);
-			      tok_linebuf = lb1.buffer;
-			    }
 			  if (structdef == sinbody
 			      && definedef == dnone && is_func)
 			    {	/* function defined in C++ class body */
 			      sprintf (tokb, "%s::%.*s",
-				       structtag[0] == '\0' ? "_anonymous_"
-				       : structtag,
+				       ((structtag[0] == '\0')
+					? "_anonymous_" : structtag),
 				       tok.len, tok.p);
 			      tok.rewritten = TRUE;
 			    }
@@ -1657,49 +1613,148 @@
 			    {
 			      sprintf (tokb, "%.*s", tok.len, tok.p);
 			    }
-			  pfnote (tokb, is_func, tok.rewritten, tok_linebuf,
-			     tokoff + toklen + (tok_at_end_of_line ? 0 : 1),
-				  tok.lineno, GET_CHARNO (tok.linestart));
-			  gotone = is_func;	/* function */
+
+			  if (funcdef == ftagseen || structdef == stagseen)
+			    {
+			      if (newndx == curndx)
+				curndx = 1 - curndx; /* switch line buffers */
+			    }
+			  else
+			    MAKE_TAG_FROM_NEW_LB (is_func);
 			}
 		      midtoken = FALSE;
 		    }
-		}
+		} /* if (endtoken (c)) */
 	      else if (intoken (c))
-		toklen++;
-	    }
+		{
+		  toklen++;
+		  continue;
+		}
+	    } /* if (midtoken) */
 	  else if (begtoken (c))
 	    {
-	      tokoff = lp - 1 - lb.buffer;
-	      toklen = 1;
-	      midtoken = TRUE;
+	      switch (funcdef)
+		{
+		case flistseen:
+		  MAKE_TAG_FROM_OTH_LB (TRUE);
+		  /* FALLTHRU */
+		case ftagseen:
+		  funcdef = fnone;
+		  break;
+		}
+	      if (structdef == stagseen)
+		structdef = snone;
+	      if (!yacc_rules || lp == newlb.buffer + 1)
+		{
+		  tokoff = lp - 1 - newlb.buffer;
+		  toklen = 1;
+		  midtoken = TRUE;
+		}
+	      continue;
 	    }
-	}
-      /* Detect end of line, having handled the last token on the line.  */
-      if (c == 0)
+	} /* if must look at token */
+
+
+      /* Detect end of line, colon, comma, semicolon and various braces
+	 after having handled the last token on the line.*/
+      switch (c)
 	{
-	  if (incomm || inquote || quotednl)
+	case ':':
+	  if (structdef == stagseen)
+	    structdef = scolonseen;
+	  else if (yacc_rules && funcdef == ftagseen)
+	    {
+	      MAKE_TAG_FROM_OTH_LB (FALSE);
+	      funcdef == fnone;
+	    }
+	  break;
+	case ';':
+	  funcdef = fnone;
+	  /* FALLTHRU */
+	case ',':
+	  if (funcdef != finlist)
+	    funcdef = fnone;
+	  if (level == 0 && typdef == tend)
+	    typdef = tnone;
+	  /* FALLTHRU */
+	case '[':
+	  if (funcdef != finlist)
+	    funcdef = fnone;
+	  if (structdef == stagseen)
+	    structdef = snone;
+	  break;
+	case '(':
+	  switch (funcdef)
 	    {
-	      CNL_SAVE_DEFINEDEF;
+	    case ftagseen:
+	      funcdef = finlist;
+	      break;
+	    case finlist:
+	    case flistseen:
+	      funcdef = fnone;
+	      break;
 	    }
-	  else
+	  break;
+	case ')':
+	  if (funcdef == finlist)
+	    funcdef = flistseen;
+	  break;
+	case '{':
+	  if (typdef == ttypedseen)
+	    typdef = tinbody;
+	  switch (structdef)
 	    {
-	      CNL;
+	    case skeyseen:	/* unnamed struct */
+	      structtag[0] = '\0';
+	      structdef = sinbody;
+	      break;
+	    case stagseen:
+	    case scolonseen:	/* named struct */
+	      structdef = sinbody;
+	      MAKE_TAG_FROM_OTH_LB (FALSE);
+	      break;
 	    }
-	  gotone = FALSE;
-	}
-      if (c == ';' && tydef == end)	/* clean with typedefs */
-	tydef = none;
-    }
+	  level++;
+	  /* FALLTHRU */
+	case '*':
+	  if (funcdef == flistseen)
+	    {
+	      MAKE_TAG_FROM_OTH_LB (TRUE);
+	      funcdef = fnone;
+	    }
+	  break;
+	case '}':
+	  if (!noindentypedefs && lp == newlb.buffer + 1)
+	    level = 0;	/* reset level if first column */
+	  else if (level > 0)
+	    level--;
+	  if (level == 0)
+	    {
+	      if (typdef == tinbody)
+		typdef = tend;
+	      structdef = snone;
+	      (void) strcpy (structtag, "<error 2>");
+	    }
+	  break;
+	case '\0':
+	  /* If a macro spans multiple lines don't reset its state. */
+	  if (quotednl)
+	    CNL_SAVE_DEFINEDEF;
+	  else
+	    CNL;
+	  break;
+	} /* switch (c) */
+
+    } /* while not eof */
 }
 
 /*
  * consider_token ()
  *	checks to see if the current token is at the start of a
- *	function, or corresponds to a typedef.  It updates the input
- *	line pointer *LPP so that the '(' will be in it when it returns.
+ *	function, or corresponds to a typedef, or is a struct/union/enum
+ *	tag.
  *
- *	*IS_FUNC gets TRUE iff the token is a function.
+ *	*IS_FUNC gets TRUE iff the token is a function or macro with args.
  *	C_EXT is which language we are looking at.
  *
  *	In the future we will need some way to adjust where the end of
@@ -1708,31 +1763,30 @@
  *	whatever follows `operator'.
  *
  * Globals
- *	structdef	IN OUT
- *	definedef	IN OUT
- *	tydef		IN OUT
+ *	funcdef			IN OUT
+ *	structdef		IN OUT
+ *	definedef		IN OUT
+ *	typdef			IN OUT
+ *	next_token_is_func	IN OUT
  */
 
 logical
-consider_token (c, lpp, tokp, is_func, c_ext, level)
-     reg char c;		/* IN: first char after the token */
-     char **lpp;		/* IN OUT: *lpp points
-				   to 2nd char after the token */
-     reg TOKEN *tokp;		/* IN */
-     logical *is_func;		/* OUT */
+consider_token (c, lp, tokp, c_ext, level, is_func)
+     register char c;		/* IN: first char after the token */
+     register char *lp;		/* IN: lp points to 2nd char after the token */
+     register TOKEN *tokp;	/* IN */
      int c_ext;			/* IN */
      int level;			/* IN */
+     logical *is_func;		/* OUT */
 {
-  reg char *lp = *lpp;
   logical firsttok;		/* TRUE if have seen first token in ()'s */
   Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
   enum sym_type toktype = stab_type (tokse);
 
-  *is_func = TRUE;		/* a function */
+  *is_func = FALSE;		/* not a function */
 
   /*
-   * Advance the definedef state machine.  We set `gotone' for good measure;
-   * it's redundant.
+   * Advance the definedef state machine.
    */
   switch (definedef)
     {
@@ -1743,95 +1797,63 @@
       if (toktype == st_C_define)
 	{
 	  definedef = ddefineseen;
-	  gotone = FALSE;
 	}
       else
 	{
 	  definedef = dignorerest;
-	  gotone = TRUE;
 	}
-      goto badone;
+      return (FALSE);
     case ddefineseen:
       /*
        * Make a tag for any macro.
-       * This will flub up if there is a newline immediately following
-       * the macro name.
        */
-      *is_func = (c == '(');
       definedef = dignorerest;
-      gotone = TRUE;
+      *is_func = (c == '(');
       if (!*is_func && !constantypedefs)
-	goto badone;
-      goto goodone;
+	return (FALSE);
+      else
+	return (TRUE);
     case dignorerest:
-      goto badone;
+      return (FALSE);
     default:
       error ("internal error: definedef value");
     }
 
   /*
-   * Skip whitespace and comments after the token.  This loop should
-   * also skip C++ comments.
+   * Now typedefs
    */
-  while (1)
+  switch (typdef)
     {
-      /* At whitespace => skip it.  */
-      if (iswhite (c))
-	{
-	  c = *lp++;
-	}
-      /* At a comment => skip to end of comment.  */
-      else if (c == '/' && *lp == '*')
+    case tnone:
+      if (toktype == st_C_typedef)
 	{
-	  /* If we find a comment, skip it.  */
-	  while (!(c == '*' && *lp == '/'))
-	    {
-	      c = *lp++;
-	      if (c == 0)
-		{
-		  lp--;
-		  break;
-		}
-	    }
-	  if (c == '*' && *lp == '/')
-	    {
-	      lp++;		/* lp now points past the '/' */
-	      c = *lp++;	/* c is now the --whatever-- after the '/' */
-	    }
+	  if (typedefs)
+	    typdef = ttypedseen;
+	  return (FALSE);
 	}
-      else
-	break;
-
-      /* If we arrived at eof or eol, decide which one it is.
-	 If it's eol, advance to the next line.  */
-
-      if (c == 0)
+      break;
+    case ttypedseen:
+      switch (toktype)
 	{
-	  lp--;
+	case st_none:
+	case st_C_typespec:
+	  typdef = tend;
+	  break;
+	case st_C_struct:
+	case st_C_enum:
 	  break;
 	}
-    }
-
-  /*
-   * If you have custom token types, or when configuration files can
-   * define custom token types, this switch will be larger.
-   */
-  switch (toktype)
-    {
-    case st_C_typedef:
-      if (typedefs)
+      /* Do not return here, so the structdef stuff has a chance. */
+      break;
+    case tend:
+      switch (toktype)
 	{
-	  tydef = begin;
-	  goto badone;
+	case st_C_typespec:
+	case st_C_struct:
+	case st_C_enum:
+	  return (FALSE);
 	}
-      break;
-    case st_C_typespec:
-      if (tydef == begin || tydef == end)
-	{
-	  tydef = end;
-	  goto badone;
-	}
-      break;
+      return (TRUE);
     }
 
   /*
@@ -1843,71 +1865,45 @@
    * file is plain C.  This is because a struct tag may have the same
    * name as another tag, and this loses with ctags.
    *
-   * This if statement deals with the tydef state machine as follows: if
-   * tydef==begin and token is struct/union/class/enum, goto badone.
-   * All the other code here is for the structdef state machine.
+   * This if statement deals with the typdef state machine as 
+   * follows: if typdef==ttypedseen and token is struct/union/class/enum,
+   * return (FALSE).  All the other code here is for the structdef 
+   * state machine.
    */
   switch (toktype)
     {
     case st_C_struct:
     case st_C_enum:
-      if (tydef == begin
+      if (typdef == ttypedseen
 	  || (typedefs_and_cplusplus && level == 0 && structdef == snone))
 	{
 	  structdef = skeyseen;
 	  structkey = tokse;
 	}
-      goto badone;
+      return (FALSE);
     }
-
   if (structdef == skeyseen)
     {
-      /* If next char is '{' or (for C++) ':', found a structure tag. */
-      if (c == '{' || (c_ext && c == ':'))
+      if (stab_type (structkey) == st_C_struct)
 	{
-	  /*
-	   * We should do this slightly differently for straight C:
-	   * instead of defining `tag', as we now do, we should define
-	   * `struct tag'.  (Do this only if the find-tag defaulting is
-	   * done on a sophisticated per-mode basis, so that if the user
-	   * says meta-. anywhere in `struct foo', the default comes out
-	   * `struct foo', not `struct' or `foo'.)  This will require
-	   * remembering which keyword (struct/union/class/enum) we saw, as a
-	   * Stab_entry* -- this will also make it possible to merge the
-	   * skeyseen and senumseen states, if we want.
-	   */
-	  if (stab_type (structkey) == st_C_struct)
-	    {
-	      (void) strncpy (structtag, tokp->p, tokp->len);
-	      structtag[tokp->len] = '\0';	/* for struct/union/class */
-	      structdef = stagseen;
-	    }
-	  else
-	    {
-	      structtag[0] = '\0';	/* for enum */
-	    }
-	  *is_func = FALSE;	/* not a function */
-	  goto goodone;
+	  (void) strncpy (structtag, tokp->p, tokp->len);
+	  structtag[tokp->len] = '\0';	/* for struct/union/class */
 	}
       else
 	{
-	  /* Not a definition: reset structdef */
-	  structdef = snone;
-	  (void) strcpy (structtag, "<error 3>");
+	  structtag[0] = '\0';	/* for enum (why is it treated differently?) */
 	}
-      /* Now what?  And how does/should this stuff interact with tydef??  */
-      /* Also maybe reset lp to *lpp for sake of function-finding code.  */
+      structdef = stagseen;
+      return (TRUE);
     }
-  if (tydef == begin)
+
+  /* Avoid entering funcdef stuff if typdef is going on. */
+  if (typdef != tnone)
     {
-      tydef = end;
-      goto badone;
+      definedef = dnone;
+      return (FALSE);
     }
-  if (tydef == end)
-    {
-      *is_func = 0;
-      goto goodone;
-    }
+
   /* Detect GNUmacs's function-defining macros. */
   if (definedef == dnone)
     {
@@ -1917,70 +1913,31 @@
 	  || strneq (tokp->p, "PSEUDO", 6))
 	{
 	  next_token_is_func = TRUE;
-	  goto badone;
+	  return (FALSE);
 	}
-      else if (strneq (tokp->p, "EXFUN", 5))
+      if (strneq (tokp->p, "EXFUN", 5))
 	{
 	  next_token_is_func = FALSE;
-	  goto badone;
+	  return (FALSE);
 	}
     }
   if (next_token_is_func)
     {
       next_token_is_func = FALSE;
-      goto goodone;
+      return (TRUE);
     }
-  if (c != '(')
-    goto badone;
-  firsttok = FALSE;
-  while ((c = *lp++) != ')')
-    {
-      if (c == 0)
-	{
-	  lp--;
-	  break;
-	}
-      /*
-	* This line used to confuse ctags:
-	*	int	(*oldhup)();
-	* This fixes it. A nonwhite char before the first
-	* token, other than a / (in case of a comment in there)
-	* makes this not a declaration.
-	*/
-      if (begtoken (c) || c == '/')
-	firsttok++;
-      else if (!iswhite (c) && !firsttok)
-	goto badone;
-    }
-  while (iswhite (c = *lp++))
+
+  /* A function? */
+  switch (toktype)
     {
-      if (c == 0)
-	{
-	  lp--;
-	  break;
-	}
+    case st_C_typespec:
+      funcdef == fnone;		/* should be useless */
+      return (FALSE);
+    default:
+      funcdef = ftagseen;
+      *is_func = TRUE;
+      return (TRUE);
     }
-  if (!isgood (c))
-    goto badone;
-
-goodone:
-  *lpp = lp - 1;
-  return TRUE;
-
-badone:
-  *lpp = lp - 1;
-  return FALSE;
-}
-
-void
-getline (atcookie)
-     long atcookie;
-{
-  long saveftell = ftell (inf);
-
-  (void) fseek (inf, atcookie, 0);
-  (void) readline (&lb1, inf);
-  (void) fseek (inf, saveftell, 0);
 }
 
 /* Fortran parsing */