143 lines
4.1 KiB
C++
143 lines
4.1 KiB
C++
#include "CommandMap.h"
|
|
#include "Command.h"
|
|
#include <cstring>
|
|
|
|
void CommandMap::add(const char * s, uint32_t id,
|
|
std::shared_ptr<CommandMap> next_map, bool following_char)
|
|
{
|
|
size_t length = strlen(s);
|
|
if (length < 1u)
|
|
return;
|
|
std::vector<uint32_t> v(length);
|
|
for (size_t i = 0u; i < length; i++)
|
|
{
|
|
v[i] = s[i];
|
|
}
|
|
add(v, id, next_map, following_char);
|
|
}
|
|
|
|
void CommandMap::add(const std::vector<uint32_t> & s, uint32_t id,
|
|
std::shared_ptr<CommandMap> next_map, bool following_char)
|
|
{
|
|
Node * node = &m_root_node;
|
|
size_t length = s.size();
|
|
if (length < 1u)
|
|
return;
|
|
for (size_t i = 0u; i < length; i++)
|
|
{
|
|
const uint32_t c = s[i];
|
|
auto it = node->next_chars.find(c);
|
|
if (it != node->next_chars.end())
|
|
{
|
|
node = &*it->second;
|
|
}
|
|
else
|
|
{
|
|
auto new_node = std::make_shared<Node>();
|
|
node->next_chars[c] = new_node;
|
|
node = &*new_node;
|
|
}
|
|
}
|
|
uint8_t flags = Node::FLAG_TERMINATOR;
|
|
if (following_char)
|
|
flags |= Node::FLAG_FOLLOWING_CHAR;
|
|
node->id = id;
|
|
node->flags = flags;
|
|
node->next_map = next_map;
|
|
}
|
|
|
|
uint8_t CommandMap::lookup_command(const uint32_t * command_characters,
|
|
size_t length, Command & command) const
|
|
{
|
|
std::list<Command::Unit> units;
|
|
uint8_t scan_result = scan_units(units, command_characters, length, &m_root_node);
|
|
if (scan_result == COMMAND_COMPLETE)
|
|
{
|
|
int i = 0;
|
|
for (const auto & unit : units)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
command.main = unit;
|
|
break;
|
|
case 1:
|
|
command.motion = unit;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return scan_result;
|
|
}
|
|
|
|
uint8_t CommandMap::scan_units(
|
|
std::list<Command::Unit> & units,
|
|
const uint32_t * command_characters, size_t length,
|
|
const Node * start_node) const
|
|
{
|
|
if (length < 1u)
|
|
return COMMAND_INCOMPLETE;
|
|
uint8_t result = COMMAND_INCOMPLETE;
|
|
uint8_t recurse_result = COMMAND_INVALID;
|
|
bool gathering_count = true;
|
|
Command::Unit unit;
|
|
const Node * node = start_node;
|
|
for (size_t i = 0u; i < length; i++)
|
|
{
|
|
uint32_t c = command_characters[i];
|
|
if (gathering_count &&
|
|
((('1' <= c) && (c <= '9')) ||
|
|
((c == '0') && (unit.count != 0u))))
|
|
{
|
|
unit.count *= 10u;
|
|
unit.count += (c - '0');
|
|
}
|
|
else
|
|
{
|
|
gathering_count = false;
|
|
auto it = node->next_chars.find(c);
|
|
if (it != node->next_chars.end())
|
|
{
|
|
node = &*it->second;
|
|
if (node->flags & Node::FLAG_TERMINATOR)
|
|
{
|
|
unit.id = node->id;
|
|
if (node->flags & Node::FLAG_FOLLOWING_CHAR)
|
|
{
|
|
if (i < (length - 1u))
|
|
{
|
|
unit.following_char = command_characters[i + 1u];
|
|
units.push_front(unit);
|
|
return COMMAND_COMPLETE;
|
|
}
|
|
return COMMAND_INCOMPLETE;
|
|
}
|
|
else if (node->next_map)
|
|
{
|
|
recurse_result = scan_units(units,
|
|
&command_characters[i + 1u],
|
|
length - i - 1u, &node->next_map->m_root_node);
|
|
if (recurse_result == COMMAND_COMPLETE)
|
|
{
|
|
units.push_front(unit);
|
|
return COMMAND_COMPLETE;
|
|
}
|
|
result = recurse_result;
|
|
}
|
|
else
|
|
{
|
|
units.push_front(unit);
|
|
return COMMAND_COMPLETE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return recurse_result;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|