C++ 编译期 parser combinator 实现计算器

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值