在看到类似 mathics 的项目后和 symja ,我正在尝试在 C++ 中使用 flex 和 bison 为 Wolfram 语言实现一个开源解析器。调用 bison -d 和 flex++ 不会引发任何问题,但是当我使用 g++ 时,我收到以下错误消息:
parser.tab.cpp:1242:16: error: use of undeclared identifier 'yylex'
yychar = YYLEX;
^
parser.tab.cpp:598:16: note: expanded from macro 'YYLEX'
# define YYLEX yylex ()
^
1 error generated.
这是我的 .lpp 和 .ypp 文件以供引用
词法分析器.lpp
%{
#include <iostream>
#include "parser.tab.hpp"
using namespace std;
extern "C"
{
int yylex(void);
}
%}
%option c++
%option noyywrap
%%
[1-9][0-9]*(.[0-9]*)? { return NUM; }
"\[" { return LBRACE; }
"\]" cout << "rBrace" << endl;
"\(" cout << "lParen" << endl;
"\)" cout << "rParen" << endl;
"\{" cout << "lBracket" << endl;
"\}" cout << "rBracket" << endl;
"," cout << "comma" << endl;
"@@" cout << "apply" << endl;
"Apply\[" cout << "apply" << endl;
"/@" cout << "map" << endl;
"Map\[" cout << "map" << endl;
"/." cout << "rule" << endl;
"===" cout << "sameQ" << endl;
"SameQ\[" cout << "sameQ" << endl;
"+" cout << "plus" << endl;
"-" cout << "minus" << endl;
"*" cout << "times" << endl;
"/" cout << "divide" << endl;
"^" cout << "power" << endl;
"Power\[" cout << "power" << endl;
--Abbreviated--
. ECHO;
%%
int main()
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
解析器.ypp
%{
#include <iostream>
#include <string>
using namespace std;
extern "C"
{
int yyparse(void);
}
void yyerror(const char *s);
%}
%union {
double dval;
char *str;
}
%token <dval> NUM;
%token <str> RBRACE;
%token <str> LBRACE;
%%
expr:
NUM { cout << $1 << endl;}
| NUM "+" NUM { cout << $1 + $3}
| NUM "-" NUM { cout << $1 - $3}
| NUM "*" NUM { cout << $1 * $3}
| NUM "/" NUM { cout << $1 / $3}
;
%%
int main(int argc, char **argv)
{
yyparse();
}
void yyerror(const char *s)
{
cout << s << endl;
}
如有任何帮助,我们将不胜感激。谢谢!
最佳答案
yylex
在生成的扫描器中定义并在生成的解析器中(自动)使用。由于结果只是普通的 C(++),因此没有魔法;如果您在文件中使用 yylex
,则需要在该文件中声明它。
您可能希望 bison 自动包含声明,但事实并非如此。一方面,它不知道您想要(不必要且可能徒劳地)将声明包装在 extern "C"{...}
中。
此外,您还会遇到 C++ 接口(interface)问题。 yylex
是 flex C++ API 中的成员函数,因此您不能将其声明为 extern "C"
,也不能仅将其调用为 yylex
在外部文件中。
YMMV,但我个人更喜欢使用普通的(稳定且文档齐全的)C API,它将像 C++ 一样完美地编译,避免需要任何 extern "C"
声明。
如果您想避免使用全局变量,请使用可重入扫描器/纯解析器接口(interface)。
最后,flex
带有一个非常好的调试选项,只需在命令行上指定 -d
即可以几乎零成本使用该选项。使用该标志生成的扫描器将自动输出有关扫描的每个 token 的信息性消息,并且删除命令行标志比编辑整个 flex 描述要容易得多。
bison
有类似的机制,但它不是那么自动:您需要在生成解析器时启用它,然后您需要通过设置运行时来打开它旗帜。两者在各自的手册中都有详细记录。
关于c++ - 在 flex、bison、c++ 中实现 Wolfram 语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28162923/