posts - 5, comments - 10, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2014年7月6日

作者:flysnwoxg
c++编译器模板解析确实很强大。基本上可以把编译器看做是一个虚拟机,c++模板源代码就是被执行的脚本代码。
基本上你可以在编译期实现任何算法。
下面是一个按照从小到大,然后从大到小对数值对排序的程序,程序使用了冒泡排序,排序在编译期完成。
例如程序的原始输入为: ((5,6),(1,5),(3,4))
将被从小到大排序为  ((1,5),(3,4),(5,6))
然后被从大到小排序为  ((5,6),(3,4),(1,5))


//author:flysnowxg 
#include "stdio.h"
//用模板表示类型,模板的实例化表示对象(如pait_t<1,2> 表示(1,2)这样的两个值的对象)
template<int _first,int _second>
struct pair_t{
    static const int first=_first;
    static const int second=_second;
    static void print(){printf("%d %d",first,second);}
};

//计算两个不同的pair_t类型的实例的小于关系
template <typename T1,typename T2
struct  less_t{
    static const int first_le=T1::first<T2::first;
    static const int first_eq=T1::first==T2::first;
    static const int second_le=(first_eq&&(T1::second<T2::second));
    static const int result=first_le || second_le;
};

//计算两个不同的pair_t类型的实例的大于关系
template <typename T1,typename T2
struct  greate_t{
    static const int result=!less_t<T1,T2>::result;
};

struct null_t;
//类型列表
template <typename T1,typename T2struct list_t;
template <typename T>
struct list_t<T,null_t>{
    typedef T value;
    typedef null_t next;
};
template <typename T1,typename T2,typename T3>
struct list_t<T1,list_t<T2,T3> >
{
    typedef T1 value;
    typedef list_t<T2,T3next
};
#define list_t1(e1list_t<e1,null_t>
#define list_t2(e1,e2list_t<e1,list_t1(e2)>
#define list_t3(e1,e2,e3list_t<e1,list_t2(e2,e3)>
#define list_t4(e1,e2,e3,e4list_t<e1,list_t3(e2,e3,e4)>
#define list_t5(e1,e2,e3,e4,e5list_t<e1,list_t4(e2,e3,e4,e5)>
#define list_t6(e1,e2,e3,e4,e5,e6list_t<e1,list_t5(e2,e3,e4,e5,e6)>
#define list_t7(e1,e2,e3,e4,e5,e6,e7list_t<e1,list_t6(e2,e3,e4,e5,e6,e7)>
#define list_t8(e1,e2,e3,e4,e5,e6,e7,e8list_t<e1,list_t7(e2,e3,e4,e5,e6,e7,e8)>
#define list_t9(e1,e2,e3,e4,e5,e6,e7,e8,e9list_t<e1,list_t8(e2,e3,e4,e5,e6,e7,e8,e9)>
#define list_t10(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10list_t<e1,list_t9(e2,e3,e4,e5,e6,e7,e8,e9,e10)>

//递归打印类型列表中每个类型的值
template<typename Tstruct print_t;
template<typename T>
struct print_t<list_t<T,null_t>>
{
    typedef typename T result;
    static void print(){
        printf("\nelem::");
        result::print();
    }
};
template<typename T1,typename T2>
struct print_t<list_t<T1,T2>>
{
    typedef typename T1 result;
    static void print(){
        printf("\nelem::");
        result::print();
        print_t<T2>::print();
    }
};

//冒泡排序算法
template<typename T,template <typename,typenameclass CompareTstruct sort_t;
template<typename T,template <typename,typenameclass CompareT>
struct sort_t<list_t<T,null_t> ,CompareT>{
    typedef list_t<T,null_tsort_head;
    typedef T least_elem;
    typedef null_t remainder;
    typedef list_t<T,null_tresult;
};
template<typename T1,typename T2,template <typename,typenameclass CompareT>
struct sort_t<list_t<T1,T2>,CompareT>{
    template<bool _b_swapstruct swap_t{
        typedef list_t<T1,T2result;
    };
    template<> struct swap_t<false>{
        typedef list_t<typename T2::value,list_t<T1,typename T2::next> > result;
    };
    static const int order=!CompareT<T1,T2::value>::result;
    typedef typename swap_t<order>::result sort_head;//假如CompareT是less_t,将开头两个元素中大的放前面,小的放后面
    typedef typename sort_t<typename sort_head::next,CompareT>::least_elem least_elem;//假如CompareT是less_t,获取列表中最小的元素
    typedef list_t<typename sort_head::value,typename sort_t<typename sort_head::next,CompareT>::remainderremainder;//去掉末尾那个最小元素
    typedef list_t<least_elem,typename sort_t<remainder,CompareT>::resultresult;//将最小元素和剩余已经排好序的元素链表组成一个新链表
}; 
int main(int argccharargv[])
{
    typedef pair_t<50,6> e1_t;
    typedef pair_t<9,10> e2_t;
    typedef pair_t<1,2> e3_t;
    typedef pair_t<7,8> e4_t;
    typedef pair_t<3,4> e5_t;
    typedef pair_t<-6,4> e6_t;

    typedef list_t6(e1_t,e2_t,e3_t,e4_t,e5_t,e6_tdate_t;
    printf("原始数据:");
    print_t<date_t>::print();

    typedef sort_t<date_t,less_t>::result data_ta;
    printf("\n\n从小到大:");
    print_t<data_ta>::print();

    typedef sort_t<date_t,greate_t>::result data_tb;
    printf("\n\n从大到小:");
    print_t<data_tb>::print();
 
最后的输出:
原始数据:
elem::50 6
elem::9 10
elem::1 2
elem::7 8
elem::3 4
elem::-6 4
从小到大:
elem::-6 4
elem::1 2
elem::3 4
elem::7 8
elem::9 10
elem::50 6
从大到小:
elem::50 6
elem::9 10
elem::7 8
elem::3 4
elem::1 2
elem::-6 4

posted @ 2014-07-06 16:47 flysnowxg 阅读(2524) | 评论 (1)编辑 收藏

2013年11月28日

lisp是一种神奇的语言,scheme是lisp的一种方言。
tinyscheme是一个scheme语言的解释器实现,而这是我大幅修改并加了注释后的tinyscheme(基于tinyscheme1.41)
代码地址:http://flysnowxg.googlecode.com/svn/tinyscheme_note
原始代码: http://tinyscheme.sourceforge.net/home.html
tinyscheme据说是实现的r5rs标准(应当是实现了一部分,因为模式匹配和语法定义的那部分显然没实现)
tinyscheme代码很简短而且实现的语言功能还算比较完整,如果想研究一个lisp解释器的实现,tinyscheme是值得研究的
tinyscheme实现了lambda、宏、延续、异常、gc这些重要的语言机制,还实现了许多库函数,整个原版代码大约有6500行左右,但是原版代码有很多的宏定义和很多冗余的代码,代码分类也很混乱,可读性不算特别好,在阅读过程中我对这个代码进行了大量的修改,清除了大量冗余代码,重新组织了代码结构,主要的实现文件scheme.c被我从5000行改到只有3400行。所有代码加起来也只有4500行了,功能损失也不太多
修改一些bug,比如像‘延续’的实现,原版像下面这样的代码中, “(r 1)”这一句是没法运行的
(define r 0)
(let ((x 1))
 (set! x
  (+ x
   (call/cc (lambda (c) (set! r c) (+ 44 (c 1)))))
 )
 (display x))
(r 1)

有兴趣的可以看一看!

posted @ 2013-11-28 17:55 flysnowxg 阅读(2561) | 评论 (0)编辑 收藏

2013年9月2日

这是我用c++写的一个简单的脚本语言,非常简短,不到3000行代码


sil语言(simple interpretative lanuage)是一个简单的脚本语言,只是一个玩具,目的是演示用简短的代码去创建一个可用的脚本语言
这样一个玩具会是怎么样的呢?
sil的设计目标:
1 . 非常容易将sil解释器嵌入到c++代码中
2 . 非常容易用c++代码来扩展sil的函数调用,使得c++和sil脚本非常容易交互
3 . 成为一个有简洁语法的动态语言,有容易使用的语法
4 . 拥有一个语言一般都应当拥有的语法

sil语法的完整定义可参考《sil语法说明》。
sil语言是动态类型的,编译时不会检查函数的参数个数,参数类型是否合适,甚至不会检查函数定义是否存在,只有到了运行时才会查找函数,检查参数个数是否匹配。
对于内置函数还会检查参数类型是否匹配,如果不匹配会试着进行参数类型转换
对于用户定义函数,不会进行参数类型匹配的检查
第一节 语法:
1. 类型:
 sil暂时支持整形,浮点型,字符串三种数据类型,暂时不支持数组,也不支持自定义类型(这两点是比较严重的缺点)
 sil是弱类型的,变量不会和类型绑定
 变量定义像是这样的:
 var vi=1; //定义一个值为整数1的变量vi
 var vf=1.0;//定义一个值为浮点数1.0的变量vf
 var vs="1.0";//定义一个值为字符串"1.0"的字符串vs
 
2. 函数
 sil是弱类型的,所以定义函数时不需要声明形参的类型,支持return语句
 函数像这样定义:
 function myfun(str)
 {
  print(str);
  return 0;
  print("after return\n");
 }
 函数像这样调用:myfun("hello sil");
 
3. 分支
 sil支持if else 语句,
 像这样:
 var i=read();
 if(i==1) print("a");
 else if(i==2)
 {
  print("b");
 }
 else print("c");
 
4. 循环
 sil支持while和for循环,支持continue,break语句
 while像这样:
 var i=1;
 while(true)
 {
  print("hello sil\n");
  i=i+1;
  if(i>5) break;
  if(i<3) continue;
  print("after continue\n");
 }
 for循环像这样
 for(var i=0;i<5;i=i+1) print(i+"\n");

5. 基本运算符
 比较运算支持 == != > <
 算术运算支持 + - * / % ,还支持一元 -
 逻辑运算支持 !  && ||
 支持括号 ( ) 改变求值顺序
 算符优先级和c中一样
 
5. 内置函数
 sil类内置函数是非常少的,详见函数说明,以下列出两个比较重要的。
 eval 可对一个字符串形式的sil代码求值
 例如 eval("for(var i=0;i<5;i=i+1)print(i);");
 load 可以加载一个sil代码文件,代码文件中亦可递归调用load函数
 
6. c++嵌入和扩展
 寥寥数行代码即可将sil嵌入到c++中
 一个c函数只要形参和返回值类型是int float string,简单调用一个register_function即可将函数注册到sil中,脚本即可方便的调用这些扩展函数
 extern工程中的代码示例了如何对sil提供文件读写函数的支持
 
第二节 源代码
 这是一个用vs2008创建的工程,由于使用了shared_ptr,如果给vs2005引入shared_ptr的支持亦可在vs2005下编译通过
 src目录下是sil语言用c++实现的内核
 consle目录下是sil语言的命令行解释器
 extern目录下是一个例子,演示了如何扩展sil的内置函数
 lib目录下是用sil写的库代码和一些测试代码,但是现在只有简单的测试代码(里面有一个开平方根和求圆周率的有意思的例子)
 doc目录下是文档
 bin目录下是可执行文件
 
第三节 函数说明
 to_int 将一个值转换为int类型,例如:to_int("123");
 to_float 将一个值转换为float类型,例如:to_float(2);
 to_string 将一个值转换为string类型,例如:to_string(254);
 strlen 求字符串的长度,例如:strlen("hello");
 substr 截取字符串的的一部分,例如:substr("hello",1,3);
 eval 可以求值一个字符串形式的表达式,例如:  var code="1+2*3";eval(code);
 load 可以加载并执行一个sil代码的文件,例如: load("../lib/math_test.sil");
 exit 终止脚本的执行,例如:print("hello");exit();print("world");
 print 打印一个值,例如:print("hello world"+3);
 read 可以从控制台读取一个字符串,例如:var tmp=read();print(tmp);
 bat 可以执行一个windows命令,例如:bat("dir");
 list_function 打印已经定义的内置函数和脚本函数,例如:list_funciton();
 list_asm_code 打印编译出的代码,例如:list_asm_code();
 set_sil 可以设置解释器的一些开关,例如:set_sil("",0);
 help 显示帮助信息,例如:help();

posted @ 2013-09-02 15:45 flysnowxg 阅读(3258) | 评论 (9)编辑 收藏

2012年5月17日

什么时候动笔?

posted @ 2012-05-17 22:25 flysnowxg 阅读(388) | 评论 (0)编辑 收藏

2012年4月29日

!

posted @ 2012-04-29 17:32 flysnowxg 阅读(285) | 评论 (0)编辑 收藏