Skip to content

Instantly share code, notes, and snippets.

@matovitch
Last active October 12, 2018 11:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matovitch/625b0a9776917ddb164c723ffe5dbb2e to your computer and use it in GitHub Desktop.
Save matovitch/625b0a9776917ddb164c723ffe5dbb2e to your computer and use it in GitHub Desktop.
// https://coliru.stacked-crooked.com/a/a138703355819566
#include <string_view>
#include <iostream>
#include <cstdint>
template <uint8_t low,
uint8_t high>
struct TIsBetween
{
bool operator()(const uint8_t byte) const
{
return byte >= low &&
byte <= high;
}
};
template <uint8_t... bytes>
struct TIsIn
{
bool operator()(const uint8_t byte) const
{
const auto compare = [byte](const uint8_t test) { return byte == test; };
return (compare(bytes) || ...);
}
};
template <uint8_t byte>
using TIs = TIsIn<byte>;
using isDigit = TIsBetween<'0', '9'>;
using isDigitExceptZero = TIsBetween<'1', '9'>;
using isExponent = TIsIn<'e', 'E'>;
using isPlusOrMinus = TIsIn<'+', '-'>;
using isDot = TIs<'.'>;
enum Token
{
UNKNOWN,
INT,
FLOAT
};
static const char* TOKEN_AS_CSTR[] =
{
"UNKNOWN",
"INT",
"FLOAT"
};
class Reader
{
public:
Reader(const std::string_view stringToRead) :
_head{reinterpret_cast<const uint8_t*>(stringToRead.data())},
_tail{_head + stringToRead.size()}
{}
operator bool() const
{
return _head < _tail;
}
uint8_t operator*() const
{
return *_head;
}
void operator++()
{
_head++;
}
private:
const uint8_t* _head;
const uint8_t* const _tail;
};
template <class GotoPredicate, int GOTO_NEXT_STATE_INDEX>
struct TGoto
{
using Predicate = GotoPredicate;
static constexpr int NEXT_STATE_INDEX = GOTO_NEXT_STATE_INDEX;
};
template <int MATCH, class... GotosOrMatch>
struct TState;
template <int INDEX>
struct TStateIndex;
template <>
struct TStateIndex<1>
{
using Type = TState
<
UNKNOWN,
TGoto<isDigitExceptZero , 2>,
TGoto<isPlusOrMinus , 3>,
TGoto<isDot , 4>
>;
};
template <>
struct TStateIndex<2>
{
using Type = TState
<
INT,
TGoto<isDigit , 2>,
TGoto<isDot , 5>
>;
};
template <>
struct TStateIndex<3>
{
using Type = TState
<
UNKNOWN,
TGoto<isDigitExceptZero , 2>,
TGoto<isDot , 4>
>;
};
template <>
struct TStateIndex<4>
{
using Type = TState
<
UNKNOWN,
TGoto<isDigit , 5>
>;
};
template <>
struct TStateIndex<5>
{
using Type = TState
<
FLOAT,
TGoto<isDigit , 5>,
TGoto<isExponent , 6>
>;
};
template <>
struct TStateIndex<6>
{
using Type = TState
<
UNKNOWN,
TGoto<isPlusOrMinus , 7>,
TGoto<isDigit , 8>
>;
};
template <>
struct TStateIndex<7>
{
using Type = TState
<
UNKNOWN,
TGoto<isDigit, 8>
>;
};
template <>
struct TStateIndex<8>
{
using Type = TState
<
FLOAT,
TGoto<isDigit, 8>
>;
};
template <int INDEX>
using TGetState = typename TStateIndex<INDEX>::Type;
template <int STATE_INDEX>
void tGotoState(Reader& reader)
{
TGetState<STATE_INDEX>{}(reader);
}
template <int MATCH>
struct TState<MATCH>
{
void operator()(Reader& reader) const
{
if constexpr (MATCH == UNKNOWN)
{
++reader;
}
std::cout << "Matched: " << TOKEN_AS_CSTR[MATCH] << std::endl;
tGotoState<1>(reader);
}
};
template <int MATCH, class Goto, class... Gotos>
struct TState<MATCH, Goto, Gotos...>
{
using Predicate = typename Goto::Predicate;
static constexpr int NEXT_STATE_INDEX = Goto::NEXT_STATE_INDEX;
void operator()(Reader& reader) const
{
if (!reader)
{
return;
}
if (!Predicate{}(*reader))
{
return TState<MATCH, Gotos...>{}(reader);
}
++reader;
tGotoState<NEXT_STATE_INDEX>(reader);
}
};
void runMachine(const std::string_view stringToLex)
{
Reader reader{stringToLex};
tGotoState<1>(reader);
}
int main()
{
runMachine("52 -22 +1 -.2 2.37e-05 ");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment