【发布时间】:2015-11-19 02:09:16
【问题描述】:
我正在 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 = $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;
}
语法.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
有什么解决办法吗?
【问题讨论】:
标签: macos bison yacc flex-lexer lex