1 //===--- GLR.cpp   -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang-pseudo/GLR.h"
10 #include "clang-pseudo/Grammar.h"
11 #include "clang-pseudo/LRTable.h"
12 #include "clang/Basic/TokenKinds.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/ErrorHandling.h"
18 #include "llvm/Support/FormatVariadic.h"
19 #include <algorithm>
20 #include <memory>
21 #include <queue>
22 
23 #define DEBUG_TYPE "GLR.cpp"
24 
25 namespace clang {
26 namespace pseudo {
27 
28 using StateID = LRTable::StateID;
29 
30 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const GSS::Node &N) {
31   std::vector<std::string> ParentStates;
32   for (const auto *Parent : N.parents())
33     ParentStates.push_back(llvm::formatv("{0}", Parent->State));
34   OS << llvm::formatv("state {0}, parsed symbol {1}, parents {2}", N.State,
35                       N.Payload->symbol(), llvm::join(ParentStates, ", "));
36   return OS;
37 }
38 
39 const ForestNode &glrParse(const TokenStream &Tokens, const ParseParams &Params,
40                            SymbolID StartSymbol) {
41   llvm::ArrayRef<ForestNode> Terminals = Params.Forest.createTerminals(Tokens);
42   auto &G = Params.G;
43   (void)G;
44   auto &GSS = Params.GSStack;
45 
46   // Lists of active shift, reduce, accept actions.
47   std::vector<ParseStep> PendingShift, PendingReduce, PendingAccept;
48   auto AddSteps = [&](const GSS::Node *Head, SymbolID NextTok) {
49     for (const auto &Action : Params.Table.getActions(Head->State, NextTok)) {
50       switch (Action.kind()) {
51       case LRTable::Action::Shift:
52         PendingShift.push_back({Head, Action});
53         break;
54       case LRTable::Action::Reduce:
55         PendingReduce.push_back({Head, Action});
56         break;
57       case LRTable::Action::Accept:
58         PendingAccept.push_back({Head, Action});
59         break;
60       default:
61         llvm_unreachable("unexpected action kind!");
62       }
63     }
64   };
65   std::vector<const GSS::Node *> NewHeads = {
66       GSS.addNode(/*State=*/Params.Table.getStartState(StartSymbol),
67                   /*ForestNode=*/nullptr, {})};
68   for (const ForestNode &Terminal : Terminals) {
69     LLVM_DEBUG(llvm::dbgs() << llvm::formatv("Next token {0} (id={1})\n",
70                                              G.symbolName(Terminal.symbol()),
71                                              Terminal.symbol()));
72     for (const auto *Head : NewHeads)
73       AddSteps(Head, Terminal.symbol());
74     NewHeads.clear();
75     glrReduce(PendingReduce, Params,
76               [&](const GSS::Node * NewHead) {
77                 // A reduce will enable more steps.
78                 AddSteps(NewHead, Terminal.symbol());
79               });
80 
81     glrShift(PendingShift, Terminal, Params,
82              [&](const GSS::Node *NewHead) { NewHeads.push_back(NewHead); });
83   }
84   LLVM_DEBUG(llvm::dbgs() << llvm::formatv("Next is eof\n"));
85   for (const auto *Heads : NewHeads)
86     AddSteps(Heads, tokenSymbol(tok::eof));
87   glrReduce(PendingReduce, Params,
88             [&](const GSS::Node * NewHead) {
89               // A reduce will enable more steps.
90               AddSteps(NewHead, tokenSymbol(tok::eof));
91             });
92 
93   if (!PendingAccept.empty()) {
94     LLVM_DEBUG({
95       llvm::dbgs() << llvm::formatv("Accept: {0} accepted result:\n",
96                                              PendingAccept.size());
97       for (const auto &Accept : PendingAccept)
98         llvm::dbgs() << "  - " << G.symbolName(Accept.Head->Payload->symbol())
99                      << "\n";
100     });
101     assert(PendingAccept.size() == 1);
102     return *PendingAccept.front().Head->Payload;
103   }
104   // We failed to parse the input, returning an opaque forest node for recovery.
105   return Params.Forest.createOpaque(StartSymbol, /*Token::Index=*/0);
106 }
107 
108 // Apply all pending shift actions.
109 // In theory, LR parsing doesn't have shift/shift conflicts on a single head.
110 // But we may have multiple active heads, and each head has a shift action.
111 //
112 // We merge the stack -- if multiple heads will reach the same state after
113 // shifting a token, we shift only once by combining these heads.
114 //
115 // E.g. we have two heads (2, 3) in the GSS, and will shift both to reach 4:
116 //   0---1---2
117 //       └---3
118 // After the shift action, the GSS is:
119 //   0---1---2---4
120 //       └---3---┘
121 void glrShift(std::vector<ParseStep> &PendingShift, const ForestNode &NewTok,
122               const ParseParams &Params, NewHeadCallback NewHeadCB) {
123   assert(NewTok.kind() == ForestNode::Terminal);
124   assert(llvm::all_of(PendingShift,
125                       [](const ParseStep &Step) {
126                         return Step.Action.kind() == LRTable::Action::Shift;
127                       }) &&
128          "Pending shift actions must be shift actions");
129   LLVM_DEBUG(llvm::dbgs() << llvm::formatv("  Shift {0} ({1} active heads):\n",
130                                            Params.G.symbolName(NewTok.symbol()),
131                                            PendingShift.size()));
132 
133   // We group pending shifts by their target state so we can merge them.
134   llvm::stable_sort(PendingShift, [](const ParseStep &L, const ParseStep &R) {
135     return L.Action.getShiftState() < R.Action.getShiftState();
136   });
137   auto Rest = llvm::makeArrayRef(PendingShift);
138   llvm::SmallVector<const GSS::Node *> Parents;
139   while (!Rest.empty()) {
140     // Collect the batch of PendingShift that have compatible shift states.
141     // Their heads become TempParents, the parents of the new GSS node.
142     StateID NextState = Rest.front().Action.getShiftState();
143 
144     Parents.clear();
145     for (const auto &Base : Rest) {
146       if (Base.Action.getShiftState() != NextState)
147         break;
148       Parents.push_back(Base.Head);
149     }
150     Rest = Rest.drop_front(Parents.size());
151 
152     LLVM_DEBUG(llvm::dbgs() << llvm::formatv("    --> S{0} ({1} heads)\n",
153                                              NextState, Parents.size()));
154     NewHeadCB(Params.GSStack.addNode(NextState, &NewTok, Parents));
155   }
156   PendingShift.clear();
157 }
158 
159 namespace {
160 // A KeyedQueue yields pairs of keys and values in order of the keys.
161 template <typename Key, typename Value>
162 using KeyedQueue =
163     std::priority_queue<std::pair<Key, Value>,
164                         std::vector<std::pair<Key, Value>>, llvm::less_first>;
165 
166 template <typename T> void sortAndUnique(std::vector<T> &Vec) {
167   llvm::sort(Vec);
168   Vec.erase(std::unique(Vec.begin(), Vec.end()), Vec.end());
169 }
170 } // namespace
171 
172 // Perform reduces until no more are possible.
173 //
174 // Generally this means walking up from the heads gathering ForestNodes that
175 // will match the RHS of the rule we're reducing into a sequence ForestNode,
176 // and ending up at a base node.
177 // Then we push a new GSS node onto that base, taking care to:
178 //  - pack alternative sequence ForestNodes into an ambiguous ForestNode.
179 //  - use the same GSS node for multiple heads if the parse state matches.
180 //
181 // Examples of reduction:
182 //   Before (simple):
183 //     0--1(expr)--2(semi)
184 //   After reducing 2 by `stmt := expr semi`:
185 //     0--3(stmt)                // 3 is goto(0, stmt)
186 //
187 //   Before (splitting due to R/R conflict):
188 //     0--1(IDENTIFIER)
189 //   After reducing 1 by `class-name := IDENTIFIER` & `enum-name := IDENTIFIER`:
190 //     0--2(class-name)          // 2 is goto(0, class-name)
191 //     └--3(enum-name)           // 3 is goto(0, enum-name)
192 //
193 //   Before (splitting due to multiple bases):
194 //     0--2(class-name)--4(STAR)
195 //     └--3(enum-name)---┘
196 //   After reducing 4 by `ptr-operator := STAR`:
197 //     0--2(class-name)--5(ptr-operator)    // 5 is goto(2, ptr-operator)
198 //     └--3(enum-name)---6(ptr-operator)    // 6 is goto(3, ptr-operator)
199 //
200 //   Before (joining due to same goto state, multiple bases):
201 //     0--1(cv-qualifier)--3(class-name)
202 //     └--2(cv-qualifier)--4(enum-name)
203 //   After reducing 3 by `type-name := class-name` and
204 //                  4 by `type-name := enum-name`:
205 //     0--1(cv-qualifier)--5(type-name)  // 5 is goto(1, type-name) and
206 //     └--2(cv-qualifier)--┘             //      goto(2, type-name)
207 //
208 //   Before (joining due to same goto state, the same base):
209 //     0--1(class-name)--3(STAR)
210 //     └--2(enum-name)--4(STAR)
211 //   After reducing 3 by `pointer := class-name STAR` and
212 //                  2 by`enum-name := class-name STAR`:
213 //     0--5(pointer)       // 5 is goto(0, pointer)
214 void glrReduce(std::vector<ParseStep> &PendingReduce, const ParseParams &Params,
215                NewHeadCallback NewHeadCB) {
216   // There are two interacting complications:
217   // 1.  Performing one reduce can unlock new reduces on the newly-created head.
218   // 2a. The ambiguous ForestNodes must be complete (have all sequence nodes).
219   //     This means we must have unlocked all the reduces that contribute to it.
220   // 2b. Similarly, the new GSS nodes must be complete (have all parents).
221   //
222   // We define a "family" of reduces as those that produce the same symbol and
223   // cover the same range of tokens. These are exactly the set of reductions
224   // whose sequence nodes would be covered by the same ambiguous node.
225   // We wish to process a whole family at a time (to satisfy complication 2),
226   // and can address complication 1 by carefully ordering the families:
227   // - Process families covering fewer tokens first.
228   //   A reduce can't depend on a longer reduce!
229   // - For equal token ranges: if S := T, process T families before S families.
230   //   Parsing T can't depend on an equal-length S, as the grammar is acyclic.
231   //
232   // This isn't quite enough: we don't know the token length of the reduction
233   // until we walk up the stack to perform the pop.
234   // So we perform the pop part upfront, and place the push specification on
235   // priority queues such that we can retrieve a family at a time.
236 
237   // A reduction family is characterized by its token range and symbol produced.
238   // It is used as a key in the priority queues to group pushes by family.
239   struct Family {
240     // The start of the token range of the reduce.
241     Token::Index Start;
242     SymbolID Symbol;
243     // Rule must produce Symbol and can otherwise be arbitrary.
244     // RuleIDs have the topological order based on the acyclic grammar.
245     // FIXME: should SymbolIDs be so ordered instead?
246     RuleID Rule;
247 
248     bool operator==(const Family &Other) const {
249       return Start == Other.Start && Symbol == Other.Symbol;
250     }
251     // The larger Family is the one that should be processed first.
252     bool operator<(const Family &Other) const {
253       if (Start != Other.Start)
254         return Start < Other.Start;
255       if (Symbol != Other.Symbol)
256         return Rule > Other.Rule;
257       assert(*this == Other);
258       return false;
259     }
260   };
261 
262   // The base nodes are the heads after popping the GSS nodes we are reducing.
263   // We don't care which rule yielded each base. If Family.Symbol is S, the
264   // base includes an item X := ... • S ... and since the grammar is
265   // context-free, *all* parses of S are valid here.
266   // FIXME: reuse the queues across calls instead of reallocating.
267   KeyedQueue<Family, const GSS::Node *> Bases;
268 
269   // A sequence is the ForestNode payloads of the GSS nodes we are reducing.
270   // These are the RHS of the rule, the RuleID is stored in the Family.
271   // They specify a sequence ForestNode we may build (but we dedup first).
272   using Sequence = llvm::SmallVector<const ForestNode *, Rule::MaxElements>;
273   KeyedQueue<Family, Sequence> Sequences;
274 
275   Sequence TempSequence;
276   // Pop walks up the parent chain(s) for a reduction from Head by to Rule.
277   // Once we reach the end, record the bases and sequences.
278   auto Pop = [&](const GSS::Node *Head, RuleID RID) {
279     LLVM_DEBUG(llvm::dbgs() << "  Pop " << Params.G.dumpRule(RID) << "\n");
280     const auto &Rule = Params.G.lookupRule(RID);
281     Family F{/*Start=*/0, /*Symbol=*/Rule.Target, /*Rule=*/RID};
282     TempSequence.resize_for_overwrite(Rule.Size);
283     auto DFS = [&](const GSS::Node *N, unsigned I, auto &DFS) {
284       if (I == Rule.Size) {
285         F.Start = TempSequence.front()->startTokenIndex();
286         Bases.emplace(F, N);
287         LLVM_DEBUG(llvm::dbgs() << "    --> base at S" << N->State << "\n");
288         Sequences.emplace(F, TempSequence);
289         return;
290       }
291       TempSequence[Rule.Size - 1 - I] = N->Payload;
292       for (const GSS::Node *Parent : N->parents())
293         DFS(Parent, I + 1, DFS);
294     };
295     DFS(Head, 0, DFS);
296   };
297   auto PopPending = [&] {
298     for (const ParseStep &Pending : PendingReduce)
299       Pop(Pending.Head, Pending.Action.getReduceRule());
300     PendingReduce.clear();
301   };
302 
303   std::vector<std::pair</*Goto*/ StateID, const GSS::Node *>> FamilyBases;
304   std::vector<std::pair<RuleID, Sequence>> FamilySequences;
305 
306   std::vector<const GSS::Node *> TempGSSNodes;
307   std::vector<const ForestNode *> TempForestNodes;
308 
309   // Main reduction loop:
310   //  - pop as much as we can
311   //  - process one family at a time, forming a forest node
312   //  - produces new GSS heads which may enable more pops
313   PopPending();
314   while (!Bases.empty()) {
315     // We should always have bases and sequences for the same families.
316     Family F = Bases.top().first;
317     assert(!Sequences.empty());
318     assert(Sequences.top().first == F);
319 
320     LLVM_DEBUG(llvm::dbgs() << "  Push " << Params.G.symbolName(F.Symbol)
321                             << " from token " << F.Start << "\n");
322 
323     // Grab the sequences for this family.
324     FamilySequences.clear();
325     do {
326       FamilySequences.emplace_back(Sequences.top().first.Rule,
327                                    Sequences.top().second);
328       Sequences.pop();
329     } while (!Sequences.empty() && Sequences.top().first == F);
330     // Build a forest node for each unique sequence.
331     sortAndUnique(FamilySequences);
332     auto &SequenceNodes = TempForestNodes;
333     SequenceNodes.clear();
334     for (const auto &SequenceSpec : FamilySequences)
335       SequenceNodes.push_back(&Params.Forest.createSequence(
336           F.Symbol, SequenceSpec.first, SequenceSpec.second));
337     // Wrap in an ambiguous node if needed.
338     const ForestNode *Parsed =
339         SequenceNodes.size() == 1
340             ? SequenceNodes.front()
341             : &Params.Forest.createAmbiguous(F.Symbol, SequenceNodes);
342     LLVM_DEBUG(llvm::dbgs() << "    --> " << Parsed->dump(Params.G) << "\n");
343 
344     // Grab the bases for this family.
345     // As well as deduplicating them, we'll group by the goto state.
346     FamilyBases.clear();
347     do {
348       FamilyBases.emplace_back(
349           Params.Table.getGoToState(Bases.top().second->State, F.Symbol),
350           Bases.top().second);
351       Bases.pop();
352     } while (!Bases.empty() && Bases.top().first == F);
353     sortAndUnique(FamilyBases);
354     // Create a GSS node for each unique goto state.
355     llvm::ArrayRef<decltype(FamilyBases)::value_type> BasesLeft = FamilyBases;
356     while (!BasesLeft.empty()) {
357       StateID NextState = BasesLeft.front().first;
358       auto &Parents = TempGSSNodes;
359       Parents.clear();
360       for (const auto &Base : BasesLeft) {
361         if (Base.first != NextState)
362           break;
363         Parents.push_back(Base.second);
364       }
365       BasesLeft = BasesLeft.drop_front(Parents.size());
366 
367       // Invoking the callback for new heads, a real GLR parser may add new
368       // reduces to the PendingReduce queue!
369       NewHeadCB(Params.GSStack.addNode(NextState, Parsed, Parents));
370     }
371     PopPending();
372   }
373   assert(Sequences.empty());
374 }
375 
376 } // namespace pseudo
377 } // namespace clang
378