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