C++ 编译期 parser combinator 实现计算器
详细注释
//g++ test.cpp -std=c++17
#include <type_traits>
namespace mx {
//定义两个基类,stream和ints
template <char...>
struct stream {
using stream_type = stream;
};
template <auto...>
struct ints {
using ints_type = ints;
};
//定义pop/push ints/stream的偏特化版本和展开版本
template <typename>
struct pop_stream {
};
template <char c, char... cs>
struct pop_stream<stream<c, cs...>>
: std::integral_constant<char, c>, stream<cs...> {
};
template <char, typename>
struct push_stream {
};
template <char c, char... cs>
struct push_stream<c, stream<cs...>> : stream<c, cs...> {
};
template <auto, typename>
struct push_ints {
};
template <auto i, auto... is>
struct push_ints<i, ints<is...>> : ints<i, is...> {
};
template <typename>
struct pop_ints {
};
template <auto i, auto... is>
struct pop_ints<ints<i, is...>>
: std::integral_constant<decltype(i), i>, ints<is...> {
};
//用户定义的字面值常量后缀 operator""
//使用方法,"xxx"_str返回相应的stream
template <typename t, t... cs>
constexpr stream<cs...> operator""_str() { return {}; }
//过滤空格
//不然就push到stream里面去
template <char c, char... cs>
constexpr auto filter_space(stream<c, cs...>)
{
if constexpr (c == ' ')
return filter_space(stream<cs...> {});
else
return typename push_stream<c,
decltype(filter_space(stream<cs...> {}))>::stream_type {};
}
//递归终止
constexpr auto filter_space(stream<>)
{
return stream<> {};
}
//存放我们的解析对
template <typename a, typename b>
struct parse_pair {
using fst = a;
using snd = b;
};
//同样是递归终止
struct nothing {
};
//如果是相同类型则不做处理
//反之用fun判断操作是什么,并从栈弹出一个字符和接下来的流一起构造一个解析对
constexpr auto parse_char_with_pred = [](auto fun, auto stm) constexpr
{
if constexpr (std::is_same_v<decltype(stm), stream<>>)
return nothing {};
else if constexpr (fun(pop_stream<decltype(stm)>::value))
return parse_pair<ints<pop_stream<decltype(stm)>::value>,
typename pop_stream<decltype(stm)>::stream_type> {};
else
return nothing {};
};
//将解析下降到辅助函数,即
//parse_char_with_pred
constexpr auto parse_add = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == '+'; }, stm);
};
constexpr auto parse_sub = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == '-'; }, stm);
};
constexpr auto parse_mul = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == '*'; }, stm);
};
constexpr auto parse_div = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == '/'; }, stm);
};
constexpr auto parse_lbrk = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == '('; }, stm);
};
constexpr auto parse_rbrk = [](auto stm) constexpr
{
return parse_char_with_pred([](char c) { return c == ')'; }, stm);
};
//合并结果
template <int ret = 0, char c, char... cs>
static constexpr auto merge(stream<c, cs...>)
{
if constexpr (c >= '0' && c <= '9')
return merge<10 * ret + (c - '0')>(stream<cs...> {});
else
return parse_pair<ints<ret>, stream<c, cs...>> {};
}
//递归终止
template <int ret = 0>
static constexpr auto merge(stream<>)
{
return parse_pair<ints<ret>, stream<>> {};
}
//读取数字,merge算是辅助函数
constexpr auto parse_int = [](auto stm) constexpr
{
if constexpr (std::is_same_v<decltype(stm), stream<>>)
return nothing {};
else if constexpr (pop_stream<decltype(stm)>::value >= '0' && pop_stream<decltype(stm)>::value <= '9')
return merge(stm);
else
return nothing {};
};
template <typename par1, typename par2>
constexpr auto operator&(par1 p1, par2 p2)
{
return
[=](auto stm) constexpr
{
if constexpr (std::is_same_v<decltype(stm), stream<>>)
return nothing {};
else if constexpr (!std::is_same_v<decltype(p1(stm)), nothing>) {
if constexpr (!std::is_same_v<decltype(
p2(typename decltype(p1(stm))::snd {})),
nothing>) {
return parse_pair<
typename push_ints<
pop_ints<typename decltype(
p2(typename decltype(
p1(stm))::snd {}))::fst>::value,
typename decltype(p1(stm))::fst>::ints_type,
typename decltype(
p2(typename decltype(
p1(stm))::snd {}))::snd> {};
} else {
return nothing {};
}
} else {
return nothing {};
}
};
}
template <int i, typename b, auto... is>
constexpr auto calc(parse_pair<ints<i, is...>, b>)
{
return parse_pair<ints<i, is...>, b> {};
}
template <int i1, int i2, typename b, auto... is>
constexpr auto calc(parse_pair<ints<i1, '+', i2, is...>, b>)
{
return parse_pair<ints<i2 + i1, is...>, b> {};
}
template <int i1, int i2, typename b, auto... is>
constexpr auto calc(parse_pair<ints<i1, '-', i2, is...>, b>)
{
return parse_pair<ints<i2 - i1, is...>, b> {};
}
template <int i1, int i2, typename b, auto... is>
constexpr auto calc(parse_pair<ints<i1, '*', i2, is...>, b>)
{
return parse_pair<ints<i2 * i1, is...>, b> {};
}
template <int i1, int i2, typename b, auto... is>
constexpr auto calc(parse_pair<ints<i1, '/', i2, is...>, b>)
{
return parse_pair<ints<i2 / i1, is...>, b> {};
}
template <int i, typename b, auto... is>
constexpr auto calc(parse_pair<ints<')', i, '(', is...>, b>)
{
return parse_pair<ints<i, is...>, b> {};
}
constexpr auto form = [](auto p) constexpr
{
return
[=](auto stm) constexpr
{
if constexpr (std::is_same_v<decltype(stm), stream<>>)
return nothing {};
else if constexpr (std::is_same_v<decltype(p(stm)), nothing>)
return nothing {};
else
return calc(p(stm));
};
};
template <typename par1, typename par2>
constexpr auto operator|(par1 p1, par2 p2)
{
return
[=](auto stm) constexpr
{
if constexpr (!std::is_same_v<decltype(p1(stm)), nothing>)
return p1(stm);
else
return p2(stm);
};
}
//优先级区别
constexpr auto fact();
constexpr auto term =
[](auto stm) constexpr
{
return form(fact() & parse_mul & term | fact() & parse_div & term | fact())(stm);
};
constexpr auto expr =
[](auto stm) constexpr
{
return form(term & parse_add & expr | term & parse_sub & expr | term)(stm);
};
constexpr auto fact()
{
return
[](auto stm) constexpr
{
return form(parse_lbrk & expr & parse_rbrk | parse_int)(stm);
};
}
}
using namespace mx;
#include <iostream>
int main()
{
constexpr auto ret = expr(filter_space("(20 * (3 * 5 + 1 - 6) + 7) / 3"_str));
std::cout << pop_ints<typename decltype(ret)::fst>::value;
}