无法在 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 版本) .
我正在 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 版本) .