Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

error: initializer element is not constant

148 views
Skip to first unread message

Bart Vandewoestyne

unread,
Oct 3, 2012, 9:16:46 AM10/3/12
to
Hello all,

I am currently trying to get started with the code for Chapter 3
'Parsing' in Appel's 'Modern Compiler Implementation in C'. After
downloading the files and fixing some small bugs in it, the only problem
I'm left with when typing 'make' is the following error:

cc -g -c lex.yy.c
lex.yy.c:20:1: error: initializer element is not constant
lex.yy.c:20:1: error: (near initialization for �yyin�)
lex.yy.c:20:1: error: initializer element is not constant
lex.yy.c:20:1: error: (near initialization for �yyout�)
make: *** [lex.yy.o] Error 1

The file lex.yy.c is an output file of an old version of lex, and the
error is for the line:

FILE *yyin = {stdin}, *yyout = {stdout};

I would now like to know what is the cleanest way to solve this
compilation error. From the net, I've found that I can simply declare
yyin and yyout:

FILE *yyin, *yyout;

(which works), and then later initialize them in a main(), probably
something like:

int main()
{
yyin = stdin;
yyout = stdout;
}

However, i don't have a main function, so I was wondering where and how
I should initialize yyin and yyout. My educated guess is that this
should happen at the beginning of the yylex() function. So there, I added:

yylex() {
int nstr; extern int yyprevious;
yyin = stdin; yyout = stdout;
... other code...

See also lines 20-21 and 78-79 in
https://github.com/BartVandewoestyne/c/blob/master/books/Modern_Compiler_Implementation_in_C/chap03/lex.yy.c

Is this the correct, cleanest and most portable way to fix the above error?

Thanks,
Bart

Eric Sosman

unread,
Oct 3, 2012, 9:35:12 AM10/3/12
to
On 10/3/2012 9:16 AM, Bart Vandewoestyne wrote:
> Hello all,
>
> I am currently trying to get started with the code for Chapter 3
> 'Parsing' in Appel's 'Modern Compiler Implementation in C'. After
> downloading the files and fixing some small bugs in it, the only problem
> I'm left with when typing 'make' is the following error:
>
> cc -g -c lex.yy.c
> lex.yy.c:20:1: error: initializer element is not constant
> lex.yy.c:20:1: error: (near initialization for �yyin�)
> lex.yy.c:20:1: error: initializer element is not constant
> lex.yy.c:20:1: error: (near initialization for �yyout�)
> make: *** [lex.yy.o] Error 1
>
> The file lex.yy.c is an output file of an old version of lex, and the
> error is for the line:
>
> FILE *yyin = {stdin}, *yyout = {stdout};
>
> I would now like to know what is the cleanest way to solve this
> compilation error. From the net, I've found that I can simply declare
> yyin and yyout:
>
> FILE *yyin, *yyout;
>
> (which works), and then later initialize them in a main(), probably
> something like:
>
> int main()
> {
> yyin = stdin;
> yyout = stdout;
> }
>
> However, i don't have a main function, [...]

Really? C'mon, now: REALLY?

> [...] so I was wondering where and how
> I should initialize yyin and yyout. My educated guess is that this
> should happen at the beginning of the yylex() function. So there, I added:
>
> yylex() {
> int nstr; extern int yyprevious;
> yyin = stdin; yyout = stdout;
> ... other code...
>
> See also lines 20-21 and 78-79 in
> https://github.com/BartVandewoestyne/c/blob/master/books/Modern_Compiler_Implementation_in_C/chap03/lex.yy.c
>
>
> Is this the correct, cleanest and most portable way to fix the above error?

A good first step might be to discard the "old version of lex"
and see whether a more up-to-date version generates code that needs
less fixing. You might also consider using a lex-ish program like
flex instead of Original Model T lex.

If that doesn't help, then you need to ensure that yyin and yyout
are initialized at some point before their first uses. Off-hand I don't
know whether yylex() is the best place for this; maybe it should be
done in yylex()'s caller (where, for example, you might call fopen()
to use streams other than stdin and stdout).

--
Eric Sosman
eso...@ieee-dot-org.invalid

Bart Vandewoestyne

unread,
Oct 3, 2012, 10:33:35 AM10/3/12
to
On 10/03/2012 03:35 PM, Eric Sosman wrote:
>
> A good first step might be to discard the "old version of lex"
> and see whether a more up-to-date version generates code that needs
> less fixing. You might also consider using a lex-ish program like
> flex instead of Original Model T lex.

Hmm... you're probably right. The code compiles now, but when I run the
parser it gets stuck in the yylook() function for some or the other
reason... If I compile with -Wall and -Wextra, then I see quite some
warnings...

If I use my own lex.yy.c file (that I obtained while writing the lexer
from Chapter 2 of the book), it just works... so I'll stick with that one.

The reason why I was trying to use the book's lex.yy.c is simply because
I really wanted to use the author's lexer instead of mine (mine might
still contain errors...)

But anyway, given the too old lex.yy.c and the problems that come with
it, I guess I'll have to have faith in myself and use my own lexer.

Regards,
Bart

Chad

unread,
Oct 3, 2012, 11:01:03 AM10/3/12
to
Maybe it's just me, but I feel the parser is more difficult to get right than the lexer. In particular, depending on how you handle the AST, you might have to use some kind of backtracking algorithm in order to generate the correct error message. Also, if I remember right, certain parsing techniques can make a programming language more expressive.

Keith Thompson

unread,
Oct 3, 2012, 4:56:23 PM10/3/12
to
Bart Vandewoestyne <MyFirstName...@telenet.be> writes:
> I am currently trying to get started with the code for Chapter 3
> 'Parsing' in Appel's 'Modern Compiler Implementation in C'. After
> downloading the files and fixing some small bugs in it, the only problem
> I'm left with when typing 'make' is the following error:
>
> cc -g -c lex.yy.c
> lex.yy.c:20:1: error: initializer element is not constant
> lex.yy.c:20:1: error: (near initialization for �yyin�)
> lex.yy.c:20:1: error: initializer element is not constant
> lex.yy.c:20:1: error: (near initialization for �yyout�)
> make: *** [lex.yy.o] Error 1
>
> The file lex.yy.c is an output file of an old version of lex, and the
> error is for the line:
>
> FILE *yyin = {stdin}, *yyout = {stdout};

Apparently lex is assuming that stdin and stdout are constant
expressions. This is likely true for some implementations,
presumably including the ones on which lex was originally developed,
but it's not guaranteed.

> I would now like to know what is the cleanest way to solve this
> compilation error. From the net, I've found that I can simply declare
> yyin and yyout:
>
> FILE *yyin, *yyout;
>
> (which works), and then later initialize them in a main(), probably
> something like:
>
> int main()
> {
> yyin = stdin;
> yyout = stdout;
> }
>
> However, i don't have a main function, so I was wondering where and how
> I should initialize yyin and yyout.

You should have a main function *somewhere*.

> My educated guess is that this
> should happen at the beginning of the yylex() function. So there, I added:
>
> yylex() {
> int nstr; extern int yyprevious;
> yyin = stdin; yyout = stdout;
> ... other code...

Can you create an initialization function that assigns values to yyin
and yyout, and require that the main program (wherever it is) must call
that function?

> See also lines 20-21 and 78-79 in
> https://github.com/BartVandewoestyne/c/blob/master/books/Modern_Compiler_Implementation_in_C/chap03/lex.yy.c
>
> Is this the correct, cleanest and most portable way to fix the above error?

That file no longer exists. The version I think you're referring to can
be seen at

https://github.com/BartVandewoestyne/c/blob/cb0daed9ee4b0bd8c803980c89095ae84f36f706/books/Modern_Compiler_Implementation_in_C/chap03/lex.yy.c

The file lex.yy.c is normally *generated* from an input file. Your
makefile assumes that it already exists.

GNU flex is a relatively newer implementation of lex, and it should be
reasonable compatible. I just tried feeding your "tiger.lex" file to
yacc, and it generated a lex.yy.c file that doesn't have the problem you
reported. It has:

if ( ! yyin )
yyin = stdin;

if ( ! yyout )
yyout = stdout;

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Nobody

unread,
Oct 3, 2012, 7:15:22 PM10/3/12
to
On Wed, 03 Oct 2012 13:56:23 -0700, Keith Thompson wrote:

>> However, i don't have a main function, so I was wondering where and how
>> I should initialize yyin and yyout.
>
> You should have a main function *somewhere*.

It might be the one in libfl.a (or libfl_pic.a).

Gordon Burditt

unread,
Oct 6, 2012, 7:55:41 PM10/6/12
to
yylex() is called repeatedly to get each token. If you initialize
yyin and yyout there, you'll mess up any code that tries to temporarily
change that (if there is any - many lexers read only one file).
For example, some programs handle possibly-nested "include files"
in the lexer alone. I don't think it is possible to do that parsing
C (it would seem to prohibit preprocessor substitutions in a #include
directive).

If you intend to read only one file (from stdin), and put:
yyin = stdin;
at the start of yylex(), you'll be fine, although you'll execute a
redundant assignment repeatedly after the first call.

Certainly you don't want to do something like:
yyin = fopen(filename, "r");
at the beginning of yylex() since you'd read the first token of the
file repeatedly until you run out of open file handles, hit a syntax
error in the parser or lexer, or get an error for trying to open
the same file twice in the same program. Put such a statement at
the beginning of main() before a call to yylex() or yyparse().

There is a YACC library, liby.a (or -ly on the command line), that
contains a main program that consistes essentially of:
exit(yyparse());
and the YACC-generate yyparse() calls yylex(), so if you really
don't have a main() in your source code, that might be where it's
coming from (or the lex library, below). It is often appropriate
to write your own main() with setup (like parsing command-line
arguments, initializing yyin and assorted other variables, like
perhaps a line counter) and cleanup (like closing files you opened,
and possibly outputting trailer info.)

The YACC library also contains a default yyerror() routine to print
error messages. Essentially, it prints the message on stderr,
adding a trailing newline. You can supply your own if you want
(say, to pop up a dialog box on your windowing system instead of
stderr, or send it to syslog, or include a line number, or include
some of the offending text in the message).

The Lex library libl.a (-ll on the command line) also contains a
main() program that consists essentially of:
while (yylex() != 0)
; /* loop */
return 0;
and you might want to replace it for the same reasons as replacing
the one in the YACC library. The Lex library also contains a
definition of yywrap(), which returns 1 to indicate that there are
no more files to process.

0 new messages