[comp.bugs.4bsd] C preprocessor question

brett@wjvax.UUCP (01/28/87)

I have a question about the C preprocessor.  I have the following code
fragment, which fails to compile on my system (4.2BSD):

#define	GROUP(group,subgroup)	(((group) << 8) | (subgroup))

#if	GROUP(0,0)
#endif

The #if chokes for some reason.  Can anyone in comp.lang.c see my error?
If there is no error, is this a known bug of the 4.2BSD cpp?
-- 
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett

apn@nonvon.UUCP (01/29/87)

in article <818@wjvax.wjvax.UUCP>, brett@wjvax.UUCP (Brett Galloway) says:
> 
> I have a question about the C preprocessor.  I have the following code
> fragment, which fails to compile on my system (4.2BSD):
> 
> #define	GROUP(group,subgroup)	(((group) << 8) | (subgroup))
> 
> #if	GROUP(0,0)
> #endif
> 
> The #if chokes for some reason.  Can anyone in comp.lang.c see my error?
> If there is no error, is this a known bug of the 4.2BSD cpp?
> -- 

	I don't think this should work....

	try running 'cc -E file.c' for some clues.
	this will give you a output essentially a file
	which is what your program looks like to the actual
	c compiler after macros are expanded.

CPP evaluates the macro 'GROUP' with arguments 0,0
to be:

(((0) << 8) | ( 0 ))

which is not a valid c line if it is stand alone.

be carefull.. CPP is for just that , preprocessing.... i.e.
#if's are compile time options and not
run time options. 


-- 
	Alex P Novickis

	UUCP:   {seismo, sun, ihnp4, 'etc' }!ptsfa!nonvon!apn

{* Only those who attempt the absurd   ...   will achieve the impossible   *}
{* I think... I think it's in my basement... Let me go upstairs and check. *}
{*                                                      -escher            *}

tps@sdchem.UUCP (01/29/87)

In article <818@wjvax.wjvax.UUCP> brett@wjvax.UUCP (Brett Galloway) writes:
>I have a question about the C preprocessor.  I have the following code
>fragment, which fails to compile on my system (4.2BSD):
>
>#define	GROUP(group,subgroup)	(((group) << 8) | (subgroup))
>
>#if	GROUP(0,0)
>#endif
>
>The #if chokes for some reason.  Can anyone in comp.lang.c see my error?
>If there is no error, is this a known bug of the 4.2BSD cpp?
>Brett Galloway

I have replicated your reported behavior on our 4.3BSD system.
Sure looks like a bug to me.  The surprising thing is that it goes away
if you just replace GROUP by hand.  That is,
	
	#if (((0) << 8) | (0))
	#endif
works fine.

|| Tom Stockfisch, UCSD Chemistry	tps%chem@sdcsvax.UCSD

guy@gorodish.UUCP (01/29/87)

>I have a question about the C preprocessor.  I have the following code
>fragment, which fails to compile on my system (4.2BSD):

It ain't gonna work on S5, either.

>The #if chokes for some reason.  Can anyone in comp.lang.c see my error?
>If there is no error, is this a known bug of the 4.2BSD cpp?

Well, it's certainly "known" in some sense now, but I never knew
about it until now.  I don't know if the fact that it has persisted
in the Reiser preprocessor (as used in most UNIX C compilers) to this
day indicates that it wasn't known or that it was known but nobody
wanted to fix it.

K&R isn't very clear on what happens to macros inside the
"conditional-expression" in an "#if".  The Reiser preprocessor will
expand macros that have no formal arguments, but doesn't seem to
bother with macros that have formals.  The ANSI C draft of October 1,
1986 says that

	In a controlling constant expression, each identifier
	currently defined as a macro name is replaced by its token
	sequence (except for those identifiers modified by "defined",
	just as in normal text.

This doesn't distinguish between "object-like" and "function-like"
macros, although the language seems to be written specifically around
object-like macros (since when a "function-like" macro call is
expanded, the identifier and the actual argument list, not just the
identifier, is replaced).  This requires some clarification.

Unless there's some compelling reason not to do so, I think that both
kinds of macros should be expanded (the Principle of Least Surprise
rules here, and you certainly were surprised by the behavior of the
Reiser preprocessor).  I don't know whether the Reiser preprocessor's
reluctance to expand "function-like" macro calls here is caused by
conceptual problems with doing that or implementation problems.

guy@gorodish.UUCP (01/30/87)

>	try running 'cc -E file.c' for some clues.
>	this will give you a output essentially a file
>	which is what your program looks like to the actual
>	c compiler after macros are expanded.

The problem is not that "ccom" is choking, it's that "cpp" is
choking.  Running "cc -E file.c" in this case will give the exact
same diagnostic as the regular "cc" did, so it won't help a bit.

>CPP evaluates the macro 'GROUP' with arguments 0,0
>to be:
>
>(((0) << 8) | ( 0 ))
>
>which is not a valid c line if it is stand alone.

The problem is that "cpp" *isn't* evaluating the macro "GROUP" - it's
getting a syntax error.  The "cpp" grammar doesn't include anything
with a macro-call-with-arguments syntax, so the parser gives up in
disgust.  The fact that it's not valid if it stands alone is
irrelevant; it *doesn't* stand alone, because it has a "#if" in front
of it.

What it arguably *should* have done is expand the macro, giving

	#if (((0) << 8) | ( 0 ))

which *is* a valid C line (given that "C" includes preprocessor
commands), and is equivalent to

	#if 0

which tells it not to include the text surrounded by #if/#endif.

jtr485@umich.UUCP (01/30/87)

In article <818@wjvax.wjvax.UUCP>, brett@wjvax.UUCP writes:
> I have a question about the C preprocessor.  I have the following code
> fragment, which fails to compile on my system (4.2BSD):
> 
> #define	GROUP(group,subgroup)	(((group) << 8) | (subgroup))
> 
> #if	GROUP(0,0)
> #endif
> 
> The #if chokes for some reason.  Can anyone in comp.lang.c see my error?
> If there is no error, is this a known bug of the 4.2BSD cpp?
> Brett Galloway
What do you expect his to do?

The #if is not going to evaluate the expression (((0) << 8) | (0))

The #if takes an expression defined (recursively) by:
an <expression> is
	1) an integer string
     or 2) (<expression> | <expression>)
     or 3) (<expression> & <expression>)
and nothing else.
The only test you could perform on GROUP would be #ifdef.

--j.a.tainter

chris@mimsy.UUCP (Chris Torek) (02/02/87)

The example was:

>>#define GROUP(group,subgroup) (((group) << 8) | (subgroup))
>>#if GROUP(0,0)
>>#endif

In article <4136@brl-adm.ARPA> moss@BRL.ARPA (Gary S. Moss (SLCBR-VLD-V))
writes:
>The pre-processor defined macros are not evaluated by CPP.

Some are; others are confused.

>In other words, "#if GROUP(0,0)" is illegal because GROUP(0,0) has no value.

Yet

	#define GROUP 1
	#if GROUP
	...
	#endif

is legal, and works.

The 4.3BSD cpp gets very confused when handed

	#define I(a) a
	#if I(1)
	gorp
	#endif

Compiling this with `cc -E' produces

	# 1 "xx.c"

	xx.c: 4: syntax error
	 1
	gorp
	#endif
	xx.c: 5: missing endif

which is hardly proper behaviour.  If parameterised macros are not
to be evaluated, this should be either a syntax error (`#if
<unparseable>') or a false conditional (`#if <undefined>' is now
treated as is `#if 0').  If they are to be evaluated, this should
be equivalent to `#if 1', and the original example should have
worked too.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

pedz@bobkat.UUCP (02/04/87)

In article <55@umich.UUCP> jtr485@umich.UUCP (Johnathan Tainter) writes:
>The #if is not going to evaluate the expression (((0) << 8) | (0))
>The #if takes an expression defined (recursively) by:
>an <expression> is
>	1) an integer string
>     or 2) (<expression> | <expression>)
>     or 3) (<expression> & <expression>)
>and nothing else.

This may be how it works but is not how it is defined.  The value
after the #if is suppose to be a constant expression.  Constant
expressions include almost all of the operators including << and
?:.  I refer you to K&R section 15 page 211.  Notice that it is
suppose to include sizeof which cpp can not cope with either.  i.e.
cpp is -----.
-- 
Perry Smith
pedz@bobkat
{ti-csl,infotel}!pollux!bobkat!pedz

billj@zaphod.UUCP (02/13/87)

In article <818@wjvax.wjvax.UUCP> brett@wjvax.UUCP (Brett Galloway) writes:
>...fails to compile on my system (4.2BSD):
>
>#define	GROUP(group,subgroup)	(((group) << 8) | (subgroup))
>#if	GROUP(0,0)
>#endif
>
>The #if chokes for some reason.

A couple of other writers (jtr485@umich and pedz@bobkat) argue
respectively that this shouldn't work, since the <expression> of a #if
is very restricted; or that it should, as should everything including
sizeof.  Well, it depends on your cpp.  Since V7, the #if should work
with all non-assignment operators, including comma, but *not* sizeof
since that's only determinable by the compiler proper, as are casts and
enums.  K&R section 12.3 did a hand wave on this one.

In article <12300@sun.uucp> guy@sun.UUCP (Guy Harris) writes:
>I don't know whether the Reiser preprocessor's
>reluctance to expand "function-like" macro calls here is caused by
>conceptual problems with doing that or implementation problems.

I think I do.  The Reiser cpp is getting its fancy scanner pointers
mixed up after performing the substitution.  As Tom Stockfish pointed
out, the problem vanishes if you run cpp past the presubstituted form
instead.  The sloscan() set by ppcontrol() when it starts interpreting
the contents of the #if line is being reset to fasscan() during the
macro substitution, and cotoken() then blazes past all the substitued
'(' characters.  The following patch to the parameter substitution code
in subst() stops that.  Beware that the copy of cpp we have here is a
decidedly non-vanilla version, and your line numbers will vary.
--
Bill Jones, Develcon Electronics, 856 51 St E, Saskatoon S7K 5C7 Canada
uucp:  ...ihnp4!sask!zaphod!billj                phone:  (306) 931-1504

RCS file: RCS/cpp.c,v
retrieving revision 1.2
diff -c -r1.2 cpp.c
*** /tmp/,RCSt1001409	Fri Feb 13 13:07:00 1987
--- cpp.c	Fri Feb 13 12:06:35 1987
***************
*** 2566,2571
  {
  	register char	*ca, *vp;
  	int		params;
  	char		*actual[MAXFRM]; /* actual[n-1] is text of nth actual */
  	char		acttxt[MAXBUF];	/* space for actuals */
  

--- 2575,2581 -----
  {
  	register char	*ca, *vp;
  	int		params;
+ 	int		wasfast = 0;
  	char		*actual[MAXFRM]; /* actual[n-1] is text of nth actual */
  	char		acttxt[MAXBUF];	/* space for actuals */
  
***************
*** 2595,2601
  		ca = acttxt;
  		pa = actual;
  		if (params > 1) params--;
! 		sloscan();
  
  		/*
  		 * no expansion during search for actuals

--- 2605,2614 -----
  		ca = acttxt;
  		pa = actual;
  		if (params > 1) params--;
! 		if (!isslo) {
! 			sloscan();
! 			wasfast++;
! 		}
  
  		/*
  		 * no expansion during search for actuals
***************
*** 2728,2734
  			vp--;
  		}
  		skip--;
! 		fasscan();
  	}
  	else if (inif)
  	{

--- 2741,2747 -----
  			vp--;
  		}
  		skip--;
! 		if (wasfast) fasscan();
  	}
  	else if (inif)
  	{
-- 
Bill Jones, Develcon Electronics, 856 51 St E, Saskatoon S7K 5C7 Canada
uucp:  ...ihnp4!sask!zaphod!billj                phone:  (306) 931-1504