在flex、bison、c+中实现Wolfram语言+; 在查看类似的项目之后,我尝试用C++中的Flex和Byon实现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.

在flex、bison、c+中实现Wolfram语言+; 在查看类似的项目之后,我尝试用C++中的Flex和Byon实现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.,c++,bison,flex-lexer,wolfram-language,C++,Bison,Flex Lexer,Wolfram Language,以下是我的.lpp和.ypp文件,以供参考 lexer.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 LBRA

以下是我的.lpp和.ypp文件,以供参考

lexer.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;
}
%{
#包括
#包括“parser.tab.hpp”
使用名称空间std;
外部“C”
{
int yylex(无效);
}
%}
%选项C++
%选项No yywrap
%%
[1-9][0-9]*(.[0-9]*)?     {return NUM;}
“\[”{return LBRACE;}

“\]”cout
yylex
在生成的扫描程序中定义,并在生成的解析器中(自动)使用。由于结果只是普通的C(++),因此没有魔力;如果在文件中使用
yylex
,则需要在该文件中声明它

您可能希望bison自动包含声明,但事实并非如此。首先,它不知道您想要(不必要且可能徒劳地)将声明包装在
extern“C”{…}


也会遇到C++接口的问题。代码> ylex < /Cl>是Flex C++ API中的成员函数,因此不能将其声明为代码> Extn“C”<代码>,也不能仅将它称为“代码> yyex < /Cl>在外部文件中。

YMMV,但我个人更喜欢使用普通的(稳定的和文档化的)C API,它将编译成C++,避免了对任何<代码>外部“C”<代码>声明的需要。 如果要避免全局,请使用可重入扫描程序/纯解析器接口

最后,
flex
提供了一个非常好的调试选项,只需在命令行上指定
-d
,几乎可以零成本使用。使用该标志生成的扫描器将自动输出有关扫描的每个标记的信息性消息,删除命令行标志比编辑整个flex描述要容易得多

bison
有一个类似的机制,但它不是完全自动的:您需要在生成解析器时启用它,然后需要通过设置运行时标志来启用它。两者都在各自的手册中有详细的记录

%{
#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;
}