无法在 OS X 上编译 flex & bison(但可以在 Linux 上运行)

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

我正在 OS X 上使用 flex & bison 编写一个编译器。我刚写了一个程序,但发现它无法编译。我收到以下错误:

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

但是当我将它复制到另一台计算机上我的Linux虚拟机时,我惊讶地发现它可以在那里编译。虽然我的程序中仍然有很多错误导致它无法正常工作,但它可以成功编译。我的 OS X 系统出了什么问题?

这是我的代码:

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 = ;}
            ;

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

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

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


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

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

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

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

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

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

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

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

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

stmt:         KWD_IF expr KWD_DO stmt_list KWD_ENDIF ';' {$$ = new AstNodeStmt(IfStmtNode, 2, , );}
            | KWD_IF expr KWD_DO stmt_list KWD_ELSE stmt_list KWD_ENDIF';' {$$ = new AstNodeStmt(IfStmtNode, 3, , , );}
            | KWD_WHILE expr KWD_DO stmt_list KWD_ENDWHILE ';' {$$ = new AstNodeStmt(WhileStmtNode, 2, , );}
            | KWD_FOR expr_list ':' empt_expr ':' expr_list KWD_DO stmt_list KWD_ENDFOR ';' {$$ = new AstNodeStmt(ForStmtNode, 4, , , , );}
            | KWD_FOREACH IDENTIFIER ':' IDENTIFIER KWD_DO stmt_list KWD_ENDFOREACH ';' {$$ = new AstNodeStmt(ForachStmtNode, 3, new AstNodeId(), new AstNodeId(), );}
            | 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, );}
            | expr ';' {$$ = (AstNodeStmt *);}
            ;

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

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

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

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

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

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(); }
            | IDENTIFIER { $$ = new AstNodeType(); }
            ;

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

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

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

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

生成文件

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

有什么解决办法吗?

错误告诉你符号root在syntax.ypp和lex.yy.c中都有定义,而且它应该只在一个地方定义。我能看到的唯一实际定义是 syntax.ypp 文件顶部的 AstNode *root;。因此,在 OSX 上,您可能通过头文件在 lex.yy.c 中获得了另一个定义。

检查以确保 Bison 没有将该定义复制到 syntax.tab.hpp(它不应该,但也许你安装了一些特殊的、损坏的、仅 OSX 的 Bison 版本) .