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