• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rieske / trans / 29698450533

19 Jul 2026 06:17PM UTC coverage: 90.744% (+0.2%) from 90.53%
29698450533

Pull #46

github

rieske
Experimental parser generator optimization
Pull Request #46: Experimental parser generator optimization

494 of 504 new or added lines in 17 files covered. (98.02%)

1 existing line in 1 file now uncovered.

5284 of 5823 relevant lines covered (90.74%)

309085.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.97
/src/parser/Grammar.cpp
1
#include "Grammar.h"
2

3
#include <algorithm>
4
#include <sstream>
5

6
#include "scanner/Token.h"
7

8
namespace parser {
9

10
Grammar::Grammar(std::map<std::string, int> symbolIDs,
452✔
11
        std::vector<int> terminals,
12
        std::vector<int> nonterminals,
13
        std::vector<Production> rules):
452✔
14
    symbolIDs{std::move(symbolIDs)},
452✔
15
    nonterminalIDs{std::move(nonterminals)},
452✔
16
    terminalIDs{std::move(terminals)},
452✔
17
    startSymbol { -1 },
452✔
18
    endSymbol { 0 },
452✔
19
    topRule{startSymbol, {nonterminalIDs[0]}, static_cast<int>(rules.size())}
1,356✔
20
{
21
    int maxId = 0;
452✔
22
    for (const auto& entry : this->symbolIDs) {
61,686✔
23
        maxId = std::max(maxId, entry.second);
61,234✔
24
    }
25
    endSymbol = maxId + 1;
452✔
26

27
    this->symbolIDs.insert({"<__start__>", startSymbol});
452✔
28
    this->symbolIDs.insert({scanner::Token::END, endSymbol});
452✔
29

30
    firstTerminalId = this->terminalIDs.empty() ? endSymbol : this->terminalIDs[0];
452✔
31
    this->terminalIDs.push_back(endSymbol);
452✔
32

33
    rules.push_back(topRule);
452✔
34
    for (const auto& production: rules) {
96,282✔
35
        rulesByDefiningSymbol.insert({production.getDefiningSymbol(), {}}).first->second.push_back(production);
95,830✔
36
        rulesById.insert({production.getId(), production});
95,830✔
37
    }
38

39
    idToTerminalBit_.fill(-1);
452✔
40
    terminalBitToId_.reserve(this->terminalIDs.size());
452✔
41
    for (const int terminalId : this->terminalIDs) {
35,264✔
42
        if (terminalId < 0 || static_cast<std::size_t>(terminalId) >= idToTerminalBit_.size()) {
69,632✔
43
            throw std::runtime_error { "terminal symbol id out of mapping range" };
2✔
44
        }
45
        if (idToTerminalBit_[static_cast<std::size_t>(terminalId)] >= 0) {
34,814✔
46
            continue;
2✔
47
        }
48
        if (terminalBitToId_.size() >= LOOKAHEAD_BITSET_SIZE) {
34,812✔
49
            throw std::runtime_error { "too many terminals for lookahead bitset" };
2✔
50
        }
51
        idToTerminalBit_[static_cast<std::size_t>(terminalId)] = static_cast<int>(terminalBitToId_.size());
34,810✔
52
        terminalBitToId_.push_back(terminalId);
34,810✔
53
    }
54
}
476✔
55

56
std::size_t Grammar::ruleCount() const {
410✔
57
    return rulesById.size();
410✔
58
}
59

60
const Production& Grammar::getTopRule() const {
34✔
61
    return topRule;
34✔
62
}
63

64
const Production& Grammar::getRuleById(int index) const {
1,967,622✔
65
    return rulesById.at(index);
1,967,622✔
66
}
67

68
const std::vector<Production>& Grammar::getProductionsOfSymbol(int symbolId) const {
2,042,542✔
69
    return rulesByDefiningSymbol.at(symbolId);
2,042,542✔
70
}
71

72
const std::vector<int>& Grammar::getTerminalIDs() const {
154,474✔
73
    return terminalIDs;
154,474✔
74
}
75

76
const std::vector<int>& Grammar::getNonterminalIDs() const {
732✔
77
    return nonterminalIDs;
732✔
78
}
79

80
int Grammar::getStartSymbol() const {
6✔
81
    return startSymbol;
6✔
82
}
83

84
int Grammar::getEndSymbol() const {
40✔
85
    return endSymbol;
40✔
86
}
87

88
std::string Grammar::getSymbolById(int symbolId) const {
165,414✔
89
    auto symbolIt = std::find_if(symbolIDs.begin(), symbolIDs.end(), [&](const std::pair<std::string, int>& pair) {
165,414✔
90
        return pair.second == symbolId;
11,001,412✔
91
    });
92
    return symbolIt->first;
330,828✔
93
}
94

95
int Grammar::symbolId(std::string definition) const {
177,048✔
96
    return symbolIDs.at(definition);
177,048✔
97
}
98

99
bool Grammar::isTerminal(int symbolId) const {
2,923,256✔
100
    return symbolId >= firstTerminalId;
2,923,256✔
101
}
102

103
int Grammar::terminalBit(int symbolId) const {
2,858✔
104
    if (symbolId < 0 || static_cast<std::size_t>(symbolId) >= idToTerminalBit_.size()) {
5,712✔
105
        throw std::out_of_range { "symbol id out of range for terminal bit map" };
6✔
106
    }
107
    const int bit = idToTerminalBit_[static_cast<std::size_t>(symbolId)];
2,852✔
108
    if (bit < 0) {
2,852✔
109
        throw std::out_of_range { "symbol is not a terminal" };
2✔
110
    }
111
    return bit;
2,850✔
112
}
113

114
int Grammar::terminalIdFromBit(std::size_t bit) const {
39,806✔
115
    return terminalBitToId_.at(bit);
39,806✔
116
}
117

118
LookaheadSet Grammar::toLookaheadBits(const std::vector<int>& symbolIds) const {
38✔
119
    LookaheadSet bits;
38✔
120
    for (const int id : symbolIds) {
76✔
121
        bits.set(static_cast<std::size_t>(terminalBit(id)));
38✔
122
    }
123
    return bits;
38✔
124
}
125

126
std::vector<int> Grammar::toTerminalIds(const LookaheadSet& bits) const {
154✔
127
    std::vector<int> ids;
154✔
128
    ids.reserve(bits.count());
154✔
129
    for (std::size_t bit = 0; bit < terminalBitToId_.size(); ++bit) {
888✔
130
        if (bits.test(bit)) {
734✔
131
            ids.push_back(terminalBitToId_[bit]);
258✔
132
        }
133
    }
134
    return ids;
154✔
NEW
135
}
×
136

137
std::string Grammar::str(int symbolId) const {
60,744✔
138
    return getSymbolById(symbolId);
60,744✔
139
}
140

141
std::string Grammar::str(const Production& production) const {
32✔
142
    std::stringstream s;
32✔
143
    s << str(production.getDefiningSymbol()) << " ::= ";
32✔
144
    for (const auto& symbol: production) {
88✔
145
        s << str(symbol) << " ";
56✔
146
    }
147
    auto productionStr = s.str();
32✔
148
    return productionStr.substr(0, productionStr.length()-1);
64✔
149
}
32✔
150

151
std::ostream& operator<<(std::ostream& out, const Grammar& grammar) {
404✔
152
    out << "\nTerminals:\n";
404✔
153
    for (auto& terminal : grammar.getTerminalIDs()) {
34,200✔
154
        out << terminal << ":" << grammar.str(terminal) << "\n";
33,796✔
155
    }
156
    out << "\nNonterminals:\n";
404✔
157
    for (auto& nonterminal : grammar.getNonterminalIDs()) {
26,720✔
158
        out << nonterminal << ":" << grammar.str(nonterminal) << "\n";
26,316✔
159
    }
160
    out << "\nRules total: " << grammar.ruleCount() << "\n";
404✔
161
    return out;
404✔
162
}
163

164
} // namespace parser
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc