Tooth movement / efficiency

I am working on building my syntax data structure from the semantic values โ€‹โ€‹of bison. One particular structure is of type std::vector<double> . I am curious how internal teeth handle semantic meanings. I tried to parse a C ++ file. M4 and found:

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

Unfortunately, I canโ€™t decrypt it almost enough to figure out the efficiency of moving the data structure, for example, std :: vector, partly because of my ignorance of the m4 syntax.

Given this in my grammar:

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

I am not sure about the performance. Note that this will be compiled by the C ++ 98 compiler, not the C ++ 11 compiler; therefore, the semantics of movement will not be.

I assume that the operator $$ = std::vector<double>() can be deleted; I assume that it will be built by default already, but I have not tested it, and I'm not sure how the type of internal variant of the bison works. I'm particularly interested in $$ = $1; $$.push_back($3); $$ = $1; $$.push_back($3); Will a vector be copied for each item to be added?

I cannot determine if this is the case for switching the type to std::vector<double> * ; admittedly, most of the argument for using a variant of a bison variant was to use simple C ++ types instead of concatenating pointers.


I also had similar curiosities to a parser that actually uses C ++ 11/14 and in particular std::unique_ptr . If one line of the left recursive rule is assigned, say $$ = std::make_unique<...>(...) whether $$ = $1; $$->... can do this $$ = $1; $$->... $$ = $1; $$->... ?

+5
source share
1 answer

I am clearly not a Bison / Yacc expert, but you can look at the generated code:

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

What lies inside the parser::parse methods and where yylhs is a local variable of type stack_symbol_type and yystack_ is an attribute of the parser class of type stack_type (which contains stack_symbol_type ).

It seems like the answer is yes , the whole vector will be copied when you do $$ = $1 , I donโ€™t see how the compiler could optimize it. The as declaration is as follows:

 template <typename T> T& as (); 

In addition, the variant is const , therefore, affectation is performed according to the type T , which in your case is std::vector<double> , and thus a copy is made. Even if you used c++11 move semantics, a copy would be made because RHS is not an xvalue .

+1
source

Source: https://habr.com/ru/post/1245433/


All Articles