Flex和Bison:无法解析完整的脚本文件

时间:2013-06-09 21:12:51

标签: bison flex-lexer

我正在尝试使用flex和bison编写扫描程序和解析器来解析一个简单的脚本文件。我只能解析脚本文件的第一行。之后,程序终止并出现错误'yyerror:syntax error'。如何让我的程序继续进入脚本的下一行?

我正在使用带有以下编译选项的Window7。

汇编:

flex lex.l  
bison -d yacc.y  
g++ lex.yy.c yacc.tab.c -lfl -o scanner.exe

这里我附加了.l,.y文件和我的script.txt文件。

文件:lex.l

%{
#include <iostream>
#include <stdio.h>
#include "yacc.tab.h"
#define YY_DECL extern "C" int yylex()

using namespace std;
%}

DOT             "."
COLON           ":"
SEMICOLON       ";"
COMMA           ","
ANGLE_LEFT      "<"
ANGLE_RIGHT     ">"
AT              "@"
EQUAL           "="
SQUARE_OPEN     "["
SQUARE_CLOSE    [^\\]"]"
OPENBRACE       "\("
CLOSEBRACE      "\)"
QUOTE           "\""
QUOTE_OPEN      "\""
QUOTE_CLOSE     [^\\]"\""
SPACE           " "
TAB             "\t"
CRLF            "\r\n"
QUOTED_PAIR     "\\"[^\r\n]
DIGIT           [0-9]
ALPHA           [a-zA-Z]
QTEXT           [0-9a-zA-Z!#$%&'()*+,\-.\/:;<=>?@\[\]^_`{|}~]
%%

{SPACE}*{OPENBRACE}{SPACE}*     { return TOK_OPENBRACE; }

{SPACE}*{CLOSEBRACE}{SPACE}*    { return TOK_CLOSEBRACE; }

{SPACE}*{SEMICOLON}{SPACE}*     { return TOK_SEMICOLON; }

{SPACE}*{COMMA}{SPACE}*         { return TOK_COMMA; }

{QUOTE_OPEN}({SPACE}*{QTEXT}*{QUOTED_PAIR}*)*{QUOTE_CLOSE}  {
                                yylval.sval = &yytext[1];
                                yylval.sval[strlen(yylval.sval) - 1] = '\0';
                                return TOK_QUOTED_STRING;
                                }

{DIGIT}+                        {
                                yylval.lval = atoi(yytext);
                                return TOK_LONG;
                                }

"true"|"false"                  {
                                yylval.ival = ((0 == strcmp(yytext, "true")) ? 1 : 0 );
                                return TOK_BOOL;
                                }
^"function1"                    { return TOK_FUNC1; }
^"function2"                    { return TOK_FUNC2; }
^"function3"                    { return TOK_FUNC3; }

^{CRLF}                         { return TOK_EMPTY_LINE; }
{CRLF}                          {}
.                               {}/* ignore unknown chars */

档案:yacc.y

%{
#include <iostream>
#include <stdio.h>

using namespace std;

extern "C" int yylex();
extern "C" FILE *yyin;

int yyerror(const char *s);
%}

// Symbols.
%union
{
    char    *sval;
    long    lval;
    int        ival;
};

%token TOK_FUNC1
%token TOK_FUNC2
%token TOK_FUNC3

%token <sval> TOK_QUOTED_STRING
%token <lval> TOK_LONG
%token <ival> TOK_BOOL

%token TOK_SEMICOLON
%token TOK_OPENBRACE
%token TOK_CLOSEBRACE
%token TOK_COMMA
%token TOK_EMPTY_LINE

%start program
%%

program    :    func1
        |    func2
        |    func3
        |   empty_line
        ;

func1 :   TOK_FUNC1 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
                    {
                    cout << "function1:" << $3 << " " << $5 << " " << $7;
                    }

func2 : TOK_FUNC2 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
                    {
                        cout << "function2:" << $3 << " " << $5 << " " << $7;
                    }

func3 : TOK_FUNC3 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
                    {
                        cout << "function3:" << $3 << " " << $5 << " " << $7;
                    }

empty_line : TOK_EMPTY_LINE
                    {
                    }
%%

int yyerror(const char *s) {
  cout << "yyerror : " << s << endl;
}

int main(void) {
    FILE * pt = fopen("script.txt", "r" );
    yyin = pt;
        yyparse();      
}

file:script.txt

function1("scanner1", 1234, true );
function2("scanner2", 4321, false );
function3("scanner3", 0123, true );

输出:

function1:scanner1 1234 1
yyerror : syntax error

预期产出:

function1:scanner1 1234 1
function2:scanner2 4321 0
function3:scanner3 0123 1

2 个答案:

答案 0 :(得分:0)

你的语法的开始制作program只接受一行(func1,func2,func3或空行)。所以它不接受第二行。

您还有其他一些问题。

首先,flex使用标准的C I / O库,以ascii模式打开文件,所以我不相信它会在CRLF中看到\r,即使在Windows上也是如此。

其次,yylval.sval = &yytext[1];不会复制yytext的内容。 yytext属于flex,因此您不应修改它;此外,您需要注意flex可能会在词法分析器返回值后立即修改它。因此,您需要制作副本,可能使用strdup,然后您需要确保释放副本。 (见bison FAQ entry

答案 1 :(得分:0)

这是修改后的野牛文件yacc.y

    %{
#include <iostream>
#include <stdio.h>

using namespace std;

extern "C" int yylex();
extern "C" FILE *yyin;

int yyerror(const char *s);
%}

// Symbols.
%union
{
    char    *sval;
    long    lval;
    int        ival;
};

%token TOK_FUNC1
%token TOK_FUNC2
%token TOK_FUNC3

%token <sval> TOK_QUOTED_STRING
%token <lval> TOK_LONG
%token <ival> TOK_BOOL

%token TOK_SEMICOLON
%token TOK_OPENBRACE
%token TOK_CLOSEBRACE
%token TOK_COMMA
%token TOK_EMPTY_LINE

%start program
%%

program : funcs
        ;

funcs   : funcs func
        | func
        ;

func :  TOK_FUNC1 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
        {
        cout << "function1:" << $3 << " " << $5 << " " << $7;
        }
        | TOK_FUNC2 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
        {
            cout << "function2:" << $3 << " " << $5 << " " << $7;
        }
        | TOK_FUNC3 TOK_OPENBRACE TOK_QUOTED_STRING TOK_COMMA TOK_LONG TOK_COMMA TOK_BOOL TOK_CLOSEBRACE TOK_SEMICOLON
        {
            cout << "function3:" << $3 << " " << $5 << " " << $7;
        }
        | TOK_EMPTY_LINE
        {
        }
%%

int yyerror(const char *s) {
  cout << "yyerror : " << s << endl;
}

int main(void) {
    FILE * pt = fopen("script.txt", "r" );
    yyin = pt;
        yyparse();      
}