Helin Guo
Helin Guo

Reputation: 13

Can't compile flex & bison on OS X (but it works on Linux)

I am writing a compiler using flex & bison on OS X. I've just written a program but found it can't be compiled. I got the following error:

clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
duplicate symbol _root in:
    /var/folders/x1/y3dqmh217q77ppkzzzm3f5w00000gn/T/syntax-cef84b.o
    /var/folders/x1/y3dqmh217q77ppkzzzm3f5w00000gn/T/lex-80fad5.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [all] Error 1

But when I copy it to my Linux virtual machine on another computer, I am surprised to find that it could be compiled there. Although there is still lots of bugs in my program that makes it not working correctly but it could successfully compiled. What is happened to my OS X system?

Here is my code:

syntax.ypp

%{
    #include "astTree.h"
    #include <stdio.h>
    #include <fstream>
    AstNode *root;
    extern int yylex();
    extern FILE *yyin;
    void yyerror(const char*s);
%}
%glr-parser
%union{
    AstNode *basic_node;    
    AstNodeVarDec *vardec_node;
    AstNodeFuncDec *funcdec_node;
    AstNodeFuncDef *funcdef_node;
    AstNodeClassDec *classdec_node;
    AstNodeClassDef *classdef_node;
    AstNodeParam *param_node;
    AstNodeStmt *stmt_node;
    AstNodeExpr *expr_node;
    AstNodeType *type_node;
    AstNodeValue *value_node;
    AstNodeFieldAccess *field_node;
    AstNodeArrayAccess *array_node;
    AstNodeInvocation *invocation_node;
    char *id;
    long value;
    float float_val;
}

%type <basic_node> program comp_list comp param_list stmt_list class_body class_comp expr_list left_val primary;
%type <vardec_node> var_dec;
%type <funcdec_node> func_dec;
%type <funcdef_node> func_def;
%type <classdec_node> class_dec;
%type <classdef_node> class_def;
%type <param_node> param;
%type <stmt_node> stmt;
%type <expr_node> expr empt_expr;
%type <type_node> type;
%type <value_node> right_val;
%type <field_node> field_access;
%type <array_node> array_access;
%type <invocation_node> invocation;

%token <id> IDENTIFIER;
%token <value> INT CHAR;
%token <float_val> FLOAT;
%token KWD_FUNC KWD_ENDFUNC KWD_DO KWD_CLASS KWD_ENDCLASS KWD_EXTENDS KWD_IF KWD_ENDIF KWD_ELSE KWD_WHILE KWD_ENDWHILE KWD_FOR KWD_ENDFOR KWD_BREAK KWD_CONTINUE KWD_RETURN KWD_FOREACH KWD_ENDFOREACH KWD_THIS ERROR
%token KWD_INT KWD_FLOAT KWD_CHAR KWD_LONG

%left '.'
%right '!' '~' '@' OPT_ADDR
%left '*' '/' '%'
%left '+' '-'
%left '<' '>' OPT_GE OPT_LE
%left OPT_EQ OPT_NE
%left '&' '^' '|'
%left OPT_AND
%left OPT_OR
%left '='

%%
program:      comp_list {root = $1;}
            ;

comp_list:   /*empty*/ {$$ = new AstNode(ComponentListNode);}
            | comp_list comp {$1->addChild($2); $$ = $1;}
            ;

comp:         var_dec {$$ = (AstNode *)$1;}
            | func_dec {$$ = (AstNode *)$1;}
            | func_def {$$ = (AstNode *)$1;}
            | class_dec {$$ = (AstNode *)$1;}
            | class_def {$$ = (AstNode *)$1;}
            ;

var_dec:      type IDENTIFIER ';' {$$ = new AstNodeVarDec($1, $2);}
            ;


func_dec:     KWD_FUNC IDENTIFIER ':' param_list ':' type ';' {$$ = new AstNodeFuncDec($2, $4, $6);}
            ;

func_def:     KWD_FUNC IDENTIFIER ':' param_list ':' type KWD_DO stmt_list KWD_ENDFUNC ';' {$$ = new AstNodeFuncDef($2, $4, $6, $8); }
            ;

class_dec:    KWD_CLASS IDENTIFIER ';' {$$ = new AstNodeClassDec($2);}
            ;

class_def:    KWD_CLASS IDENTIFIER KWD_DO class_body KWD_ENDCLASS ';' {$$ = new AstNodeClassDef($2, $4);}
            | KWD_CLASS IDENTIFIER KWD_EXTENDS IDENTIFIER KWD_DO class_body KWD_ENDCLASS ';' {$$ = new AstNodeClassDef($2, $4, $6);}
            ;

param_list:   /*empty*/ {$$ = new AstNode(ParamListNode);}
            | param_list ',' param {$1->addChild($3); $$ = $1;}
            ;

param:        type IDENTIFIER {$$ = new AstNodeParam($1, $2); }
            ;

stmt_list:    /*empty*/ {$$ = new AstNode(StmtListNode);}
            | stmt_list stmt {$1->addChild($2); $$ = $1;}
            | stmt_list var_dec {$1->addChild($2); $$ = $1;}
            ;

class_body:   /*empty*/ {$$ = new AstNode(ClassBodyNode);}
            | class_body class_comp {$1->addChild($2); $$ = $1;}
            ;

class_comp:   var_dec {$$ = $1;}
            | func_def {$$ = $1;}
            ;

stmt:         KWD_IF expr KWD_DO stmt_list KWD_ENDIF ';' {$$ = new AstNodeStmt(IfStmtNode, 2, $2, $4);}
            | KWD_IF expr KWD_DO stmt_list KWD_ELSE stmt_list KWD_ENDIF';' {$$ = new AstNodeStmt(IfStmtNode, 3, $2, $4, $6);}
            | KWD_WHILE expr KWD_DO stmt_list KWD_ENDWHILE ';' {$$ = new AstNodeStmt(WhileStmtNode, 2, $2, $4);}
            | KWD_FOR expr_list ':' empt_expr ':' expr_list KWD_DO stmt_list KWD_ENDFOR ';' {$$ = new AstNodeStmt(ForStmtNode, 4, $2, $4, $6, $8);}
            | KWD_FOREACH IDENTIFIER ':' IDENTIFIER KWD_DO stmt_list KWD_ENDFOREACH ';' {$$ = new AstNodeStmt(ForachStmtNode, 3, new AstNodeId($2), new AstNodeId($4), $6);}
            | KWD_BREAK ';' {$$ = new AstNodeStmt(BreakStmtNode, 0);}
            | KWD_CONTINUE ';' {$$ = new AstNodeStmt(ContinueStmtNode, 0);}
            | KWD_RETURN ';' {$$ = new AstNodeStmt(ReturnStmtNode, 0);}
            | KWD_RETURN expr ';' {$$ = new AstNodeStmt(ReturnStmtNode, 1, $2);}
            | expr ';' {$$ = (AstNodeStmt *)$1;}
            ;

expr_list:     /*empty*/ {$$ = new AstNode(ExprNode);}
            | expr_list ',' expr { $1->addChild($3); $$ = $1;}
            ;

empt_expr:    /*empty*/ {$$ = NULL;} 
            | expr {$$ = $1;}
            ;

expr:         left_val '=' expr {$$ = new AstNodeExpr(AssignExprNode, 2, $1, $3);}
            | field_access {$$ = (AstNodeExpr*)$1;}
            | array_access {$$ = (AstNodeExpr*)$1;}
            | '(' type ')' expr {$$ = new AstNodeExpr(TypeCastExprNode, 2, $2, $4);}
            | '!' expr {$$ = new AstNodeExpr(NotExprNode, 1, $2);}
            | '~' expr {$$ = new AstNodeExpr(BitNotExprNode, 1, $2);}
            | '@' expr {$$ = new AstNodeExpr(AtExprNode, 1, $2);}
            | '&' expr %prec OPT_ADDR{$$ = new AstNodeExpr(AddrExprNode, 1, $2);}
            | expr '*' expr {$$ = new AstNodeExpr(MultiExprNode, 2, $1, $3);}
            | expr '/' expr {$$ = new AstNodeExpr(DivideExprNode, 2, $1, $3);}
            | expr '%' expr {$$ = new AstNodeExpr(ModExprNode, 2, $1, $3);}
            | expr '+' expr {$$ = new AstNodeExpr(PlusExprNode, 2, $1, $3);}
            | expr '-' expr {$$ = new AstNodeExpr(MinusExprNode, 2, $1, $3);}
            | expr OPT_GE expr {$$ = new AstNodeExpr(GeExprNode, 2, $1, $3);}
            | expr OPT_LE expr {$$ = new AstNodeExpr(LeExprNode, 2, $1, $3);}
            | expr '<' expr {$$ = new AstNodeExpr(LessExprNode, 2, $1, $3);}
            | expr '>' expr {$$ = new AstNodeExpr(GreaterExprNode, 2, $1, $3);}
            | expr OPT_EQ expr {$$ = new AstNodeExpr(EqualExprNode, 2, $1, $3);}
            | expr OPT_NE expr {$$ = new AstNodeExpr(NotEqualExprNode, 2, $1, $3);}
            | expr '&' expr {$$ = new AstNodeExpr(BitAndExprNode, 2, $1, $3);}
            | expr '|' expr {$$ = new AstNodeExpr(BitOrExprNode, 2, $1, $3);}
            | expr '^' expr {$$ = new AstNodeExpr(BitXOrExprNode, 2, $1, $3);}
            | expr OPT_AND expr {$$ = new AstNodeExpr(AndExprNode, 2, $1, $3);}
            | expr OPT_OR expr {$$ = new AstNodeExpr(OrExprNode, 2, $1, $3);}
            | primary {$$ = (AstNodeExpr*)$1;}
            | '(' expr ')' {$$ = $2;}
            ;

primary:      left_val {$$ = $1;}
            | right_val {$$ = $1;}
            ;

left_val:     IDENTIFIER {$$ = new AstNodeId($1);}
            | field_access {$$ = $1;}
            | array_access {$$ = $1;}
            ;

type:         KWD_INT { $$ = new AstNodeType(AstNodeType::Int); }
            | KWD_FLOAT { $$ = new AstNodeType(AstNodeType::Float); }
            | KWD_CHAR { $$ = new AstNodeType(AstNodeType::Char); }
            | KWD_LONG { $$ = new AstNodeType(AstNodeType::Long); }
            | type '*' { $$ = new AstNodeType($1); }
            | IDENTIFIER { $$ = new AstNodeType($1); }
            ;

right_val:    INT { $$ = new AstNodeValue($1); }
            | CHAR { $$ = new AstNodeValue($1); }
            | FLOAT { $$ = new AstNodeValue($1); }
            | invocation { $$ = (AstNodeValue *)$1; }
            ;

field_access: left_val '.' IDENTIFIER { $$ = new AstNodeFieldAccess($1, $3);}
            ;

array_access: left_val '[' left_val ']' { $$ = new AstNodeArrayAccess($1, $3); }
            | left_val '[' right_val ']' { $$ = new AstNodeArrayAccess($1, $3); }
            ;
invocation:   IDENTIFIER '(' expr_list ')' { $$ = new AstNodeInvocation($1, $3); }
            | field_access '(' expr_list ')' { $$ = new AstNodeInvocation($1, $3); }
            ;
%%

void yyerror(const char*s)
{
    fprintf(stderr, "%s\n", s);
}

int main(int argc, char **argv) {
    if (argc > 1)
        yyin = fopen(argv[1], "r");
    std::ofstream output;
    if (argc > 2)
        output.open(argv[2]);
    yyparse();
    if (argc > 2)
        output.close();
    return 0;
}

syntax.l

%{
    #include "syntax.tab.hpp"
%}
%option noyywrap
%%
"+"         { return '+'; }
"-"         { return '-'; }
"*"         { return '*'; }
"/"         { return '/'; }
"%"         { return '%'; }
">"         { return '>'; }
"<"         { return '<'; }
"&"         { return '&'; }
"^"         { return '^'; }
"|"         { return '|'; }
"="         { return '='; }
"@"         { return '@'; }
"!"         { return '!'; }
"~"         { return '~'; }
"("         { return '('; }
")"         { return ')'; }
"["         { return '['; }
"]"         { return ']'; }
"{"         { return '{'; }
"}"         { return '}'; }
":"         { return ':'; }
";"         { return ';'; }

"&&"        { return OPT_AND; }
"||"        { return OPT_OR; }
">="        { return OPT_GE; }
"<="        { return OPT_LE; }
"=="        { return OPT_EQ; }
"!="        { return OPT_NE; }

"int"       { return KWD_INT; }
"long"      { return KWD_LONG; }
"char"      { return KWD_CHAR; }
"float"     { return KWD_FLOAT; }

"break"     { return KWD_BREAK; }
"continue"  { return KWD_CONTINUE; }

"for"       { return KWD_FOR; }
"foreach"   { return KWD_FOREACH; }
"while"     { return KWD_WHILE; }

"do"        { return KWD_DO; }

"if"        { return KWD_IF; }
"else"      { return KWD_ELSE; }

"return"    { return KWD_RETURN; }

"extends"   { return KWD_EXTENDS; }

"class"     { return KWD_CLASS; }
"func"      { return KWD_FUNC; }

"endif"     { return KWD_ENDIF; }
"endfor"    { return KWD_ENDFOR; }
"endforeach" { return KWD_ENDFOREACH; }
"endfunc"   { return KWD_ENDFUNC; }
"endwhile"  { return KWD_ENDWHILE; }

0|[1-9][0-9]*   { yylval.value = atoi(yytext); return INT; }
0|[1-9][0-9]*\.[0-9]*   { yylval.float_val = atof(yytext); return FLOAT; }
'[0-9a-zA-Z]'   { int c = *yytext; yylval.value = c; return CHAR; }
[a-zA-Z][a-zA-Z0-9]* { yylval.id = strdup(yytext); return IDENTIFIER; }

"#".*$|[ \t\n]+     /* ignore */ 

%%

astTree.h

#ifndef ASTTREE_H
#define ASTTREE_H

#include <vector>
#include <string>
#include <stdarg.h>
enum NodeType
{
    BasicNode,
    ComponentListNode,
    VarDecNode,
    FuncDecNode,
    FuncDefNode,
    ClassDecNode,
    ClassDefNode,
    ParamListNode,
    ParamNode,
    StmtListNode,
    ClassBodyNode,
    IfStmtNode,
    WhileStmtNode,
    ForStmtNode,
    ForachStmtNode,
    BreakStmtNode,
    ContinueStmtNode,
    ReturnStmtNode,
    ExprNode,
    AssignExprNode,
    TypeCastExprNode,
    NotExprNode,
    BitNotExprNode,
    AtExprNode,
    AddrExprNode,
    MultiExprNode,
    DivideExprNode,
    ModExprNode,
    PlusExprNode,
    MinusExprNode,
    GeExprNode,
    LeExprNode,
    GreaterExprNode,
    LessExprNode,
    EqualExprNode,
    NotEqualExprNode,
    BitAndExprNode,
    BitOrExprNode,
    BitXOrExprNode,
    AndExprNode,
    OrExprNode,
    TypeNode,
    ValueNode,
    FieldAccessNode,
    ArrayAccessNode,
    InvocationNode,
    IdNode
};

// basic nodes, paramListNode, ComponentListNode
class AstNode
{
public:
    AstNode() { nodeType = BasicNode; }
    AstNode(NodeType type)
    {
        nodeType = type;
    }
    ~AstNode() {}
    void addChild(AstNode *node) { children.push_back(node); }
    virtual std::string toString()
    {
        // TODO: finish this for later use
        return "";
    }
    NodeType getType() { return nodeType; }
protected:
    NodeType nodeType;
    std::vector<AstNode *>children;
};

class AstNodeType : public AstNode
{
public:
    enum VarType
    {
        Int,
        Char,
        Float,
        Long,
        Object,
        Ptr
    };

    AstNodeType(VarType type)
    {
        nodeType = TypeNode;
        baseType = type;
    }

    AstNodeType(char * typeName)
    {
        nodeType = TypeNode;
        baseType = Object;
        this->typeName = std::string(typeName);
    }

    AstNodeType(AstNodeType *type)
    {
        nodeType = TypeNode;
        baseType = Ptr;
        addChild(type);
    }

    ~AstNodeType()
    {
    }

private:
    VarType baseType;
    std::string typeName;
};

class AstNodeId : public AstNode
{
public:
    AstNodeId(char * id)
    {
        nodeType = IdNode;
        this->id = std::string(id);
    }

    ~AstNodeId()
    {
    }

private:
    std::string id;
};

class AstNodeVarDec : public AstNode
{
public:
    AstNodeVarDec(AstNodeType *type, char * id)
    {
        nodeType = VarDecNode;
        addChild(type);
        addChild(new AstNodeId(id));
    }
    ~AstNodeVarDec() {}
};

class AstNodeFuncDec : public AstNode
{
public:
    AstNodeFuncDec(char * id, AstNode *params, AstNodeType *retType)
    {
        nodeType = FuncDecNode;
        addChild(new AstNodeId(id));
        addChild(params);
        addChild(retType);
    }
    ~AstNodeFuncDec() {}
};

class AstNodeFuncDef : public AstNode
{
public:
    AstNodeFuncDef(char *id, AstNode *params, AstNodeType *retType, AstNode *body)
    {
        nodeType = FuncDefNode;
        addChild(new AstNodeId(id));
        addChild(params);
        addChild(retType);
        addChild(body);
    }
    ~AstNodeFuncDef() {}

private:

};

class AstNodeClassDec : public AstNode
{
public:
    AstNodeClassDec(char * id)
    {
        nodeType = ClassDecNode;
        addChild(new AstNodeId(id));
    }
    ~AstNodeClassDec() {}

private:
};

class AstNodeClassDef : public AstNode
{
public:
    AstNodeClassDef(char * id, AstNode *body)
    {
        nodeType = ClassDefNode;
        addChild(new AstNodeId(id));
        addChild(body);
    }
    AstNodeClassDef(char * id, char * parent, AstNode *body)
    {
        nodeType = ClassDefNode;
        addChild(new AstNodeId(id));
        addChild(new AstNodeId(parent));
        addChild(body);
    }
    ~AstNodeClassDef(){}

private:

};

class AstNodeParam : public AstNode
{
public:
    AstNodeParam(AstNodeType *type, char * id)
    {
        nodeType = ParamNode;
        addChild(type);
        addChild(new AstNodeId(id));
    }
    ~AstNodeParam() {}

private:

};

class AstNodeStmt : public AstNode
{
public:
    AstNodeStmt(NodeType type, size_t n, ...)
    {
        nodeType = type;
        va_list args;
        va_start(args, n);
        for (size_t i = 0; i < n; i++)
        {
            addChild(va_arg(args, AstNode *));
        }
    }
    ~AstNodeStmt() {}

private:

};

class AstNodeExpr : public AstNode
{
public:
    AstNodeExpr(NodeType type, size_t n, ...)
    {
        nodeType = type;
        va_list args;
        va_start(args, n);
        for (size_t i = 0; i < n; i++)
        {
            addChild(va_arg(args, AstNode *));
        }
    }
    ~AstNodeExpr()
    {}

private:

};


class AstNodeValue : public AstNode
{
public:
    AstNodeValue(long value)
    {
        nodeType = ValueNode;
        numVal = value;
    }

    AstNodeValue(float value)
    {
        nodeType = ValueNode;
        floatVal = value;
    }

    ~AstNodeValue()
    {
    }

private:
    long numVal;
    float floatVal;
};

class AstNodeFieldAccess : public AstNode
{
public:
    AstNodeFieldAccess(AstNode *left, char * right)
    {
        nodeType = FieldAccessNode;
        addChild(left);
        addChild(new AstNodeId(right));
    }

    ~AstNodeFieldAccess()
    {
    }

private:

};

class AstNodeArrayAccess : public AstNode
{
public:
    AstNodeArrayAccess(AstNode *left, AstNode *right)
    {
        nodeType = ArrayAccessNode;
        addChild(left);
        addChild(right);
    }

    ~AstNodeArrayAccess()
    {
    }

private:

};


class AstNodeInvocation : public AstNode
{
public:
    AstNodeInvocation(char * id, AstNode *params)
    {
        nodeType = InvocationNode;
        addChild(new AstNodeId(id));
        addChild(params);
    }

    AstNodeInvocation(AstNodeFieldAccess *method, AstNode *params)
    {
        nodeType = InvocationNode;
        addChild(method);
        addChild(params);
    }

    ~AstNodeInvocation()
    {
    }

private:

};

#endif

Makefile

syLEX = flex
YACC = bison
CXX = g++

all:
    $(LEX) syntax.l
    $(YACC) syntax.ypp -d
    $(CXX) syntax.tab.cpp lex.yy.c -o grammar

clean:
    rm -f *.hpp *.cpp *.yy.c grammar

Any ideas how to fix it?

Upvotes: 1

Views: 1190

Answers (1)

Chris Dodd
Chris Dodd

Reputation: 126428

The error is telling you that the symbol root is defined in both syntax.ypp and lex.yy.c, and it should only be defined in one place. The only actual definition I can see is the AstNode *root; in the top of the syntax.ypp file. So somehow on OSX you're getting another definition in lex.yy.c, probably via a header file.

Check to make sure Bison isn't copying that definition into syntax.tab.hpp (which it shouldn't, but perhaps you have some special, broken, OSX-only version of Bison installed).

Upvotes: 1

Related Questions