1

I have the following lex basic example:

%{

/* INCLUDE FILES */
#include <stdlib.h>

/* STATES */
enum {
        LOOKUP = 0,
        VERB,
        ADJ,
        ADV,
        NOUN,
        PREP,
        PRON,
        CONJ
};

int state;

/* FUNCTION DECLARATION */
int add_word(int type, char *word);
int lookup_word(char *word);

%}

%%

        /* RESET TO LOOKUP ON NEW LINE CHARACTER */
\n      { state = LOOKUP; }

        /* DEFINE STATES WHEN KEYWORD FOUND AS THE FIRST WORD */
^verb   { state = VERB; }
^adj    { state = ADJ; }
^adv    { state = ADV; }
^noun   { state = NOUN; }
^prep   { state = PREP; }
^pron   { state = PRON; }
^conj   { state = CONJ; }

[a-zA-Z]+ {


        if(state!=LOOKUP) {
                add_word(state, yytext);
        } else {
                switch(lookup_word(yytext)) {
                        case VERB: printf("%s: verb\n", yytext); break;
                        case ADJ: printf("%s: adjective\n", yytext); break;
                        case ADV: printf("%s: adverb\n", yytext); break;
                        case NOUN: printf("%s: noun\n", yytext); break;
                        case PREP: printf("%s: preposition\n", yytext); break;
                        case PRON: printf("%s: pronoun\n", yytext); break;
                        case CONJ: printf("%s: conjunction\n", yytext); break;
                        default:
                                printf("%s: don't recognize\n", yytext);
                                break;
                }
        }

}

.       /* IGNORE ANYTHING ELSE */

%%

int main() {
        yylex();
}

/* LINKED LIST TO STORE WORDS */
struct word {
        char *word_name;
        int word_type;
        struct word *next;
};
struct word *word_list;

/* ADD WORD METHOD: ADDS A WORD TO SYMBOL TABLE */
int add_word(int type, char *word) {

        struct word *wp;

        if(lookup_word(word) != LOOKUP) {
                printf("WARNING: word %s is already defined\n", word);
                return 0;
        }

        wp = (struct word *) malloc(sizeof(struct word));
        wp->next = word_list;
        wp->word_name = (char *) malloc(strlen(word) + 1 );
        strcpy(wp->word_name, word);
        wp->word_type = type;
        word_list = wp;
        return 1;
}

/* LOOKUP WORD METHOD: RETRIEVES A WORD FROM SYMBOL TABLE */
int lookup_word(char *word) {

        struct word *wp = word_list;

        /* SEARCH DOWN THE LIST */
        for(; wp!=NULL; wp = wp->next) {
                if(strcmp(wp->word_name, word) == 0)
                    return wp->word_type;
        }

        return LOOKUP;  /* NOT FOUND */

}

    

When I try to compile it I get:

% lex ch1-04.l 
% cc -o ch1-04 -ll lex.yy.c
ld: error: duplicate symbol: main
>>> defined at libmain.c:29 (/usr/src/contrib/flex/libmain.c:29)
>>>            libmain.o:(main) in archive /usr/lib/libl.a
>>> defined at lex.yy.c
>>>            /tmp/lex-d06804.o:(.text+0x24E0)
cc: error: linker command failed with exit code 1 (use -v to see invocation)

I am using FreeBSD 12.1

M.E.
  • 4,955
  • 4
  • 49
  • 128
  • Apparently you already have `main()` in `libmain.c` – Brecht Sanders Jul 10 '20 at 19:25
  • 3
    On a hunch, try moving `-ll` after `lex.yy.c` on the command line. – Nate Eldredge Jul 10 '20 at 19:27
  • @Nate Eldrege good hunch, it works!. Could you please elaborate on why this happened? – M.E. Jul 10 '20 at 19:27
  • 3
    If you do `nm` on (e.g.) `/usr/lib64/libl.a`, it defines a `T` [text] symbol for `main`. If `-ll` occurs first, _this_ version of `main` will be linked. This is a "soft" symbol [because it comes from a `.a`]. When the "hard" symbol [in (e.g.) `lex.yy.o`] is found, this _must_ be loaded but conflicts. If `-ll` occurs last, the `main` will be taken from `lex.yy.o`, and when it's [later] found in `libl.a`, there's no need to load the symbol from the `.a` because it's already been resolved. – Craig Estey Jul 10 '20 at 19:34
  • Thanks a lot for such detailed explanation. I followed your instructions and understood what was happening – M.E. Jul 10 '20 at 19:37
  • 1
    The idea is that you can choose to be lazy and not define your own `main` function, in which case lex's `-ll` library provides one for you, which does nothing except call `yylex()` in a loop until it returns 0. If you do define your own `main`, it should take precedence over the default one; but as Craig explains, this only works if `-ll` is listed after your source or object file. I think for dynamic linking, the mechanism is more complicated but the effect is the same. – Nate Eldredge Jul 10 '20 at 19:43
  • 2
    As a general rule, libraries should always be linked **after** your own source and object files. See https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc for more info on link order. – Nate Eldredge Jul 10 '20 at 19:44

0 Answers0