2012-03-09 11 views
2

私は多項式を解析する働く文法(lexとbisonで書かれています)を持っています。それはあなたの標準的なテキストブックの計算機のような構文です。lexのC++ istream

Expr 
: DOUBLE  {$$ = newConstExpr($1);} 
| Expr '+' Expr {$$ = newBinaryExpr('+', $1, $2);} 
| Expr '*' Expr {$$ = NewBinaryExpr('*', $1, $2);} 
| '(' Expr ')' {$$ = $2;} 
; 

私の問題は、レックスがyyinのためのFILE *を使用していることであり、私はC++はistreamからの入力を解析する必要があります。ここでは文法の非常に単純化したバージョンです。私はflex ++がFlexLexerクラスを生成することができることを知っていますが、それはBisonと噛み合うのが難しく、作成者自身も(生成されたレクサーファイルのコメントで)バギーです。

誰かがFILE *の代わりに入力としてC++ istreamオブジェクトを使ってflexスキャナとbisonパーサを使う良い方法を知っているのであれば、私は疑問に思います。

+0

バイソンマニュアルの[example](http://www.gnu.org/software/bison/manual/bison.html#A-Complete-C_002b_002b-例)を読んだことがありますか?または[その他の](http://idlebox.net/2007/flex-bison-cpp-example/)[examples](http://www.thebinaryidiot.com/archives/2010/03/06/flex-bison -cpp-example /)googleが見つかりましたか? – rve

+0

私はこれらのいくつかを見て、彼らが役に立たないと感じました。しかし、これらの例の1つは有望に見えます。私はそれを徹底的に調べます。ありがとうございました。 – Nick

答えて

1

カスタムのYY_INPUTマクロを定義して、必要に応じてlexに入力することができます。実際の例については

は、私を見てみましょう:ここ

http://www.kylheku.com/cgit/txr/tree/parser.l

は、私は、動的オブジェクトライブラリの一部である特殊なストリームオブジェクトを操作するflexスキャナをリダイレクトします。 iostreamのように、これらはFILE *ではありません。

これは、プログラムが-c <script text>で実行されているときに、コマンドラインを字句解析するようなことをすることができます。 YY_INPUTマクロが私のget_byte機能を使用する理由です

(余談、スキャナが8ビットバイトで動作したよう。。yyin_streamは、文字列ストリームである場合には、get_byte実装が実際にUTF-8エンコーディングのバイトは対応出しますストリングが文字列の次の文字に進む前に、複数のget_byte呼び出しが必要な場合があります。get_byteは、基礎となるOSストリームからバイトを取得します。

+0

'YY_INPUT'は意図的に読み込みを中止し、改行を見ると部分的に満たされたバッファを返します。基礎となるストリームがインタラクティブである場合は、これが重要です。 'YY_INPUT'はバッファを満たすまで文字を読み続けるだけで、インタラクティブなバッファなしストリームやラインバッファストリームの効果を元に戻し、バッファリングされるようにします。lexから一瞬の即時の応答性が必要な場合は、YY_INPUTをバッファラインに書き直さなければなりません(基盤となるシステムからのそのような入力スタイルの手配に加えて)。 – Kaz

0

これは、文字列内のUnicode文字に変換されます。インタラクティブなistreamから読み込むためのカスタムYY_INPUTマクロの実際の例。

%{ 
// 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スタイルで生成されています)はうまく動作します。実験的なフレックスオプション%option c++を試すこともできます。 Flexマニュアルの「C++スキャナの生成」を参照してください。 Bisonパーサとこれらのスキャナを統合することに関する多くの情報はないようです。

最後に、メモリからの読み取りで十分である場合は、YY_INPUTの再定義を避けることができます。フレックスマニュアルのyy_scan_buffer()を参照してください。