Macro Mystery ... help?

R

Ray

I'm having trouble debugging the following routine, and don't understand
why. It uses a macro, in what I think is a fairly straightforward way,
to do a generic operation.

Background: there are three different struct types, one each
for questions, synonym lists, and comments. Each has a field
named next, which is a self-typed pointer for forming lists, and
a field named idnum, which is an integer. The idnum is a unique
ID reflecting the order in which the statements appeared in the
input file. I'm roundtripping a script-language here (writing
back/recreating the input file after manipulating it
programmatically with programming tools) so I use the ID number
to write things back in the same order they originally appeared.

Each struct type has a separate routine that writes it.

I have a "write progress record" that contains pointers to each
type of linked list.

So.... My macro, WRITEIFLEAST, is supposed to check to make
sure that its first parameter is non-null and that the next
two are either null or have a greater ID number. If all these
conditions are met, it calls the writer (provided as argument 4)
to write the first argument, advances the corresponding pointer
in the progress record, and returns 'success'. I call it once
for the 'current' member of each statement type, in an effort
to write whichever statement comes "next" in the sequence.

I compile using 'gcc -ansi -pedantic' and get the error message,

language.c: In function ‘writestatement’:
language.c:198: error: expected ‘;’ before ‘{’ token

Line 198 is the first use of the macro WRITEIFLEAST. The only
'{' appearing in this line would be the one that opens the body
of the 'elseif' block in the macro, but it makes no sense to
expect a statement terminator between the condition and the
opening of the conditional block it controls, so, aside from
making sure my 'elseif' condition is well-formed (parens match
and everything) I cannot figure out what I should do.

Lines 199 and 200 don't trigger this message, so I think it
has to be something before the first macro use. But I cannot
find it!


########################################################

/* writestatement takes a pointer at a write progress record. If
there are questions, comments, or synonym lists that remain
unwritten, writes whichever has the lowest ID number and returns
1. Otherwise, or in case of error, writes nothing and returns 0.

Note that the token 'output' appears free in this macro, referring
to an output file visible in the scope of writestatement.
*/


#define WRITEIFLEAST(parma, parmb, parmc, writer) \
elseif ((parma != NULL) && \
(parmb == NULL || parmb->idnum > parma->idnum) && \
(parmc == NULL || parmc->idnum > parma->idnum)){ \
writer(parma, output); \
parma = parma->next; \
return(1); \
}

int writestatement(struct writeprogress *prog, FILE *output){

if (prog == NULL || output == NULL ||
(prog->comments == NULL &&
prog->synonyms == NULL &&
prog->questions == NULL)){
return(0);
}
/* writecomment, writesynspec, and writequestion are routines.
A writeprogress struct is a set of pointers to lists of each
of the different statement types.
All 3 record types have a field named idnum and a self-typed
pointer named next; other fields vary. */
WRITEIFLEAST(prog->comments, prog->synonyms, prog->questions, writecomment)
WRITEIFLEAST(prog->synonyms, prog->comments, prog->questions, writesynspec)
WRITEIFLEAST(prog->questions, prog->synonyms, prog->comments, writequestion)

else return(0);
}

#undef WRITEIFLEAST



##############################################################

Anyway, because I was baffled, I ran 'gpp language.c' to see what
was getting generated, and the relevant bit of code is this (I
have added whitespace and one comment for readability, but neither
added nor removed other tokens).

Unfortunately I am *still* baffled. I do not understand what is
wrong with the expanded code. But when I paste it in for the macro
version above, I still get the same error. And it still refers to
expecting a semicolon between the first elseif condition and the
corresponding body, which still makes no sense whatsoever.

##############################################################
int writestatement(struct writeprogress *prog, FILE *output){

if (prog == ((void *)0) || output == ((void *)0) ||
(prog->comments == ((void *)0) && prog->synonyms == ((void *)0) &&
prog->questions == ((void *)0)))
return(0);

elseif
((prog->comments != ((void *)0)) &&
(prog->synonyms == ((void *)0) || prog->synonyms->idnum > prog->comments->idnum) &&
(prog->questions == ((void *)0) || prog->questions->idnum > prog->comments->idnum))
/* here is the location that the compiler is complaining about! */ {
writecomment(prog->comments, output);
prog->comments = prog->comments.next;
return(1);
}


elseif
((prog->synonyms != ((void *)0)) &&
(prog->comments == ((void *)0) || prog->comments->idnum > prog->synonyms->idnum) &&
(prog->questions == ((void *)0) || prog->questions->idnum > prog->synonyms->idnum)){
writesynspec(prog->synonyms, output);
prog->synonyms = prog->synonyms.next;
return(1);
}

elseif
((prog->questions != ((void *)0)) &&
(prog->synonyms == ((void *)0) || prog->synonyms->idnum > prog->questions->idnum) &&
(prog->comments == ((void *)0) || prog->comments->idnum > prog->questions->idnum)) {
writequestion(prog->questions, output);
prog->questions = prog->questions.next;
return(1);
}

else return(0);
}


################################################################


TIA guys. Any help in understanding this would be most appreciated.

Bear
 
L

Lew Pitcher

I'm having trouble debugging the following routine, and don't understand
why. It uses a macro, in what I think is a fairly straightforward way,
to do a generic operation.

Background: there are three different struct types, one each
for questions, synonym lists, and comments. Each has a field
named next, which is a self-typed pointer for forming lists, and
a field named idnum, which is an integer. The idnum is a unique
ID reflecting the order in which the statements appeared in the
input file. I'm roundtripping a script-language here (writing
back/recreating the input file after manipulating it
programmatically with programming tools) so I use the ID number
to write things back in the same order they originally appeared.

Each struct type has a separate routine that writes it.

I have a "write progress record" that contains pointers to each
type of linked list.

So.... My macro, WRITEIFLEAST, is supposed to check to make
sure that its first parameter is non-null and that the next
two are either null or have a greater ID number. If all these
conditions are met, it calls the writer (provided as argument 4)
to write the first argument, advances the corresponding pointer
in the progress record, and returns 'success'. I call it once
for the 'current' member of each statement type, in an effort
to write whichever statement comes "next" in the sequence.

I compile using 'gcc -ansi -pedantic' and get the error message,

language.c: In function ‘writestatement’:
language.c:198: error: expected ‘;’ before ‘{’ token

Line 198 is the first use of the macro WRITEIFLEAST. The only
'{' appearing in this line would be the one that opens the body
of the 'elseif' block in the macro, but it makes no sense to
expect a statement terminator between the condition and the
opening of the conditional block it controls, so, aside from
making sure my 'elseif' condition is well-formed (parens match
and everything) I cannot figure out what I should do.

Lines 199 and 200 don't trigger this message, so I think it
has to be something before the first macro use. But I cannot
find it!


########################################################

/* writestatement takes a pointer at a write progress record. If
there are questions, comments, or synonym lists that remain
unwritten, writes whichever has the lowest ID number and returns
1. Otherwise, or in case of error, writes nothing and returns 0.

Note that the token 'output' appears free in this macro, referring
to an output file visible in the scope of writestatement.
*/


#define WRITEIFLEAST(parma, parmb, parmc, writer) \
elseif ((parma != NULL) && \
(parmb == NULL || parmb->idnum > parma->idnum) && \
(parmc == NULL || parmc->idnum > parma->idnum)){ \

"elseif" is not a C keyword. Perhaps the compiler sees it as a function
call.

If so, then the compiler would expect some sort of statement-ending content
(a semicolon, or an "else" statement to match the previous "if" statement)
between the end of the function call parameters and the start of the next
compound statement.

Consider changing your macro to read
#define WRITEIFLEAST(parma, parmb, parmc, writer) \
else if ((parma != NULL) && \
etc.

writer(parma, output); \
parma = parma->next; \
return(1); \
}

int writestatement(struct writeprogress *prog, FILE *output){

if (prog == NULL || output == NULL ||
(prog->comments == NULL &&
prog->synonyms == NULL &&
prog->questions == NULL)){
return(0);
}
/* writecomment, writesynspec, and writequestion are routines.
A writeprogress struct is a set of pointers to lists of each
of the different statement types.
All 3 record types have a field named idnum and a self-typed
pointer named next; other fields vary. */
WRITEIFLEAST(prog->comments, prog->synonyms, prog->questions,
writecomment) WRITEIFLEAST(prog->synonyms, prog->comments,
prog->questions, writesynspec) WRITEIFLEAST(prog->questions,
prog->synonyms, prog->comments, writequestion)

else return(0);
}
[snip]
 
K

Kaz Kylheku

#define WRITEIFLEAST(parma, parmb, parmc, writer) \
elseif ((parma != NULL) && \
(parmb == NULL || parmb->idnum > parma->idnum) && \
(parmc == NULL || parmc->idnum > parma->idnum)){ \
writer(parma, output); \
parma = parma->next; \
return(1); \
}

Defining macros for fragments of a statement is a bad idea, probably.

And note that C does not have an elseif keyword. It's ``else if''.

This ``else if'' idiom means that you have an else clause, and that clause is
an if statement. It's usually formated in a vertical fashion.

Writing it as follows clarifies the true nesting of the syntax:

if (...)
...
else if (....)
...
else if (....)
...
else
...

but this ``if/else ladder'' is usually collapsed like this:

if (...)
...
else if (....)
...
else if (....)
...
else
 
R

Ray

Kaz said:
Defining macros for fragments of a statement is a bad idea, probably.

Eh. I allow it to myself when the #define and #undef are on the same
screen, with all the macro calls between them. If it were a macro that
could be called "from anywhere" as the saying goes, then yes, I'd want
to make it more function-like and complete unto itself.
And note that C does not have an elseif keyword. It's ``else if''.

Ding! That was it. Thank you, I was getting C crossed up with some
other language. I may have too many languages in my head now to ever
be truly free of this effect. One side effect of having something
like that pointed out is that now I feel like an idiot for having
asked in the first place. Sigh.

Thanks again,
Bear
 
N

Nick Keighley

Eh.  I allow it to myself when the #define and #undef are on the same
screen, with all the macro calls between them.  If it were a macro that
could be called "from anywhere" as the saying goes, then yes, I'd want
to make it more function-like and complete unto itself.


Ding!  That was it.  Thank you, I was getting C crossed up with some
other language.  I may have too many languages in my head now to ever
be truly free of this effect.  One side effect of having something
like that pointed out is that now I feel like an idiot for having
asked in the first place. Sigh.  


its always abvious when you know the answer
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top