1

mathicssymjaなどのプロジェクトを見た後、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 ファイルは次のとおりです。

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

どんな助けでも大歓迎です。ありがとうございました!

4

1 に答える 1

1

yylex生成されたスキャナーで定義され、生成されたパーサーで (自動的に) 使用されます。結果は普通の C(++) であるため、魔法はありません。ファイルで使用する場合はyylex、そのファイルで宣言する必要があります。

bison が自動的に宣言をインクルードすることを期待するかもしれませんが、そうではありません。1 つには、(不必要に、そしておそらく無駄に) 宣言を でラップしたいという考えがありませんextern "C" {...}


また、C++ インターフェイスで問題が発生します。yylexはフレックス C++ API のメンバー関数であるため、 として宣言することはできません。また、外部ファイルでextern "C"単に呼び出すこともできません。yylex

extern "C"YMMV ですが、個人的には通常の (安定しており、十分に文書化された) C API を使用することを好みます。これは、C++ として完全に適切にコンパイルされ、宣言の必要性を回避します。

グローバルを回避したい場合は、リエントラント スキャナー/純粋なパーサー インターフェイスを使用してください。

最後に、コマンドラインflexで指定するだけでほぼゼロコストで利用できる完全に優れたデバッグ オプションが付属しています。-dそのフラグで生成されたスキャナーは、スキャンされたすべてのトークンに関する有益なメッセージを自動的に出力します。コマンドライン フラグを削除する方が、flex の説明全体を編集するよりもはるかに簡単です。

bisonにも同様のメカニズムがありますが、それほど自動ではありません。パーサーを生成するときに有効にする必要があり、実行時フラグを設定して有効にする必要があります。どちらも、それぞれのマニュアルで十分に文書化されています。

于 2015-01-27T03:56:07.040 に答える