boost::spirit实现sprintf

看了下boost::spirit,这个库很有趣,可以直接用c++写EBNF。试着用它写了一个sprintf,内部是利用stringstream格式化,效率什么的都没有考虑,主要目的就是用boost::spirit写printf格式化字符串的EBNF。函数粗略的测试过,并没有支持全部的功能(hh,l之类的长度操作就没有支持,嫌麻烦),EBNF也不是那么严谨,但普通的格式化还是可以的:)


#include <string>
#include <sstream>
#include <iomanip>
#include <stdarg.h>
#include "boost/spirit.hpp"
#include "boost/function.hpp"
#include "boost/bind.hpp"

using namespace std;
using namespace boost;
using namespace boost::spirit;

    struct Formatter
    {
        enum Flags
        {
            SHARP,
            MINUS,
            SPACE,
            PLUS,
            NONE
        };
        stringstream formatStream;
        ios::fmtflags oldFlags;
        Flags flag;
        va_list& argsList;
        Formatter(va_list& args):argsList(args)
        {
            oldFlags=formatStream.flags();
        }
        void onChar(const char& ch)
        {
            formatStream<<ch;
        }
        void onPINT(const char* const begin,const char* const end)
        {
            int* pi=va_arg(argsList,int*);
            formatStream<<*pi;
        }
        void onPOINTER(const char* const begin,const char* const end)
        {
            void* ui=va_arg(argsList,void*);
            formatStream<<hex<<ui;
        }
        void onCSTRING(const char* const begin,const char* const end)
        {
            char* str=va_arg(argsList,char*);
            formatStream<<str;
        }
        void onCHARACTER(const char* const begin,const char* const end)
        {
            formatStream.setf(ios::fixed);
            int k=va_arg(argsList,int);
            formatStream<<(char)k;
        }
        void onDOUBLE_HEX(const char* const begin,const char* const end)
        {
            formatStream.setf(ios::fixed);
            double k=va_arg(argsList,double);
            formatStream<<hex<<k;
        }
        void onDOUBLE_FIX(const char* const begin,const char* const end)
        {
            formatStream.setf(ios::fixed);
            double k=va_arg(argsList,double);
            formatStream<<k;
        }
        void onDOUBLE(const char* const begin,const char* const end)
        {
            formatStream.setf(ios::fixed);
            double k=va_arg(argsList,double);
            formatStream<<k;
        }
        void onDOUBLE_E(const char* const begin,const char* const end)
        {
            formatStream.setf(ios::scientific);
            double k=va_arg(argsList,double);
            formatStream<<k;
        }
        void onUINT_OCT(const char* const begin,const char* const end)
        {
            unsigned int k=va_arg(argsList,unsigned int);
            formatStream<<oct<<k;
        }
        void onUINT_HEX(const char* const begin,const char* const end)
        {
            unsigned int k=va_arg(argsList,unsigned int);
            formatStream<<hex<<k;
        }
        void onUINT_DEC(const char* const begin,const char* const end)
        {
            unsigned int k=va_arg(argsList,unsigned int);
            formatStream<<dec<<k;
        }
        void onINTEGER(const char* const begin,const char* const end)
        {
            int k=va_arg(argsList,int);
            formatStream<<dec<<k;
        }
        void onLENGTH(const char* const begin,const char* const end)
        {
            string len(begin,end);
            ///@todo implement me
        }
        void onPRECETION(int val)
        {
            formatStream.precision(val);
        }
        void onWIDTH(int val)
        {
            formatStream.width(val);
        }
        void onFLAG(const char* const begin,const char* const end)
        {
            switch(*begin)
            {
                case '#':
                    flag=SHARP;
                    formatStream.setf(ios::showbase);
                    break;
                case '-':
                    flag=MINUS;
                    break;
                case ' ':
                    flag=SPACE;
                    break;
                case '+':
                    flag=PLUS;
                    break;
                case '0':
                    formatStream<<setfill('0');
                default:
                    break;
            }
        }
        void onCONTENT(const char* const begin,const char* const end)
        {
            flag=NONE;
        }
        void onFMT_STR(const char* const begin,const char* const end)
        {
        }
        void onFMTStart(const char ch)
        {
            flag=NONE;
            formatStream.flags(oldFlags);
            formatStream.width(0);
            formatStream.precision(6);
            formatStream<<setfill(' ');
        }
    };

inline string sprintf(const char* fmt,...)
{
    //EBNF of sprintf's format
    va_list arg_ptr;
    va_start(arg_ptr,fmt);
    Formatter fo(arg_ptr);
    rule<> PINT=ch_p('n');
    rule<> POINTER=ch_p('p');
    rule<> CSTRING=ch_p('s');
    rule<> CHARACTER=ch_p('c');
    rule<> DOUBLE_HEX=ch_p('a')|'A';
    rule<> DOUBLE_FIX=ch_p('g')|'G';
    rule<> DOUBLE=ch_p('f')|'F';
    rule<> DOUBLE_E=ch_p('e')|'E';
    rule<> UINT_OCT=ch_p('o');
    rule<> UINT_HEX=ch_p('x')|'X';
    rule<> UINT_DEC=ch_p('u');
    rule<> UINT=
                UINT_DEC[bind(&Formatter::onUINT_DEC,ref(fo),_1,_2)] |
                UINT_HEX[bind(&Formatter::onUINT_HEX,ref(fo),_1,_2)] |
                UINT_OCT[bind(&Formatter::onUINT_OCT,ref(fo),_1,_2)];
    rule<> INTEGER=ch_p('d')|'i';
    rule<> TYPE_SPEC =
                       INTEGER[bind(&Formatter::onINTEGER,ref(fo),_1,_2)] |
                       UINT |
                       DOUBLE_HEX[bind(&Formatter::onDOUBLE_HEX,ref(fo),_1,_2)] |
                       DOUBLE_FIX[bind(&Formatter::onDOUBLE_FIX,ref(fo),_1,_2)] |
                       DOUBLE[bind(&Formatter::onDOUBLE,ref(fo),_1,_2)] |
                       DOUBLE_E[bind(&Formatter::onDOUBLE_E,ref(fo),_1,_2)] |
                       CHARACTER[bind(&Formatter::onCHARACTER,ref(fo),_1,_2)] |
                       CSTRING[bind(&Formatter::onCSTRING,ref(fo),_1,_2)] |
                       POINTER[bind(&Formatter::onPOINTER,ref(fo),_1,_2)] |
                       PINT[bind(&Formatter::onPINT,ref(fo),_1,_2)];
    rule<> LENGTH=longest_d[chseq_p("hh")|"h"|"ll"|"l"|"L"|"q"|"j"|"z"|"t"];
    rule<> PRECITION='.'>>int_p[bind(&Formatter::onPRECETION,ref(fo),_1)];
    rule<> WIDTH=int_p[bind(&Formatter::onWIDTH,ref(fo),_1)];
    rule<> FLAG=ch_p('#')|'-'|space_p|'+'|'0';
    rule<> CONTENT=ch_p('%')[bind(&Formatter::onFMTStart,ref(fo),_1)]>>
            *FLAG[bind(&Formatter::onFLAG,ref(fo),_1,_2)]>>
            *WIDTH>>
            *PRECITION>>
            *LENGTH[bind(&Formatter::onLENGTH,ref(fo),_1,_2)]>>
            TYPE_SPEC;
    rule<> FMT_STR=*((~ch_p('%'))[bind(&Formatter::onChar,ref(fo),_1)]|CONTENT[bind(&Formatter::onCONTENT,ref(fo),_1,_2)]);
    //parse string
    parse(fmt,FMT_STR[bind(&Formatter::onFMT_STR,ref(fo),_1,_2)]);
    va_end(arg_ptr);
    return fo.formatStream.str();
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值