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