简体   繁体   中英

Linker error while using lex to compile simple print file. have newest version of macOS 13.1 and xcode installed

I'm trying to run a simple progam in flex that reads the string "hello world" and prints "Goodbye"

here is the file:

%%

"hello world"  printf("Goodbye\n");
.              ;

%%

the commands are

% flex ex1.l
% gcc lex.yy.c -ll

Error message:

ld: warning: object file (/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libl.a(libmain.o)) was built for newer macOS version (13.1) than being linked (13.0)

I have redownloaded the newest version of Xcode and have the updated macOS. I'm not sure what I can try to get this error code to go away.

I have also ran

% CMAKE_OSX_DEPLOYMENT_TARGET 13.0

to try and force the link to V13.0 without success.

The lex library, which the linker will use if given the -ll command-line flag, is supposed to be a convenience to make it easier to write quick and dirty (f)lex programs. If your compiler toolchain installation is OK, then it is a small convenience, but it seems like it's pretty easy to get the installation wrong, and since no-one seems to bother documenting the details of toolchain installation, it's hard to debug configuration issues unless you have lots of experience. That makes it a lot less convenient.

You could use this is as a learning experience in configuring your compilation environment, a skill which you will certainly find useful. But if you just want to get on with flex, it's really easy to avoid the need to use of the lex library.

The lex library consists of exactly two things, neither of which are necessary.

First, it contains a definition of yywrap() . The generated lexer calls yywrap() when it encounters the end of an input file. If yywrap returns 0, the lexer assumes that you have done something which will allow the lexer to continue reading input. That's actually not a very common use case, because most parsers just read one input file from beginning to end, and then finish. So a good default is to write a version of yywrap() which always returns 1, in which case the lexer will return an end-of-file token (0), and that should cause the lexer's caller to stop calling the lexer. The lex library includes the definition of precisely that simple default implementation:

int yywrap() { return 1; }

So you could include that code in your flex file, but a better solution is to tell flex to omit the yywrap() call and just assume that end-of-file means that there is no more input. Which you do by inserting the following declaration in your Flex prologue ( not in the %{...%} code section):

%option noyywrap

I always recommend using a few more options:

%option noinput nounput noyywrap nodefault

The first two of those suppress the generation of the input() and unput() functions, so that you don't get "Unused function" warnings when you compile. Or better said, so that you wouldn't get warnings if you requested warnings when you compiled. But you should always request warnings. (And you should read them and act on them.) See the sample build instructions at the end of this answer.

The last option, nodefault , causes flex to produce a warning if there is any input which could trigger the automatic default action. The automatic default is to write the unmatched input to stdout and do nothing else, which is practically never what you want to do with unmatched input. Even if you wanted to ignore all unmatched input, which is a good way of ignoring programming errors, you'd very rarely want to print unmatched input to the output.

As it happens, your code will trigger this warning if you add the nodefault option, because you used . as your fallback pattern. . in (f)lex matches anything other than a newline character , and nothing in your program matches a newline, so the newline will go unmatched. Which means it will be echoed to standard output. Instead, you should use .|\n so that your default pattern also matches a newline. (Alternatively, with flex, you can use the s pattern flag, which causes . to really match anything: (?s:.) .)

The other thing that the lex library contains is a default definition of main() . It's somewhat interesting that this is even possible. It works because the linker only includes functions from a library if the functions are not defined in the object files being linked. And, in C, main() really acts like an ordinary function. So if you link with a library which defines main() , that main program will be used whenever you don't define main() in your source code. That can be handy for debugging, but it's not really recommended in production code.

The particular main() function which is included in -ll just calls yylex() repeatedly until it returns an end-of-file token (0):

int main() {
  while (yylex() != 0) { }
  return 0;
}

So instead of relying on the lex library, just add those four lines at the end of your lexer definition, after the second %% .

If you apply both of these suggestions, you will end up with:

%option noinput nounput noyywrap nodefault
%{
/* So that `printf` is declared */
#include <stdio.h>
%}

%%

"hello world"  printf("Goodbye\n");
.|\n           ;

%%

int main() {
    while (yylex() != 0) { }
    return 0;
}

You can then build it without the -ll flag. But you should always build with compiler warnings enabled, and personally I think that using the default executable name a.out is bad style:

% flex ex1.l
% gcc -Wall -o ex1 lex.yy.c

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM