summaryrefslogtreecommitdiffhomepage
path: root/grammer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'grammer.cpp')
-rw-r--r--grammer.cpp46
1 files changed, 19 insertions, 27 deletions
diff --git a/grammer.cpp b/grammer.cpp
index 8f38e3e..07e527f 100644
--- a/grammer.cpp
+++ b/grammer.cpp
@@ -105,13 +105,10 @@ bool Compiler::subTreeIsComplete(index_t node_id, index_t& to_fill)
return true;
}
-bool Compiler::StartsWith(const std::vector<Token>& tokens, const std::vector<std::string>& types)
+size_t Compiler::CommonPrefix(const std::vector<Token>& tokens, const std::vector<std::string>& types)
{
- if (tokens.size() < types.size())
- return false;
-
auto [tokens_it, types_it] = std::mismatch(tokens.begin(), tokens.end(), types.begin(), types.end(), [](const Token& token, const std::string& s){ return token.type == s; });
- return types_it == types.end(); // no mismatch: tokens (types) start wit specified types list
+ return types_it - types.begin(); // a distance, 0 on no match
}
void Compiler::AddFirstNode()
@@ -127,21 +124,22 @@ void Compiler::AddFirstNode()
std::string node_type;
index_t node_variant;
- std::deque<std::string> alternatives; // only for valid elements from alternatives_set
+ std::deque<std::pair<std::string, index_t>> alternatives; // only for valid elements from alternatives_set
std::vector<index_t> child_ids;
for (const auto& type : alternatives_set) {
const auto& variants{bnf[type]};
for (int i = 0; i < variants.size(); i++) {
const std::vector<std::string> & variant{variants[i]};
- if (StartsWith(tokens, variant)) { // match
- if (node_type == "") {
+ size_t common{};
+ if ((common = CommonPrefix(tokens, variant)) > 0) { // match a common prefix
+ if (node_type == "") { // no match yet
node_type = type;
node_variant = i;
- for (int token_id = 0; token_id < variant.size())
+ for (int token_id = 0; token_id < common; token_id++)
child_ids.push_back(ChildIdFromTokenId(token_id));
} else
- alternatives.push_back(type); // duplicates possible: variants of same type!
+ alternatives.emplace_back(type, i);
}
}
}
@@ -172,7 +170,7 @@ bool Compiler::AddRootNode()
std::string node_type;
index_t node_variant;
- std::deque<std::string> alternatives; // only for valid elements from alternatives_set
+ std::deque<std::pair<std::string, index_t>> alternatives; // only for valid elements from alternatives_set
std::vector<index_t> child_ids{1, old_root_node_id};
for (const auto& type : alternatives_set) {
@@ -184,12 +182,12 @@ bool Compiler::AddRootNode()
node_type = type;
node_variant = i;
} else
- alternatives.push_back(type); // duplicates possible: variants of same type
+ alternatives.emplace_back(type, i); // duplicates possible: variants of same type
}
}
}
- if (node_type == "") // no matching type found
+ if (node_type == "") // no matching type found (maybe backtrack possible?)
return false;
// now add!
@@ -232,28 +230,22 @@ void ChangeNodeType()
TreeNode& node {nodes.back()};
index_t node_id = node.node_id;
- if (node.alternative_types.empty())
+ if (node.alternatives.empty())
throw std::runtime_error("No alternatives found during Backtrack"); // ICE
- if (node.alternative_types.front() == node.type) { // Keep type, change variant
- if (root_node_id == node_id) { // Root node
- // TODO ...
- } else if (node.child_ids().empty()) { // leaf node
- } else
- throw std::runtime_error("Backtrack: Can't set alternative in the middle of the tree.");
- } else { // Different type
- if (root_node_id == node_id) { // Root node
- } else if (node.child_ids().empty()) { // leaf node
- } else
- throw std::runtime_error("Backtrack: Can't set alternative in the middle of the tree.");
- }
+ auto& [type, variant] {node.alternatives.front()};
+
+ node.type = type;
+ node.variant = variant;
+
+ node.alternatives.pop_front();
}
// throws if no further track back is possible: compile error
void Compiler::TrackBack()
{
// Search backwards for alternatives: last node with alternatives (variant or alt. token)
- while (!nodes.empty() && nodes.last().alternative_types.empty()) {
+ while (!nodes.empty() && nodes.last().alternatives.empty()) {
RemoveLastNode();
}