Coverage Report

Created: 2024-01-17 10:31

/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