40 #include <llvm/ADT/SmallPtrSet.h>
41 #include <llvm/ADT/Twine.h>
42 #include <llvm/Support/raw_ostream.h>
44 #include <google/protobuf/text_format.h>
48 #if __has_include(<unordered_map>) and !defined(__linux__)
49 #include <unordered_map>
50 #include <unordered_set>
51 using std::unordered_map;
52 using std::unordered_set;
54 #include <tr1/unordered_map>
55 #include <tr1/unordered_set>
56 using std::tr1::unordered_map;
57 using std::tr1::unordered_set;
65 using google::protobuf::TextFormat;
71 using std::stringstream;
83 :
Automaton(A), Use(Use), Descriptions(Descriptions),
84 SubAutomataAllowed(true)
96 void Parse(OwningPtr<NFA>& Out,
unsigned int id);
100 bool Init =
false,
bool Cleanup =
false);
110 void ConvertIncOrToExcOr(
State& InitialState,
State& EndState);
111 void CalculateReachableTransitionsBetween(
const State& InitialState,
State& EndState, SmallVector<Transition*,16>& Ts);
114 void CreateParallelAutomaton(SmallVector<Transition*,16>& lhs, SmallVector<Transition*,16>& rhs,
State& InitialState,
State& EndState);
115 void CreateTransitionChainCopy(SmallVector<Transition*,16>& chain,
State& InitialState,
State& EndState);
121 bool SubAutomataAllowed;
132 const Usage *Use, StringRef Name,
134 : id(id), assertion(A), use(Use), name(Name), Transitions(Transitions)
143 if (!T->IsRealisable())
151 ss <<
"automaton '" <<
Name() <<
"' {\n";
155 ss <<
"\t" << S->String() <<
"\n";
167 <<
" * " <<
Name() <<
"\n"
169 <<
"digraph automaton_" <<
id <<
" {\n"
170 <<
"\tgraph [ truecolor=true, bgcolor=\"transparent\", dpi = 60 ];\n"
172 <<
" shape = circle,"
173 <<
" fontname = \"Monospace\","
174 <<
" style = filled, fillcolor = \"white\""
176 <<
"\tedge [ fontname = \"Monospace\" ];\n"
181 ss <<
"\t" << S->Dot() <<
"\n";
186 string color = (
"\"/dark28/" + Twine(i++ % 8 + 1) +
"\"").str();
187 auto *Head = *EquivalenceClass.begin();
191 <<
"\t * " << Head->ShortLabel() <<
"\n"
194 <<
"color = " << color <<
", "
195 <<
"fontcolor = " << color <<
",\n\t\t"
196 <<
"label = \"" << Head->DotLabel();
198 if (Head->RequiresInit())
199 ss <<
"\\n«init»";
201 if (Head->RequiresCleanup())
202 ss <<
"\\n«cleanup»";
208 for (
auto *T : EquivalenceClass)
210 <<
"\t" << T->Source().ID() <<
" -> " << T->Destination().ID() <<
";\n"
218 <<
"\tfontname = \"Monospace\";\n"
219 <<
"\tlabel = \"" <<
Name() <<
"\";\n"
220 <<
"\tlabelloc = top;\n"
221 <<
"\tlabeljust = left;\n"
252 const Usage *Use, StringRef Name,
261 assert(Allow || Descriptions != NULL &&
"need a source of subautomata");
262 SubAutomataAllowed = Allow;
268 debugs(
"tesla.automata.parsing")
271 size_t VariableRefs = 0;
273 if (A.type() == Argument::Variable)
282 if (Use && Use->has_beginning()) {
286 TextFormat::PrintToString(Use->
beginning(), &Str);
287 panic(
"failed to parse automaton 'beginning' event: " + Str);
297 if (Use && Use->has_end()) {
298 End =
Parse(Use->
end(), *End,
false,
true);
301 TextFormat::PrintToString(Use->
end(), &Str);
302 panic(
"failed to parse automaton 'end' event: " + Str);
308 debugs(
"tesla.automata.parsing.out-of-scope") <<
"out-of-scope events:\n";
309 vector<const Transition*> OutOfScope;
317 bool AlreadyHave =
false;
319 if (Existing->EquivalentTo(*T)) {
324 if (!AlreadyHave && !T->IsStrict() && !T->RequiresInit()) {
325 OutOfScope.push_back(T);
326 debugs(
"tesla.automata.parsing.out-of-scope")
327 <<
" " << T->String() <<
"\n";
331 for (
auto *T : OutOfScope) {
332 State& Destination = *(T->RequiresCleanup() ? End : Start);
334 switch (T->getKind()) {
350 TextFormat::PrintToString(
Automaton, &Description);
357 debugs(
"tesla.automata.parsing") <<
"parsed '" << Out->Name() <<
"'.\n\n";
361 bool Init,
bool Cleanup) {
363 switch (Expr.
type()) {
366 panic(
"boolean expression cannot do initialisation");
369 panic(
"boolean expression cannot do cleanup");
371 return Parse(Expr.booleanexpr(), Start);
375 panic(
"sequence transition cannot do initialisation");
378 panic(
"sequence transition cannot do cleanup");
382 case Expression::NULL_EXPR:
384 panic(
"epsilon transition cannot do initialisation");
387 panic(
"epsilon transition cannot do cleanup");
392 return Parse(Expr.
now(), Start, Init, Cleanup);
394 case Expression::FUNCTION:
397 case Expression::FIELD_ASSIGN:
398 return Parse(Expr.fieldassign(), Start, Init, Cleanup);
402 panic(
"sub-automaton transition cannot do initialisation");
405 panic(
"sub-automaton transition cannot do cleanup");
407 if (SubAutomataAllowed)
408 return SubAutomaton(Expr.subautomaton(), Start);
412 assert(Descriptions != NULL);
414 auto i = Descriptions->find(ID);
415 if (i == Descriptions->end())
418 return Parse(i->second->expression(), Start);
424 assert(Expr.expression_size() == 2);
425 const Expression& LHS = Expr.expression(0);
426 const Expression& RHS = Expr.expression(1);
428 State *LHSFinal =
Parse(LHS, Branch);
429 State *RHSFinal =
Parse(RHS, Branch);
431 if (!LHSFinal || !RHSFinal)
438 switch (Expr.operation()) {
442 case BooleanExpr::BE_Or:
443 ConvertIncOrToExcOr(Branch, *Join);
448 errs() <<
"TESLA WARNING: using unsupported AND feature\n";
454 State *Current = &Start;
455 for (
const Expression& E : Seq.expression())
456 Current =
Parse(E, *Current);
462 bool Init,
bool Cleanup) {
470 bool Init,
bool Cleanup) {
477 bool Init,
bool Cleanup) {
483 State* NFAParser::SubAutomaton(
const Identifier& ID, State& InitialState) {
492 ss << T->String() <<
" ";
500 for (
auto& TV : TVs) {
509 void NFAParser::ConvertIncOrToExcOr(
State& InitialState,
State& EndState) {
510 debugs(
"tesla.automata.inclusive_or")
511 <<
"Converting inclusive-or to exclusive-or\n";
531 SmallVector<Transition*,16> lhs, rhs;
532 auto TI = InitialState.
begin();
536 debugs(
"tesla.automata.inclusive_or")
537 <<
"Lhs: " << LhsFirstT->
String() <<
"\n"
538 <<
"Rhs: " << RhsFirstT->
String() <<
"\n"
541 lhs.push_back(LhsFirstT);
542 rhs.push_back(RhsFirstT);
543 CalculateReachableTransitionsBetween(LhsFirstT->
Destination(), EndState, lhs);
544 CalculateReachableTransitionsBetween(RhsFirstT->
Destination(), EndState, rhs);
546 debugs(
"tesla.automata.inclusive_or")
547 <<
"Calculated reachable transitions for lhs: "
549 <<
"Calculated reachable transitions for rhs: "
558 CreateParallelAutomata(lhsPrefixes, rhs, InitialState, EndState);
559 CreateParallelAutomata(rhsPrefixes, lhs, InitialState, EndState);
560 CreateParallelAutomaton(lhs, rhs, InitialState, EndState);
563 void NFAParser::CalculateReachableTransitionsBetween(
const State& Start, State& End, SmallVector<Transition*,16>& Ts) {
564 Transition* T = *Start.begin();
565 if (Start.ID() == End.ID()) {
568 if (!isa<NullTransition>(T)) {
571 CalculateReachableTransitionsBetween(T->Destination(), End, Ts);
574 TransitionVectors NFAParser::GenerateTransitionPrefixesOf(SmallVector<Transition*,16>& Ts) {
576 debugs(
"tesla.automata.inclusive_or")
577 <<
"Generating transition prefixes of "
582 SmallVector<Transition*,16> lastPrefix;
584 prefixes.push_back(lastPrefix);
586 bool nonEmptyPrefix =
false;
588 lastPrefix.push_back(T);
589 prefixes.push_back(lastPrefix);
590 nonEmptyPrefix =
true;
592 if (nonEmptyPrefix) {
597 debugs(
"tesla.automata.inclusive_or")
603 void NFAParser::CreateParallelAutomata(
TransitionVectors& prefixes, SmallVector<Transition*,16>& rhs, State& InitialState, State& EndState) {
604 for (
auto prefix : prefixes) {
607 if (!prefix.empty()) {
608 CreateParallelAutomaton(prefix, rhs, InitialState, EndState);
614 void NFAParser::CreateParallelAutomaton(SmallVector<Transition*,16>& lhs, SmallVector<Transition*,16>& rhs, State& InitialState, State& EndState) {
626 debugs(
"tesla.automata.inclusive_or")
627 <<
"Entering CreateParallelAutomaton("
633 CreateTransitionChainCopy(rhs, InitialState, EndState);
635 else if (rhs.empty()) {
636 CreateTransitionChainCopy(lhs, InitialState, EndState);
641 Transition *LhsFirstT = lhs.front();
644 SmallVector<Transition*,16> lhsCopy = lhs;
645 lhsCopy.erase(lhsCopy.begin());
646 CreateParallelAutomaton(lhsCopy, rhs, *LhsFirstTNewDest, EndState);
649 Transition *RhsFirstT = rhs.front();
652 SmallVector<Transition*,16> rhsCopy = rhs;
653 rhsCopy.erase(rhsCopy.begin());
654 CreateParallelAutomaton(lhs, rhsCopy, *RhsFirstTNewDest, EndState);
657 debugs(
"tesla.automata.inclusive_or")
658 <<
"Exiting CreateParallelAutomaton("
664 void NFAParser::CreateTransitionChainCopy(SmallVector<Transition*,16>& chain, State& InitialState, State& EndState) {
665 State* CurrSource = &InitialState;
667 debugs(
"tesla.automata.inclusive_or")
668 <<
"Creating copy of transition chain: "
672 for (
auto TI=chain.begin(), TE=chain.end()-1; TI != TE; TI++) {
674 debugs(
"tesla.automata.inclusive_or")
675 <<
"Creating copy of transition: " << T->String() <<
"\n";
695 if (S.size() == 0)
return 0;
701 raw_ostream& Out,
const unordered_map<NFAState, State*, NFAStateHash>& M) {
702 for (
auto I : M) Out << (I.second->ID()) <<
" = " << I.first;
709 unordered_map<NFAState, State*, NFAStateHash> DFAStates;
711 unordered_set<unsigned> FinishedStates;
714 std::pair<NFAState, std::pair<bool,bool> >, 16> UnfinishedStates;
720 void collectFrontier(
NFAState& N,
const State* S,
bool& Start,
bool& Final) {
726 collectFrontier(N, &T->Destination());
732 collectFrontier(N, S, Start, Final);
734 State *stateForNFAStates(
NFAState& NStates,
bool Start,
bool Final) {
735 auto Existing = DFAStates.find(NStates);
736 if (Existing != DFAStates.end())
737 return Existing->second;
745 std::stringstream Name;
746 std::copy(NStates.begin(), NStates.end(),
747 std::ostream_iterator<int>(Name,
","));
748 Builder.SetName(StringRef(
"NFA:" + Name.str()).drop_back(1));
750 State *DS = Builder.Build();
751 DFAStates.insert(std::make_pair(NStates, DS));
752 UnfinishedStates.push_back(
753 std::make_pair(NStates, std::make_pair(Start, Final)));
764 collectFrontier(NStates, S, Start, Final);
765 return stateForNFAStates(NStates, Start, Final);
773 assert(States.empty());
776 stateForNFAState(N->
States.front());
777 while (!UnfinishedStates.empty()) {
778 CurrentState = UnfinishedStates.back().first;
779 auto StartFinal = UnfinishedStates.back().second;
780 bool Start = StartFinal.first;
781 bool Final = StartFinal.second;
782 UnfinishedStates.pop_back();
784 State *DS = stateForNFAStates(CurrentState, Start, Final);
785 if (FinishedStates.find(DS->
ID()) != FinishedStates.end())
787 FinishedStates.insert(DS->
ID());
791 unordered_set<Transition*> FinishedTransitions;
793 for (
auto SI=CurrentState.begin(), SE=CurrentState.end() ; SI!=SE ; ++SI) {
798 for (
auto TI=NState->
begin(), TE=NState->
end() ; TI!=TE ; ++TI) {
802 if (FinishedTransitions.count(T) != 0)
continue;
804 collectFrontier(Destinations, &T->
Destination(), Start, Final);
805 FinishedTransitions.insert(T);
808 for (++DTI ; DTI!=TE ; ++DTI) {
809 if ((*DTI)->EquivalentTo(*T)) {
810 assert(FinishedTransitions.count(*DTI) == 0);
811 FinishedTransitions.insert(*DTI);
812 collectFrontier(Destinations, &(*DTI)->Destination(), Start, Final);
816 for (++DSI ; DSI!=SE ; ++DSI)
818 if (DT->EquivalentTo(*T)) {
819 assert(FinishedTransitions.count(DT) == 0);
820 FinishedTransitions.insert(DT);
821 collectFrontier(Destinations, &DT->Destination(), Start, Final);
825 State *Dest = stateForNFAStates(Destinations, Start, Final);
835 N->
Use(), N->
Name(), States, TEquivClasses);
837 debugs(
"tesla.automata.dfa")
838 <<
"DFA conversion results:\n"
839 <<
"> NFA: " << N->
String() <<
"\n"
840 <<
"> DFA: " << D->
String() <<
"\n"
841 <<
">> DFA state map:\n"
843 <<
">> DFA transition equivalence classes:\n"
869 assert(T->IsRealisable());