使用Bison从char *字符串解析

时间:2013-10-05 13:13:19

标签: c++ parsing bison flex-lexer

如何让 yyparse 函数从C字符串中读取其输入?

尝试 yy_scan_buffer (使用“fp”前缀代替“yy”):

extern YY_BUFFER_STATE fs_scan_string ( const char *str );

struct fs *parse(char *s)
{
fp_scan_buffer(s);
int r = fpparse();
return r == 0 ? AST : NULL;

}

可是:

h1.cpp:27: error: ‘YY_BUFFER_STATE’ does not name a type
h1.cpp: In function ‘fs* parse(char*)’:
h1.cpp:32: error: ‘fp_scan_buffer’ was not declared in this scope

尝试使用 yy_delete_buffer ,同样的结果:未在此范围内声明。

fp.y

%{
#include "ft.h"
#include <map>
#include <iostream>

int fplex(); 
int fperror(char *p);
int fperror(char *p) { }

using namespace std;

struct fs *AST;
bool fpworking = true;
%}

%union {
    struct fs *f;
    struct ts *t;
    std::list<struct ts *> *tl;
    std::string *s;
}

%token END_OF_FILE
MORE TOKEN HERE...

%%

s : formula '\n'    { AST = $1; fpworking = true; YYACCEPT; }
MORE RULE HERE...

FP.L

%{
#include <iostream>
#include <list>
using namespace std;
#include "fp.tab.h"
%}

%option noyywrap

%%
[a-z][a-zA-Z0-9]*       { fplval.s = new std::string(fptext); return (TERM_ID); }
MORE PATTERN HERE...

h1.cpp

#include <iostream>
#include <list>
#include <string>
#include <map>
#include <stdlib.h>
#include <fstream>
#include "ft.h"

int fpparse();
int signparse();

extern bool fpworking;
extern struct fs *AST;

int main(int argc, char **argv)
{
    MORE CODE HERE...
}

2 个答案:

答案 0 :(得分:2)

bison生成的解析器不执行I / O.读取(或以其他方式获取)输入的责任被提供给扫描仪,其通常由(f)lex生成。您引用的缓冲区管理功能是flex框架的一部分。它们不会在任何标头中导出,因此您需要在插入flex输入文件的代码中使用它们,或者将它们显式添加到您自己的头文件中。

flexbison(或者,通常是lexyacc的衍生物)的传统用法在很大程度上依赖于全局状态变量,因此难以集成多个解析器和/或扫描器成为单个可执行文件。修改yy前缀并不能真正解决这个问题,但它确实允许多个单例。更新版本的代码生成器允许生成pure解析器和扫描器,它们将包含状态的结构作为附加参数。可以将自己的状态添加到这些结构中,甚至可以将它们组合成单个结构。这可以产生更优雅的界面,但这些工具对API设计没有太大帮助。无论如何,使用纯粹的解析器和扫描仪,可以从外部获得更少的状态访问。

简而言之,您应该将自己的缓冲区管理API添加到flex文件中,将其界面导出到您自己的头文件中,然后将该文件导入扫描仪,解析器及其使用者。

答案 1 :(得分:1)

为了使用各种flex定义的符号(例如YY_BUFFER_STATEyy_scan_buffer),执行此操作的代码必须放在.l文件的第3部分中。

问题是这些符号只在​​lex.yy.c文件中定义,而不是在其他地方#include的任何头文件中定义。

所以你需要做的就是将你的parse代码(上面的第一个块)放在.l文件的末尾(在第二个%%行之后)并从{{1}调用它它应该可以正常工作。