🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

2 total messages Started by Gray Watson Mon, 13 Apr 1992 02:07
cccp patch for multi-arg defines...
#374
Author: Gray Watson
Date: Mon, 13 Apr 1992 02:07
334 lines
10737 bytes
Not a bug.  A feature upgrade on-top of gcc version 2.1.

>From my own message on Fri, 27 Mar 92 12:09:23 EST:

> I think a vote should be taken on an extension to cpp to handle
> variable argument macros.

Well??

>	#define vmacro (...)		(void)printf(...)
>	/* '...' will absorb as many arguments as possible and regurgite them
>	   to the '...' in the destination code, comma seperated. */
>
>	Example:
>		main() { vmacro("hello %s\n", "world"); }
>
>	would become:
>		main() { (void)printf("hello %s\n", "world"); }

Below I have the patches to cccp.c for the above feature.  RMS mentioned that
since ... is already defined (for case ranges) that another token should be
chosen as the magical multiple-argument-token.  He's correct, but ... is the
perfect one.  Oh well.

After a couple of hours of deep discussion here, we came up with __REST__ as
magical token.  It is quite arbitrary and is #defined on in the patches so it
can be changed easily.

In any case.  It seems to work fine here.  Can anyone see any problems with
this being integrated into ccp?

gray

-------------------------------------------------------------------------------
$Id: absorb_rest,v 1.2 1992/03/28 16:15:31 gray Exp $
-------------------------------------------------------------------------------

*** cccp.c.ORG	Fri Mar 27 15:21:45 1992
--- cccp.c	Sat Mar 28 11:04:52 1992
***************
*** 572,577 ****
--- 572,578 ----
    U_CHAR *expansion;
    int line;			/* Line number of definition */
    char *file;			/* File of definition */
+   char rest_args;		/* Nonzero if last arg. absorbs the rest */
    struct reflist {
      struct reflist *next;
      char stringify;		/* nonzero if this arg was preceded by a
***************
*** 600,605 ****
--- 601,609 ----
    KEYDEF *keydef;
  };
  
+ /* special macro argument that will absorb the rest of the arguments */
+ static char rest_args_string[] = "__REST__";
+ #define REST_ARGS_LENGTH	(sizeof (rest_args_string) - 1)
  
  /* The structure of a node in the hash table.  The hash table
     has entries for all tokens defined by #define commands (type T_MACRO),
***************
*** 4524,4529 ****
--- 4528,4534 ----
    int sym_length;		/* and how long it is */
    int line = instack[indepth].lineno;
    char *file = instack[indepth].nominal_fname;
+   int rest_args = 0;
  
    DEFINITION *defn;
    int arglengths = 0;		/* Accumulate lengths of arg names
***************
*** 4560,4571 ****
        temp->argno = argno++;
        arg_ptrs = temp;
  
!       if (!is_idstart[*bp])
! 	pedwarn ("parameter name starts with a digit in `#define'");
  
!       /* Find the end of the arg name.  */
!       while (is_idchar[*bp]) {
! 	bp++;
        }
        temp->length = bp - temp->name;
        arglengths += temp->length + 2;
--- 4565,4588 ----
        temp->argno = argno++;
        arg_ptrs = temp;
  
!       if (rest_args)
! 	pedwarn ("parameter is specified after '%s' rest-args token",
! 		 rest_args_string);
! 
!       /* do we have a "special" rest-args token here? */
!       if (limit - bp > REST_ARGS_LENGTH &&
! 	  strncmp (rest_args_string, bp, REST_ARGS_LENGTH) == 0) {
! 	bp += REST_ARGS_LENGTH;
! 	rest_args = 1;
!       }
!       else {
! 	if (!is_idstart[*bp])
! 	  pedwarn ("parameter name starts with an illegal character in `#define'");
  
! 	/* Find the end of the arg name.  */
! 	while (is_idchar[*bp]) {
! 	  bp++;
! 	}
        }
        temp->length = bp - temp->name;
        arglengths += temp->length + 2;
***************
*** 4604,4609 ****
--- 4621,4627 ----
      if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
      /* now everything from bp before limit is the definition. */
      defn = collect_expansion (bp, limit, argno, arg_ptrs);
+     defn->rest_args = rest_args;
  
      /* Now set defn->args.argnames to the result of concatenating
         the argument names in reverse order
***************
*** 4860,4865 ****
--- 4878,4884 ----
    U_CHAR *stringify = 0;
    int maxsize;
    int expected_delimiter = '\0';
+   int rest_args;
  
    /* Scan thru the replacement list, ignoring comments and quoted
       strings, picking up on the macro calls.  It does a linear search
***************
*** 5010,5025 ****
        }
      }
  
      /* Handle the start of a symbol.  */
!     if (is_idchar[c] && nargs > 0) {
        U_CHAR *id_beg = p - 1;
        int id_len;
  
        --exp_p;
!       while (p != limit && is_idchar[*p]) p++;
        id_len = p - id_beg;
  
!       if (is_idstart[c]) {
  	register struct arglist *arg;
  
  	for (arg = arglist; arg != NULL; arg = arg->next) {
--- 5029,5051 ----
        }
      }
  
+     /* do we have a rest_args_string symbol here? */
+     rest_args = (limit - (p - 1) >= REST_ARGS_LENGTH &&
+ 		 strncmp (rest_args_string, p - 1, REST_ARGS_LENGTH) == 0);
+ 
      /* Handle the start of a symbol.  */
!     if ((is_idchar[c] || rest_args) && nargs > 0) {
        U_CHAR *id_beg = p - 1;
        int id_len;
  
        --exp_p;
!       if (rest_args)
! 	p += REST_ARGS_LENGTH - 1;
!       else
! 	while (p != limit && is_idchar[*p]) p++;
        id_len = p - id_beg;
  
!       if (is_idstart[c] || rest_args) {
  	register struct arglist *arg;
  
  	for (arg = arglist; arg != NULL; arg = arg->next) {
***************
*** 6720,6725 ****
--- 6746,6752 ----
    register U_CHAR *xbuf;
    int xbuf_len;
    int start_line = instack[indepth].lineno;
+   int rest_args;
  
    CHECK_DEPTH (return;);
  
***************
*** 6753,6765 ****
  
      /* Parse all the macro args that are supplied.  I counts them.
         The first NARGS args are stored in ARGS.
!        The rest are discarded.  */
      i = 0;
      do {
        /* Discard the open-parenthesis or comma before the next arg.  */
        ++instack[indepth].bufp;
!       parse_error
! 	= macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0);
        if (parse_error) {
  	error_with_line (line_for_error (start_line), parse_error);
  	break;
--- 6780,6803 ----
  
      /* Parse all the macro args that are supplied.  I counts them.
         The first NARGS args are stored in ARGS.
!        The rest are discarded.
!        If rest_args is set then we assume macarg absorbed the rest of the args.
!        */
      i = 0;
+     rest_args = 0;
      do {
        /* Discard the open-parenthesis or comma before the next arg.  */
        ++instack[indepth].bufp;
!       if (rest_args)
! 	continue;
!       if (i < nargs || (nargs == 0 && i == 0)) {
! 	/* if we are working on last arg which absorbes rest of args... */
! 	if (i == nargs - 1 && defn->rest_args)
! 	  rest_args = 1;
! 	parse_error = macarg (&args[i], rest_args);
!       }
!       else
! 	parse_error = macarg (0, 0);
        if (parse_error) {
  	error_with_line (line_for_error (start_line), parse_error);
  	break;
***************
*** 7007,7018 ****
  
  /*
   * Parse a macro argument and store the info on it into *ARGPTR.
   * Return nonzero to indicate a syntax error.
   */
  
  static char *
! macarg (argptr)
       register struct argdata *argptr;
  {
    FILE_BUF *ip = &instack[indepth];
    int paren = 0;
--- 7045,7058 ----
  
  /*
   * Parse a macro argument and store the info on it into *ARGPTR.
+  * REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
   * Return nonzero to indicate a syntax error.
   */
  
  static char *
! macarg (argptr, rest_args)
       register struct argdata *argptr;
+      int rest_args;
  {
    FILE_BUF *ip = &instack[indepth];
    int paren = 0;
***************
*** 7022,7028 ****
    /* Try to parse as much of the argument as exists at this
       input stack level.  */
    U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
! 			&paren, &newlines, &comments);
  
    /* If we find the end of the argument at this level,
       set up *ARGPTR to point at it in the input stack.  */
--- 7062,7068 ----
    /* Try to parse as much of the argument as exists at this
       input stack level.  */
    U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
! 			&paren, &newlines, &comments, rest_args);
  
    /* If we find the end of the argument at this level,
       set up *ARGPTR to point at it in the input stack.  */
***************
*** 7060,7066 ****
        newlines = 0;
        comments = 0;
        bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
! 		    &newlines, &comments);
        final_start = bufsize;
        bufsize += bp - ip->bufp;
        extra += newlines;
--- 7100,7106 ----
        newlines = 0;
        comments = 0;
        bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
! 		    &newlines, &comments, rest_args);
        final_start = bufsize;
        bufsize += bp - ip->bufp;
        extra += newlines;
***************
*** 7149,7161 ****
     Value returned is pointer to stopping place.
  
     Increment *NEWLINES each time a newline is passed.
!    Set *COMMENTS to 1 if a comment is seen.  */
  
  static U_CHAR *
! macarg1 (start, limit, depthptr, newlines, comments)
       U_CHAR *start;
       register U_CHAR *limit;
       int *depthptr, *newlines, *comments;
  {
    register U_CHAR *bp = start;
  
--- 7189,7203 ----
     Value returned is pointer to stopping place.
  
     Increment *NEWLINES each time a newline is passed.
!    Set *COMMENTS to 1 if a comment is seen.
!    REST_ARGS notifies macarg1 that it should absorb the rest of the args. */
  
  static U_CHAR *
! macarg1 (start, limit, depthptr, newlines, comments, rest_args)
       U_CHAR *start;
       register U_CHAR *limit;
       int *depthptr, *newlines, *comments;
+      int rest_args;
  {
    register U_CHAR *bp = start;
  
***************
*** 7226,7232 ****
        }
        break;
      case ',':
!       if ((*depthptr) == 0)
  	return bp;
        break;
      }
--- 7268,7275 ----
        }
        break;
      case ',':
!       /* if we've returned to lowest level and we aren't absorbing all args */
!       if ((*depthptr) == 0 && rest_args == 0)
  	return bp;
        break;
      }
Re: cccp patch for multi-arg defines...
#387
Author: Lars Henrik Mathiesen
Date: Tue, 14 Apr 1992 11:08
38 lines
2326 bytes
gray@antaire.COM (Gray Watson) writes:
>Not a bug.  A feature upgrade on-top of gcc version 2.1.
>>	#define vmacro (...)		(void)printf(...)

>After a couple of hours of deep discussion here, we came up with __REST__ as
>magical token.  It is quite arbitrary and is #defined on in the patches so it
>can be changed easily.

Some years ago, I saw a description of another implementation of this
feature, the syntax of which I liked better:

#define errprint(fmt args) \
	(void)fprintf(stderr, "%s: "##fmt##": %s\n", prog args, strerr(errno))

Note the ``missing'' commas in both parameter and replacement lists;
the expansion of the last parameter includes the leading comma (if
any) to allow for the number of variable arguments to be zero. (Yes,
this causes odd expansions like |foo(, bar)| --- but varargs functions
in Standard C always have at least one fixed argument, so this would
only occur when using the preprocessor for other purposes.)

>In any case.  It seems to work fine here.  Can anyone see any problems with
>this being integrated into ccp?

Well, it seems to me that the above version is better because it
allows a proper name for the parameter, and allows it to cover zero
arguments. Since implementation in GCC probably is the only hope of
creating prior art so that a feature like this can be included in a
future revision of Standard C, I'd like to see as capable a version as
possible.

I don't have the 2.1 cccp.c unpacked at the moment, and more
importantly, I don't have the time to test anything, but I looked at
the 1.40 cccp.c and the patch file you sent, and I think this version
can be implemented with about the same amount of changes as the
__REST__ version, or perhaps a bit less. Perhaps after Easter ...

Lars Mathiesen (U of Copenhagen CS Dep) <thorinn@diku.dk> (Humour NOT marked)
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads