Rename next_{terminals,non_terminals} to first_set and follow_sets

This is to prepare for keeping track of lookahead symbols as part
of computing follow sets
This commit is contained in:
Max Brunsfeld 2014-01-19 01:49:56 -08:00
parent 289992344e
commit 1bf216b796
16 changed files with 172 additions and 116 deletions

View file

@ -0,0 +1,53 @@
#include "spec_helper.h"
#include "build_tables/first_set.h"
#include "grammar.h"
#include "rules.h"
using std::set;
using namespace build_tables;
using namespace rules;
START_TEST
describe("computing FIRST sets", []() {
Grammar grammar({
{ "A", choice({
seq({
sym("B"),
sym("x"),
sym("B") }),
sym("B") }) },
{ "B", choice({
seq({
sym("y"),
sym("z"),
sym("y") }),
sym("y") }) },
{ "C", seq({
choice({
sym("x"),
blank() }),
sym("y") }) }
});
describe("for a rule starting with a non-terminal B", [&]() {
it("includes FIRST(B)", [&]() {
auto terminals = first_set(grammar.rules.find("A")->second, grammar);
AssertThat(terminals, Equals(set<Symbol>({
Symbol("y")
})));
});
});
describe("for a sequence xy", [&]() {
it("includes FIRST(y) when x can be blank", [&]() {
auto terminals = first_set(grammar.rules.find("C")->second, grammar);
AssertThat(terminals, Equals(set<Symbol>({
Symbol("x"),
Symbol("y")
})));
});
});
});
END_TEST

View file

@ -1,38 +0,0 @@
#include "spec_helper.h"
#include "build_tables/next_symbols.h"
#include "grammar.h"
#include "rules.h"
using std::set;
using namespace build_tables;
using namespace rules;
START_TEST
describe("computing FIRST sets", []() {
Grammar grammar({
{ "A", choice({
seq({
sym("B"),
sym("x"),
sym("B") }),
sym("B") }) },
{ "B", choice({
seq({
sym("y"),
sym("z"),
sym("y") }),
sym("y") }) },
});
describe("for a rule", [&]() {
it("searches the tree for terminals", [&]() {
auto terminals = next_terminals(grammar.rules.find("A")->second, grammar);
AssertThat(terminals, Equals(set<Symbol>({
Symbol("y")
})));
});
});
});
END_TEST

View file

@ -1,4 +1,4 @@
#include "next_symbols.h"
#include "first_set.h"
#include "rule_transitions.h"
#include "grammar.h"
#include <vector>
@ -35,7 +35,11 @@ namespace tree_sitter {
}
void visit(const Seq *rule) {
value = apply(rule->left, grammar);
if (rule_can_be_blank(rule->left)) {
value = set_union(apply(rule->left, grammar), apply(rule->right, grammar));
} else {
value = apply(rule->left, grammar);
}
}
public:
@ -46,37 +50,14 @@ namespace tree_sitter {
}
};
template<bool isTerminal>
set<rules::Symbol> next_symbols(const rules::rule_ptr &rule, const Grammar &grammar) {
set<rules::Symbol> result;
for (auto pair : rule_transitions(rule)) {
auto symbol = dynamic_pointer_cast<const rules::Symbol>(pair.first);
if (symbol && (grammar.has_definition(*symbol) == !isTerminal))
result.insert(*symbol);
}
return result;
}
set<rules::Symbol> next_terminals(const rules::rule_ptr &rule, const Grammar &grammar) {
set<rules::Symbol> first_set(const rules::rule_ptr &rule, const Grammar &grammar) {
return FirstSetVisitor::apply(rule, grammar);
}
set<rules::Symbol> next_non_terminals(const rules::rule_ptr &rule, const Grammar &grammar) {
return next_symbols<false>(rule, grammar);
}
set<rules::Symbol> next_terminals(const ParseItem &item, const Grammar &grammar) {
return next_terminals(item.rule, grammar);
}
set<rules::Symbol> next_non_terminals(const ParseItem &item, const Grammar &grammar) {
return next_non_terminals(item.rule, grammar);
}
set<rules::Symbol> next_terminals(const ParseItemSet &item_set, const Grammar &grammar) {
set<rules::Symbol> first_set(const ParseItemSet &item_set, const Grammar &grammar) {
set<rules::Symbol> result;
for (auto item : item_set)
for (rules::Symbol symbol : next_terminals(item, grammar))
for (rules::Symbol symbol : first_set(item.rule, grammar))
result.insert(symbol);
return result;
}

View file

@ -0,0 +1,17 @@
#ifndef __tree_sitter__first_set__
#define __tree_sitter__first_set__
#include "item.h"
#include "symbol.h"
#include <set>
namespace tree_sitter {
class Grammar;
namespace build_tables {
std::set<rules::Symbol> first_set(const rules::rule_ptr &rule, const Grammar &grammar);
std::set<rules::Symbol> first_set(const ParseItemSet &item_set, const Grammar &grammar);
}
}
#endif

View file

@ -0,0 +1,29 @@
#include "follow_sets.h"
#include "rule_transitions.h"
#include "grammar.h"
using std::unordered_map;
using std::set;
using std::dynamic_pointer_cast;
using tree_sitter::rules::Symbol;
namespace tree_sitter {
class Grammar;
namespace build_tables {
unordered_map<Symbol, set<Symbol>> follow_sets(const ParseItem &item, const Grammar &grammar) {
unordered_map<Symbol, set<Symbol>> result;
for (auto pair : rule_transitions(item.rule)) {
auto symbol = dynamic_pointer_cast<const rules::Symbol>(pair.first);
if (symbol && grammar.has_definition(*symbol)) {
set<Symbol> following_terminals;
following_terminals.insert(rules::Symbol("__END__"));
result.insert({ *symbol, following_terminals });
}
}
return result;
}
}
}

View file

@ -0,0 +1,17 @@
#ifndef __tree_sitter__follow_sets__
#define __tree_sitter__follow_sets__
#include "item.h"
#include "symbol.h"
#include <set>
#include <unordered_map>
namespace tree_sitter {
class Grammar;
namespace build_tables {
std::unordered_map<rules::Symbol, std::set<rules::Symbol>> follow_sets(const ParseItem &item, const Grammar &grammar);
}
}
#endif

View file

@ -12,10 +12,7 @@ namespace tree_sitter {
rule(rule) {};
bool Item::is_done() const {
for (auto pair : rule_transitions(rule))
if (*pair.first == rules::Blank())
return true;
return false;
return rule_can_be_blank(rule);
}
ostream& operator<<(ostream &stream, const Item &item) {
@ -39,10 +36,10 @@ namespace tree_sitter {
return rule_names_eq && rules_eq;
}
ParseItem::ParseItem(const std::string &rule_name, const rules::rule_ptr rule, int consumed_sym_count) :
ParseItem::ParseItem(const std::string &rule_name, const rules::rule_ptr rule, int consumed_sym_count, const std::string &lookahead_sym_name) :
Item(rule_name, rule),
consumed_sym_count(consumed_sym_count),
lookahead_sym_name("") {}
lookahead_sym_name(lookahead_sym_name) {}
bool ParseItem::operator==(const ParseItem &other) const {
bool rule_names_eq = other.rule_name == rule_name;

View file

@ -28,7 +28,7 @@ namespace tree_sitter {
class ParseItem : public Item {
public:
ParseItem(const std::string &rule_name, const rules::rule_ptr rule, int consumed_sym_count);
ParseItem(const std::string &rule_name, const rules::rule_ptr rule, int consumed_sym_count, const std::string &lookahead_sym_name);
bool operator==(const ParseItem &other) const;
const int consumed_sym_count;

View file

@ -1,9 +1,10 @@
#include "item_set_closure.h"
#include "./next_symbols.h"
#include "./follow_sets.h"
#include "grammar.h"
#include "item.h"
#include <vector>
using std::set;
using std::vector;
namespace tree_sitter {
@ -12,16 +13,16 @@ namespace tree_sitter {
return (std::find(items.begin(), items.end(), item) != items.end());
}
ParseItem parse_item_at_beginning_of_rule(const rules::Symbol &symbol, const Grammar &grammar) {
return ParseItem(symbol.name, grammar.rule(symbol.name), 0);
}
static void add_item(ParseItemSet &item_set, const ParseItem &item, const Grammar &grammar) {
if (!contains(item_set, item)) {
item_set.insert(item);
for (rules::Symbol rule : next_non_terminals(item, grammar)) {
auto next_item = parse_item_at_beginning_of_rule(rule, grammar);
add_item(item_set, next_item, grammar);
for (auto pair : follow_sets(item, grammar)) {
auto non_terminal = pair.first;
auto terminals = pair.second;
for (rules::Symbol terminal : terminals) {
auto next_item = ParseItem(non_terminal.name, grammar.rule(non_terminal.name), 0, terminal.name);
add_item(item_set, next_item, grammar);
}
}
}
}

View file

@ -26,7 +26,7 @@ namespace tree_sitter {
transition_map<rules::Symbol, ParseItemSet> result;
for (ParseItem item : item_set) {
for (auto transition : rule_transitions(item.rule)) {
auto new_item = ParseItem(item.rule_name, transition.second, item.consumed_sym_count + 1);
auto new_item = ParseItem(item.rule_name, transition.second, item.consumed_sym_count + 1, item.lookahead_sym_name);
auto rule = dynamic_pointer_cast<const rules::Symbol>(transition.first);
if (rule.get()) {
auto new_item_set = make_shared<ParseItemSet>(item_set_closure(ParseItemSet({ new_item }), grammar));

View file

@ -1,19 +0,0 @@
#ifndef __tree_sitter__first_terminal__
#define __tree_sitter__first_terminal__
#include "item.h"
#include "symbol.h"
#include <set>
namespace tree_sitter {
class Grammar;
namespace build_tables {
std::set<rules::Symbol> next_terminals(const rules::rule_ptr &rule, const Grammar &grammar);
std::set<rules::Symbol> next_terminals(const ParseItemSet &item_set, const Grammar &grammar);
std::set<rules::Symbol> next_terminals(const ParseItem &item, const Grammar &grammar);
std::set<rules::Symbol> next_non_terminals(const ParseItem &item, const Grammar &grammar);
}
}
#endif

View file

@ -1,7 +1,7 @@
#include "./perform.h"
#include "item.h"
#include "item_set_closure.h"
#include "next_symbols.h"
#include "first_set.h"
#include "item_set_transitions.h"
#include "rules.h"
#include "grammar.h"
@ -84,7 +84,7 @@ namespace tree_sitter {
LexItemSet lex_item_set_for_parse_item_set(const ParseItemSet &parse_item_set) {
LexItemSet result;
for (rules::Symbol symbol : next_terminals(parse_item_set, grammar))
for (rules::Symbol symbol : first_set(parse_item_set, grammar))
result.insert(LexItem(symbol.name, lex_grammar.rule(symbol.name)));
return result;
}
@ -110,7 +110,7 @@ namespace tree_sitter {
lex_grammar(lex_grammar) {};
pair<ParseTable, LexTable> build() {
auto item = ParseItem(ParseTable::START, rules::sym(grammar.start_rule_name), 0);
auto item = ParseItem(ParseTable::START, rules::sym(grammar.start_rule_name), 0, ParseTable::END_OF_INPUT);
ParseItemSet item_set = item_set_closure(ParseItemSet({ item }), grammar);
add_parse_state(item_set);
return pair<ParseTable, LexTable>(parse_table, lex_table);

View file

@ -5,6 +5,10 @@ using namespace tree_sitter::rules;
namespace tree_sitter {
namespace build_tables {
bool is_blank(const rule_ptr &rule) {
return typeid(*rule) == typeid(Blank);
}
class TransitionsVisitor : public rules::Visitor {
public:
transition_map<Rule, Rule> value;
@ -30,7 +34,7 @@ namespace tree_sitter {
void visit(const Seq *rule) {
value = rule_transitions(rule->left).map<Rule>([&](const rule_ptr left_rule) -> rule_ptr {
if (typeid(*left_rule) == typeid(Blank))
if (is_blank(left_rule))
return rule->right;
else
return seq({ left_rule, rule->right });
@ -55,6 +59,13 @@ namespace tree_sitter {
}
};
bool rule_can_be_blank(const rule_ptr &rule) {
for (auto pair : rule_transitions(rule))
if (is_blank(pair.first))
return true;
return false;
}
transition_map<Rule, Rule> rule_transitions(const rule_ptr &rule) {
TransitionsVisitor visitor;
rule->accept(visitor);

View file

@ -6,6 +6,7 @@
namespace tree_sitter {
namespace build_tables {
bool rule_can_be_blank(const rules::rule_ptr &rule);
transition_map<rules::Rule, rules::Rule> rule_transitions(const rules::rule_ptr &rule);
}
}

View file

@ -28,7 +28,7 @@ namespace tree_sitter {
namespace std {
template<>
struct hash<tree_sitter::rules::Rule> {
size_t operator()(const tree_sitter::rules::Rule &rule) {
size_t operator()(const tree_sitter::rules::Rule &rule) const {
return rule.hash_code();
}
};

View file

@ -17,8 +17,9 @@
1225CC6418765693000D4723 /* prepare_grammar_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1225CC6318765693000D4723 /* prepare_grammar_spec.cpp */; };
1251209B1830145300C9B56A /* rule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1251209A1830145300C9B56A /* rule.cpp */; };
125120A4183083BD00C9B56A /* arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 125120A3183083BD00C9B56A /* arithmetic.cpp */; };
12AB465F188BD03E00DE79DF /* follow_sets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12AB465D188BD03E00DE79DF /* follow_sets.cpp */; };
12BC470518822B27005AC502 /* parse_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12BC470318822A17005AC502 /* parse_config.cpp */; };
12BC470718830BC5005AC502 /* next_symbols_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12BC470618830BC5005AC502 /* next_symbols_spec.cpp */; };
12BC470718830BC5005AC502 /* first_set_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12BC470618830BC5005AC502 /* first_set_spec.cpp */; };
12D136A4183678A2005F3369 /* repeat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12D136A2183678A2005F3369 /* repeat.cpp */; };
12EDCF8A187B498C005A7A07 /* tree_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCF89187B498C005A7A07 /* tree_spec.cpp */; };
12EDCF8D187C6282005A7A07 /* document.c in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCF8C187C6282005A7A07 /* document.c */; };
@ -34,7 +35,7 @@
12EDCFBD188205BF005A7A07 /* perform_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCFB7188205BA005A7A07 /* perform_spec.cpp */; };
12EDCFC018820880005A7A07 /* item_set_closure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCFBE18820880005A7A07 /* item_set_closure.cpp */; };
12EDCFC318820A70005A7A07 /* item_set_transitions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCFC118820A70005A7A07 /* item_set_transitions.cpp */; };
12EDCFC61882153D005A7A07 /* next_symbols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCFC41882153D005A7A07 /* next_symbols.cpp */; };
12EDCFC61882153D005A7A07 /* first_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12EDCFC41882153D005A7A07 /* first_set.cpp */; };
12F9A64E182DD5FD00FAF50C /* spec_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */; };
12F9A651182DD6BC00FAF50C /* grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12F9A64F182DD6BC00FAF50C /* grammar.cpp */; };
12FD4061185E68470041A84E /* c_code.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12FD405F185E68470041A84E /* c_code.cpp */; };
@ -94,8 +95,10 @@
1251209A1830145300C9B56A /* rule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rule.cpp; sourceTree = "<group>"; };
125120A218307FFD00C9B56A /* arithmetic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arithmetic.h; path = spec/fixtures/grammars/arithmetic.h; sourceTree = SOURCE_ROOT; };
125120A3183083BD00C9B56A /* arithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arithmetic.cpp; path = spec/fixtures/grammars/arithmetic.cpp; sourceTree = SOURCE_ROOT; };
12AB465D188BD03E00DE79DF /* follow_sets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = follow_sets.cpp; sourceTree = "<group>"; };
12AB465E188BD03E00DE79DF /* follow_sets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = follow_sets.h; sourceTree = "<group>"; };
12BC470318822A17005AC502 /* parse_config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parse_config.cpp; sourceTree = "<group>"; };
12BC470618830BC5005AC502 /* next_symbols_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = next_symbols_spec.cpp; sourceTree = "<group>"; };
12BC470618830BC5005AC502 /* first_set_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = first_set_spec.cpp; sourceTree = "<group>"; };
12C344421822F27700B07BE3 /* transition_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transition_map.h; path = ../build_tables/transition_map.h; sourceTree = "<group>"; };
12D1369E18342088005F3369 /* todo.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = todo.md; sourceTree = "<group>"; };
12D136A0183570F5005F3369 /* pattern_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pattern_spec.cpp; path = spec/compiler/rules/pattern_spec.cpp; sourceTree = SOURCE_ROOT; };
@ -130,8 +133,8 @@
12EDCFBF18820880005A7A07 /* item_set_closure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = item_set_closure.h; sourceTree = "<group>"; };
12EDCFC118820A70005A7A07 /* item_set_transitions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = item_set_transitions.cpp; sourceTree = "<group>"; };
12EDCFC218820A70005A7A07 /* item_set_transitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = item_set_transitions.h; sourceTree = "<group>"; };
12EDCFC41882153D005A7A07 /* next_symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = next_symbols.cpp; sourceTree = "<group>"; };
12EDCFC51882153D005A7A07 /* next_symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = next_symbols.h; sourceTree = "<group>"; };
12EDCFC41882153D005A7A07 /* first_set.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = first_set.cpp; sourceTree = "<group>"; };
12EDCFC51882153D005A7A07 /* first_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = first_set.h; sourceTree = "<group>"; };
12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = spec_helper.cpp; path = spec/spec_helper.cpp; sourceTree = SOURCE_ROOT; };
12F9A64D182DD5FD00FAF50C /* spec_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spec_helper.h; path = spec/spec_helper.h; sourceTree = SOURCE_ROOT; };
12F9A64F182DD6BC00FAF50C /* grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = grammar.cpp; path = src/compiler/grammar.cpp; sourceTree = SOURCE_ROOT; };
@ -204,14 +207,16 @@
12130618182C84B700FCF928 /* build_tables */ = {
isa = PBXGroup;
children = (
12EDCFC41882153D005A7A07 /* first_set.cpp */,
12EDCFC51882153D005A7A07 /* first_set.h */,
12AB465D188BD03E00DE79DF /* follow_sets.cpp */,
12AB465E188BD03E00DE79DF /* follow_sets.h */,
12EDCFA218820137005A7A07 /* item.cpp */,
12EDCFA318820137005A7A07 /* item.h */,
12EDCFBE18820880005A7A07 /* item_set_closure.cpp */,
12EDCFBF18820880005A7A07 /* item_set_closure.h */,
12EDCFC118820A70005A7A07 /* item_set_transitions.cpp */,
12EDCFC218820A70005A7A07 /* item_set_transitions.h */,
12EDCFC41882153D005A7A07 /* next_symbols.cpp */,
12EDCFC51882153D005A7A07 /* next_symbols.h */,
12EDCFA418820137005A7A07 /* perform.cpp */,
12EDCFA518820137005A7A07 /* perform.h */,
12EDCFA618820137005A7A07 /* rule_transitions.cpp */,
@ -226,7 +231,7 @@
children = (
12EDCFB6188205BA005A7A07 /* rule_transitions_spec.cpp */,
12EDCFB7188205BA005A7A07 /* perform_spec.cpp */,
12BC470618830BC5005AC502 /* next_symbols_spec.cpp */,
12BC470618830BC5005AC502 /* first_set_spec.cpp */,
);
name = build_tables;
path = compiler/build_tables;
@ -470,8 +475,9 @@
12130617182C3D2900FCF928 /* string.cpp in Sources */,
12EDCFC018820880005A7A07 /* item_set_closure.cpp in Sources */,
12EDCFBD188205BF005A7A07 /* perform_spec.cpp in Sources */,
12EDCFC61882153D005A7A07 /* next_symbols.cpp in Sources */,
12EDCFC61882153D005A7A07 /* first_set.cpp in Sources */,
12130611182C3A1100FCF928 /* blank.cpp in Sources */,
12AB465F188BD03E00DE79DF /* follow_sets.cpp in Sources */,
1213060E182C398300FCF928 /* choice.cpp in Sources */,
12F9A64E182DD5FD00FAF50C /* spec_helper.cpp in Sources */,
12EDCFB018820392005A7A07 /* item.cpp in Sources */,
@ -495,7 +501,7 @@
12EDCFBC188205BF005A7A07 /* rule_transitions_spec.cpp in Sources */,
12130605182C348F00FCF928 /* character.cpp in Sources */,
12EDCFB418820519005A7A07 /* compile.cpp in Sources */,
12BC470718830BC5005AC502 /* next_symbols_spec.cpp in Sources */,
12BC470718830BC5005AC502 /* first_set_spec.cpp in Sources */,
1213060B182C389100FCF928 /* symbol.cpp in Sources */,
1251209B1830145300C9B56A /* rule.cpp in Sources */,
27A343CA69E17E0F9EBEDF1C /* pattern.cpp in Sources */,