Reputation: 57
I have the following function and cannot figure out why it is not working.
Parameters are a set of Nonterminals and a vector of GrammarSymbol* (a word). Nonterminal is a subclass of GrammarSymbol. The function is supposed to filter all Nonterminals that are contained in the word as well as in the Nonterminal set and return them in a set.
std::set<Nonterminal> Filter(const std::set<Nonterminal>& symbolSet, const std::vector<GrammarSymbol*> w){
//resulting set
std::set<Nonterminal> rSet;
std::vector<GrammarSymbol*>::const_iterator wit;
std::set<Nonterminal>::const_iterator ntit;
//iterate over all symbols of the word
for(wit = w.begin(); wit != w.end(); wit++){
//test if current symbol is a nonterminal
const Nonterminal* nt = dynamic_cast<const Nonterminal*>(*wit);
if(nt != NULL){
std::cout << "current symbol " << nt->Str() << " is nonterminal" << std::endl;
for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){
std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl;
}
//look for the symbol in the nonterminal set
ntit = symbolSet.find(*nt);
//if the symbol was found, insert it into resulting set
if(ntit != symbolSet.end()){
rSet.insert(*ntit);
std::cout << "inserted " << ntit->Str() << "into set, size: " << rSet.size() << std::endl;
}
else{
std::cout << "not found in symbolSet" << std::endl;
}
}
}
return rSet;
}
This yields the output
current symbol (1, 2, 2) is nonterminal
(1, 2, 2) 1
(2, 3, 3) 0
(3, 2) 0
(4, 3) 0
(5, 3, 1) 0
not found in symbolSet
It works just fine if I don't rely on the filter function and filter on my own:
std::set<Nonterminal> Filter(const std::set<Nonterminal>& symbolSet, const std::vector<GrammarSymbol*> w){
//resulting set
std::set<Nonterminal> rSet;
std::vector<GrammarSymbol*>::const_iterator wit;
std::set<Nonterminal>::const_iterator ntit;
//iterate over all symbols of the word
for(wit = w.begin(); wit != w.end(); wit++){
//test if current symbol is a nonterminal
const Nonterminal* nt = dynamic_cast<const Nonterminal*>(*wit);
if(nt != NULL){
std::cout << "current symbol " << nt->Str() << " is nonterminal" << std::endl;
for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){
std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl;
if(!(*ntit < *nt) && !(*nt < *ntit)){
rSet.insert(*ntit);
}
}
}
}
return rSet;
}
Can anyone explain to me what happens here? As far as I know, std::set is supposed to compare elements with the operator<. Comparing seems to work just fine, as shown by the output.
I would just continue with the selfmade filter, but I fear there is a bigger underlying problem.
Thanks!
Edit: Nonterminal and operator< for Nonterminal:
class Nonterminal : public GrammarSymbol{
public:
/** The start state*/
Idx mStartState;
/** The stack symbol*/
Idx mOnStack;
/** The end state */
Idx mEndState;
//...
}
Idx is just a typedef for an int.
bool Nonterminal::operator<(const GrammarSymbol& other) const{
if(typeid(*this) != typeid(other)) return true; //other is a terminal
const Nonterminal& nt = dynamic_cast<const Nonterminal&>(other); //other is a nonterminal
if (mStartState < nt.StartState()) return true;
if (mOnStack < nt.OnStack()) return true;
if (mEndState < nt.EndState()) return true;
return false;
}
Upvotes: 1
Views: 2014
Reputation:
You operator <
is incorrect
Consider
Nonterminal nt1 (1,2,3);
Nonterminal nt2 (3,2,1);
bool b1 = nt1 < nt2;
bool b2 = nt2 < nt1;
For nt1 < nt2
comparison:
1 < 3
immediatelly yelds true
; For nt2 < nt1
:
3 < 1
doesn't hold, so you proceed to 2 < 2
which doesn't hold, so you proceed to 1 < 3
which holdsThus both b1
and b2
will be true
, which is nonsense
As for your second variant of filter
, it works becase of logic error
for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){
std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl;
if(!(*ntit < *nt) && !(*nt < *ntit)){
rSet.insert(*ntit);
}
here rSet.insert(*ntit);
will be called every time if(!(*ntit < *nt) && !(*nt < *ntit))
doesn't hold, not once as it should.
Upvotes: 3