David Angyal
David Angyal

Reputation: 241

Using Bison to parse from a char* string

How can I make the yyparse function read its input from a C string?

Tried yy_scan_buffer (using "fp" prefix instead of "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;

}

But:

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

Tried using yy_delete_buffer, same result: was not declared in this scope.

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...
}

Upvotes: 0

Views: 1580

Answers (2)

Chris Dodd
Chris Dodd

Reputation: 126140

In order to use the various flex-defined symbols (such as YY_BUFFER_STATE and yy_scan_buffer), the code that does so must be placed in the 3rd section of the .l file.

The issue is that these symbols are only defined in the lex.yy.c file, and not in any header file that you can #include elsewhere.

So all you need to do is put your parse code (the first block above) at the end of the .l file (after the second %% line) and call it from main and it should work fine.

Upvotes: 1

rici
rici

Reputation: 241671

The parser generated by bison does no I/O. The responsibility for reading (or otherwise acquiring) input is given to the scanner, which is often generated by (f)lex. The buffer management functions you refer to are part of the flex framework. They are not exported in any header, so you either need to use them within the code inserted into the flex input file, or explicitly add them to your own header file.

The traditional use of flex and bison (or, in general, derivatives of lex and yacc) relied heavily on global state variables, making it difficult to integrate multiple parsers and/or scanners into a single executable. Modifying the yy prefix does not really solve this problem, but it does allow multiple singletons. More recent versions of the code-generators allow the generation of pure parsers and scanners which take as an additional argument a structure containing the state. It's possible to add your own state to these structures, or even to combine them into a single structure. This can produce a more elegant interface, but the tools don't help you very much with API design. In any event, with pure parsers and scanners, even less state access is externally available.

In short, you should probably add your own buffer management API to your flex file, export its interface(s) in your own header file, and import that file in your scanner, your parser, and their consumers.

Upvotes: 2

Related Questions