🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.emacs.bug
Article #99883

Diffs to make etags work with C++

#99883
From: Ray Lischner
Date: Mon, 19 Mar 1990 22:57
428 lines
12457 bytes
We do a lot of C++ development, so we needed etags to recognize C++
instead of C.  I made some changes that seem to work.  The tricky
parts were recognizing the C++ keyword "operator", with the operator
token that follows it, e.g., "operator++", "operator->*", and handling
C++ class definitions.  Inline member functions declared in the class
definition are not recognized; use separate inline declarations
instead.

Following are the diffs for etags.c that came with GNU Emacs 18.55.  I
successfully compiled and ran it on an Apollo DN4000, running
Domain/OS 10.2; since I didn't alter any headers, I see no reason why
it should not work on other systems.


*** etags.c-dist	Fri May 12 19:08:05 1989
--- etags.c	Mon Mar 19 11:13:12 1990
***************
*** 130,135 ****
--- 130,136 ----
  #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 iscpp(arg)	(_cpptk[arg])	/* T if char can be C++ operator */
  
  #define	max(I1,I2)	(I1 > I2 ? I1 : I2)
  
***************
*** 154,160 ****
  int number; /* tokens found so far on line starting with # (including #) */
  logical gotone,				/* found a func already on line	*/
  					/* boolean "func" (see init)	*/
! 	_wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
  
  	/* typedefs are recognized using a simple finite automata,
  	 * tydef is its state variable.
--- 155,161 ----
  int number; /* tokens found so far on line starting with # (including #) */
  logical gotone,				/* found a func already on line	*/
  					/* boolean "func" (see init)	*/
! 	_wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177],_cpptk[0177];
  
  	/* typedefs are recognized using a simple finite automata,
  	 * tydef is its state variable.
***************
*** 178,186 ****
--- 179,190 ----
  				/* token starting chars			*/
  	*intk	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
  				/* valid in-token chars			*/
+ 	*cpptk = "()[]+-=<>,/*&^|~!%",
+ 				/* additional C++ operator chars	*/
  	*notgd	= ",;";		/* non-valid after-function chars	*/
  
  int	file_num = 0;		/* current file number			*/
+ int	cppflag = 0;		/* -+: .c means C++ */
  int	aflag = 0;		/* -a: append to tags */
  int	tflag = 0;		/* -t: create tags for typedefs */
  int	uflag = 0;		/* -u: update tags */
***************
*** 285,290 ****
--- 289,297 ----
  	      eflag = 0;
  	      break;
  #endif
+ 	    case '+':
+ 	      cppflag++;
+ 	      break;
  	    case 'a':
  	      aflag++;
  	      break;
***************
*** 460,466 ****
  
    for (i = 0; i < 0177; i++)
      {
!       _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
        _gd[i] = TRUE;
      }
    for (sp = white; *sp; sp++)
--- 467,473 ----
  
    for (i = 0; i < 0177; i++)
      {
!       _cpptk[i] = _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
        _gd[i] = TRUE;
      }
    for (sp = white; *sp; sp++)
***************
*** 473,483 ****
--- 480,493 ----
      _btk[*sp] = TRUE;
    for (sp = notgd; *sp; sp++)
      _gd[*sp] = FALSE;
+   for (sp = cpptk; *sp; sp++)
+     _cpptk[*sp] = TRUE;
    _wht[0] = _wht['\n'];
    _etk[0] = _etk['\n'];
    _btk[0] = _btk['\n'];
    _itk[0] = _itk['\n'];
    _gd[0] = _gd['\n'];
+   _cpptk[0] = _cpptk['\n'];
  }
  
  /*
***************
*** 517,524 ****
        fclose(inf);
        return;
      }
!   /* .scm or .sm or .scheme implies scheme source code */
    if (cp && (!strcmp (cp + 1, "sm")
  	     || !strcmp (cp + 1, "scm")
  	     || !strcmp (cp + 1, "scheme")
  	     || !strcmp (cp + 1, "t")
--- 527,535 ----
        fclose(inf);
        return;
      }
!   /* .scm or .sc or .sm or .scheme implies scheme source code */
    if (cp && (!strcmp (cp + 1, "sm")
+ 	     || !strcmp (cp + 1, "sc")
  	     || !strcmp (cp + 1, "scm")
  	     || !strcmp (cp + 1, "scheme")
  	     || !strcmp (cp + 1, "t")
***************
*** 533,538 ****
--- 544,562 ----
        fclose(inf);
        return;
      }
+   /* .C, .cc, .cxx, .hxx mean C++; or the user gave us -+ with .c or .h */
+   if (cp && (!strcmp (cp + 1, "C")
+ 	     || !strcmp (cp + 1, "cc")
+ 	     || !strcmp (cp + 1, "cxx")
+ 	     || !strcmp (cp + 1, "hxx")
+ 	     || (cppflag && (!strcmp (cp + 1, "c")
+ 			     || !strcmp (cp + 1, "h")))))
+   {
+       C_entries(1);
+       fclose(inf);
+       return;
+   }
+ 
    /* if not a .c or .h or .y file, try fortran */
    if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
        && cp[2] == '\0')
***************
*** 544,550 ****
  	}
        rewind(inf);	/* no fortran tags found, try C */
      }
!   C_entries();
    fclose(inf);
  }
  
--- 568,574 ----
  	}
        rewind(inf);	/* no fortran tags found, try C */
      }
!   C_entries(0);
    fclose(inf);
  }
  
***************
*** 595,608 ****
    np->left = np->right = 0;
    if (eflag)
      {
!       linestart[linelen] = 0;
      }
    else if (xflag == 0)
      {
        sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
        linestart = tem;
      }
-   np->pat = savestr (linestart);
    if (head == NULL)
      head = np;
    else
--- 619,632 ----
    np->left = np->right = 0;
    if (eflag)
      {
!       np->pat = savenstr (linestart, linelen);
      }
    else if (xflag == 0)
      {
        sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
        linestart = tem;
+       np->pat = savestr (linestart);
      }
    if (head == NULL)
      head = np;
    else
***************
*** 782,788 ****
    number = 0; \
  }
  
! C_entries ()
  {
    register int c;
    register char *token, *tp, *lp;
--- 806,877 ----
    number = 0; \
  }
  
! /*
!   With C++, the keyword "operator" can be followed by an operator
!   token, e.g., operator++, which must be treated as an identifier.
!   This is irritating because we need to look for the magic keyword,
!   operator, then grab the following token, making sure we don't
!   grab too much, e.g., operator()() is valid: we want "operator()".
!   There can be white space between the "operator" and the token,
!   which we delete by shifting the rest of the line over.  This
!   makes it easier for the user to find the operator, even if it
!   makes type cast operators look funny: "operatorint".
! 
!   The value of "tokend" is a little odd. It points two past the last
!   character of the token, e.g., the line contains "operator+=(int x)",
!   then tokstart points to the letter 'o', and tokend points to the
!   character '='.  On exit, tokend points to the letter 'i' of "int".
!   The "tokptr" operator is there just so we can update it.  On entry,
!   in our example, it pointer to the 'r' in "operator"; on exit, it
!   points to the '=' character.
! */
! #define OPERATOR	"operator"
! #define OPERLEN		(sizeof(OPERATOR)-1)
! 
! check_operator(tokptr, tokend, tokstart)
! char** tokptr;		/* pointer to last character of the token */
! char** tokend;		/* two past the last character of the token */
! char* tokstart;		/* first character of the token */
! {
!     char* ws;
!     char* p;
! 
!     if (*tokend-tokstart-1 != OPERLEN)
! 	return;
!     else if (strncmp(OPERATOR, tokstart, OPERLEN) != 0)
! 	return;
! 
!     /* skip over the white space */
!     for (ws = *tokend - 1; iswhite(*ws); ++ws)
! 	;
!     /* shift the rest of the line to delete the white space */
!     for (p = *tokend - 1; *ws; )
! 	*p++ = *ws++;
! 
!     p = *tokend - 1;
! 
!     /* identifiers are different */
!     if (begtoken(*p))
!     {
! 	for (p = *tokend - 1; intoken(*p); ++p)
! 	    ;
!     }
!     else
!     {
! 	for (p = *tokend - 1; iscpp(*p); ++p)
! 	    if (p[1] == '(')
! 	    {
! 		++p;
! 		break;
! 	    }
!     }
! 
!     *tokend = p + 1;
!     *tokptr = p - 1;
! }
! 
! C_entries (is_cpp)
! int is_cpp;		/* T means C++; F means C */
  {
    register int c;
    register char *token, *tp, *lp;
***************
*** 856,861 ****
--- 945,954 ----
  	      lp++;
  	      incomm = TRUE;
  	    }
+ 	  /* C++ comments can start with "//", and go to the end of the line */
+ 	  else if (is_cpp && *lp == '/')
+ 	      /* this is one way to discard the rest of the line */
+ 	      lp += strlen(lp);
  	  continue;
  	case '#':
  	  if (lp == lb.buffer + 1)
***************
*** 887,893 ****
  		{
  		  int f;
  		  char *buf = lb.buffer;
! 		  int endpos = lp - lb.buffer;
  		  char *lp1 = lp;
  		  int line = lineno;
  		  long linestart = linecharno;
--- 980,986 ----
  		{
  		  int f;
  		  char *buf = lb.buffer;
! 		  int endpos;
  		  char *lp1 = lp;
  		  int line = lineno;
  		  long linestart = linecharno;
***************
*** 894,900 ****
  #ifdef VMS
  		  long vmslinestart = vmslinecharno;
  #endif
! 		  int tem = consider_token (&lp1, token, &f, level);
  		  lp = lp1;
  		  if (tem)
  		    {
--- 987,999 ----
  #ifdef VMS
  		  long vmslinestart = vmslinecharno;
  #endif
! 		  int tem;
! 
! 		  if (is_cpp)
! 		      check_operator(&tp, &lp1, token);
! 		  endpos = lp1 - lb.buffer;
! 
! 		  tem = consider_token (&lp1, token, &f, level, is_cpp);
  		  lp = lp1;
  		  if (tem)
  		    {
***************
*** 923,928 ****
--- 1022,1032 ----
  		}
  	      else if (intoken(c))
  		tp++;
+ 	      else if (is_cpp && c == ':' && *lp == ':')
+ 	      {
+ 		  ++lp;
+ 		  tp += 2;
+ 	      }
  	    }
  	  else if (begtoken(c))
  	    {
***************
*** 941,949 ****
   * It updates the input line * so that the '(' will be
   * in it when it returns.
   */
! consider_token (lpp, token, f, level)
       char **lpp, *token;
       int *f, level;
  {
    reg char *lp = *lpp;
    reg char c;
--- 1045,1054 ----
   * It updates the input line * so that the '(' will be
   * in it when it returns.
   */
! consider_token (lpp, token, f, level, is_cpp)
       char **lpp, *token;
       int *f, level;
+      int is_cpp;
  {
    reg char *lp = *lpp;
    reg char c;
***************
*** 986,993 ****
        tydef=begin;
        goto badone;
      }
    if (tydef==begin && (istoken(token, "struct", 6) ||
! 		       istoken(token, "union", 5) || istoken(token, "enum", 4)))
    {
      tydef=tag_ok;      
      goto badone;
--- 1091,1111 ----
        tydef=begin;
        goto badone;
      }
+   /* in C++, class foo {}; behaves like a typedef in C by defining "foo"
+      as a type name.  The same goes for struct, union, and enum.
+    */
+   if (tflag && is_cpp && (istoken(token, "class", 5) ||
+ 			  istoken(token, "struct", 6) ||
+ 			  istoken(token, "union", 5) ||
+ 			  istoken(token, "enum", 4)))
+   {
+     tydef=tag_ok;
+     goto badone;
+   }
+ 
    if (tydef==begin && (istoken(token, "struct", 6) ||
! 		       istoken(token, "union", 5) || istoken(token, "enum", 4)||
! 		       (is_cpp && istoken(token, "class", 5))))
    {
      tydef=tag_ok;      
      goto badone;
***************
*** 995,1001 ****
    if (tydef==tag_ok)
      {
        tydef=middle;
!       goto badone;
      }
    if (tydef==begin)		/* e.g. typedef ->int<- */
      {
--- 1113,1133 ----
    if (tydef==tag_ok)
      {
        tydef=middle;
!       if (is_cpp && c == ';')
!       {
! 	  /* things like "struct foo;" need to be ignored; this is not a
! 	     definition of struct foo.
! 	   */
! 	tydef=none;
!       }
!       else if (is_cpp)
!       {
! 	*f = 0;
! 	win = 1;
! 	goto ret;
!       }
!       else
! 	goto badone;
      }
    if (tydef==begin)		/* e.g. typedef ->int<- */
      {
Technical Details
Message-ID: <9003192257.AA00312@pdx.MENTOR.COM>
Path: arc1-ca.pugleaf.net!gmdzi!unido!mcsun!uunet!bu.edu!snorkelwacker!tut.cis.ohio-state.edu!GARP.MIT.EDU!ogicse!mntgfx!lisch

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: fb2f1,db48ac8a61a9b13a,start
X-Google-Attributes: gidfb2f1,public
X-Google-ArrivalTime: 1990-03-20 02:33:21 PST
Path: arc1-ca.pugleaf.net!gmdzi!unido!mcsun!uunet!bu.edu!snorkelwacker!tut.cis.ohio-state.edu!GARP.MIT.EDU!ogicse!mntgfx!lisch
From: ogicse!mntgfx!lisch@GARP.MIT.EDU (Ray Lischner)
Newsgroups: gnu.emacs.bug
Subject: Diffs to make etags work with C++
Message-ID: <9003192257.AA00312@pdx.MENTOR.COM>
Date: 19 Mar 90 22:57:10 GMT
Sender: daemon@tut.cis.ohio-state.edu
Distribution: gnu
Organization: GNUs Not Usenet
Lines: 428
Posted: Mon Mar 19 23:57:10 1990