我正在尝试使用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
答案 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();
}