Errors with typedefs

E

Erica

Hi,

I am currently working on a Pascal-to-C translation, and I am getting an
error that I can't seem to debug.

I have a globals.h file, and here is a snippet from it:

--

typedef char ShortString[100];

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

typedef struct SpellRec* SpellTableEntry;

--

Then, I have the following function in one of my .c files:

--

SpellTableEntry NewSpell(ShortString na, TokenKind k,
SpellTableEntry ne) {

SpellTableEntry spell = (SpellTableEntry)malloc(sizeof(SpellTableEntry));
spell->name = na;
spell->kind = k;
spell->symbol = NULL;
spell->next = ne;
return spell;
} /* NewSpell */

--

I get the following errors:
scanner.c:20: error: syntax error before "TokenKind"
scanner.c: In function 'NewSpell':
scanner.c:24: error: incompatible types in assignment
scanner.c:25: error: 'k' undeclared (first use in this function)
scanner.c:25: error: (Each undeclared identifier is reported only once for
each function it appears in.)
scanner.c:27: error: 'ne' undeclared (first use in this function)

Does anyone have any clue how I could fix this? I am at my wits end, and any
help is greatly appreciated.

TIA,
Erica
 
D

dandelion

Not very difficult... A Question of syntax.

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

You now have a anonymous type and a structure called SpellRec. Compare, for
instance,

struct foobar
{
...
};

and

struct
{
...
} foobar;

The first defines a structure, the second a variable.

Try

typedef struct
{
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
} SpellRec ;

You now have a type called SpellRec with an anonymoust structure as
"content".

HTH.

dandelion.
 
X

xarax

Erica said:
Hi,

I am currently working on a Pascal-to-C translation, and I am getting an
error that I can't seem to debug.

I have a globals.h file, and here is a snippet from it:

Ok, fine. ShortString is typedef name that is
an alias for char[100] type.

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

typedef struct SpellRec* SpellTableEntry;


Try changing the above to:

typedef struct SpellRec* SpellTableEntry;

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
SpellTableEntry next;
} SpellRec;

I've defined the struct pointer name before
the struct itself. I've used the struct pointer
name within the struct. Finally, I've given
the struct a typedef name.

/snip/
 
E

Erica

Hmmm...I tried that, and I still get the same errors. I don't think that the
problem is with the SpellRec, but rather the arguments that I'm passing to
the function.

Here is the definition of ShortString:

typedef char ShortString[100];

Here's TokenKind:

enum TokenKind {tInvisibleToken,
tIdent,
tIntNum, tRealNum,
tEND, tREAL, tINTEGER,
tARRAY, tFUNCTION, tPROCEDURE, tRETURN, tVAR,
tIF, tTHEN, tELSE, tWHILE, tDO, tREAD, tWRITE,
tAND, tOR, tNOT,
tPeriod, tSemicolon, tComma, tAssign,
tPlus, tMinus, tTimes, tDivide,
tEq, tNotEq, tLess, tLessEq, tGtr, tGtrEq,
tLParen, tRParen
};

And SpellTableEntry:
typedef struct SpellRec* SpellTableEntry;

Thanks though!!
--Erica
 
K

kevin.bagust

Erica said:
I am currently working on a Pascal-to-C translation, and I am getting an
error that I can't seem to debug.
I have a globals.h file, and here is a snippet from it:

typedef char ShortString[100];
typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

The above typedef is wrong. You need to either drop the typedef and make
it a plain struct SpellRec {, or you need to add the name to typedef to
after the closing curly bracket. So


typedef struct SpellRec { char name[12]; enum TokenKind kind;
SymbolTableEntry symbol; struct SpellRec* next;
} SpellRec;

typedef struct SpellRec* SpellTableEntry;

Then, I have the following function in one of my .c files:

SpellTableEntry NewSpell(ShortString na, TokenKind k, SpellTableEntry
ne) {

You have not provided a definition for TokenKind, or enum TokenKind, but
presuming that they are both the same thing and they are not typedefed
then you will need to add the enum key word to this function declaration
so you will have:

SpellTableEntry NewSpell(ShortString na, enum TokenKind k, SpellTableEntry
ne) {
SpellTableEntry spell =
(SpellTableEntry)malloc(sizeof(SpellTableEntry));
spell->name = na;

The above line is wrong, as you cannot copy strings using the equals
operator. You need to either use a library routine to copy the string, or
copy the string character by character, or change name to a pointer to a
char. Taking the first option gives you (and making sure not to copy more
characters than name can hold, and making sure to include string.h at the
top of the file):

strncpy( spell->name, na, sizeof(spell->name)-1); spell->name[
sizeof(spell->name)-1] = '\0';
spell->kind = k;
spell->symbol = NULL;
spell->next = ne;
return spell;
} /* NewSpell */

Does anyone have any clue how I could fix this? I am at my wits end, and
any help is greatly appreciated.

The three changes I have suggested above should fix them.

Kevin
 
C

Chris Torek

Others have addressed the "typedef int /* no alias here */;" issue:
typedef's syntax is funky, in that it takes the existing type, then
a series of variable declarations, and changes the variable declarations
into alias-declarations instead.

No one has, however, directly mentioned the more important thing:
C's "typedef" does not define types at all.

C's "struct" (and "union" and "enum" keywords as well, but they
are "lesser", as it were) is what actually declares new types.

Unlike Pascal, where you really want to declare a bunch of types
first, then use them in variable declarations, C lets you mix everything
together. It does this by requiring the "struct" keyword each time.
Just think of "struct" as meaning "type" and you will be fine. :)

Similarly, you need the word "enum" to mean "(enumerated) type", when
referring back to an enumeration. In Pascal you would make up type
names for your records and enumerations, and then use those; in C,
you do them all at once:

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

If you drop the "typedef" entirely, you will have:

struct SpellRec { ...contents... };

which defines a type named "struct SpellRec" (complete with the
"struct" keyword). This contains something of type "char [12]",
then something of type "enum TokenKind" (complete with the "enum"
keyword), then something of type "SymbolTableEntry" (no keyword --
must be a typedef-alias for some other "real" type), then something
of type "struct SpellRec *" (pointer to struct SpellRec, using the
"struct" keyword).

Except in a few peculiar corner cases involving <stdarg.h>, you
never *need* the typedef keyword at all, in C. You may decide
that you like it -- especially if you have been programming in
Pascal -- but you need to learn, deep in your gut as it were,
that typedef does not create types. If you write, for instance:

typedef double Temperature;
typedef double Area;

you probably want to prevent people from doing silly things like:

Temperature t;
Area a;
...
a = t; /* same area as a temperature (?!?) */

In C, though, typedefs are just aliases. "a" and "t" are really
both just "double"s, just as if you had written:

double t;
double a;

and therefore "a = t" is a perfectly good assignment.

To create new types, so that "a = t" becomes an error, you have
to encapsulate your data inside a "struct" (or union, or -- except
that enumerations are just integers -- enum):

struct temperature { double val; };
struct area { double val; };
...
struct temperature t;
struct area a;
...
a = t; /* error, and a C compiler must emit a diagnostic */

Although the structures have the same "shape" (one double) and
element-names ("val"), they are different types, and you cannot
pass a "struct temperature" where a "struct area" is required,
for instance.
typedef char ShortString[100];
typedef struct SpellRec* SpellTableEntry;

These just make aliases for the existing types "char [100]" (array
of size 100 of char) and "struct SpellRec *" (pointer to struct
SpellRec).

Note that you can make an alias for a structure type before
defining the (new) structure type:

typedef struct newtype alias_for_newtype;
struct newtype { ...contents... };

In general, I prefer not to use such typedefs at all, but this is
a matter of taste (I know chocolate is better than vanilla, and
dark chocolate better than milk chocolate, but I realize other
people believe otherwise, no matter how wrong they are :) ).
Then, I have the following function in one of my .c files:

SpellTableEntry NewSpell(ShortString na, TokenKind k,
SpellTableEntry ne) {

SpellTableEntry spell =
(SpellTableEntry)malloc(sizeof(SpellTableEntry));
spell->name = na;
spell->kind = k;
spell->symbol = NULL;
spell->next = ne;
return spell;
} /* NewSpell */

This is because there is no typedef-alias named "TokenKind".

Your structure uses a type named "enum TokenKind", and presumably
this is what "k" should be, so the function should read:

struct SpellRec *NewSpell(char na[100], enum TokenKind k,
struct SpellRec *ne) {
...
}

(or put in some or all of your typedef-aliases if you prefer
them).

Note that the "value" of an array is a pointer to its first element,
and "na" is declared as if it were an array. Since C always passes
by value (there is nothing directly equivalent to Pascal's "var";
you have to simulate it with pointers), a C function that *appears*
to take an array as a paremter actually receives a pointer to the
array's first element. (See also <http://web.torek.net/torek/c/pa.html>
and "The Rule" about arrays and pointers in C.) Thus, I would
actually change the above even a bit more, to read:

struct SpellRec *NewSpell(char *na, enum TokenKind k,
struct SpellRec *ne) {
...
}

Because arrays have this peculiar behavior when passed as parameters,
I think one should *never* use a typedef to make an alias for an
array type. It is not that you cannot make this work, it is just
that, without knowing whether "T" is the name of an array type, you
cannot predict how a parameter of type "T" behaves.

The remaining errors:
scanner.c: In function 'NewSpell':
scanner.c:24: error: incompatible types in assignment
scanner.c:25: error: 'k' undeclared (first use in this function)
scanner.c:25: error: (Each undeclared identifier is reported only once for
each function it appears in.)
scanner.c:27: error: 'ne' undeclared (first use in this function)

are just "cascades" produced because of the first error.
 
O

Old Wolf

Erica said:
typedef char ShortString[100];

typedef struct SpellRec {
char name[12];
enum TokenKind kind;
SymbolTableEntry symbol;
struct SpellRec* next;
};

When you write:
struct SpellRec { .... };
you declare a type called "struct SpellRec". At this point,
the compiler would not recognize the name "SpellRec" unless
it was preceded by "struct".

When you write:
typedef SOMETHING SpellRec;
you declare an alias "SpellRec" that means the same as an
existing type.

So, what you wrote is invalid syntax. It is like writing:
typedef int;

You could write:

struct SpellRec { ...... };
typedef struct SpellRec SpellRec;

or, identically, combine the two as:

typedef struct SpellRec { ....... } SpellRec;

Then "struct SpellRec" is a type, and "SpellRec" by itself
is an alias for that type.
This doesn't cause confusion to the compiler, there are
different namespaces for struct tags as for type aliases.


[Note - here I am going to place the compiler error messages
you wrote, after the line that it applies to]
typedef struct SpellRec* SpellTableEntry;

SpellTableEntry NewSpell(ShortString na, TokenKind k,
SpellTableEntry ne) {

scanner.c:20: error: syntax error before "TokenKind"

You must have declared TokenKind as:
enum TokenKind { ..... };
That means you have to refer to it as "enum TokenKind" everywhere
(as you correctly did in the declaration of SpellRec).

This is similar to your problem with declaring "struct SpellRec".
If you want to have a type alias "TokenKind" on its own then go:

enum TokenKind { ........ };
typedef enum TokenKind TokenKind;
or just
typedef enum TokenKind { ......... } TokenKind;
SpellTableEntry spell =
(SpellTableEntry)malloc(sizeof(SpellTableEntry));

You malloc'd the wrong number of bytes, this is an example of
why most people dislike pointer typedefs. You need to malloc
the size of a SpellRec struct. Also it is silly to cast the
return value of malloc. Instead:

SpellRec *spell = malloc(sizeof *spell);

Make sure you had "#include said:
spell->name = na;

scanner.c: In function 'NewSpell':
scanner.c:24: error: incompatible types in assignment

You can't use '=' to assign arrays, unfortunately.
You have to be especially careful with this case, because
"name" is a char[12] but "na" is a (char *) which probably
points to an array of size 100. So you have to copy at
most 12 bytes out of "na", and make sure that "name" gets
0-terminated correctly. (If you don't understand what I
just wrote then go and read the FAQ section on C string
handling).
My preferred way to do this is:

snprintf(spell->name, sizeof spell->name, "%s", na);

although if your system does not have snprintf you can go:

strncpy(spell->name, na, sizeof spell->name);
spell->name[sizeof spell->name - 1] = '\0';
spell->kind = k;
spell->symbol = NULL;
spell->next = ne;

scanner.c:25: error: 'k' undeclared (first use in this function)
scanner.c:27: error: 'ne' undeclared (first use in this function)

These errors should go away when you fix the TokenKind problem,
they occurred because the compiler stopped reading the function
parameters when it couldn't understand 'TokenKind'.
 

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
474,147
Messages
2,570,835
Members
47,383
Latest member
EzraGiffor

Latest Threads

Top