1*06f32e7eSjoerg //===- DFAEmitter.cpp - Finite state automaton emitter --------------------===// 2*06f32e7eSjoerg // 3*06f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information. 5*06f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06f32e7eSjoerg // 7*06f32e7eSjoerg //===----------------------------------------------------------------------===// 8*06f32e7eSjoerg // 9*06f32e7eSjoerg // This class can produce a generic deterministic finite state automaton (DFA), 10*06f32e7eSjoerg // given a set of possible states and transitions. 11*06f32e7eSjoerg // 12*06f32e7eSjoerg // The input transitions can be nondeterministic - this class will produce the 13*06f32e7eSjoerg // deterministic equivalent state machine. 14*06f32e7eSjoerg // 15*06f32e7eSjoerg // The generated code can run the DFA and produce an accepted / not accepted 16*06f32e7eSjoerg // state and also produce, given a sequence of transitions that results in an 17*06f32e7eSjoerg // accepted state, the sequence of intermediate states. This is useful if the 18*06f32e7eSjoerg // initial automaton was nondeterministic - it allows mapping back from the DFA 19*06f32e7eSjoerg // to the NFA. 20*06f32e7eSjoerg // 21*06f32e7eSjoerg //===----------------------------------------------------------------------===// 22*06f32e7eSjoerg #define DEBUG_TYPE "dfa-emitter" 23*06f32e7eSjoerg 24*06f32e7eSjoerg #include "DFAEmitter.h" 25*06f32e7eSjoerg #include "CodeGenTarget.h" 26*06f32e7eSjoerg #include "SequenceToOffsetTable.h" 27*06f32e7eSjoerg #include "TableGenBackends.h" 28*06f32e7eSjoerg #include "llvm/ADT/SmallVector.h" 29*06f32e7eSjoerg #include "llvm/ADT/StringExtras.h" 30*06f32e7eSjoerg #include "llvm/ADT/UniqueVector.h" 31*06f32e7eSjoerg #include "llvm/Support/Debug.h" 32*06f32e7eSjoerg #include "llvm/Support/raw_ostream.h" 33*06f32e7eSjoerg #include "llvm/TableGen/Record.h" 34*06f32e7eSjoerg #include "llvm/TableGen/TableGenBackend.h" 35*06f32e7eSjoerg #include <cassert> 36*06f32e7eSjoerg #include <cstdint> 37*06f32e7eSjoerg #include <map> 38*06f32e7eSjoerg #include <set> 39*06f32e7eSjoerg #include <string> 40*06f32e7eSjoerg #include <vector> 41*06f32e7eSjoerg 42*06f32e7eSjoerg using namespace llvm; 43*06f32e7eSjoerg 44*06f32e7eSjoerg //===----------------------------------------------------------------------===// 45*06f32e7eSjoerg // DfaEmitter implementation. This is independent of the GenAutomaton backend. 46*06f32e7eSjoerg //===----------------------------------------------------------------------===// 47*06f32e7eSjoerg 48*06f32e7eSjoerg void DfaEmitter::addTransition(state_type From, state_type To, action_type A) { 49*06f32e7eSjoerg Actions.insert(A); 50*06f32e7eSjoerg NfaStates.insert(From); 51*06f32e7eSjoerg NfaStates.insert(To); 52*06f32e7eSjoerg NfaTransitions[{From, A}].push_back(To); 53*06f32e7eSjoerg ++NumNfaTransitions; 54*06f32e7eSjoerg } 55*06f32e7eSjoerg 56*06f32e7eSjoerg void DfaEmitter::visitDfaState(DfaState DS) { 57*06f32e7eSjoerg // For every possible action... 58*06f32e7eSjoerg auto FromId = DfaStates.idFor(DS); 59*06f32e7eSjoerg for (action_type A : Actions) { 60*06f32e7eSjoerg DfaState NewStates; 61*06f32e7eSjoerg DfaTransitionInfo TI; 62*06f32e7eSjoerg // For every represented state, word pair in the original NFA... 63*06f32e7eSjoerg for (state_type &FromState : DS) { 64*06f32e7eSjoerg // If this action is possible from this state add the transitioned-to 65*06f32e7eSjoerg // states to NewStates. 66*06f32e7eSjoerg auto I = NfaTransitions.find({FromState, A}); 67*06f32e7eSjoerg if (I == NfaTransitions.end()) 68*06f32e7eSjoerg continue; 69*06f32e7eSjoerg for (state_type &ToState : I->second) { 70*06f32e7eSjoerg NewStates.push_back(ToState); 71*06f32e7eSjoerg TI.emplace_back(FromState, ToState); 72*06f32e7eSjoerg } 73*06f32e7eSjoerg } 74*06f32e7eSjoerg if (NewStates.empty()) 75*06f32e7eSjoerg continue; 76*06f32e7eSjoerg // Sort and unique. 77*06f32e7eSjoerg sort(NewStates); 78*06f32e7eSjoerg NewStates.erase(std::unique(NewStates.begin(), NewStates.end()), 79*06f32e7eSjoerg NewStates.end()); 80*06f32e7eSjoerg sort(TI); 81*06f32e7eSjoerg TI.erase(std::unique(TI.begin(), TI.end()), TI.end()); 82*06f32e7eSjoerg unsigned ToId = DfaStates.insert(NewStates); 83*06f32e7eSjoerg DfaTransitions.emplace(std::make_pair(FromId, A), std::make_pair(ToId, TI)); 84*06f32e7eSjoerg } 85*06f32e7eSjoerg } 86*06f32e7eSjoerg 87*06f32e7eSjoerg void DfaEmitter::constructDfa() { 88*06f32e7eSjoerg DfaState Initial(1, /*NFA initial state=*/0); 89*06f32e7eSjoerg DfaStates.insert(Initial); 90*06f32e7eSjoerg 91*06f32e7eSjoerg // Note that UniqueVector starts indices at 1, not zero. 92*06f32e7eSjoerg unsigned DfaStateId = 1; 93*06f32e7eSjoerg while (DfaStateId <= DfaStates.size()) 94*06f32e7eSjoerg visitDfaState(DfaStates[DfaStateId++]); 95*06f32e7eSjoerg } 96*06f32e7eSjoerg 97*06f32e7eSjoerg void DfaEmitter::emit(StringRef Name, raw_ostream &OS) { 98*06f32e7eSjoerg constructDfa(); 99*06f32e7eSjoerg 100*06f32e7eSjoerg OS << "// Input NFA has " << NfaStates.size() << " states with " 101*06f32e7eSjoerg << NumNfaTransitions << " transitions.\n"; 102*06f32e7eSjoerg OS << "// Generated DFA has " << DfaStates.size() << " states with " 103*06f32e7eSjoerg << DfaTransitions.size() << " transitions.\n\n"; 104*06f32e7eSjoerg 105*06f32e7eSjoerg // Implementation note: We don't bake a simple std::pair<> here as it requires 106*06f32e7eSjoerg // significantly more effort to parse. A simple test with a large array of 107*06f32e7eSjoerg // struct-pairs (N=100000) took clang-10 6s to parse. The same array of 108*06f32e7eSjoerg // std::pair<uint64_t, uint64_t> took 242s. Instead we allow the user to 109*06f32e7eSjoerg // define the pair type. 110*06f32e7eSjoerg // 111*06f32e7eSjoerg // FIXME: It may make sense to emit these as ULEB sequences instead of 112*06f32e7eSjoerg // pairs of uint64_t. 113*06f32e7eSjoerg OS << "// A zero-terminated sequence of NFA state transitions. Every DFA\n"; 114*06f32e7eSjoerg OS << "// transition implies a set of NFA transitions. These are referred\n"; 115*06f32e7eSjoerg OS << "// to by index in " << Name << "Transitions[].\n"; 116*06f32e7eSjoerg 117*06f32e7eSjoerg SequenceToOffsetTable<DfaTransitionInfo> Table; 118*06f32e7eSjoerg std::map<DfaTransitionInfo, unsigned> EmittedIndices; 119*06f32e7eSjoerg for (auto &T : DfaTransitions) 120*06f32e7eSjoerg Table.add(T.second.second); 121*06f32e7eSjoerg Table.layout(); 122*06f32e7eSjoerg OS << "std::array<NfaStatePair, " << Table.size() << "> " << Name 123*06f32e7eSjoerg << "TransitionInfo = {{\n"; 124*06f32e7eSjoerg Table.emit( 125*06f32e7eSjoerg OS, 126*06f32e7eSjoerg [](raw_ostream &OS, std::pair<uint64_t, uint64_t> P) { 127*06f32e7eSjoerg OS << "{" << P.first << ", " << P.second << "}"; 128*06f32e7eSjoerg }, 129*06f32e7eSjoerg "{0ULL, 0ULL}"); 130*06f32e7eSjoerg 131*06f32e7eSjoerg OS << "}};\n\n"; 132*06f32e7eSjoerg 133*06f32e7eSjoerg OS << "// A transition in the generated " << Name << " DFA.\n"; 134*06f32e7eSjoerg OS << "struct " << Name << "Transition {\n"; 135*06f32e7eSjoerg OS << " unsigned FromDfaState; // The transitioned-from DFA state.\n"; 136*06f32e7eSjoerg OS << " "; 137*06f32e7eSjoerg printActionType(OS); 138*06f32e7eSjoerg OS << " Action; // The input symbol that causes this transition.\n"; 139*06f32e7eSjoerg OS << " unsigned ToDfaState; // The transitioned-to DFA state.\n"; 140*06f32e7eSjoerg OS << " unsigned InfoIdx; // Start index into " << Name 141*06f32e7eSjoerg << "TransitionInfo.\n"; 142*06f32e7eSjoerg OS << "};\n\n"; 143*06f32e7eSjoerg 144*06f32e7eSjoerg OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n"; 145*06f32e7eSjoerg OS << "// The initial state is 1, not zero.\n"; 146*06f32e7eSjoerg OS << "std::array<" << Name << "Transition, " << DfaTransitions.size() << "> " 147*06f32e7eSjoerg << Name << "Transitions = {{\n"; 148*06f32e7eSjoerg for (auto &KV : DfaTransitions) { 149*06f32e7eSjoerg dfa_state_type From = KV.first.first; 150*06f32e7eSjoerg dfa_state_type To = KV.second.first; 151*06f32e7eSjoerg action_type A = KV.first.second; 152*06f32e7eSjoerg unsigned InfoIdx = Table.get(KV.second.second); 153*06f32e7eSjoerg OS << " {" << From << ", "; 154*06f32e7eSjoerg printActionValue(A, OS); 155*06f32e7eSjoerg OS << ", " << To << ", " << InfoIdx << "},\n"; 156*06f32e7eSjoerg } 157*06f32e7eSjoerg OS << "\n}};\n\n"; 158*06f32e7eSjoerg } 159*06f32e7eSjoerg 160*06f32e7eSjoerg void DfaEmitter::printActionType(raw_ostream &OS) { OS << "uint64_t"; } 161*06f32e7eSjoerg 162*06f32e7eSjoerg void DfaEmitter::printActionValue(action_type A, raw_ostream &OS) { OS << A; } 163*06f32e7eSjoerg 164*06f32e7eSjoerg //===----------------------------------------------------------------------===// 165*06f32e7eSjoerg // AutomatonEmitter implementation 166*06f32e7eSjoerg //===----------------------------------------------------------------------===// 167*06f32e7eSjoerg 168*06f32e7eSjoerg namespace { 169*06f32e7eSjoerg // FIXME: This entire discriminated union could be removed with c++17: 170*06f32e7eSjoerg // using Action = std::variant<Record *, unsigned, std::string>; 171*06f32e7eSjoerg struct Action { 172*06f32e7eSjoerg Record *R = nullptr; 173*06f32e7eSjoerg unsigned I = 0; 174*06f32e7eSjoerg std::string S = nullptr; 175*06f32e7eSjoerg 176*06f32e7eSjoerg Action() = default; 177*06f32e7eSjoerg Action(Record *R, unsigned I, std::string S) : R(R), I(I), S(S) {} 178*06f32e7eSjoerg 179*06f32e7eSjoerg void print(raw_ostream &OS) const { 180*06f32e7eSjoerg if (R) 181*06f32e7eSjoerg OS << R->getName(); 182*06f32e7eSjoerg else if (!S.empty()) 183*06f32e7eSjoerg OS << '"' << S << '"'; 184*06f32e7eSjoerg else 185*06f32e7eSjoerg OS << I; 186*06f32e7eSjoerg } 187*06f32e7eSjoerg bool operator<(const Action &Other) const { 188*06f32e7eSjoerg return std::make_tuple(R, I, S) < 189*06f32e7eSjoerg std::make_tuple(Other.R, Other.I, Other.S); 190*06f32e7eSjoerg } 191*06f32e7eSjoerg }; 192*06f32e7eSjoerg 193*06f32e7eSjoerg using ActionTuple = std::vector<Action>; 194*06f32e7eSjoerg class Automaton; 195*06f32e7eSjoerg 196*06f32e7eSjoerg class Transition { 197*06f32e7eSjoerg uint64_t NewState; 198*06f32e7eSjoerg // The tuple of actions that causes this transition. 199*06f32e7eSjoerg ActionTuple Actions; 200*06f32e7eSjoerg // The types of the actions; this is the same across all transitions. 201*06f32e7eSjoerg SmallVector<std::string, 4> Types; 202*06f32e7eSjoerg 203*06f32e7eSjoerg public: 204*06f32e7eSjoerg Transition(Record *R, Automaton *Parent); 205*06f32e7eSjoerg const ActionTuple &getActions() { return Actions; } 206*06f32e7eSjoerg SmallVector<std::string, 4> getTypes() { return Types; } 207*06f32e7eSjoerg 208*06f32e7eSjoerg bool canTransitionFrom(uint64_t State); 209*06f32e7eSjoerg uint64_t transitionFrom(uint64_t State); 210*06f32e7eSjoerg }; 211*06f32e7eSjoerg 212*06f32e7eSjoerg class Automaton { 213*06f32e7eSjoerg RecordKeeper &Records; 214*06f32e7eSjoerg Record *R; 215*06f32e7eSjoerg std::vector<Transition> Transitions; 216*06f32e7eSjoerg /// All possible action tuples, uniqued. 217*06f32e7eSjoerg UniqueVector<ActionTuple> Actions; 218*06f32e7eSjoerg /// The fields within each Transition object to find the action symbols. 219*06f32e7eSjoerg std::vector<StringRef> ActionSymbolFields; 220*06f32e7eSjoerg 221*06f32e7eSjoerg public: 222*06f32e7eSjoerg Automaton(RecordKeeper &Records, Record *R); 223*06f32e7eSjoerg void emit(raw_ostream &OS); 224*06f32e7eSjoerg 225*06f32e7eSjoerg ArrayRef<StringRef> getActionSymbolFields() { return ActionSymbolFields; } 226*06f32e7eSjoerg /// If the type of action A has been overridden (there exists a field 227*06f32e7eSjoerg /// "TypeOf_A") return that, otherwise return the empty string. 228*06f32e7eSjoerg StringRef getActionSymbolType(StringRef A); 229*06f32e7eSjoerg }; 230*06f32e7eSjoerg 231*06f32e7eSjoerg class AutomatonEmitter { 232*06f32e7eSjoerg RecordKeeper &Records; 233*06f32e7eSjoerg 234*06f32e7eSjoerg public: 235*06f32e7eSjoerg AutomatonEmitter(RecordKeeper &R) : Records(R) {} 236*06f32e7eSjoerg void run(raw_ostream &OS); 237*06f32e7eSjoerg }; 238*06f32e7eSjoerg 239*06f32e7eSjoerg /// A DfaEmitter implementation that can print our variant action type. 240*06f32e7eSjoerg class CustomDfaEmitter : public DfaEmitter { 241*06f32e7eSjoerg const UniqueVector<ActionTuple> &Actions; 242*06f32e7eSjoerg std::string TypeName; 243*06f32e7eSjoerg 244*06f32e7eSjoerg public: 245*06f32e7eSjoerg CustomDfaEmitter(const UniqueVector<ActionTuple> &Actions, StringRef TypeName) 246*06f32e7eSjoerg : Actions(Actions), TypeName(TypeName) {} 247*06f32e7eSjoerg 248*06f32e7eSjoerg void printActionType(raw_ostream &OS) override; 249*06f32e7eSjoerg void printActionValue(action_type A, raw_ostream &OS) override; 250*06f32e7eSjoerg }; 251*06f32e7eSjoerg } // namespace 252*06f32e7eSjoerg 253*06f32e7eSjoerg void AutomatonEmitter::run(raw_ostream &OS) { 254*06f32e7eSjoerg for (Record *R : Records.getAllDerivedDefinitions("GenericAutomaton")) { 255*06f32e7eSjoerg Automaton A(Records, R); 256*06f32e7eSjoerg OS << "#ifdef GET_" << R->getName() << "_DECL\n"; 257*06f32e7eSjoerg A.emit(OS); 258*06f32e7eSjoerg OS << "#endif // GET_" << R->getName() << "_DECL\n"; 259*06f32e7eSjoerg } 260*06f32e7eSjoerg } 261*06f32e7eSjoerg 262*06f32e7eSjoerg Automaton::Automaton(RecordKeeper &Records, Record *R) 263*06f32e7eSjoerg : Records(Records), R(R) { 264*06f32e7eSjoerg LLVM_DEBUG(dbgs() << "Emitting automaton for " << R->getName() << "\n"); 265*06f32e7eSjoerg ActionSymbolFields = R->getValueAsListOfStrings("SymbolFields"); 266*06f32e7eSjoerg } 267*06f32e7eSjoerg 268*06f32e7eSjoerg void Automaton::emit(raw_ostream &OS) { 269*06f32e7eSjoerg StringRef TransitionClass = R->getValueAsString("TransitionClass"); 270*06f32e7eSjoerg for (Record *T : Records.getAllDerivedDefinitions(TransitionClass)) { 271*06f32e7eSjoerg assert(T->isSubClassOf("Transition")); 272*06f32e7eSjoerg Transitions.emplace_back(T, this); 273*06f32e7eSjoerg Actions.insert(Transitions.back().getActions()); 274*06f32e7eSjoerg } 275*06f32e7eSjoerg 276*06f32e7eSjoerg LLVM_DEBUG(dbgs() << " Action alphabet cardinality: " << Actions.size() 277*06f32e7eSjoerg << "\n"); 278*06f32e7eSjoerg LLVM_DEBUG(dbgs() << " Each state has " << Transitions.size() 279*06f32e7eSjoerg << " potential transitions.\n"); 280*06f32e7eSjoerg 281*06f32e7eSjoerg StringRef Name = R->getName(); 282*06f32e7eSjoerg 283*06f32e7eSjoerg CustomDfaEmitter Emitter(Actions, std::string(Name) + "Action"); 284*06f32e7eSjoerg // Starting from the initial state, build up a list of possible states and 285*06f32e7eSjoerg // transitions. 286*06f32e7eSjoerg std::deque<uint64_t> Worklist(1, 0); 287*06f32e7eSjoerg std::set<uint64_t> SeenStates; 288*06f32e7eSjoerg unsigned NumTransitions = 0; 289*06f32e7eSjoerg SeenStates.insert(Worklist.front()); 290*06f32e7eSjoerg while (!Worklist.empty()) { 291*06f32e7eSjoerg uint64_t State = Worklist.front(); 292*06f32e7eSjoerg Worklist.pop_front(); 293*06f32e7eSjoerg for (Transition &T : Transitions) { 294*06f32e7eSjoerg if (!T.canTransitionFrom(State)) 295*06f32e7eSjoerg continue; 296*06f32e7eSjoerg uint64_t NewState = T.transitionFrom(State); 297*06f32e7eSjoerg if (SeenStates.emplace(NewState).second) 298*06f32e7eSjoerg Worklist.emplace_back(NewState); 299*06f32e7eSjoerg ++NumTransitions; 300*06f32e7eSjoerg Emitter.addTransition(State, NewState, Actions.idFor(T.getActions())); 301*06f32e7eSjoerg } 302*06f32e7eSjoerg } 303*06f32e7eSjoerg LLVM_DEBUG(dbgs() << " NFA automaton has " << SeenStates.size() 304*06f32e7eSjoerg << " states with " << NumTransitions << " transitions.\n"); 305*06f32e7eSjoerg 306*06f32e7eSjoerg const auto &ActionTypes = Transitions.back().getTypes(); 307*06f32e7eSjoerg OS << "// The type of an action in the " << Name << " automaton.\n"; 308*06f32e7eSjoerg if (ActionTypes.size() == 1) { 309*06f32e7eSjoerg OS << "using " << Name << "Action = " << ActionTypes[0] << ";\n"; 310*06f32e7eSjoerg } else { 311*06f32e7eSjoerg OS << "using " << Name << "Action = std::tuple<" << join(ActionTypes, ", ") 312*06f32e7eSjoerg << ">;\n"; 313*06f32e7eSjoerg } 314*06f32e7eSjoerg OS << "\n"; 315*06f32e7eSjoerg 316*06f32e7eSjoerg Emitter.emit(Name, OS); 317*06f32e7eSjoerg } 318*06f32e7eSjoerg 319*06f32e7eSjoerg StringRef Automaton::getActionSymbolType(StringRef A) { 320*06f32e7eSjoerg Twine Ty = "TypeOf_" + A; 321*06f32e7eSjoerg if (!R->getValue(Ty.str())) 322*06f32e7eSjoerg return ""; 323*06f32e7eSjoerg return R->getValueAsString(Ty.str()); 324*06f32e7eSjoerg } 325*06f32e7eSjoerg 326*06f32e7eSjoerg Transition::Transition(Record *R, Automaton *Parent) { 327*06f32e7eSjoerg BitsInit *NewStateInit = R->getValueAsBitsInit("NewState"); 328*06f32e7eSjoerg NewState = 0; 329*06f32e7eSjoerg assert(NewStateInit->getNumBits() <= sizeof(uint64_t) * 8 && 330*06f32e7eSjoerg "State cannot be represented in 64 bits!"); 331*06f32e7eSjoerg for (unsigned I = 0; I < NewStateInit->getNumBits(); ++I) { 332*06f32e7eSjoerg if (auto *Bit = dyn_cast<BitInit>(NewStateInit->getBit(I))) { 333*06f32e7eSjoerg if (Bit->getValue()) 334*06f32e7eSjoerg NewState |= 1ULL << I; 335*06f32e7eSjoerg } 336*06f32e7eSjoerg } 337*06f32e7eSjoerg 338*06f32e7eSjoerg for (StringRef A : Parent->getActionSymbolFields()) { 339*06f32e7eSjoerg RecordVal *SymbolV = R->getValue(A); 340*06f32e7eSjoerg if (auto *Ty = dyn_cast<RecordRecTy>(SymbolV->getType())) { 341*06f32e7eSjoerg Actions.emplace_back(R->getValueAsDef(A), 0, ""); 342*06f32e7eSjoerg Types.emplace_back(Ty->getAsString()); 343*06f32e7eSjoerg } else if (isa<IntRecTy>(SymbolV->getType())) { 344*06f32e7eSjoerg Actions.emplace_back(nullptr, R->getValueAsInt(A), ""); 345*06f32e7eSjoerg Types.emplace_back("unsigned"); 346*06f32e7eSjoerg } else if (isa<StringRecTy>(SymbolV->getType()) || 347*06f32e7eSjoerg isa<CodeRecTy>(SymbolV->getType())) { 348*06f32e7eSjoerg Actions.emplace_back(nullptr, 0, R->getValueAsString(A)); 349*06f32e7eSjoerg Types.emplace_back("std::string"); 350*06f32e7eSjoerg } else { 351*06f32e7eSjoerg report_fatal_error("Unhandled symbol type!"); 352*06f32e7eSjoerg } 353*06f32e7eSjoerg 354*06f32e7eSjoerg StringRef TypeOverride = Parent->getActionSymbolType(A); 355*06f32e7eSjoerg if (!TypeOverride.empty()) 356*06f32e7eSjoerg Types.back() = TypeOverride; 357*06f32e7eSjoerg } 358*06f32e7eSjoerg } 359*06f32e7eSjoerg 360*06f32e7eSjoerg bool Transition::canTransitionFrom(uint64_t State) { 361*06f32e7eSjoerg if ((State & NewState) == 0) 362*06f32e7eSjoerg // The bits we want to set are not set; 363*06f32e7eSjoerg return true; 364*06f32e7eSjoerg return false; 365*06f32e7eSjoerg } 366*06f32e7eSjoerg 367*06f32e7eSjoerg uint64_t Transition::transitionFrom(uint64_t State) { 368*06f32e7eSjoerg return State | NewState; 369*06f32e7eSjoerg } 370*06f32e7eSjoerg 371*06f32e7eSjoerg void CustomDfaEmitter::printActionType(raw_ostream &OS) { OS << TypeName; } 372*06f32e7eSjoerg 373*06f32e7eSjoerg void CustomDfaEmitter::printActionValue(action_type A, raw_ostream &OS) { 374*06f32e7eSjoerg const ActionTuple &AT = Actions[A]; 375*06f32e7eSjoerg if (AT.size() > 1) 376*06f32e7eSjoerg OS << "std::make_tuple("; 377*06f32e7eSjoerg bool First = true; 378*06f32e7eSjoerg for (const auto &SingleAction : AT) { 379*06f32e7eSjoerg if (!First) 380*06f32e7eSjoerg OS << ", "; 381*06f32e7eSjoerg First = false; 382*06f32e7eSjoerg SingleAction.print(OS); 383*06f32e7eSjoerg } 384*06f32e7eSjoerg if (AT.size() > 1) 385*06f32e7eSjoerg OS << ")"; 386*06f32e7eSjoerg } 387*06f32e7eSjoerg 388*06f32e7eSjoerg namespace llvm { 389*06f32e7eSjoerg 390*06f32e7eSjoerg void EmitAutomata(RecordKeeper &RK, raw_ostream &OS) { 391*06f32e7eSjoerg AutomatonEmitter(RK).run(OS); 392*06f32e7eSjoerg } 393*06f32e7eSjoerg 394*06f32e7eSjoerg } // namespace llvm 395