2016-03-20 9 views
5

Ich arbeite daran, meine Parse-Datenstruktur aus Bisons semantischen Werten zu konstruieren. Eine bestimmte Struktur ist vom Typ std::vector<double>. Ich bin gespannt, wie die Bison-Interna semantische Werte bewegen. Ich versuchte, die C++ m4-Datei zu analysieren und gefunden:.Bison value moving/efficiency

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;])[ 
    } 

Leider habe ich nicht entziffern kann fast genug, um die Effizienz der Bewegung eine Datenstruktur wie std :: vector zu entziffern, zum Teil meiner Unkenntnis des Grund m4 Syntax.

Vor diesem Hintergrund in meiner Grammatik:

%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); } 
; 

Ich bin der Auswirkungen auf die Leistung ungewiss. Beachten Sie, dass dies mit einem C++ 98-Compiler und nicht mit einem C++ 11-Compiler kompiliert wird; daher wird es keine Bewegungssemantik geben.

Ich vermute, dass die $$ = std::vector<double>() Anweisung entfernt werden konnte; Ich nehme an, es wäre bereits default-konstruiert, aber ich habe es nicht getestet und bin mir nicht sicher, wie Bisons interner Variant-Typ funktioniert. Was mich besonders interessiert, ist die $$ = $1; $$.push_back($3); Wird der Vektor für jedes hinzuzufügende Objekt kopiert?

Ich kann nicht feststellen, ob dies für das Umschalten des Typs auf std::vector<double> * ist; zugegebenermaßen bestand ein großer Teil der Gründe für die Verwendung des Bison-Variantentyps in der Verwendung einfacher C++ - Typen anstelle einer Vereinigung von Zeigern.


Ich habe auch ähnliche Kuriositäten auf einem Parser, der in der Tat tut Verwendung von C++ 14.11 und insbesondere std::unique_ptr machen. Wenn eine Zeile einer linksrekursiven Regel zugewiesen wäre, beispielsweise $$ = std::make_unique<...>(...), wäre Folgendes möglich: $$ = $1; $$->...?

Antwort

1

Ich bin eindeutig nicht um ein Bison/Yacc Experte, aber Sie auf den generierten Code aussehen:

 { 
    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; 

, die innerhalb der parser::parse Methoden legt und wo yylhs ist eine lokale Variable vom Typ stack_symbol_type und yystack_ ist ein Attribut der parser Klasse des Typs stack_type (die stack_symbol_type enthält).

Es sieht aus wie die Antwort ist ja, der gesamte Vektor wird kopiert, wenn Sie $$ = $1 tun, sehe ich nicht, wie ein Compiler dies optimieren könnte. Die Erklärung von as ist wie folgt:

template <typename T> 
T& as(); 

Mit auch einer const Variante, so wird die Affektiertheit von der Art T, die in Ihrem Fall ist std::vector<double> getan, und damit eine Kopie erstellt wird. Selbst wenn Sie c++11 Bewegungssemantik verwendet hätten, wäre eine Kopie erstellt worden, weil die RHS keine xvalue ist.

+0

Danke! Ich wollte wirklich vermeiden, das Pointer-zu-Vektor-Konstrukt zu machen, aber es sieht so aus, als ob das das Beste ist. – Zac

+1

@Zac hast du erwogen, '$ 1' und' $$' zu tauschen, anstatt zuzuteilen? –

+0

@Michael hatte ich nicht. Beziehen Sie sich auf std :: swap()? – Zac