《国产编程语言R++ V15.pdf》由会员分享,可在线阅读,更多相关《国产编程语言R++ V15.pdf(50页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、R+1.1+2=32.C3.面向对象4.S表达式5.省略括号6.常量当做对象7.运算符DIY8.无缝内联汇编9.伪代码10.模板函数11.宏12.函数指针13.动态调用函数14.元函数15.动态类型16.反射17.JIT18.多重继承19.可变参数20.默认参数21.多线程22.本地调用23.类型转换24.动态数组25.多参数组26.重载27.指针和引用28.成员变量29.局部变量30.常量31.控制结构32.模板类33.包34.堆35.数据结构36.库37.调试38.文言文39.语言特性1.1+2=3很多语言的第一个程序都是hello world,但是它太难了。下面是R+的第一个例子。mai
2、na=1b=2puts a+b2.CR+也支持C风格,上一个程序可以写成这样:void main()int a=1;int b=2;puts(a+b);对比上一节的程序可以看到R+的一些特点:*更彻底地类型推断,C+11需要使用关键字auto,R+可以省略auto*函数定义和函数调用均可省略后面的小括号*语句后面的分号也可以省略*对于返回值为void的函数,可以省略void(标准C默认返回int)3.面向对象同时R+也支持Java(C#)风格,比如上一个程序可以写成这样:public class mainpublic static void main()int a=1;int b=2;puts
3、(a+b);4.S表达式R+试图模仿Lisp,它可以很好的融合C+的中缀表达式和Lisp的S表达式:mainint aint b=a 1=b 2rf print+a b其中rf print+a b等价于rf print(a+b)等价于rf.print(+a b)等价于rf.print(a+b)注意S表达式不以逗号作为分隔符,所以适当的时候需要加上括号。另一个S表达式的例子:example/4.2.h5.省略括号控制结构(if/for/while)后面的小括号是可以省略的,比如有一个递归求和的函数:int sum(int a)if a=1return 1return sum(a-1)+a那么if
4、 a=1等价于if(a=1)如果if后面有括号,则括号不能省略即不要写成if(a)=1正确的写法是if(a)运算符)借助于R+的运算符自定义功能可以实现一些很有趣的功能比如D=(AB)(AC)这是数学书上的一个表达式,在R+里只要自定义和两个运算符然后设定好优先级,再写两个运算符函数friend vector operator(vector&a,vector&b).friend vector operator(vector&a,vector&b).这段表达式就是可以运行的。看起来就像是你自己定义了一个专用于数学集合运算的新语言因此,R+这种灵活的语法很适合实现领域特定语言(DSL)R+相同优先
5、级的运算符都是从左往右运算的C语言可以这样*p=2但R+只能这样*(*p)=2注意R+的乘法运算符和指针运算符都是*,优先级相同,均为2。而标准C乘法运算符优先级是2,指针运算符优先级是1,两者明显有区别。R+的系统库也不支持连续赋值,C语言里可以这样a=b=2R+只能这样b=2a=b如果一定要连续赋值,可以修改rsrc/int.h这个文件将operator=这个函数改成这样:int&operator=(int a)mov esi,thismov esi,areturn this然后就可以这样a=(b=2)注意括号是必须的可以看到这样的话多返回了一个引用,影响效率rsrc/int.h里面还添加
6、一个反向赋值的运算符函数friend int&operator=(int a,int&this)mov esi,thismov esi,areturn this那么使用这个运算符就可以连续反向赋值2=a=b这样a和b都会赋值为2,其实从左往右赋值有时看起来更直观一些。打开rsrc/basic.h可以找到define-=define !=可见赋值运算符还有另一种写法a-2其等价于a=2而不等于运算符也有另一种写法a!=2等价于a 2BASIC语言的好像看起来更直观一些标准C中减法运算符和负号运算符都是-而R+中减法运算符是-负号运算符是 neg下面3句是等价的:a=-2a=(-2)a=neg 2
7、对于加了括号的常量表达式,会在编译阶段进行求值8.无缝内联汇编在上一节的例子中可以看到,R+用this引用代替了C+的this指针,实际上R+内部引用和指针完全就是一个东西,只是外部访问的时候有些区别C+是这样this-printR+则是this.print同时也可以看到R+支持无缝内联汇编C内联汇编需要用关键字asmasm mov esi,a或者asmmov esi,aR+可以省略关键字asmmov esi,aa是一个局部变量,编译器会把它替换为mov esi,ebp+n其中n是局部变量a的偏移R+的栈空间安排是这样的:(地址从低地址到高地址)ebp局部变量1局部变量2局部变量n返回地址函数
8、参数1函数参数2函数参数n返回值返回值由调用者析构,而函数参数和局部变量由被调用者析构,函数参数从右往左入栈。注意和stdcall以及cdecl都是有区别的,R+的返回值统一放在堆栈中传递,而不是通过eax举个例子:friend int operator+(int a,int b)add a,bmov s_ret,a编译器生成的汇编代码是这样push ebpmov ebp,espadd ebp+8 ,ebp+12 mov ebp+16 ,ebp+8 pop ebpreti 8其中有四条汇编语句是编译器生成的,另外两条是程序员写的由于R+所有类和函数都是public,故友元的含义已经变了,fri
9、end和static是同义语,它们都表示该函数不会自动生成this引用,也就是该函数无法访问到本类的数据成员另外,从V1.5开始operator不再是R+的关键字,也就是说friend int operator+(int a,int b)等价于friend int+(int a,int b)再看看如何调用int.+(int,int)这个函数表达式1+2会首先翻译为int.+(1,2)再翻译成汇编代码sub esp,4push 2push 1call&int.+(int,int)mov esi,espmov ebx,esi add esp,4结合上面的栈空间安排表可以很清楚的看到函数的调用过程所
10、有的寄存器也可以当做一个int类型的变量使用比如想查看一下esp的值可以直接这样:puts esp想计算ecx与edx的商可以这样:puts ecx/edx判断寄存器是否为0:if(eax)但是不可以对寄存器赋值,下面这样是错误的eax=1+2可以改为1+2mov eax,ebx因为凡是返回int或者bool或者指针或者引用的表达式,编译器均会把这个返回值保存到ebx中。R+中bool和int是一样的都是占用4个字节(C+的bool只占用一个字节)R+的汇编指令与x86大部分是相同的,只是另外增加了一些虚拟指令(也可以理解为伪指令),但是这些虚拟指令很容易转换成标准的x86指令。完整的指令列表
11、请参考inside/下的源码。9.伪代码可以把R+当做伪代码写,下面就是算法导论开篇的插入排序代码(由于R+数组从下标0开始而算法导论从1开始,故稍微修改了下)define =insertion_sort(rstr&a)for j 1 to a.count-1key aji j-1while i=0&a.get(i)keyai+1 aii i-1ai+1 keymainrstr a=cab132putsl ainsertion_sort aputsl a其中forto也是一种语法糖for i=1 to 10等价于for i=1;i=10;i+对于方法(函数)参数为空的情况,可以省略后面的括号即
12、a.count等价于a.count()10.模板函数R+的函数模板可以替换任何单词,跟宏差不多,比如有一个递归求和的函数(参考第5节)和一个递归求阶乘的函数int sum(int a)if a=1return 1return sum(a-1)+aint pro(int a)if a=1return 1return pro(a-1)*a发现这两个函数极其相似,那么可以这样定义一个模板函数int func(int a)if a=1return 1return func(a-1)T a像下面这样调用就可以了mainputs func(10)puts func(10)puts func 10puts
13、func 10R+v1.5的模板函数十分强大,不仅支持模板函数作为类的成员,还支持模板动态生成:mainint*p=1pp.to.printlputsl typeof(p.to)A aputs a.funcputs a.funcclass Aint m_a=2int funcreturn m_a+T可以看到模板函数和普通使用方法完全相同,也不需要关键字template,看起来更简洁一些。但是R+的模板函数暂不支持类型推测,也就是说调用模板函数时后面的尖括号是必须的。11.宏R+的define是在预处理阶段进行替换,功能比较弱,一般不需要使用。R+另有一个更好用的宏mac,mac宏属于类的成员,
14、而不是作用于全局,这样可以更好地封装。比如mac fadd(a,b)a+b等价于C语言的#define fadd(a,b)(a)+(b)对于mac宏R+会自动加上一些小括号避免优先级问题c=fadd(1,2)*fadd(1,2)puts c将输出正确的值9另外R+还支持另一种不加括号的宏比如mac fadd2(a,b)a+b这时用c=fadd2(1,2)*fadd2(1,2)puts c得到的是5,显然不是我们想要的结果但是这种宏另有不错的用法请看下面的例子:mainpro=1for i=2;i=10;i+pro+=iputs propro=1for i=2;i=10;i+pro*=iputs
15、 pro这是一个循环求和与循环求阶乘的程序可以看到两段代码明显有相似之处,那么用mac定义一个宏mac fpro(T)pro=1for i=2;i=10;i+pro T iputs pro最后可以这样调用mainfpro(+=)fpro(*=)可以看到这与模板函数极其相似,与C语言的宏相比不需要写一堆的折行符号实际上R+也没有折行符号另外,R+还支持一种拆分宏比如#putsl(1,abc,98)宏展开后是这样:putsl(1)putsl(abc)putsl(98)那么连续插入vector或者set就很方便了vector v#v.push(1,99,2)拆分宏的另一种用法请参考example/1
16、1.3.h12.函数指针R+使用一个比C语言更简单的函数指针语法比如有一个这样的函数:int fadd(int a,int b)return a+b;C语言通常是这样typedef int(*FADD)(int,int);FADD p=fadd;p(1,2);或者int(*p)(int,int)=fadd;p(1,2);可以看到C语言必须要指定函数指针的类型但R+可以直接这样调用int&fadd,1,2或者p=&faddintp,1,2中括号左边表示返回值的类型,(即使返回值为空也必须写void)中括号里面的第一个参数是函数的地址而后面的参数编译器会自动推断出类型&fadd表示获取到函数的地址
17、,这是一个静态地址,注意与标准C的区别,前面的取地址运算符是必须的由于R+的函数指针只有一种类型,即void*那么&fadd得到一个类型为 void*的指针常量如果有多个名字都是fadd的函数(重载),那就必须指定参数的类型:&fadd(int,int)如果类A需要获取到类B的某一函数的地址,那就必须指定类名&B.fadd(int,int)或者&B:fadd(int,int)因为R+中作用域运算符和成员运算符是等价的再看一个函数func(int&a).千万不要这样调用a=2void&func,a因为func的第一个参数a的类型是引用正确的做法是:a=2void&func,&a如果有另外一个函数
18、func2(int*a).也可以这样调用:a=2void&func2,&a13.动态调用函数在运行的过程中决定调用哪一个函数(跟虚函数有点像)这个特性在一些动态语言(python、ruby等)中十分常见。还是拿上一节的函数举例:int fadd(int a,int b)return a+b那么可以根据字符串找到这个函数的地址p=findf(fadd)然后调用puts intp,1,2或者合并上面两句:puts intfindf(fadd),1,2如果有函数重载的情况,就必须明确参数的类型p=findf(fadd(int,int)或者p=findf(main.fadd(int,int)注意这种用
19、法和上一节的函数指针有很大的区别,上一节的函数地址是在编译时确定的,而本节的函数地址是通过在运行时查找字符串获取到的。14.元函数就是用一个程序去生成另一个程序,这个特性在lisp和javascript中十分常见。例如:voidmeta(void lambda()puts 123)等价于voidmeta()puts 123)可以看到元函数的定义方法和普通函数没有区别,一般支持元编程的语言都可以用一行代码实现计算器,R+的版本是这样:voidmeta()putsl+getsl+)或者可以更简单:self(putsl+getsl)R+的self拥有其他语言不具备的能力:mainint a=0sel
20、f(a=3)puts a即self可以和自身进行交互,直接访问函数的局部变量或者参数。访问类成员变量也很容易:class Aint m_a=2funcself(puts this.m_a)另外,R+的元函数是线程安全的。15.动态类型R+既支持静态类型也支持动态类型比如可以这样写func(a,b)puts a+b然后这样调用mainvar a=1var b=2func a,ba=hellob=34func a,b输出是3 hello34可以看到var中保存了变量的类型,那么就可以在运行过程中根据类型调用合适的函数参考rsrc/rt.h可以发现目前R+的动态类型还十分简陋。不过配合typeof关
21、键字和动态调用函数可以实现完整的动态类型。typeof用法请参考:example/15.2.h16.反射R+拥有完整的反射和自省机制,解释器和R+代码几乎可以融为一体:import rpp.hmaintasm*p=&mainp-ptfi-name.printlp-ptfi-ptci-name.printl上面的代码可以打印出自身的所属的函数和类,而打印自身的汇编代码以及表达式语句也很容易:import rpp.hmainr_print_asm(main)putslr_print_sent(main)遍历所有类请参考example/16.3.h以及rsrc/rpp.h17.JITR+V1.5使用
22、PJIT(Pseudocode Just-In-Time),所有的函数在需要时才会被编译,也就是边运行边编译。R+将在下一版本支持RJIT(Real Just-In-Time),理论上RJIT的运行速度和C+完全相同,而编译速度却比C+快得多。下面是各种编译方式的对比表:编译速度运行速度动态特性跨平台传统编译慢快PJIT极快慢RJIT快快表中跨平台意思是无需修改源码,也无需重新编译。18.多重继承R+支持多重继承,不过R+的继承方式很特别,简单而有效举例说明:class Aint m_afam_a=1class B:Afbm_a=2然后这样使用:B bb.faputs b.m_ab.fbput
23、s b.m_a可以看到B类继承了A类的数据成员m_a和函数成员fa对于B类继承自A类,R+只是简单地拷贝代码,因此,R+的继承对程序员是透明的:class Bint m_afam_a=1fbm_a=2就像上面这样,直接把A类的所有代码拷贝到B类的头部。这也是R+的哲学:熟练地运用“Ctrl+C”和“Ctrl+V”可以省下人生80的时间。显然,R+的子类构造时不会自动调用父类的构造函数。且不允许父类和子类存在同名且参数类型和个数都相同的函数。R+目前支持3种继承:*模板继承模板 A:B*模板继承非模板 A:C,D*非模板继承非模板 E:C暂不支持继承模板实例 C:A多重继承的例子请参考examp
24、le/18.2.h19.可变参数R+使用中括号进行可变参数调用,求两个数的和:sum1,2求三个数的和:sum1,2,3实际上R+会自动把参数的个数作为参数传递过去,即sum1,2等价于int&sum,2,1,2目前R+的可变参数用起来虽然简单,写起来却比较痛苦:int sum(int count)/sub esp,sizeof(s_local)/push ebp/mov ebp,espint*p=&count+1int ret=0for(i=0;im_a=2;.R+则是这样:class Aint m_astatic void thread(A&this)this.m_a=2.或者可以更简单地
25、:class Aint m_athreadm_a=2.因为不加static编译器会自动生成一个this引用。创建线程直接调用函数即可:A ap=rf.create_thr(&A.thread,&a)如果需要等待线程退出则:rf.wait_thr(p)如果不想把线程封装进类可以直接这样:rf.create_thr(&thread)22.本地调用由于R+的所有数据类型和C/C+二进制兼容,因此R+调用外部函数十分方便:stdcall(MessageBoxA,0,abc,123,0)注意R+的字符串常量统一使用UTF8,调用UTF16版本的API需要转换编码:stdcall(MessageBoxW,
26、0,utf16c(abc),utf16c(123),0)调用外部的cdecl函数:cdecl(strlen,abc)如果DLL没有加载到当前的进程空间,请先调用LoadLibraryA(W)。23.类型转换R+是强类型语言,没有强制转换,可以通过函数转换类型比如2.touint或者2.to或者uint(2)把有符号整数2转换成无符号整数整数和字符串之间的相互转换是很方便的2.torstr123.tointR+系统库只定义了char和int的相互转换char ch=aputsl ch.toint将输出97char ch=-1putsl ch.toint将输出255注意和标准C的区别,R+将cha
27、r转换为int不会进行符号扩展如果需要char和uint的相互转换请修改rsrc/char.h这个文件R+v1.5开始支持自动类型转换:func(uint a).那么func(2)会自动替换为func(uint(2)所以,请小心定义拷贝构造函数。另外,和Java一样,R+推荐尽量少使用无符号数24.动态数组特别注意下R+的命名规则:类名和对象名不可以同名C+可以这样myclass myclass;R+则不能这样写汇编的关键字不可以用来命名变量,但可以命名函数比如vector类中有一个push函数,和汇编关键字push同名vector aa.push(2)是没问题的R+用rbuf代替STL的ve
28、ctor,用rstr代替string用法大致是相同的。push就是vector的push_backcstr()就是string的c_str()打开rsrc/basic.h可以找到#define vector rbuf#define string rstr习惯于vector和string的朋友也可以使用这两个名字要注意的是rbuf的size()方法和count()方法是不同的vector aa.push(2)putsl a.sizeputsl a.count输出是41即size返回所有元素占用的字节数,而count返回元素个数,这和STL是有区别的。25.多参数组R+没有静态数组,从V1.5开始
29、也不再提供数组定义的语法糖,仅使用多参数组(数组运算符带多个参数)来实现多维数组:import rbufm.hmainrbufm arr(5,5)for i=0;i5;i+for j=0;j5;j+arri,j.print下面是三维数组的例子:import rbufm.hmainrbufm arr(5,3,4)for i=0 to 4for j=0 to 2for k=0 to 3arri,j,k.print需要注意的是,如果将数组作为函数参数传递,会传递数组的拷贝,也就是说,形参数组和实参数组互不影响。如果形参数组和实参数组需要共享内存,那么可以传递引用:func(rbufm&arr).当然
30、也可以使用嵌套的模板来定义多维数组:mainrbufrbufrbuf arrarr.alloc(5)for i in arrarri.alloc(3)for j in arriarrij.alloc(4)for i in arrfor j in arrifor k in arrijarrijk.print以上代码定义了一个5层3行4列的三维数组(未初始化输出的是随机值),其中的for.in.也是一种语法糖for i in arr等价于for(i=0;iarr.count;i+)另外,R+不支持重载小括号,但是可以重载中括号实现C+的函数对象(仿函数)。26.重载不同类型指针作为函数参数传递时不
31、需要强制转换,因此仅有指针类型不同的函数不能重载,下面的写法是有歧义的:func(int*a).func(char*a).不同类型的引用可以重载:func(int&a).func(char&a).相同类型的引用和非引用可以重载:func(int&a).func(int a).下面是自定义结构体的例子:class Aint*m_pA()m_p=r_new5A(A&a)m_p=r_new5for i=0 to 4m_pi=a.m_piA()if(m_p!=null)r_deletem_pm_p=nulloperator=(A&a).自定义类型必须提供两个拷贝构造函数(一个引用一个非引用),如果没有
32、非引用版本编译器会自动生成一个和引用版本函数体完全相同的函数,赋值函数也是一样。另外,默认参数的重载规则和C+一样,不再赘述。27.指针和引用R+里引用不是“别名”,而是地址,因此千万不要这样写:a=2int&b=a正确的做法是:a=2int&blea b,ebp+s_off a其中s_off表示取得局部变量的偏移,这样的话a与b共享同一段内存a.printb.print将输出两个2一般不会使用引用作为局部变量,而是使用引用作为函数参数:func(a)a.print函数func的定义是func(int&n)n=5指针的用法和标准C差不多:a=3p=&aa.printp-print对于二重指针(
33、或以上)则不可以使用类型推断:a=4p=&aint*pp=&p对于三重指针(或以上)R+也没有定义语法糖,因此需要使用嵌套的模板来定义:rprprp ppp=&ppputs*(*(*ppp)由此可以看到R+的指针实际上是模板类的一个实例,具体情况请参考:rsrc/rp.h28.成员变量举例说明:class Aint m_a=2int m_b(3)A()即对于类的成员变量(数据成员),可以直接在定义处初始化,上面的例子等价于:class Aint m_aint m_bA()m_a=2m_b=3即编译器会自动在该类的每一个构造函数的头部加上这么一个初始化语句另外,R+将类的成员变量统一按1字节对齐
34、:class Achar m_aint m_b这样的话sizeof A将返回5。注意这样写的话在x86上不会有问题,但移植到arm上就有问题了,故不推荐这种写法。如需使用全局变量请暂时先使用V1.129.局部变量和javascript一样,R+的局部变量在整个函数都是可见的,比如:for(int i=0;i=10).重复定义两个名字和类型都相同的变量也是允许的:vector vv.push(2)v.count.printvector vv.count.print输出是1 0因为R+中定义变量会先析构后构造,这表示将一个变量重新初始化。故R+的类必须支持空构造函数(即使没有编译器也会自动生成一个
35、),并且需要在析构的时候判断是否已经析构:class Aint*m_pA()m_p=r_new5A()if(m_p!=null)r_deletem_pm_p=null另外,可以使用赋值运算符进行类型推断:a=1+2等价于auto a=1+2等价于int a=1+230.常量R+目前还不具备perl那种强大字符串处理能力,不过也向它学习了一些经验。对于双引号扩起来的字符串,编译器并不会总是提供语法糖(请参考No.6),实际上它还是标准C的以0结尾的ASCII串。所以,为了方便处理,R+还提供了一个用单引号字符串:123等价于rstr(123)因此,单引号字符串完全可以当做内置字符串使用,转换成C
36、字符串可以这样:123.cstr连续两个反斜杠表示从当前位置到本行末均为单引号字符串,并且不进行转义:s=abc123等价于s=abc123主要用于字符串内部转义字符和引号很多的情况R+没有字符常量,但是提供一个反单引号:a等价于整数97如果整数比较长可以用下划线分隔:1_0000_0000等价于100000000以0 x开头的常量表示16进制整型常量,以0b开头的常量表示二进制整型常量:0 xa等价于0b1010等价于10双精度浮点(double)常量只有小数写法比如0.531.控制结构选择结构和大多数语言一样:if.dosomethingelif.dosomethingelsedosome
37、thing对于省略花括号的情况,编译器会自动加上花括号;对于花括号没有单独占一行的情况,编译器会自动换行,要注意编译器提示的行号是自动处理之后的行号。打开rsrc/basic.h可以找到#define elif else if即elif是一个宏条件结构是这样:switch.case 1.case 2.default.或者switch.case 1.case 2.default.R+的条件结构不需要break,case最后的冒号是可选的,但case后面的花括号是必须的。default是可选的,但如果有必须排在最后。(实际上目前R+还没有进行switch优化)循环结构是这样:for i=1;i10
38、;i+.for i10.死循环有几种写法:for true.for 1.for.打开rsrc/basic.h可以找到#define while for即while和for是同义语,是否赋初值和执行增量仅取决于条件表达式里面有没有分号另外,R+有两种continue:continued用于不执行增量直接进行条件判断continue用于执行增量后再进行条件判断至于break和大多数语言一样,不再赘述。(是否要增加关键字用于跳出多重循环是一个值得讨论的问题)和Go语言一样,R+也抛弃了do.while下面是do.while的等价写法:for.ifn(i=10)其中ifn和until都是宏,请参考rs
39、rc/basic.hR+的goto和jmp是同义语下面是一个死循环F:.jmp F如果你确定某个函数编译器没有自动换行,可以直接在jmp后面加一个整数表示直接跳转到该行,下面是直接跳转到第7行:.jmp 7进行条件跳转也是很容易的:abjebxz Gputsl a less than bG:等价于if(ab)putsl a less than b注意只有下面几种类型的表达式可以作为条件表达式:1:int2:bool3:指针4:引用如果使用其它类型作为条件表达式会在运行时出错。另外R+不支持惰性求值(这是由于R+把一切运算符都作为函数处理)而且R+会在非引用返回值传递引用的情况下增加临时变量,所
40、以不要依赖函数的传参顺序。下面的写法是错误的:if p!=null&*p=2.可用等价的写法代替if p!=nullif*p=2.或者if p=nullreturn falseif*p=2.32.模板类模板类用法与C+大致相同,但是R+不支持template meta programming,暂时也不支持模板默认参数。class AT m_aAmainA aAA ba.m_a.printb.m_a.m_a.print注意模板类构造函数和析构函数写法和C+不同,后面必须有尖括号和模板参数。关于模板类嵌套请参考example/32.2.h33.包R+中import等价于#include使用方法:i
41、mport A.h或者import A.h注意不要这样写import 因为R+不支持尖括号文件名用双引号括起来的文件名R+会在当前目录和编译器目录搜索和D语言、objective-c一样R+会自动处理重复包含的问题。R+中类和函数均不需要声明即可使用,也就是说R+没有.cpp文件,只有.h文件(这样就不需要向前声明,递归引用也是允许的)(v1.5的“包”仍在开发中,如需使用“包”请暂时先使用v1.1)另外,由于R+暂不支持类嵌套,因此命名空间里面也不可以包含类,也不允许命名空间嵌套:namespace MY/R+没有枚举变量,只有枚举常量enumc_a=2c_b=4funcputs c_ama
42、inMY.funcMY:funcputs MY.c_aputs MY:c_b打开rsrc/basic.h可以找到#define namespace friend class清楚地看到R+的命名空间不过是一个友元类,或者可以称为静态类,即所有函数都没有this。34.堆R+的new和delete既不是运算符,也不是关键字,而是模板函数:p=r_new(5)表示从堆中分配5个intr_delete(p)表示释放刚才分配的内存(不需要delete p)一般来说,不需要使用new和delete,(一个很简单的原因,不用new就几乎不可能出现内存泄露)推荐使用rbuf来进行内存分配:rbuf a(5)因
43、为rbuf会在析构时自动释放内存,当然也可以手动释放:a.free可以使用数组运算符或者a.begin或者a.m_p访问刚才分配的内存如果只需要一个对象,Java通常是这样:B b=new B();而R+则这样:B b一个对象通常在栈中分配就行了。35.数据结构R+内核非常小,没有内置数据结构,甚至可以认为R+没有内置数据类型,所有类型均在外部定义,这样做的好处是如果需要移植到64位,编译器只要做很小的改动。下面是以模板类的形式提供的几种数据结构:名称用途rbuf动态数组,栈rstr字符串rstrwutf16字符串rlist双向链表,队列,栈rset红黑树rhash哈希表另外,rsrc/ral
44、go.h提供了快速排序、二分查找、split,示例代码请参考example/35.x.h36.库R+解释器提供了一些常用函数,可以直接调用,当然也可以使用封装好的类:名称用途rflie文件操作rdir遍历目录rsockTCP套接字rmutex互斥体示例代码请参考example/36.x.h37.调试如果语法通过而逻辑出错,建议先使用注释和输出语句来确定出错的位置,然后使用第16节的反射方法打印出相关函数的表达式语句和汇编代码。此外,R+还提供一个性能分析器(参考黑客与画家),请将rpp_debug.exe.rename改名为rpp_debug.exe然后执行rpp_debug.exe x.h运
45、行完成以后会打印出所有函数的执行次数,以便找出性能瓶颈。作为一个意外的发现,性能分析器还能检测出内存泄露,只要简单看一下malloc和mfree这两个函数调用次数是否相同。38.文言文R+的标识符支持中文,源文件支持GBK、Unicode(UTF16 little endian)以及UTF8三种编码。使用R+来进行文言文编程看起来好像用处不大,只是为了发挥DIY精神:主即曰你好也上面是中文编程的第一个例子,打印“你好”。运行这个例子之前请先设置控制台(因为R+的字符串常量使用UTF8)chcp 65001然后在命令行标题栏上点击右键,选择属性-字体,将字体修改为True Type字体Lucid
46、a Console,再点击确定将属性应用到当前窗口。然后删除rinf/optr.txt再将rinf/optr2.txt重命名为rinf/optr.txt最后反注释rsrc/basic.h中的第一行:import chs.h下面再看一个递归求和的例子:主即曰和 100也数和 数甲 即若甲 小于2归1归甲 加和 甲 减1也注意有些地方要用空格分隔,更多的例子请参考:example/38.x.h39.语言特性特性R+C+JavaLisp模板宏不太安全运算符自定义仅重载仅前缀语法简洁简洁不太简洁较简洁极简洁内联汇编指针元编程(非模板)动态编译模块(包)v1.1支持内置并行通讯依赖解释器双运行模式不依赖依赖依赖国产以上列举了几种语言的关键特性,可以看到R+的确像C+和Lisp的综合体,不过目前R+无论是运行速度还是成熟度,都无法和这些主流语言竞争。