2016-03-20 25 views
5

Ben parse veri yapısını bison'un semantik değerlerinden oluşturmaya çalışıyorum. Özel bir yapı, tip std::vector<double>'dur. Bizon içlerinin semantik değerlerin taşınmasıyla nasıl başa çıktığını merak ediyorum. . Ben C++ m4 dosyayı analiz çalıştı ve bulunan:Bison değer taşıma/verimlilik

template <typename Base> 
    inline 
    void 
    ]b4_parser_class_name[::basic_symbol<Base>::move (basic_symbol& s) 
    { 
    super_type::move(s); 
    ]b4_variant_if([b4_symbol_variant([this->type_get()], [value], [move], 
             [s.value])], 
        [value = s.value;])[]b4_locations_if([ 
    location = s.location;])[ 
    } 

Ne yazık ki, neredeyse yeterli std :: vector gibi bir veri yapısını hareketli verimliliğini çıkarmak için bu deşifre edemez, kısmen benim cehalet nedeniyle m4 sözdizimi.

benim dilbilgisi bu Verilen:

%define api.token.constructor 
%define api.value.type variant 
%type < std::vector<double> > numlist 
... 
numlist: 
    num    { $$ = std::vector<double>(); $$.push_back($1); } 
| numlist "," num { $$ = $1; $$.push_back($3); } 
; 

Ben performans etkileri belirsiz duyuyorum. Bunun bir C++ 11 derleyici ile değil, bir C++ 98 derleyici ile derleneceğini unutmayın; bu yüzden hareket anlambilimi olmayacaktır.

$$ = std::vector<double>() ifadesinin kaldırılabileceğini tahmin ediyorum; Varsayılan olarak yapılandırılmış olacağını varsayıyorum, ama test etmedim ve bison'un dahili varyant tipinin nasıl çalıştığından emin değilim. Özellikle ilgimi çeken şey, $$ = $1; $$.push_back($3); Vektör eklenecek her öğe için kopyalanacak mı?

Bu türün std::vector<double> * olarak değiştirilmesi durumunda bir durum olup olmadığını belirleyemem; kuşkusuz, bizonun varyant tipini kullanmanın ardındaki mantığın çoğu, işaretçiler birliği yerine düz C++ türlerini kullanmaktı.


Ben de C++ 11/14 ve özellikle std::unique_ptr de faydalanmak aslında yapan bir ayrıştırıcı benzer ilginçlikleri yaşadım. Bir sola özyinelemeli kuralın bir satırı $$ = std::make_unique<...>(...) ise, $$ = $1; $$->... aşağıdakileri yapabilir mi?

cevap

1

Ben açıkça bir Bison/Yacc uzman değilim ama oluşturulan kodun bakabilirsiniz:

parser::parse yöntemleri içinde bırakır ve yylhs tip stack_symbol_type ve yystack_ yerel değişken olduğu
 { 
    case 2: 
#line 20 "test.yy" // lalr1.cc:846 
    { yylhs.value.as< std::vector<double> >() = std::vector<double>(); 
     yylhs.value.as< std::vector<double> >().push_back(yystack_[0].value.as<double>()); } 
#line 1306 "test.tab.cc" // lalr1.cc:846 
    break; 

    case 3: 
#line 21 "test.yy" // lalr1.cc:846 
    { yylhs.value.as< std::vector<double> >() = yystack_[2].value.as< std::vector<double> >(); 
     yylhs.value.as< std::vector<double> >().push_back(yystack_[0].value.as<double>()); } 
#line 1312 "test.tab.cc" // lalr1.cc:846 
    break; 

bir niteliktir stack_type (stack_symbol_type içerir) sınıfının parser sınıfı.

Yanıt evet şeklinde görünüyor, $$ = $1 yaptığınızda tüm vektör kopyalanacak, bir derleyicinin bunu nasıl optimize edebileceğini göremiyorum. Ayrıca const varyantı ile

template <typename T> 
T& as(); 

yüzden özenti sizin durumunuzda std::vector<double> ve dolayısıyla bir kopyası oluşturulur tip T, yapılır şu şekildedir: as ilanıdır. c++11 taşıt semantiğini kullanmış olsanız bile, RHS bir xvalue olmadığı için bir kopya yapılmış olacaktır.

+0

Teşekkürler! İşaretçiden vektör yapısını yapmaktan kaçınmak istedim ama yapılacak en iyi şey bu gibi görünüyor. – Zac

+1

@Zac, atama yerine "$ 1" ve "$$' arasında geçiş yapmayı düşündünüz mü? –

+0

@Michael Yapmamıştım. Std :: swap() 'a atıfta bulunuyor musunuz? – Zac

İlgili konular