/src/llvm-project/clang-tools-extra/pseudo/lib/grammar/LRTableBuild.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- LRTableBuild.cpp - Build a LRTable from LRGraph ---------*- 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/grammar/Grammar.h" |
10 | | #include "clang-pseudo/grammar/LRGraph.h" |
11 | | #include "clang-pseudo/grammar/LRTable.h" |
12 | | #include "clang/Basic/TokenKinds.h" |
13 | | #include "llvm/ADT/STLExtras.h" |
14 | | #include "llvm/ADT/SmallSet.h" |
15 | | #include <cstdint> |
16 | | |
17 | | namespace clang { |
18 | | namespace pseudo { |
19 | | |
20 | 1 | LRTable LRTable::Builder::build() && { |
21 | 1 | assert(NumNonterminals != 0 && "Set NumNonterminals or init with grammar"); |
22 | 0 | LRTable Table; |
23 | | |
24 | | // Count number of states: every state has to be reachable somehow. |
25 | 1 | StateID MaxState = 0; |
26 | 1 | for (const auto &Entry : StartStates) |
27 | 3 | MaxState = std::max(MaxState, Entry.second); |
28 | 1 | for (const auto &Entry : Transition) |
29 | 27.1k | MaxState = std::max(MaxState, Entry.second); |
30 | 1 | unsigned NumStates = MaxState + 1; |
31 | | |
32 | 1 | Table.StartStates = std::move(StartStates); |
33 | | |
34 | | // Compile the goto and shift actions into transition tables. |
35 | 1 | llvm::DenseMap<unsigned, SymbolID> Gotos; |
36 | 1 | llvm::DenseMap<unsigned, SymbolID> Shifts; |
37 | 27.1k | for (const auto &E : Transition) { |
38 | 27.1k | if (isToken(E.first.second)) |
39 | 13.4k | Shifts.try_emplace(shiftIndex(E.first.first, E.first.second, NumStates), |
40 | 13.4k | E.second); |
41 | 13.6k | else |
42 | 13.6k | Gotos.try_emplace(gotoIndex(E.first.first, E.first.second, NumStates), |
43 | 13.6k | E.second); |
44 | 27.1k | } |
45 | 1 | Table.Shifts = TransitionTable(Shifts, NumStates * NumTerminals); |
46 | 1 | Table.Gotos = TransitionTable(Gotos, NumStates * NumNonterminals); |
47 | | |
48 | | // Compile the follow sets into a bitmap. |
49 | 1 | Table.FollowSets.resize(tok::NUM_TOKENS * FollowSets.size()); |
50 | 244 | for (SymbolID NT = 0; NT < FollowSets.size(); ++NT) |
51 | 243 | for (SymbolID Follow : FollowSets[NT]) |
52 | 10.6k | Table.FollowSets.set(NT * tok::NUM_TOKENS + symbolToToken(Follow)); |
53 | | |
54 | | // Store the reduce actions in a vector partitioned by state. |
55 | 1 | Table.ReduceOffset.reserve(NumStates + 1); |
56 | 1 | std::vector<RuleID> StateRules; |
57 | 1.47k | for (StateID S = 0; S < NumStates; ++S) { |
58 | 1.47k | Table.ReduceOffset.push_back(Table.Reduces.size()); |
59 | 1.47k | auto It = Reduce.find(S); |
60 | 1.47k | if (It == Reduce.end()) |
61 | 528 | continue; |
62 | 948 | Table.Reduces.insert(Table.Reduces.end(), It->second.begin(), |
63 | 948 | It->second.end()); |
64 | 948 | llvm::sort(Table.Reduces.begin() + Table.ReduceOffset.back(), |
65 | 948 | Table.Reduces.end()); |
66 | 948 | } |
67 | 1 | Table.ReduceOffset.push_back(Table.Reduces.size()); |
68 | | |
69 | | // Error recovery entries: sort (no dups already), and build offset lookup. |
70 | 5 | llvm::sort(Recoveries, [&](const auto &L, const auto &R) { |
71 | 5 | return std::tie(L.first, L.second.Result, L.second.Strategy) < |
72 | 5 | std::tie(R.first, R.second.Result, R.second.Strategy); |
73 | 5 | }); |
74 | 1 | Table.Recoveries.reserve(Recoveries.size()); |
75 | 1 | for (const auto &R : Recoveries) |
76 | 6 | Table.Recoveries.push_back({R.second.Strategy, R.second.Result}); |
77 | 1 | Table.RecoveryOffset = std::vector<uint32_t>(NumStates + 1, 0); |
78 | 1 | unsigned SortedIndex = 0; |
79 | 1.47k | for (StateID State = 0; State < NumStates; ++State) { |
80 | 1.47k | Table.RecoveryOffset[State] = SortedIndex; |
81 | 1.48k | while (SortedIndex < Recoveries.size() && |
82 | 1.48k | Recoveries[SortedIndex].first == State) |
83 | 6 | SortedIndex++; |
84 | 1.47k | } |
85 | 1 | Table.RecoveryOffset[NumStates] = SortedIndex; |
86 | 1 | assert(SortedIndex == Recoveries.size()); |
87 | | |
88 | 0 | return Table; |
89 | 1 | } |
90 | | |
91 | 1 | LRTable LRTable::buildSLR(const Grammar &G) { |
92 | 1 | auto Graph = LRGraph::buildLR0(G); |
93 | 1 | Builder Build(G); |
94 | 1 | Build.StartStates = Graph.startStates(); |
95 | 1 | for (const auto &T : Graph.edges()) |
96 | 27.1k | Build.Transition.try_emplace({T.Src, T.Label}, T.Dst); |
97 | 1 | for (const auto &Entry : Graph.recoveries()) |
98 | 6 | Build.Recoveries.push_back( |
99 | 6 | {Entry.Src, Recovery{Entry.Strategy, Entry.Result}}); |
100 | 1 | Build.FollowSets = followSets(G); |
101 | 1 | assert(Graph.states().size() <= (1 << StateBits) && |
102 | 1 | "Graph states execceds the maximum limit!"); |
103 | | // Add reduce actions. |
104 | 1.47k | for (StateID SID = 0; SID < Graph.states().size(); ++SID) { |
105 | 52.2k | for (const Item &I : Graph.states()[SID].Items) { |
106 | | // If we've just parsed the start symbol, this means we successfully parse |
107 | | // the input. We don't add the reduce action of `_ := start_symbol` in the |
108 | | // LRTable (the GLR parser handles it specifically). |
109 | 52.2k | if (G.lookupRule(I.rule()).Target == G.underscore() && !I.hasNext()) |
110 | 3 | continue; |
111 | 52.2k | if (!I.hasNext()) |
112 | | // If we've reached the end of a rule A := ..., then we can reduce if |
113 | | // the next token is in the follow set of A. |
114 | 1.05k | Build.Reduce[SID].insert(I.rule()); |
115 | 52.2k | } |
116 | 1.47k | } |
117 | 1 | return std::move(Build).build(); |
118 | 1 | } |
119 | | |
120 | | } // namespace pseudo |
121 | | } // namespace clang |