Macro Mystery ... help?

  • Follow


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

0
Reply bear (1215) 2/2/2010 9:03:38 PM

On February 2, 2010 16:03, in comp.lang.c, bear@sonic.net wrote:

>=20
> I'm having trouble debugging the following routine, and don't underst=
and
> why.  It uses a macro, in what I think is a fairly straightforward wa=
y,
> to do a generic operation.
>=20
> 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.
>=20
> Each struct type has a separate routine that writes it.
>=20
> I have a "write progress record" that contains pointers to each
> type of linked list.
>=20
> 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.
>=20
> I compile using 'gcc -ansi -pedantic' and get the error message,
>=20
> language.c: In function =E2=80=98writestatement=E2=80=99:
> language.c:198: error: expected =E2=80=98;=E2=80=99 before =E2=80=98{=
=E2=80=99 token
>=20
> 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.
>=20
> 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!
>=20
>=20
> ########################################################
>=20
> /* 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.
>=20
>    Note that the token 'output' appears free in this macro, referring=

>    to an output file visible in the scope of writestatement.
> */
>=20
>=20
> #define WRITEIFLEAST(parma, parmb, parmc, writer)               \
>   elseif ((parma !=3D NULL) &&                                    \
>           (parmb =3D=3D NULL || parmb->idnum > parma->idnum) &&     \=

>           (parmc =3D=3D NULL || parmc->idnum > parma->idnum)){      \=
=20

"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 con=
tent
(a semicolon, or an "else" statement to match the previous "if" stateme=
nt)
between the end of the function call parameters and the start of the ne=
xt
compound statement.

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


>     writer(parma, output);                                      \
>     parma =3D parma->next;                                        \
>     return(1);                                                  \
>   }
>=20
> int writestatement(struct writeprogress *prog, FILE *output){
>=20
>   if (prog =3D=3D NULL || output =3D=3D NULL ||
>       (prog->comments =3D=3D NULL &&
>        prog->synonyms =3D=3D NULL &&
>        prog->questions =3D=3D 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)
>=20
>   else return(0);
> }
[snip]

--=20
Lew Pitcher
Master Codewright & JOAT-in-training   | Registered Linux User #112576
Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.c=
a/
----------      Slackware - Because I know what I'm doing.         ----=
--


0
Reply Lew 2/2/2010 9:11:29 PM


On 2010-02-02, Ray <bear@sonic.net> wrote:
> #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


0
Reply Kaz 2/2/2010 9:14:27 PM

Kaz Kylheku wrote:

> 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

0
Reply Ray 2/3/2010 3:21:46 AM

On 3 Feb, 03:21, Ray <b...@sonic.net> wrote:
> Kaz Kylheku wrote:
> > Defining macros for fragments of a statement is a bad idea, probably.
>
> Eh. =A0I allow it to myself when the #define and #undef are on the same
> screen, with all the macro calls between them. =A0If 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! =A0That was it. =A0Thank you, I was getting C crossed up with some
> other language. =A0I may have too many languages in my head now to ever
> be truly free of this effect. =A0One 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. =A0


its always abvious when you know the answer
0
Reply Nick 2/3/2010 9:02:55 AM

4 Replies
170 Views

(page loaded in 0.198 seconds)

Similiar Articles:













7/22/2012 9:30:30 PM


Reply: