can preprocessor automatically make N array elements?

D

dan

I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

***** Here is an example of what I need to do:

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

// Start missing steps (using ## operator in some way?)
// This is the part I can't figure out.

// I think the following definitions are probably needed in the
missing steps
// I'd like ZEROES_AND_COMMAS (YEARS) to get translated to one of them

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

// End missing steps

#define ARRAY_ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60
#define ARRAY_ELEMS_YRS ZEROES_AND_COMMAS (YEARS)
#define ARRAY_ELEMS_EDU 0, 6, 8, 12, 16

int intArray [] = { ARRAY_ELEMS_AGE , ARRAY_ELEMS_YRS ,
ARRAY_ELEMS_EDU , };

// intArray ends up with { 0, 1, 5, 10, 15, 20, 40, 60, 0, 0, 0,
0, 6, 8, 12, 16, }

****** Here's one failed test program (does not compile)

#include <stdio.h>
#include <stdlib.h>

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

#define CAT(x,y) x ## y
#define XCAT(x,y) CAT(x,y)

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

#define ZEROES_AND_COMMAS(n) XCAT(ZEROES_AND_COMMAS_, n)

main () {
int intArray [] = { ZEROES_AND_COMMAS (YEARS) };
printf ("Number of elements = %d\n", sizeof (intArray) / sizeof
(int));
}

This would actually be useful. I'm very familiar with the C
preprocessor. I've experimented with the ## operator a lot, and can't
make it do the above task, including experiments related to K+R page
231 about using a second level of macro definition. Can anyone explain
how to solve this problem? Or get the test program to compile and
produce correct array length output?

Thanks,
Daniel Goldman
 
R

Richard Heathfield

dan said:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

Write, and use, a prepreprocessor. That is, write a program which takes
simple instructions from a file, and which then writes out a .h file
that suits your needs exactly. Then run the program. Then #include the
resulting .h into your code, and you're done.
 
B

Ben Bacarisse

dan said:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

***** Here is an example of what I need to do:

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

// Start missing steps (using ## operator in some way?)
// This is the part I can't figure out.

// I think the following definitions are probably needed in the
missing steps
// I'd like ZEROES_AND_COMMAS (YEARS) to get translated to one of them

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

// End missing steps

#define ARRAY_ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60
#define ARRAY_ELEMS_YRS ZEROES_AND_COMMAS (YEARS)
#define ARRAY_ELEMS_EDU 0, 6, 8, 12, 16

int intArray [] = { ARRAY_ELEMS_AGE , ARRAY_ELEMS_YRS ,
ARRAY_ELEMS_EDU , };

// intArray ends up with { 0, 1, 5, 10, 15, 20, 40, 60, 0, 0, 0,
0, 6, 8, 12, 16, }

You don't see averse to C99, going by your comment syntax, so there may
be another way:

int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };

You can introduce an index part way into an initialiser list. For
this work, you need to know (as a constant expression) the number of
ARRAY_ELEMS_AGE elements (or, of course, the total size and the number
of training EDU elements).

All elements not explicitly initialised are set to zero (provided
there is at least one value explicit value in the list).
 
D

dan

dan said:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.
***** Here is an example of what I need to do:
#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)
// Start missing steps (using ## operator in some way?)
// This is the part I can't figure out.
// I think the following definitions are probably needed in the
missing steps
// I'd like ZEROES_AND_COMMAS (YEARS) to get translated to one of them
#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0
// End missing steps
#define ARRAY_ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60
#define ARRAY_ELEMS_YRS ZEROES_AND_COMMAS (YEARS)
#define ARRAY_ELEMS_EDU 0, 6, 8, 12, 16
int intArray [] = { ARRAY_ELEMS_AGE , ARRAY_ELEMS_YRS ,
ARRAY_ELEMS_EDU , };
// intArray ends up with { 0, 1, 5, 10, 15, 20, 40, 60, 0, 0, 0,
0, 6, 8, 12, 16, }

You don't see averse to C99, going by your comment syntax, so there may
be another way:

int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };

You can introduce an index part way into an initialiser list. For
this work, you need to know (as a constant expression) the number of
ARRAY_ELEMS_AGE elements (or, of course, the total size and the number
of training EDU elements).

All elements not explicitly initialised are set to zero (provided
there is at least one value explicit value in the list).

I was not familiar with designated initializers, which does solve my
test case. I need to go through all of C99. Do you think the pre-
processor may not be able to do what I want, because I think I still
may need the preprocessor solution.

The designated initializers may not work within the context of the
other code, which I felt was too involved to explain in the initial
post. In my test case, the definition of intArray is a hard coded
macro expression. In the actual program, the intArray definition is
dynamically assembled by the preprocessor, which turns out to be very
powerful. For example, EDU may not be used (the program may not
analyze EDU), so ARRAY_ELEMS_EDU gets left out of the intArray
definition. The elements (such as AGE and YRS) that are used get
jammed together into the array. intArray ends up being part of a
"jagged array" setup. Another array, with one element for each
variable, is initialized at runtime to point into needed spots within
intArray. I hope this makes some sense.

Since parts of the intArray are left out or included, it may be
problematic having the preprocessor put together the "[N_AGES+YEARS] =
ARRAY_ELEMS_EDU" expression. The preprocessor would have to know to
substitute some other expresssion for ARRAY_ELEMS_EDU if EDU is not
used. Besides intArray, there are many other arrays that are built in
the same way, which is why I need to have it automated. Each array
specifies some attribute or characteristic. ARRAY_ELEMS_EDU is hard-
coded (0, 6, 8, 12, 16) because it is irregular and rarely changes.
ARRAY_ELEMS_YRS could also be hard-coded, but it's a maintenance
problem, because it changes every year and because there are many of
them to maintain. Your approach allows me not to hard-code it, but I
think the preprocessor would probably have a hard time generating the
designated initializer syntax.

Thanks,
Daniel Goldman
 
S

SM Ryan

# I would like to have the preprocessor automatically generate the
# number of array elements requested. Each element is zero. The elements
# get pasted into a larger array. The other elements may be non-zero.

You can probably get (or already have) a real macro processor
like m4 or macros far superior to m4. Use those and most of
your problems will disappear. Depending on your environment
you can have tools like m4, sed, awk, etc and you can write
code the way you want to, and let the software grot it into
something the c compiler can cope with.

For example, it's simple to write a tclsh filter that converts
= to == and := to =. On systems like MacOSX, you can use textutil
to convert programs written as rtfs into plain texts.

#!/usr/bin/tclsh
while {[gets stdin line]>=0} {
puts stdout [string map {:= = = == ­ != ² <= ³ >= Â !} $line]
}
exit 0

It's odd that for all the advances in user interfaces in the
past forty years, most programmers are still using the tools
and forms of sixties and seventies.
 
D

dan

dan said:


Write, and use, a prepreprocessor. That is, write a program which takes
simple instructions from a file, and which then writes out a .h file
that suits your needs exactly. Then run the program. Then #include the
resulting .h into your code, and you're done.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

That's a good idea, if I could make it work in this context. USENET is
so helpful for getting suggestions, and of course the poster can never
explain all the context of a complex application. I already use a pre-
pre-processor (shell script with various unix utilities and other
commands) to auto-generate 1) function prototypes header file, and 2)
external definitions header file. It works great.

Related to your suggestion, the pre-pre-processor might either:

- Generate a file for inclusion, with the contents 0, 0, 0

OR

- Edit (using sed) some line like the following:
#define ARRAY_ELEMS_YRS 0, 0, 0

What I don't see is the format for the "simple instructions" where the
pre-pre-processor could understand them. Right now the "simple
instructions" are like the following (embedded within a header file
with about 40,000 lines):

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

This same code is repeated many times, each time for a different data
scenario. One data set may be 1992-2006. Another may be 2000-2005. So
YEAR_1 and YEAR_2 are defined many times. Based on conditional
compilation, only one of these definitions is compiled.

I don't want to create separate files with "simple
instructions" (instead of using #define YEAR_1 #define YEAR_2). The
overhead would be more maintenance than simply hard-coding
ARRAY_ELEMS_YRS. I just want to make a change in one place (#define
YEAR_2) and everything else is automatically generated.

On further reflection... Perhaps the pre-pre-processor could do the
following:

- cpp -dM the source to generate the #define lines
- grep the conditionally compiled lines for YEAR_1 and YEAR_2
- get the values for YEAR_1 and YEAR_2
- In shell script, use while loop to build "0, 0, 0"
- sed the header file to fix up ARRAY_ELEMS_YRS

Of course, the pre-pre-processor could be invoked in the same shell
script that invokes the regular compile. You can probably tell I was
skeptical the pre-pre-processor would work in this context when I
started writing this post, and am now more optimistic. I'll give it a
try.

Am I correct to assume that you don't think the original idea (somehow
use ## within preprocessor) will work?

Thanks,
Daniel Goldman
 
R

Richard Heathfield

dan said:

You can probably tell I was
skeptical the pre-pre-processor would work in this context when I
started writing this post, and am now more optimistic. I'll give it a
try.

Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.
Am I correct to assume that you don't think the original idea (somehow
use ## within preprocessor) will work?

I don't see how, really I don't. This kind of trick isn't really what
the pre-processor is for.
 
D

dan

# I would like to have the preprocessor automatically generate the
# number of array elements requested. Each element is zero. The elements
# get pasted into a larger array. The other elements may be non-zero.

You can probably get (or already have) a real macro processor
like m4 or macros far superior to m4. Use those and most of
your problems will disappear. Depending on your environment
you can have tools like m4, sed, awk, etc and you can write
code the way you want to, and let the software grot it into
something the c compiler can cope with.

For example, it's simple to write a tclsh filter that converts
= to == and := to =. On systems like MacOSX, you can use textutil
to convert programs written as rtfs into plain texts.

#!/usr/bin/tclsh
while {[gets stdin line]>=0} {
puts stdout [string map {:= = = == ­ != ² <= ³ >= Â !} $line]}

exit 0

It's odd that for all the advances in user interfaces in the
past forty years, most programmers are still using the tools
and forms of sixties and seventies.

On m4, I looked into that a while back, and decided not. I didn't "get
it". I do use other unix utilities a lot, especially sed and shell
programming.

Can m4 be used in place of cpp for serious development? Is it a good
idea? I couldn't tell from looking at the GNU m4 site or old USENET
posts.

Daniel Goldman
 
D

dan

Yes the preprocessor can generate array elemtnes along with complicated
templates:

http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thr...

:^0

Concerning the preprocessor generating code via recursion, I looked at
the code and didn't "get it". I'm not saying it doesn't work. Your
suggestion did make me think some more, and I came up with a pretty
simple alternative that seems to work, besides the suggestions from
others (m4, C99 designated array initializaters, pre-pre-processor).
The simple alternative doesn't use recursion or parameterization, but
just tests for each value of YEARS, which is quite manageable. The
example below shows more realistically the actual problem, in terms of
some EDU possibly not being used, so left out of the array. By the
way, the example has three variables, but there can be many tens of
variables, which is why I need to take into account which ones might
be used.

Thanks,
Daniel Goldman

#include <stdio.h>
#include <stdlib.h>

#define YES 1
#define NO 0

#define ISUSED_AGE YES
#define ISUSED_EDU NO

#define YEAR_1 2000
#define YEAR_2 2002
#define YEARS (YEAR_2 - YEAR_1 + 1)

#if ISUSED_AGE == YES
#define ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60,
#endif

#if ISUSED_AGE == NO
#define ELEMS_AGE
#endif

#if ISUSED_EDU == YES
#define ELEMS_EDU 0, 6, 8, 12, 16,
#endif

#if ISUSED_EDU == NO
#define ELEMS_EDU
#endif

// assume year var always used

#if YEARS == 1
#define ELEMS_YRS 0,
#endif

#if YEARS == 2
#define ELEMS_YRS 0, 0,
#endif

#if YEARS == 3
#define ELEMS_YRS 0, 0, 0,
#endif

// more of these as needed

main () {
int ndx;
int elems;
int intArray [] = { ELEMS_AGE ELEMS_YRS ELEMS_EDU };

elems = sizeof (intArray) / sizeof (int);
for (ndx = 0; ndx < elems; ndx++) {
printf ("ndx = %d; el = %d\n", ndx, intArray [ndx]);
}
}
 
D

dan

dan said:



Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.


I don't see how, really I don't. This kind of trick isn't really what
the pre-processor is for.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.

I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.

Maybe you're going to suggest to do the jagged arrays as follows?

int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };

int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };

This is how it was previously implemented, with everything getting
filled in with cpp. It worked OK, but there were two problems:

- Had to account in code for whether EDU (or other var) was included
or not. When I needed to alphabetize or otherwise sort an array in
the code, it was "tricky". Now the array just includes the used vars,
so the code is much cleaner.

- Maintaining ageIntArray, eduIntArray, etc. as separate arrays added
a lot of header complexity. Some scenarios have 20 or more variables.
And besides "intArray" various other arrays with other attributes.
Now, instead of 20 separate arrays for intArray, I hoping for one
"jammed" array with all the used elements jammed together, and another
array that is easily set at runtime to point into the jammed array at
the right points.

Thanks,
Daniel
 
R

Richard Heathfield

dan said:

Personally, I think I'd have approached matters rather differently,
but I don't suppose you want to hear that right now, since you're so
far down this road.

I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.

Maybe you're going to suggest to do the jagged arrays as follows?

int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };

int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };

Actually, no. I was thinking rather more radically. But before I say
that, let me just remind you that C's partial initialisation rules
require implementations to use default static initialisation for the
uninitialised parts of any partly-initialised array. The default static
initialiser for int is 0. You may or may not find that information
helpful.

But no - what I was going to say was that it seems to me that age, edu,
and yrs don't really belong in the same array, because they aren't
really the same concept. If you nevertheless find that you need to
process them as if they were the same concept, it may be possible to
find an alternative data structure that still allows you to do the
processing you require in the way you require, without having this
rather strange mongrel array mixing different ideas together.

I don't know your problem domain sufficiently well to recommend a good
example, but it may be as simple as just having an array of pointers
rather than an array of ints. You were already beginning to experiment
along these lines, although you were using an array of arrays rather
than an array of pointers.
 
D

dan

dan said:

<snip>


I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.
Maybe you're going to suggest to do the jagged arrays as follows?
int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };
int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };

Actually, no. I was thinking rather more radically. But before I say
that, let me just remind you that C's partial initialisation rules
require implementations to use default static initialisation for the
uninitialised parts of any partly-initialised array. The default static
initialiser for int is 0. You may or may not find that information
helpful.

But no - what I was going to say was that it seems to me that age, edu,
and yrs don't really belong in the same array, because they aren't
really the same concept. If you nevertheless find that you need to
process them as if they were the same concept, it may be possible to
find an alternative data structure that still allows you to do the
processing you require in the way you require, without having this
rather strange mongrel array mixing different ideas together.

I don't know your problem domain sufficiently well to recommend a good
example, but it may be as simple as just having an array of pointers
rather than an array of ints. You were already beginning to experiment
along these lines, although you were using an array of arrays rather
than an array of pointers.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

Thanks for your comments. The initialization rules that set everything
to zero have not been helpful for these arrays yet, but yes, it's good
to keep in mind. It would come into play if I used the designated
initializations as suggested by Ben.

Related to age, edu, and yrs not belonging in the same array because
they are different concepts... There are a few differences, for
example year is never unknown, but otherwise I've learned from working
with them that they surprisingly ARE the same concept. Each one is
what I call a "range variable". It really makes the programming much
easier. I do a form of object-based programming in C, where the object
is one of those range variables, the object attributes are in the
arrays, the object instance is set when the array elements are
selected, and the functions automatically work the same with whatever
range variable is selected. Instead of separate sets of functions for
age, edu, and yrs (and many others), there is just one set of
functions.

I mislabelled "intArrayArray". It's should have been called
intPtrArray, because it is an array of int pointers. That's the
mechanism I was using before, which was fine, except it was awkward
dealing with the variables (objects) that weren't used. I agree the
array missing age, edu, and yrs is a mongrel, but I think it's a well-
behaved one.

Thanks,
Daniel Goldman
 
B

Ben Bacarisse

dan said:
You don't seem averse to C99, going by your comment syntax, so there may
be another way:

int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };

You can introduce an index part way into an initialiser list.
I was not familiar with designated initializers, which does solve my
test case. I need to go through all of C99. Do you think the pre-
processor may not be able to do what I want, because I think I still
may need the preprocessor solution.

OK, I was just providing more data points.
The designated initializers may not work within the context of the
other code, which I felt was too involved to explain in the initial
post.
I hope this makes some sense.

Yes, but sadly the devil is in the detail so there is not way to tell
if you are into a winner here or if the CPP solution will fail at the
last (possibly as yet unseen) hurdle.

That alone would make me wary. It is never wise to work at the very
edge of what your tools can do. I think you may be better off
switching tools.

I am not a fan on complex CPP coding, mainly because the results seem
fragile and hard to maintain. YMMV.
 
D

dan

<program outline snipped>


You don't seem averse to C99, going by your comment syntax, so there may
be another way:
int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };
You can introduce an index part way into an initialiser list.
I was not familiar with designated initializers, which does solve my
test case. I need to go through all of C99. Do you think the pre-
processor may not be able to do what I want, because I think I still
may need the preprocessor solution.

OK, I was just providing more data points.
The designated initializers may not work within the context of the
other code, which I felt was too involved to explain in the initial
post.

I hope this makes some sense.

Yes, but sadly the devil is in the detail so there is not way to tell
if you are into a winner here or if the CPP solution will fail at the
last (possibly as yet unseen) hurdle.

That alone would make me wary. It is never wise to work at the very
edge of what your tools can do. I think you may be better off
switching tools.

I am not a fan on complex CPP coding, mainly because the results seem
fragile and hard to maintain. YMMV.

You're right, I'm working kind of on the edge, which is dangerous. But
I'm not sure I have a choice. I have faith in C and the cpp and have
never failed to accomplish what was needed, because C is so
programmable. But there's always a first time. I'll know in a few
days. If it fails at an unseen hurdle, I'll go back to old version. In
any case, I'm not sure which tool I would switch to that would better
handle these problems. The problems are imposed by writing a framework
that handles multiple data analysis scenarios and can be compiled to
produce many separate executables, each one customized for a data
scenario and a different runtime environment. I am trying to make the
cpp code as simple to read and maintain as I can. Thanks to you and
other for providing the helpful advice.

Daniel Goldman
 
S

SM Ryan

# On m4, I looked into that a while back, and decided not. I didn't "get
# it". I do use other unix utilities a lot, especially sed and shell
# programming.

m4 has a number of unnecessary problems, but it is a complete
programming language, and it can do a lot more than cpp.

# Can m4 be used in place of cpp for serious development? Is it a good
# idea? I couldn't tell from looking at the GNU m4 site or old USENET
# posts.

Depends on the build system. Makefiles have no problem inserting
an m4 step, creating .c or .i files; other more advanced systems
can be less flexible.

There are better tools than cpp; people need not bash their faces
against the wall unless it gives them pleasure.
 
D

dan

# On m4, I looked into that a while back, and decided not. I didn't "get
# it". I do use other unix utilities a lot, especially sed and shell
# programming.

m4 has a number of unnecessary problems, but it is a complete
programming language, and it can do a lot more than cpp.

# Can m4 be used in place of cpp for serious development? Is it a good
# idea? I couldn't tell from looking at the GNU m4 site or old USENET
# posts.

Depends on the build system. Makefiles have no problem inserting
an m4 step, creating .c or .i files; other more advanced systems
can be less flexible.

There are better tools than cpp; people need not bash their faces
against the wall unless it gives them pleasure.

I agree cpp leaves a lot to be desired. And if Kernighan and Ritchie
wrote m4, it's probably pretty good.

Can m4 statements be inserted into C code, like cpp statements? Or
does m4 run from a separate script? I looked through the GNU m4
documentation, and could not figure it out.

If m4 can be embedded in C files, is there a web site somewhere with
examples?

Thanks,
Daniel Goldman
 
K

Keith Thompson

dan said:
I agree cpp leaves a lot to be desired. And if Kernighan and Ritchie
wrote m4, it's probably pretty good.

Can m4 statements be inserted into C code, like cpp statements? Or
does m4 run from a separate script? I looked through the GNU m4
documentation, and could not figure it out.

If m4 can be embedded in C files, is there a web site somewhere with
examples?

m4 statements can't really be inserted into C code. What you can do
is write a file that's fed to m4 as input, producing C code as output.
(The input is likely to look like C apart from any m4-specific
syntax.) The syntax and semantics of the C preprocessor, on the other
hand, are part of the C language. You can even have standard C
preprocessor directives in the m4 output (it's just text as far as m4
is concerned, just C as far as the compiler is concerned).

On the one hand, m4 is generally more powerful than the C
preprocessor. On the other hand, it causes your code to be dependent
on m4, and less likely to be understood by other C programmers.

This all applies equally to any other preprocessor. The C compiler
doesn't care how the C source code you feed it was generated.
 
S

SM Ryan

# Can m4 statements be inserted into C code, like cpp statements? Or
# does m4 run from a separate script? I looked through the GNU m4
# documentation, and could not figure it out.

The build is a series of steps, transforming some input to some
output. A C compiler traditionally includes a cpp step, a parser
step, optional optimiser steps, and object code generation step.
Many compilers can also do the final load step to create an executable,
although the loader is not traditionally part of the compiler.

I don't think C compilers include a m4 step before the cpp, so
you would have to get your build system to do that yourself.
Apparently you already have a number of preliminary steps before
calling cc, so this would be just one more. Using make you can
define the .m4 suffix as the m4 input files, and then you can
build with something like

..m4.c:
m4 -m4options $< > $@

So that somefile.m4 is mostly c code with interspersed macro
definitions and macro calls; theses are expanded and written
to somefile.c, somefile.c is then compiled with a .c.o step.

# If m4 can be embedded in C files, is there a web site somewhere with
# examples?

GNU m4 is documented there. I don't if/where the ATT documentation is.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top