我有一个工作语法(用lex和bison编写)来解析多项式表达式。这就像您的标准,教科书计算器般的语法。这是语法的一个非常简化的版本:
Expr
: DOUBLE {$$ = newConstExpr($1);}
| Expr '+' Expr {$$ = newBinaryExpr('+', $1, $2);}
| Expr '*' Expr {$$ = NewBinaryExpr('*', $1, $2);}
| '(' Expr ')' {$$ = $2;}
;
我的问题是Lex为yyin使用FILE *,我需要解析来自C ++ istream的输入。我知道flex ++可以生成FlexLexer类(可以在其构造中使用istream),但是很难让它与Bison相结合,甚至作者自己声称(在生成的lexer文件的注释中)它马车。
所以我想知道是否有人知道使用flex扫描程序和bison解析器与C ++ istream对象作为输入而不是FILE *的好方法。
答案 0 :(得分:1)
您可以通过定义自定义YY_INPUT
宏来获取lex的输入。
对于一个真实世界的例子,请看看我的:
http://www.kylheku.com/cgit/txr/tree/parser.l
在这里,我重定向flex
扫描程序以处理作为动态对象库一部分的特殊流对象。与iostream
一样,这些不是FILE *
。
这允许我在使用-c <script text>
运行程序时执行词法分析命令行等操作。
(另外,扫描器使用8位字节。这就是YY_INPUT
宏使用我的get_byte
函数的原因。当yyin_stream
是字符串流时,{{{实现将实际输出与字符串内的Unicode字符对应的UTF-8编码字节,因此在流前进到字符串的下一个字符之前可能需要多次get_byte
调用。在文件流上,get_byte
只从底层OS流中获取字节。)
答案 1 :(得分:0)
这是自定义YY_INPUT宏的工作示例,用于从交互式istream中读取。
%{
// Place this code in istr.l and run with:
// $ flex istr.l && c++ istr.cpp && ./a.out
// $ flex istr.l && c++ istr.cpp && ./a.out 1a2b 123 abc
#include <iostream>
// The stream the lexer will read from.
// Declared as an extern
extern std::istream *lexer_ins_;
// Define YY_INPUT to get from lexer_ins_
// This definition mirrors the functionality of the default
// interactive YY_INPUT
#define YY_INPUT(buf, result, max_size) \
result = 0; \
while (1) { \
int c = lexer_ins_->get(); \
if (lexer_ins_->eof()) { \
break; \
} \
buf[result++] = c; \
if (result == max_size || c == '\n') { \
break; \
} \
}
%}
/* Turn on all the warnings, don't call yywrap. */
%option warn nodefault noyywrap
/* stdinit not required - since using streams. */
%option nostdinit
%option outfile="istr.cpp"
%%
/* Example rules. */
[0-9] { std::cout << 'd'; }
\n { std::cout << std::endl; }
. { std::cout << '.'; }
<<EOF>> { yyterminate(); }
%%
//
// Example main. This could be in its own file.
//
#include <sstream>
// Define actual lexer stream
std::istream *lexer_ins_;
int main(int argc, char** argv) {
if (argc == 1) {
// Use stdin
lexer_ins_ = &std::cin;
yylex();
} else {
// Use a string stream
std::string data;
for (int n = 1; n < argc; n++) {
data.append(argv[n]);
data.append("\n");
}
lexer_ins_ = new std::istringstream(data);
yylex();
}
}
这种风格的扫描仪 - 使用C ++但是以C风格生成 - 对我来说很好。您也可以尝试实验性Flex选项%option c++
。请参阅Flex手册中的“生成C ++扫描仪”。似乎没有太多关于将这些扫描仪与Bison解析器集成的信息。
最后,如果从内存中读取内容足以满足您的使用需求,您可以避免重新定义YY_INPUT - 请参阅Flex手册中的yy_scan_buffer()
。