我正在尝试使用Lex和Yacc编写一个简单的解析器。我以前不熟悉这两个。当我完成lex和yacc文件,并编译它我得到错误。我认为错误与未正确包含的字符串头文件有关,但我自己无法弄明白。
Lex文件名为" tokens.l":
%{
#include "parser.hpp"
%}
MODEL "model"
PORT "input"|"output"|"intern"
GATE "xor"|"and"|"or"|"buf"|"cmos1"|"dff"|"dlat"|"inv"|"mux"|"nand"|"nor"|"tie0"|"tie1"|"tiex"|"tiez"|"tsh"|"tsl"|"tsli"|"xnor"
INSTNAME [A-Z0-9]+
PRIMITIVE "primitive"
LEFT "("
RIGHT ")"
COMMA ","
SEMICOLON ";"
EQUAL "="
BLANK [ \t\n]+
%%
{MODEL} {return MODEL;}
{PORT} { if (yytext == "input")
return INPUT;
else if (yytext == "output")
return OUTPUT;
else
return INTERN;
}
_{GATE} {return GATE;}
{INSTNAME} {return INSTNAME;}
{PRIMITIVE} {return PRIMITIVE;}
{LEFT} {return LEFT;}
{RIGHT} {return RIGHT;}
{COMMA} {return COMMA;}
{SEMICOLON} {return SEMICOLON;}
{EQUAL} {return EQUAL;}
{BLANK} {;}
"\0" {return END;}
%%
名为" parser.y":
的yacc文件%{
#include <iostream>
#include <string>
#include <cstdio>
extern FILE *fp;
%}
%union{
std::string* str;
}
%token <str> MODEL
%token <str> INPUT
%token <str> OUTPUT
%token <str> INTERN
%token <str> GATE
%token <str> INSTNAME
%token PRIMITIVE
%token LEFT
%token RIGHT
%token COMMA
%token SEMICOLON
%token EQUAL
%token END
%type <str> vfile modules module params param interngates interngate primitives
%%
vfile : modules END {
std::ofstream fp;
fp.open("output.v");
fp<<$1;
fp.close();
$$ = new std::string("success");
std::cout<<$$;
}
modules : modules module {$$=$1+$2;}
| module {$$=$1;}
module :MODEL INSTNAME LEFT params RIGHT LEFT interngates RIGHT
{$$ = "module "+$2+" ("+$4+");\n"+$7+"endmodule\n";}
interngates :interngates interngate {$$=$1+$2+"\n";}
|interngate {$$=$1+"\n";}
interngate :INPUT LEFT params RIGHT primitives {$$=$1+$3+"\n"+$5;}
| OUTPUT LEFT params RIGHT primitives { $$=$1+$3+"\n"+$5;}
| INTERN LEFT params RIGHT primitives {$$="wire"+$3+"\n"+$5;}
primitives :LEFT RIGHT {$$="";}
|LEFT PRIMITIVE EQUAL GATE INSTNAME params SEMICOLON RIGHT
{$$=$4+" "+$5+" ("+$6+");\n";}
params :params COMMA param {$$=$1+","+$3;}
| param {$$=$1;}
param :INSTNAME {$$=$1;}
%%
要编译文件,我使用以下命令:
bison -d -o parser.cpp parser.y
lex -o tokens.cpp tokens.l
g++ -o myparser tokens.cpp parser.cpp -lfl
有人能给我一些线索吗?非常感谢!
更新:osx上的错误报告。 http://www.edaplayground.com/x/3HL
答案 0 :(得分:2)
您不能在%union中为C ++ std :: string(或任何其他带有非平凡构造函数的字符串类)使用自动存储。您需要使用动态(堆)。
而不是
%union {
string str;
}
尝试:
%union {
std::string *str;
}
您需要更改yylval-&gt; str或$$,$ 1等的所有用途,其中$ N%类型是使用动态分配的字符串。
所以而不是
$$ = "success";
你必须这样做:
$$ = new std::string("success");
通常在yacc / bison解析器YYSTYPE%union中使用指针,以避免在堆栈上进行大量复制。请记住,除非你的解析器运行时很短并且源文件不是很大,否则你的产品应该为不再使用的令牌或非终端释放字符串,然后你可以作弊并避免释放它们或使用垃圾收集。
可以将YYSTYPE重新定义为常规字符串(非指针),但是你失去了使用联合的能力,大多数非平凡的解析器需要在语义动作中传递令牌或类型AST对象的混合。将您的作品限制为单一类型不如void *。
有用也可以重新定义YYSTYPE以使用变体/多态类型,或使用多成员结构(变体的替换较差)。前者违背了&#34;类型安全&#34;的目的。 %type和%token宏,后者强制你记住每个终端或非终端的类型,并对你的struct的成员使用显式表示法($$ - &gt; str =&#34; foo&#34;, $$ - &gt; expr.left = $ 1-&gt; str等),这是在C ++中使用基于C的解析器的缺点。您可能想尝试Bison的C ++解析器框架,由于每次我多年来尝试编译错误,我几乎没有经验。
我找到了其他(更好)的解决方法;我已经看到Bison修补了允许对YYSTYPE的boost :: variant支持%type和%token。 Google&#34; bison Michiel de Wilde&#34;或&#34;野牛变种YYSTYPE&#34; (http://lists.gnu.org/archive/html/bison-patches/2007-06/msg00000.html),然而,就像多年来的许多Bison建议一样,这些补丁会遇到一些含糊不清的论点或关于替代品的一般性讨论,然后就会失败。