这些yacc和lex文件有什么问题(使用C ++字符串)?

时间:2014-07-24 05:30:35

标签: parsing bison yacc flex-lexer lex

我正在尝试使用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

1 个答案:

答案 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建议一样,这些补丁会遇到一些含糊不清的论点或关于替代品的一般性讨论,然后就会失败。