0

我正在尝试使用 flex 和 bison 编写扫描仪和解析器来解析一个简单的脚本文件。我只能解析脚本文件的第一行。之后,程序以错误“yyerror:语法错误”终止。如何让我的程序继续到脚本的下一行?

我正在使用带有以下编译选项的 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();      
}

文件:脚本.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
4

2 回答 2

0

您的语法的开始产生式program仅接受单行(func1、func2、func3 或空行)。所以它不接受第二行。

您还有许多其他问题。

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

第二,yylval.sval = &yytext[1];不复制内容yytextyytext 属于flex,所以你不应该修改它;此外,您需要注意,flex一旦您的词法分析器返回一个值,可能会对其进行修改。因此,您确实需要制作一个副本,也许使用strdup,然后您需要确保释放该副本。(请参阅此野牛常见问题解答条目

于 2013-06-10T02:01:03.920 回答
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();      
}
于 2013-06-11T04:34:02.567 回答