1cd2292efSHaojian Wu //===--- LRTableBuild.cpp - Build a LRTable from LRGraph ---------*- C++-*-===//
2cd2292efSHaojian Wu //
3cd2292efSHaojian Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cd2292efSHaojian Wu // See https://llvm.org/LICENSE.txt for license information.
5cd2292efSHaojian Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cd2292efSHaojian Wu //
7cd2292efSHaojian Wu //===----------------------------------------------------------------------===//
8cd2292efSHaojian Wu 
9c70aeaadSHaojian Wu #include "clang-pseudo/grammar/Grammar.h"
10c70aeaadSHaojian Wu #include "clang-pseudo/grammar/LRGraph.h"
11c70aeaadSHaojian Wu #include "clang-pseudo/grammar/LRTable.h"
12cd2292efSHaojian Wu #include "clang/Basic/TokenKinds.h"
13*aba43035SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
1485eaecbeSSam McCall #include "llvm/ADT/SmallSet.h"
15cd2292efSHaojian Wu #include <cstdint>
16cd2292efSHaojian Wu 
17cd2292efSHaojian Wu namespace clang {
18cd2292efSHaojian Wu namespace pseudo {
19cd2292efSHaojian Wu 
build()209fbf1107SSam McCall LRTable LRTable::Builder::build() && {
219fbf1107SSam McCall   assert(NumNonterminals != 0 && "Set NumNonterminals or init with grammar");
22cd2292efSHaojian Wu   LRTable Table;
239fbf1107SSam McCall 
249fbf1107SSam McCall   // Count number of states: every state has to be reachable somehow.
259fbf1107SSam McCall   StateID MaxState = 0;
269fbf1107SSam McCall   for (const auto &Entry : StartStates)
279fbf1107SSam McCall     MaxState = std::max(MaxState, Entry.second);
289fbf1107SSam McCall   for (const auto &Entry : Transition)
299fbf1107SSam McCall     MaxState = std::max(MaxState, Entry.second);
309fbf1107SSam McCall   unsigned NumStates = MaxState + 1;
319fbf1107SSam McCall 
32cd2292efSHaojian Wu   Table.StartStates = std::move(StartStates);
3385eaecbeSSam McCall 
34b37dafd5SSam McCall   // Compile the goto and shift actions into transition tables.
35b37dafd5SSam McCall   llvm::DenseMap<unsigned, SymbolID> Gotos;
36b37dafd5SSam McCall   llvm::DenseMap<unsigned, SymbolID> Shifts;
379fbf1107SSam McCall   for (const auto &E : Transition) {
389fbf1107SSam McCall     if (isToken(E.first.second))
399fbf1107SSam McCall       Shifts.try_emplace(shiftIndex(E.first.first, E.first.second, NumStates),
409fbf1107SSam McCall                          E.second);
419fbf1107SSam McCall     else
429fbf1107SSam McCall       Gotos.try_emplace(gotoIndex(E.first.first, E.first.second, NumStates),
439fbf1107SSam McCall                         E.second);
44b37dafd5SSam McCall   }
45b37dafd5SSam McCall   Table.Shifts = TransitionTable(Shifts, NumStates * NumTerminals);
46b37dafd5SSam McCall   Table.Gotos = TransitionTable(Gotos, NumStates * NumNonterminals);
47b37dafd5SSam McCall 
4885eaecbeSSam McCall   // Compile the follow sets into a bitmap.
4985eaecbeSSam McCall   Table.FollowSets.resize(tok::NUM_TOKENS * FollowSets.size());
5085eaecbeSSam McCall   for (SymbolID NT = 0; NT < FollowSets.size(); ++NT)
5185eaecbeSSam McCall     for (SymbolID Follow : FollowSets[NT])
5285eaecbeSSam McCall       Table.FollowSets.set(NT * tok::NUM_TOKENS + symbolToToken(Follow));
5385eaecbeSSam McCall 
5485eaecbeSSam McCall   // Store the reduce actions in a vector partitioned by state.
5585eaecbeSSam McCall   Table.ReduceOffset.reserve(NumStates + 1);
5685eaecbeSSam McCall   std::vector<RuleID> StateRules;
5785eaecbeSSam McCall   for (StateID S = 0; S < NumStates; ++S) {
5885eaecbeSSam McCall     Table.ReduceOffset.push_back(Table.Reduces.size());
599fbf1107SSam McCall     auto It = Reduce.find(S);
609fbf1107SSam McCall     if (It == Reduce.end())
6185eaecbeSSam McCall       continue;
6285eaecbeSSam McCall     Table.Reduces.insert(Table.Reduces.end(), It->second.begin(),
6385eaecbeSSam McCall                          It->second.end());
64*aba43035SDmitri Gribenko     llvm::sort(Table.Reduces.begin() + Table.ReduceOffset.back(),
6585eaecbeSSam McCall                Table.Reduces.end());
6685eaecbeSSam McCall   }
6785eaecbeSSam McCall   Table.ReduceOffset.push_back(Table.Reduces.size());
6885eaecbeSSam McCall 
6931211674SSam McCall   // Error recovery entries: sort (no dups already), and build offset lookup.
7031211674SSam McCall   llvm::sort(Recoveries, [&](const auto &L, const auto &R) {
7131211674SSam McCall     return std::tie(L.first, L.second.Result, L.second.Strategy) <
7231211674SSam McCall            std::tie(R.first, R.second.Result, R.second.Strategy);
7331211674SSam McCall   });
7431211674SSam McCall   Table.Recoveries.reserve(Recoveries.size());
7531211674SSam McCall   for (const auto &R : Recoveries)
7631211674SSam McCall     Table.Recoveries.push_back({R.second.Strategy, R.second.Result});
7731211674SSam McCall   Table.RecoveryOffset = std::vector<uint32_t>(NumStates + 1, 0);
7831211674SSam McCall   unsigned SortedIndex = 0;
7931211674SSam McCall   for (StateID State = 0; State < NumStates; ++State) {
8031211674SSam McCall     Table.RecoveryOffset[State] = SortedIndex;
8131211674SSam McCall     while (SortedIndex < Recoveries.size() &&
8231211674SSam McCall            Recoveries[SortedIndex].first == State)
8331211674SSam McCall       SortedIndex++;
8431211674SSam McCall   }
8531211674SSam McCall   Table.RecoveryOffset[NumStates] = SortedIndex;
8631211674SSam McCall   assert(SortedIndex == Recoveries.size());
8731211674SSam McCall 
88cd2292efSHaojian Wu   return Table;
89cd2292efSHaojian Wu }
90cd2292efSHaojian Wu 
buildSLR(const Grammar & G)91cd2292efSHaojian Wu LRTable LRTable::buildSLR(const Grammar &G) {
92cd2292efSHaojian Wu   auto Graph = LRGraph::buildLR0(G);
939fbf1107SSam McCall   Builder Build(G);
9485eaecbeSSam McCall   Build.StartStates = Graph.startStates();
959fbf1107SSam McCall   for (const auto &T : Graph.edges())
969fbf1107SSam McCall     Build.Transition.try_emplace({T.Src, T.Label}, T.Dst);
9731211674SSam McCall   for (const auto &Entry : Graph.recoveries())
9831211674SSam McCall     Build.Recoveries.push_back(
9931211674SSam McCall         {Entry.Src, Recovery{Entry.Strategy, Entry.Result}});
10031211674SSam McCall   Build.FollowSets = followSets(G);
101cd2292efSHaojian Wu   assert(Graph.states().size() <= (1 << StateBits) &&
102cd2292efSHaojian Wu          "Graph states execceds the maximum limit!");
10385eaecbeSSam McCall   // Add reduce actions.
104cd2292efSHaojian Wu   for (StateID SID = 0; SID < Graph.states().size(); ++SID) {
105cd2292efSHaojian Wu     for (const Item &I : Graph.states()[SID].Items) {
1067a05942dSHaojian Wu       // If we've just parsed the start symbol, this means we successfully parse
1077a05942dSHaojian Wu       // the input. We don't add the reduce action of `_ := start_symbol` in the
1087a05942dSHaojian Wu       // LRTable (the GLR parser handles it specifically).
1097a05942dSHaojian Wu       if (G.lookupRule(I.rule()).Target == G.underscore() && !I.hasNext())
110cd2292efSHaojian Wu         continue;
11185eaecbeSSam McCall       if (!I.hasNext())
112cd2292efSHaojian Wu         // If we've reached the end of a rule A := ..., then we can reduce if
113cd2292efSHaojian Wu         // the next token is in the follow set of A.
1149fbf1107SSam McCall         Build.Reduce[SID].insert(I.rule());
115cd2292efSHaojian Wu     }
116cd2292efSHaojian Wu   }
1179fbf1107SSam McCall   return std::move(Build).build();
118cd2292efSHaojian Wu }
119cd2292efSHaojian Wu 
120cd2292efSHaojian Wu } // namespace pseudo
121cd2292efSHaojian Wu } // namespace clang
122