下面这些java字符串首字母小写串,哪个与众不同

与众不同的Forcal
与众不同的Forcal
本文罗列了Forcal与其他脚本的一些不同之处。
Forcal是一个可对字符串表达式进行动态编译和运行的动态链接库(dll)。
Forcal用等号定义一个函数。
Forcal有五种变量:自变量、动态变量、静态变量、模块变量、全局变量。
整数、实数和复数表达式。整数、实数和复数数据。
Forcal中可使用三对等效的括号( )、[ ]、{ }。
常量、变量和函数是Forcal语法的三块基石,各种运算符特别是逗号(冒号、分号)运算符和括号运算符是基石之间的粘结剂。
Forcal模块对私有数据的访问提供了良好支持。
模块命名空间可以继承,甚至可以循环继承。模块命名空间是一棵树或者是一个连通图。
Forcal程序的编译和运行不是截然分开的,在编译中有运行,在运行时可编译。
函数oo{..., a+b, ...}中的运算符将被重载。
既可以手动回收垃圾以提高运行效率,也可以完全依赖于Forcal的垃圾自动回收机制。
使用错误(异常)处理的恢复模型。
Forcal核心库没有任何内建对象,甚至连动态数组也不支持,但Forcal核心库为创建任意对象提供了良好的支持。
类模块=数据结构+算法。
FORCAL32W.DLL文件大小:约130K;不使用MSVC运行库的静态库版本,约260K~300K。
一级函数速度约为FORTRAN(或C/C++)执行速度的50%左右;其他情况,速度稍有下降。
Forcal以动态链接库的形式存在,用Win32标准函数调用方式(stdcall调用协议)输出了动态库函数,使用极为方便。
很容易对Forcal进行功能扩展,可用C/C++、delphi、FORTRAN等语言设计Forcal扩展动态库。
所有的扩展库都是根据核心库的输出函数设计的。
彻底地保护私有数据是Forcal的基本特色。
二级函数是Forcal功能扩展的基本方式,二级函数必须检测并报告所有可能出现的错误,以实现错误处理的恢复模型。
若标识符后面有句点“.”,表示将该标识符联系到一个函数,或者产生一个函数调用。
逗号、冒号和分号是Forcal的三种等价的分隔符,增强了程序的可读性。
中文编程给用户很大方便。
三种表达式、三种括号、三种分隔符、三块语法基石。
主程序和Forcal脚本中均可生成或销毁对象。
27 偏爱自动垃圾回收
用Forcal设计完全自动垃圾回收的系统。
通常,使用各种高级语言如C/C++、VB、delphi、FORTRAN等设计的程序,不能对源代码进行动态编译,Forcal可为所有这些应用程序增加对字符串源代码的动态编译功能。Forcal可用于各类数学软件的设计,也可用作报表处理、web、组态软件、游戏等的脚本,具有很高的执行效率。
Forcal32W.dll是Forcal的32位Unicode版本,是一个对Unicode字符型表达式进行编译计算的动态库。表达式中可以使用的运算符有+、-、*、/、^、&、&=、&、&=、==、!=、&、|、!、++、--等等,Forcal具有数值计算、逻辑运算、关系运算、字符数据处理、流程控制、函数调用等许多的可编程功能。
&&& Forcal用等号定义一个函数,与数学中定义函数的方式一致。例如:
f(x,y)=x+y;
Forcal有五种变量:自变量、动态变量、静态变量、模块变量、全局变量。自变量、动态变量和静态变量只能被定义该变量的表达式所访问;模块变量可被同一模块的所有表达式所访问,其他模块的表达式无法访问;全局变量可被所有的表达式所访问。自变量用于向表达式传递参数,因此自变量也称为形式参数。动态变量只在表达式执行时起作用,一旦表达式执行完毕,动态变量也随之失效。静态变量存在于表达式的整个生命周期,每次表达式执行完毕,静态变量的值被保留。FORCAL在编译表达式时,将所有静态变量初始化为0,其余的变量均不进行初始化。
&&& 定义格式如下所示:
F(a,b : x,y,static,u : s,t,common,v)=
F是表达式的名字(可以缺省),a和b是自变量,x和y是动态变量,static和u是静态变量,s和t是模块变量,common和v是全局变量。
自变量、动态变量和静态变量以及模块变量和全局变量之间用冒号分隔,即第一个冒号前为自变量,两个冒号之间为动态变量和静态变量,第二个冒号后为模块变量和全局变量。两个冒号之间用关键字static分隔动态变量和静态变量,static之前为动态变量,static及以后变量均为静态变量,关键字static只能用在两个冒号之间。第二个冒号后用关键字common分隔模块变量和全局变量,common之前为模块变量,common及以后变量均为全局变量,关键字common只能用在第二个冒号后。FORCAL中的所有变量均可缺省。
&&& 以下都是合法的变量定义的例子:
F()= ... ...&&&&&&&&&
//没有使用任何变量,称无参表达式(等号前部分连同等号可以缺省);
F(::)= ... ...&&&&&&&
//没有使用任何变量,称无参表达式(等号前部分连同等号可以缺省);
F(a,b)= ... ...&&&&&&
//定义了两个自变量a和b;
F(:x,y)= ... ...&&&&&
//定义了两个动态变量x和y;
F(:static,u)= ... ... //定义了两个静态变量static和u;
F(::s,t)= ... ...&&&&
//定义了两个模块变量s和t;
F(::common,v)= ... ...//定义了两个全局变量common和v;
F(a,b:x,y)= ... ...&&
//定义了两个自变量a和b,两个动态变量x和y;
F(a,b::s,t)= ... ...&
//定义了两个自变量a和b,两个模块变量s和t;
F(:x,y:s,t)= ... ...&
//定义了两个动态变量x和y,两个模块变量s和t;
FORCAL表达式(函数)有三种类型:整数表达式、实数表达式和复数表达式;相应地,FORCAL中有三种基本的数据类型:整数、实数和复数。例如:
//整数表达式,在一般的Forcal程序中,整数表达式以i:开头;
r:2.2+3; //实数表达式,在一般的Forcal程序中,实数表达式以r:开头;
c:2+3i;& //复数表达式,在一般的Forcal程序中,复数表达式以c:开头;
//实数表达式,在一般的Forcal程序中,缺省是实数表达式;
FORCAL编译器在编译表达式时,将整数表达式中的数据都转换成整数(64位有符号整数,范围从-75807);将实数表达式中的数据都转换成实数(64位双精度实数,范围大致从±1.7E-308~±1.7E+308);将复数表达式中的数据都转换成复数(128位双精度复数,复数的实部和虚部都是64位双精度实数,范围大致从±1.7E-308~±1.7E+308),如果数字后有i,表示一个虚数。
在FORCAL实数或复数表达式中,数字可以带小数点,也可以不带小数点,还可以用科学记数法表示数字。小数的表示非常灵活,小数点前面的零或后面的零可省,例如:5.6、5.、.6都是合法的数据表示。用科学记数法表示的数字,例如:10.3E8、2E-10等,其中用E表示以10为底的指数部分,但指数不能为小数,例如:3E5.6、8.6E-6.7不合法。
在FORCAL整数表达式中,数字既可以是10进制数,也可以是16进制数,但数字中不能包含小数点,也不能用科学记数法表示数字。16进制整数以0x开头,并用A~F表示10~16,例如:0x1A、0xB、0x123D等。
&&& Forcal的三种表达式各有所长,且可以相互调用,以方便快捷地满足各种需要。
&&& Forcal中可使用三对等效的括号( )、[ ]、{
},符合数学习惯,故代码清晰易懂。例如:
f(a,b)=2+sin{1.2-sqrt[a+(b-c)^2]};
常量、变量和函数是Forcal语法的三块基石,各种运算符特别是逗号(冒号、分号)运算符和括号运算符是基石之间的粘结剂,Forcal语法大厦由此而构成。
Forcal中没有关键字,但有些符号常量、变量名或函数名使用很频繁,可当作“关键字”来使用,这又另当别论。
&&& 逗号(冒号、分号)运算符和括号运算符使得Forcal语法简洁规范而又完整,因而是理解Forcal语法的钥匙。
表达式(或函数)中如果有多个语句,可以用逗号、冒号或分号进行分隔,FORCAL将按从左到右的顺序计算各个语句,并返回最后一个语句的值。也可以将多个用逗号、冒号
或分号分隔的语句放在一个括号内,FORCAL也将按从左到右的顺序计算各个语句,并返回最后一个语句的值。例如:
(:x)= x=2,x=5,x;&&&&&&&&&&&&&&&&&&&&&&&&
//返回值为5;
(:x)={x=2,x=5,x};&&&&&&&&&&&&&&&&&&&&&&&
//返回值为5;
(:x,y)={x=2,y=5,x=[x=x+1,y=y+1,x+y]:x};&
//返回值为9;
(:x,y)={x=2,y=5,[x=x+1,y=y+1:x+y]};&&&&&
//返回值为9;
&&& Forcal中的流程控制是用函数来实现的,且只有如下5个函数:
&&& (1)立即返回函数 return(x)
&&& 结束计算并立即返回表达式的值为x。
&&& (2)判断函数 if(x,y1,y2,... ...,yn)
&&& 当逻辑语句x的值为真时,依次执行语句y1,y2,... ...,yn,否则,不执行语句y1,y2,... ...,yn。
&&& (3)自定义分段函数
&&& 逻辑语句1,语句1,
&&& 逻辑语句2,语句2,
&&& ... ...,
&&& 逻辑语句n,语句n,
&&& 缺省语句
FORCAL从前往后计算并检测逻辑语句的值,当检测到逻辑真时,计算与此逻辑真对应的语句并返回该语句的值,如果没有检测到逻辑真,则计算缺省语句的值作为返回值,若此时没有缺省语句,则产生一个运行错误(错误代码为0)。
&&& (4)while循环函数
while循环是“当型”循环,其特点是:先判断条件是否成立,当条件成立时,则执行循环体,否则退出循环体,即“当条件成立时执行循环”。“当型”循环的循环体有可能一次也不执行。while循环函数的格式如下:
&&& y1,y2,
&&& break(),
&&& continue(),
&&& 其中x为逻辑语句;y1,y2,...,break(),...,continue(),
...yn为循环体语句。当x的值为真时,依次执行循环体语句,直到x的值为假时退出循环。当执行到break()函数时,跳出while循环,执行while循环后面的语句部分;当执行到continue()函数时,返回到while循环的开始语句x处继续执行。
&&& (5)until循环函数
until循环是“直到型”循环,其特点是:先执行循环体,再判断条件是否成立,当条件成立时,退出循环体,否则继续执行循环体,即“执行循环直到条件成立”。“直到型”循环的循环体至少执行一次。until循环函数的格式如下:
until{x1,x2,
&&& break(),
&&& continue(),
until为先执行后判断的循环函数。即先执行循环体语句x1,x2,...,break(),...,continue(),...,然后计算逻辑语句y的值,直到y的值为真时退出循环。当执行到break()函数时,跳出until循环,执行until循环后面的语句部分;当执行到continue()函数时,返回到until循环的开始语句x1处继续执行。
&&& 以下是一个Forcal程序的例子:
// 据测定,以下八皇后问题,Forcal的运行速度约为C++的1/10。
// 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是19世纪著名的数学家高斯1850年提出:
// 在8×8格的国际象棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
// 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
// 以下算法是从网上搜来的,该算法没有最终给出排列组合,仅仅给出有多少种组合,但是算法确实十分奥妙。
//Forcal源程序
i:(::sum,upperlim)=
sum=0,upperlim=1,SetIntStackMax(1000);
i:test(row, ld, rd : pos,p : sum,upperlim)=
&&& {&& row != upperlim,
&&&&&&& {&& pos = and{upperlim , not[row.or(ld).or(rd)]},
&&&&&&&&&&& while{ pos,
&&&&&&&&&&&&&&& p = and(pos,-pos),
&&&&&&&&&&&&&&& pos = pos -p,
&&&&&&&&&&&&&&& test(row+p, shl(ld+p,1), shr(rd+p,1))
&&&&&&&&&&& }
&&&&&&& },
&&&&&&& sum++
i:main(:tm,n:sum,upperlim)=
&&& tm=sys::clock(),
&&& printff(&Queens:{1,i}, &,n),
&&& upperlim=shl(upperlim,n)-1,
&&& test(0,0,0),
&&& printff(&sum:{1,i}, {2,i}毫秒.\r\n&,sum,sys::clock()-tm)
Forcal运行结果:
&&& Queens:15, sum:547毫秒.
完成相同功能的C++程序:
#include &stdio.h&
#include &stdlib.h&
#include &time.h&
long sum=0,upperlim=1;
void test(long row, long ld, long rd)
&&& if (row != upperlim)
&&&&&&&&&&& long pos = upperlim & ~(row | ld | rd);
&&&&&&&&&&& while (pos){
&&&&&&&&&&&&&&& long p = pos& -
&&&&&&&&&&&&&&& pos -=
&&&&&&&&&&&&&&& test(row+p, (ld+p)&&1, (rd+p)&&1);
&&&&&&&&&&& }
&&&&&&& sum++;
int main(int argc, char *argv[])
&&& int n=15;
&&& if(argc!=1)n=atoi(argv[1]);
&&& tm=time(0);
&&& if((n&1)||(n&32))
&&&&&&& printf(& heh..I can’t calculate that.\n&);
&&&&&&& exit(-1);
&&& printf(&%d Queens\n&,n);
&&& upperlim=(upperlim&&n)-1;
&&& test(0,0,0);
&&& printf(&Number of solutions is %ld, %d seconds\n&, sum,(int)(time(0)-tm));
&&& VC运行结果:
Number of solutions is
&&& 通常,可以用编译符#MODULE#及#END#定义一个模块,用编译符~输出模块中的全局表达式,否则为私有表达式。另外,若表达式名称前有编译符!(首先解释为立即执行编译符,而不是逻辑非运算符),在编译后将立即执行;若表达式名称前有编译符:,只编译,不执行。如下例:
#MODULE#&&&&&&&&&&&&&&&&&&&
//定义一个子模块
mvar:&&&&&&&&&&&&&&&&&&&&&&
//编译符mvar:说明该模块中没有声明的变量为模块变量
aa=11, bb=22;&&&&&&&&&&&&&&&//定义了模块变量aa、bb,在模块外部无法访问
!a()= printff(&字符串!&);&
//模块私有表达式,编译后立即执行
f(x)= x+1;&&&&&&&&&&&&&&&&& //模块私有表达式
:g()= 100;&&&&&&&&&&&&&&&&&
//模块私有表达式,只编译,不执行
~h(x)= f(x)+g()+aa+&&&&&
//全局表达式
#END#&&&&&&&&&&&&&&&&&&&&&& //子模块定义结束
mvar:&&&&&&&&&&&&&&&&&&&&&&
//编译符mvar:说明该模块中没有声明的变量为模块变量
aa=55, bb=66;&&&&&&&&&&&&&&&//定义了模块变量aa、bb,在模块外部无法访问
f(x)= x+&&&&&&&&&&&&&&&&&//主模块中的私有表达式,可以使用与其他模块中的表达式相同的名字
f[3];&&&&&&&&&&&&&&&&&&&&&& //调用主模块中的函数f
h[3];&&&&&&&&&&&&&&&&&&&&&& //调用子模块中的全局表达式
&&& 可以看出,Forcal的模块化编译功能对私有数据的访问提供了良好支持。
&&& 使用命名空间可以有效地避免函数重名问题。Forcal中可以用函数Module创建模块命名空间,命名空间创建后,可以用函数OutFun输出该模块的表达式,不管是私有表达式还是公有表达式,都可以输出。
&&&&& Module(&Name&:&Name1&,&Name2&,...
...)&&& //创建模块命名空间Name,继承自&Name1&,&Name2&,... ...
&&&&& OutFun(&fun1&,&fun2&,&fun3&,...
...)&&&&& //输出模块命名空间中的表达式&fun1&,&fun2&,&fun3&,...
&&& 模块命名空间只能创建一次,可以继承,甚至可以循环继承,如果确实有必要。模块命名空间是一棵树或者是一个连通图。
&&& 当模块中有表达式时,才能创建该模块的命名空间,当该模块中的最后一个表达式被销毁时,将同时销毁该命名空间。
&&& 当为一个命名空间指定父空间(基空间)时,该父空间是否存在可以是未知的,即父空间并不一定要先于子空间而存在。
&&& 模块命名空间中输出的表达式可以用命名空间成员访问符::调用,如:Name::fun1(...)。如果该命名空间中没有输出指定的表达式,而该空间的父空间中输出了同名表达式,就会调用父空间中的同名表达式。可以连续使用访问符::直接调用指定父空间(或该父空间的父空间)中的表达式,如:Name1::Name2::Name3::fun1(...)。可以看出,模块命名空间中的表达式调用规则类似于C++中的虚函数调用规则。
&&& 由于Module和OutFun是两个函数,为了使创建的空间及输出函数立即可用,应在编译完Module或OutFun所在的表达式后,立即执行该表达式。
&&& 例子:
//定义一个子模块
!Module(&AA&);
//创建模块命名空间AA,该表达式编译后将立即执行
Set(x::xx)= xx=x;
//模块私有表达式
Get(::xx)=
//模块私有表达式
aa()= 111;
//模块私有表达式
!OutFun(&Set&,&Get&,&aa&);
//输出模块命名空间中的表达式,该表达式编译后将立即执行
//子模块定义结束
//定义一个子模块
!Module(&BB&,&AA&);
//创建模块命名空间BB,继承自&AA&,该表达式编译后将立即执行
Set(x::xx)= xx=x;
//模块私有表达式
Get(::xx)=
//模块私有表达式
!OutFun(&Set&,&Get&);
//输出模块命名空间中的表达式,该表达式编译后将立即执行
//子模块定义结束
//以下都是主模块中的表达式
aa()= 999999;
//调用主模块中的表达式aa,结果为:999999
//通过模块空间BB调用空间AA中的表达式aa,结果为:111
BB::Set(33);
//调用模块空间BB中的表达式Set,结果为:33
BB::Get();
//调用模块空间BB中的表达式Get,结果为:33
BB::AA::Set(55);
//调用模块空间AA中的表达式Set,结果为:55
BB::AA::Get();
//调用模块空间AA中的表达式Get,结果为:55
BB::Get();
//调用模块空间BB中的表达式Get,结果为:33
AA::Get();
//调用模块空间AA中的表达式Get,结果为:55
&&& Forcal程序的编译和运行不是截然分开的,在编译中有运行,在运行时可编译。例如:
#MODULE#&&&&&&&&&&&&&&&&&&&&&&&&
//定义一个子模块
& !Module(&AA&);&&&&&&&&&&&&&&&&
//创建模块命名空间AA,该表达式编译后将立即执行
& Set(x::xx)= xx=x;&&&&&&&&&&&&&
//模块私有表达式
& Get(::xx)=&&&&&&&&&&&&&&&&
//模块私有表达式
& !OutFun(&Set&,&Get&);&&&&
//输出模块命名空间中的表达式,该表达式编译后将立即执行
#END#&&&&&&&&&&&&&&&&&&&&&&&&&&&
//子模块定义结束
AA::Set(55);&&&&&&&&&&&&&&&&
//调用模块空间AA中的表达式Set,结果为:55
AA::Get();&&&&&&&&&&&&&&&&&&&&&&
//调用模块空间AA中的表达式Get,结果为:55
&&& 以上模块中,若函数Module和OutFun不设置为编译后立即执行,则下面的函数AA::Set和AA::Get在编译时就会不可识别。
&&& 再如下面的例子:
!using(&sys&);&&&&&&&&&&&&&&&&&&&
//使用命名空间sys,编译后立即执行
main(:pf,a)=
& oo{pf=fcfor()},&&&&&&&&&&&&&&&&
//申请保存Forcal表达式句柄的FcData数据指针,
& comfor(pf,&f(x)=x+1&,2,100,0,0),&&&
//将Forcal静态字符串动态编译为全局的实数表达式
& a=HFor(&f&),&&&&&&&&&&&&&&&&&&& //获得函数f的句柄
& a[5];&&&&&&&&&&&&&&&&&&&&&&&&&& //动态调用函数f
&&& 在Forcal脚本中,函数oo{..., a+b,
...}中的运算符将被重载(该函数不可嵌套使用),运算符的第一操作数(例如a+b中的a)将被看作是一个指针(指向一个对象),Forcal在运算时将查找该指针的运算符重载函数,如果找到就调用该函数,否则将返回一个运行错误。有些重载运算符会返回一个临时对象,甚至某些二级函数也会返回一个临时对象,所有临时对象在生命期结束时自动销毁。
&&& 所有在oo函数中产生的临时对象的生命期不大于oo函数所在表达式运行时的生命期,即当一个表达式运行结束时,所有在该表达式中由oo函数产生的临时对象都将被销毁(若用函数to将临时对象转换为一般对象,则表达式的运行生命期结束时不会被销毁)。
&&& 注意:在Forcal脚本中无法定义运算符的重载,运算符重载是由设计该对象的程序员实现的。
对于C/C++或者Delphi程序员,或者只要使用的语言支持指针,都可以设计自己的对象加入Forcal系统,并为这些对象添加运算符重载功能。
&&& 以下是FcMath库中矩阵运算的例子,注意使用了运算符重载:
!using[&math&,&sys&];
(:t0,k,i,a,b)=
&&& t0=clock(),
&&& oo{k=zeros(5,5)},&&&&
//生成5×5矩阵k,初始化为0
&&& i=0,(i&1000).while{&& //循环计算1000次
&&&&&&& oo{
&&&&&&&&&&& a=rand(5,7), b=rand(7,5),
//生成5×7矩阵a,7×5矩阵b,用0~1之间的随机数初始化
&&&&&&&&&&& k.=k+a*b+a(0,4:1,5)*b(1,5:0,4)+a(neg:6)*b(3:neg)
//计算k=k+a*b+a(0,4:1,5)*b(1,5:0,4)+a(neg:6)*b(3:neg)
&&&&&&& },
&&&&&&& i++
&&& k.outm(),&& &&&&&&&&&
//输出矩阵k,然后销毁k
&&& [clock()-t0]/1000& &&
//得到计算时间,秒
C程序员要自己管理内存的分配和回收,而Python具有垃圾自动回收的机制,Forcal的动态内存管理兼有二者的特点:既可以手动回收垃圾以提高运行效率,也可以完全依赖于Forcal的垃圾自动回收机制。通常,Forcal中用类似new的函数生成动态对象,而用类似delete的函数销毁动态对象,这一点类似于C,用户可以高效地管理内存;所有用户没有销毁的对象,会由Forcal的垃圾收集器管理,并最终会被Forcal安全地回收,这一点类似于Python。
&&& Forcal核心库中并没有提供生成动态对象的函数,Forcal核心库只对创建动态对象提供了良好的支持。这意味着,支持模块可以使用C/C++、Delphi等语言创建任意的动态对象并加入Forcal系统。例如,Forcal数据类型扩展动态库FcData就是一个能创建动态对象的功能模块。
在Forcal中,一个对象用一个指针标识,在32位平台上,一个指针是存放在一个数(整数、实数或复数)的前4个字节中,此时,我们也称这个数为指向该对象的指针。若Forcal系统中的静态变量、模块变量、全局变量以及正在运行的表达式的数据区(自变量、动态变量及数据堆栈)中存在一个数指向一个对象时,该对象是有效的,否则视为垃圾对象,会被垃圾收集器所回收。
由于只要有一个指针(直接或间接)指向某对象,该对象就不会被垃圾收集器回收,故若要确保立即销毁某对象,应使用delete之类的专用函数,而不要依赖垃圾收集器。
Forcal的内存管理特点:(1)与C/C++类似,用户可立即销毁一个对象,这是推荐使用的方法;(2)被用户忽略的垃圾将被自动回收;(3)任何时候,可手动立即启动垃圾收集器;(4)垃圾回收是有运行开销的,但如果用户有效地管理了内存,垃圾回收器可以一次也不启动。
&&& 例如以下例子:
//arrayinit[1,3 :
1,2,3]用于申请存放3个变量的一维动态数组并初始化,该一维动态数组是一个FcData对象
!using[&math&];
main(:i,s,a,b,c)=
&&& s=0,i=0, while{++i&=10000,
//循环10000次,将多次自动启动垃圾收集器,效率低
&&&&&&& a=arrayinit[1,3 : 1,2,3], b=arrayinit[1,3 : 1,2,3], c=arrayinit[1,3
&&&&&&& s=s+a[0]+b[1]+c[2]
&&& s&&&&&&&&&&&&& //返回结果
&&& 改成手动管理内存可提高运行效率:
!using[&math&];
main(:i,s,a,b,c)=
&&& s=0,i=0, while{++i&=10000,
&&&&&&& a=arrayinit[1,3 : 1,2,3], b=arrayinit[1,3 : 1,2,3], c=arrayinit[1,3
&&&&&&& s=s+a[0]+b[1]+c[2], delete[a,b,c]
//用delete函数销毁对象a、b、c
错误有编译错误和运行错误两种。通常,Forcal程序总是准确定位编译期错误的。若程序编译通过,在运行时仍会发生错误,通常,Forcal程序总是记住并给出第一个运行错误的信息,错误信息包括运行出错的表达式的类型和名称(可见,给每一个表达式都起一个名字是非常重要的)、表达式所在的模块、运行出错的函数名、错误代码等等,用户可根据这些信息查找并修改错误。
&&& Forcal运行时使用错误(异常)处理的恢复模型。模块化编译运行库MForcal中提供了一组函数以支持该功能:
&&& (1)检测输出并清除Forcal运行错误:err();
&&& (2)获得Forcal运行错误:geterr(&ErrType,FunName,FunNameLen,&FunCode,&ForType,&ForHandle);
ErrType:返回运行错误的类型。
FunName:Forcal静态字符串地址。返回出错函数名。
FunNameLen:Forcal静态字符串长度。
FunCode:返回函数错误代码。
ForType:返回出错表达式的类型。
ForHandle:返回出错表达式的句柄,该句柄即编译表达式时获得的句柄。
&&& (3)设置Forcal运行错误:seterr(ErrType,FunName,FunCode,ForType,ForHandle);
ErrType:设置运行错误的类型。
FunName:设置出错的函数名,要求传递一个Forcal静态字符串(长度小于80)。
FunCode:设置函数错误代码。
ForType:设为0。
ForHandle:未使用。
&&& (4)清除Forcal运行错误:clearerr();
&&& 以下例子用函数seterr设置了一个Forcal运行错误,并用函数geterr捕获了该错误:
f(:a,b,c,d,e)=
seterr[66,&aaa&,23,0,0], geterr[&a,b=&\[10]&,10,&c,&d,&e], printff[b];
Forcal运行错误可由Forcal系统、二级函数,或者由Forcal脚本用户进行设置,可在任意位置设置运行错误,同时可在任意位置捕获该运行错误。运行错误一经设置,将始终存在,直到遇到函数clearerr()或err()为止。在执行MForcal模块的最后,将自动调用函数err()。
&&& 捕获Forcal运行错误并进行处理后,可调用函数clearerr()清除运行错误,重启程序代码,通常需借助循环完成该处理过程。
在Forcal核心库中,只有整数、实数和复数三种简单的数据,以及针对这三种简单数据进行运算的整数表达式、实数表达式和复数表达式。虽然在表达式中可以使用静态数组,但静态数组是通过字符串来定义的,故不是严格意义上的对象。
Forcal核心库没有任何内建对象,甚至连动态数组也不支持,但Forcal核心库为创建任意对象提供了良好的支持。C/C++、Delphi等程序员可以设计自己的对象及操作这些对象的函数,并把它们注册到Forcal中。“自己动手,丰衣足食”是使用Forcal的基本法则。
&&& FcData是一个Forcal扩展库,提供了动态数组、类等丰富的数据类型,并支持通过FcData向Forcal注册自己的数据类型,许多Forcal扩展库在提供自己的数据类型时,也以FcData库作为基础。
&&& 例如扩展库FcString(以FcData库为基础)中提供了动态字符串对象,函数ws用来生成一个字符串对象,函数outs用来输出一个字符串对象,下例计算并输出了三个字符串的和:
!using[&string&];
oo{[ws(&ab&)+ws(&cd&)+ws(&ef&)].outs()};
&&& 再例如扩展库FcMath(以FcData库为基础)中提供了矩阵对象,函数matrix用来生成一个矩阵并可进行初始化,函数outm用来输出一个矩阵,下例计算并输出了两个矩阵的乘积:
!using[&math&];
oo{[matrix(2,3:1,2,3,4,5,6)*matrix(3,2:1,2,3,4,5,6)].outm()};
&&& 注意FcString库中的字符串对象和FcMath库中的矩阵对象都是运算符重载的。设计对象及操作函数,对对象进行运算符重载等等,都是由程序员来实现的。“自己动手,丰衣足食”是使用Forcal的基本法则。
著名的瑞士计算机科学家沃思(N.Wirth)教授曾提出:算法+数据结构=程序。在Forcal中,算法是用函数来描述的,而模块是函数的集合,因而Forcal的模块即代表了算法。Forcal模块由Forcal核心库来实现,但Forcal的数据结构却是由Forcal扩展动态库(特别是FcData)实现的。在FcData中主要通过类的概念实现Forcal的数据结构,所有的FcData数据都通过指针进行标识。
在C++中通过类实现了面向对象设计,在Forcal中与此相关的概念是类模块(FcData中的类与Forcal模块的结合)。与C++中的类定义不同,FcData中的类与Forcal模块是相互独立的。C++是高效的静态语言,类函数必须知道类的结构才能工作,而Forcal是动态编译的,在运行前无需也不可能知道类的结构,因而也没有必要将类结构与模块函数绑定到一起。因而有理由认为:FcData中的类与Forcal模块相互独立是Forcal的一个优点。
&&& Forcal模块命名空间通常是一棵树或者是一张连通图。
&&& FcData类通常是一棵树或者是一张连通图。
&&& Forcal是轻量级绿色免安装的计算引擎。核心库FORCAL32W.DLL文件大小:约130K;不使用MSVC运行库的静态库版本,约260K~300K。
对脚本来说,编译效率和运行效率同样重要,Forcal在这两方面都有不俗表现,Forcal是追求效率的。
&&& Forcal一级函数速度约为FORTRAN(或C/C++)执行速度的50%左右;其他情况,速度稍有下降。
&&& 以下Fibonacci递归程序(n取40)体现了Forcal脚本的运行效率:
SetRealStackMax(1000);
F(n)= which{
&&& n == 0,
&&&&&&& return(0),
&&& n == 1,
&&&&&&& return(1),
&&& return [F(n - 1) + F(n - 2)]
main(:t,n)=
&&& t=sys::clock(),
&&& n=F(40),
&&& t=sys::clock()-t,
&&& printff{&\r\nfibonacci={1,i}, fibonacci_Time={2,i}毫秒={3,i}秒\r\n&,n,t,t/1000}
&&& 结果:
fibonacci=, fibonacci_Time=41859毫秒=41秒
动态库(DLL)是一个包含可由多个程序同时使用的代码和数据的库,具有以下优点:(1)扩展了应用程序的特性;(2)可以用许多种编程语言来编写;(3)简化了软件项目的管理;(4)有助于节省内存;(5)有助于资源共享;(6)有助于应用程序的本地化;(7)有助于解决平台差异;(8)可以用于一些特殊的目的。
Forcal以动态链接库的形式存在,用Win32标准函数调用方式(stdcall调用协议)输出了动态库函数,使用极为方便。
&&& 核心库 Forcal 9.0
的输出函数有30多个,主要功能有表达式编译计算、错误处理、常量或函数注册、判断表达式是否有效、从表达式获得信息、向Forcal注册(对象)信息、垃圾收集等等。
Forcal的内核很小,除提供超强的表达式编译计算功能外,着重强化了对功能扩展的支持,用户可以很方便地将自定义的对象、函数、常量等注册到Forcal系统。
很容易对Forcal进行功能扩展,功能扩展的方式可以灵活多样,但通过动态库方式进行功能扩展是最常用的方式,这种方式便于被所有的Forcal支持的程序所共享。Forcal扩展动态库中仅有一个输出函数
FcDll32W(...),设计和应用都很方便。可用C/C++、delphi、FORTRAN等语言设计Forcal扩展动态库。
&&& Forcal 9.0
的核心库是Forcal32W.dll,共有30多个输出函数,利用这些输出函数,可以设计功能丰富的各种Forcal扩展库。所有的扩展库都是根据核心库的输出函数设计的。
使用Forcal核心库的输出函数,用户可构建自己的处理系统。但作者也根据Forcal核心库的输出函数,构建了一套系统--以Forcal扩展动态库的形式对Forcal进行了功能扩展,FcData、MForcal、FcString、FcSystem等即是这套系统的重要组成部分;这套系统是以FcData和MForcal两个库为基础的,FcData提供了基本数据类型扩展功能,MForcal可对Forcal源程序进行模块化编译。如果这些Forcal扩展库能满足您的要求,您可以直接使用它们。
&&& 彻底地保护私有数据是Forcal的基本特色。
&&& 在Forcal脚本中,模块私有函数、模块变量等就体现了对私有数据的保护。
在设计Forcal扩展库(或其他形式的功能扩展模块)时,向Forcal注册的数据,有些只允许该扩展库自己的函数访问,而不允许其他外部函数访问,此时,可以私有键的方式向Forcal注册数据,这样其他功能扩展模块就无法访问这些数据,保证了扩展库的安全性。
在编译表达式时,可以对表达式所在的模块加锁;在向Forcal注册键值时,可以锁定键的类型。这些都体现了Forcal对私有数据的保护。
二级函数(外部函数)是Forcal功能扩展的基本方式,二级函数必须检测并报告所有可能出现的错误,以实现错误处理的恢复模型。
&&& 在FORCAL脚本中,函数的一般形式为:fun(x1,x2,...,xn)
&&& 与此相对应,FORCAL二级函数的通用形式为:double _stdcall fc_fun(fcINT
nn,double *xx,void vFor);
&&& 参数说明:
&&& nn:整数。nn指出自变量的个数。
&&& xx:自变量数组的指针。若nn=-1,表示该函数没有自变量,若nn=0,表示有一个自变量,若nn=1,表示有2个自变量,...
...,依次类推。xx[i]即该函数的第i+1个自变量。
&&& vFor:表达式句柄。通过该句柄可以获得表达式的详细信息。
&&& 根据函数所实现的功能,每一个自变量可以代表不同的意义,可以是一个双精度实数,也可以对它取整((int)xx[i])或使用部分字节表示其他意义,例如表示一个整数,或者表示一个指向不同对象的指针:数组、字符串、表达式或者其他任何一种对象类型。
&&& 复杂的二级函数设计必须注意以下几点:
(1)用GetForStr(...)函数获得表达式中的字符串,因为表达式的名称就是一个字符串。该函数只能在二级函数内部使用。
&&& (2)用GetFor(...)函数获得各个表达式并进行计算。该函数只能在二级函数内部使用。
&&& (3)用TestRunErr(void)获得动态库运行错误的类型。
&&& (4)用SetRunErr(int ErrType,char *FunName,int FunCode,int
ForType,void *ForHandle)设置外部函数的运行错误。
&&& (5)通常不用GetRunErr(int &ErrType,char *&FunName,int &FunCode,int
&ForType,void *&ForHandle)获取FORCAL运行错误,因为该函数将FORCAL设为无错状态。
(6)如果二级函数的参数中包含了对象,在对对象操作之前,必须验证其是否有效,并且要检查对象操作的条件是否具备。即:只有对象是有效的,且操作条件是完备的,才可以进行对象的操作,这样做到了万无一失。每个二级函数都要对自己操作的对象负责(也仅对自己操作的对象负责),这样整个Forcal系统就是安全的。
&&& 以下是Forcal标准输入输出系统扩展库FcIO中的二级函数feof的设计(功能相当于C语言中的文件操作函数feof),可以体会到二级函数设计的特点。
&&& Forcal脚本中,函数feof的用法如下:
io::feof(hFile):判断是否到文件尾
hFile:文件句柄。
返回值:没有到达文件尾时返回0,否则返回非0值。
运行错误:(1)文件没有打开;(2)非法的文件句柄。
&&& 扩展库FcIO中函数feof的C/C++代码如下:
fcIFOR _stdcall ifc_feof(fcINT
m,fcIFOR *xx,void *vFor)
&&& static wchar_t ErrName[]=L&io::feof&;
&&& fcdTYPE BT
&&& fcVOID *
&&& IsFcData(*xx,BType);&&&
&&&&&&&&&&&
//获取参数的类型,文件类型数据已被注册为FcData数据
&&& if(BType==IdFcFile)&&&&
&&&&&&&&&&&
//该参数是一个文件
&&&&&&& file=(fcVOID *)*(fcVOID *)&&
//取出文件指针
&&&&&&& if(*file)
&&&&&&&&&&& return
feof((FILE *)*file);
&&&&&&& else
&&&&&&&&&&& if(TestRunErr()==0)
SetRunErr(1,ErrName,1,0,vFor); //文件没有打开
&&&&&&& if(TestRunErr()==0)
SetRunErr(1,ErrName,2,0,vFor);&&&&
//非法的文件句柄
&&& return 0;
&&& 若标识符后面有句点“.”,表示将该标识符联系到一个函数,例如:a.sin();或者产生一个函数调用,例如:a.b
相当于 a(b)。若变量是显示说明的,则通过句点将产生隐含的oset函数或oget函数调用,称变量函数调用,例如:a.b 相当于 oget[a,b];a.b=c
相当于 oset[a,b:c]。
在FORCAL中,任何一个数都有可能是一个类或指针,这需要在运行时才能确定,所以FORCAL编译器把任何一个函数或表达式都看作类或指针的成员函数。尽管FORCAL32W.dll中没有提供类或指针的概念,但FORCAL扩展动态库FcData中定义了该概念。为了存取像类或指针等复杂数据类型时,在形式上看起来更美观一些,FORCAL32W.dll中提供了类成员运算符“.”操作类的成员函数或指针数据。如下例:
&&&&& (:x)= x=2.3, x.sin();&&&&&&&&&&&&&&&
//计算sin(x)
&&&&& (:x)= x=2.3, sin.=x;&&&&&&&&&&&&& &&
//计算sin(x)
&&&&& (:x)= x=2.3, sin.x;&&&&&&&&&&&&&&&
& //计算sin(x)
&&&&& f(x,y)= x.y.atan2().sin();&&&&&&&&&&
//定义函数f,计算sin(atan2(x,y))
&&&&& (:x,y)= x=2.3,y=3.3, x.f(y);&&&&&&&&
//计算f(x,y)
&&&&& (:x,y)= x=2.3,y=3.3, f.x.y;&&&&&&&&
&//计算f(x,y)
&&&&& (:x,y)= x=2.3,y=3.3, f[x]=y;&&&&&&&&
//计算f(x,y)
&&&&& (:x,y)= x=2.3,y=3.3, f.x.=y;&&&&&&&&
//计算f(x,y)
&&&&& (:x,y)= x=2.3,y=3.3, f.x=y;&&&&&&&&
&//计算f(x,y)
&&&&& &字符串也可以的&.printff[];&&&&&&&&&&//执行printff[&字符串也可以的&]
&&&&& printff.&字符串也可以的&;&&&&&&&&&&&
//执行printff[&字符串也可以的&]
&&&&& (:f,x,y)= x=2,y=3.3, f.x=y;&&&&&&&&
&//因f是一个显示说明的变量,计算oset(f,x:y)
&&&&& (:f,x,y)= x=2,y=3, f.x.y;&&&&&&&&
//因f是一个显示说明的变量,计算oget(f,x,y)
&&&&& (:f,x,y)= x=2,y=3, f.x.y=f.x.y+1;&&&&//因f是一个显示说明的变量,计算oset[f,x,y
: oget(f,x,y)+1]
若句点“.”没有将标识符联系到一个函数,则第一个句点前只能是一个类似变量的标识符,其他句点“.”前允许是常量名、变量名、字符串、括号运算符或函数。
若句点“.”将标识符联系到一个函数,则任一句点“.”前允许是常量名、变量名、字符串、括号运算符或函数。运算符“.”表示它前面的参数是它后面最近的函数的一个参数,所以称为函数参数运算符,该运算符之所以也称为类成员运算符,是因为“.”就是为了表示类的成员关系而设置的。成员函数在调用时,先把类成员运算符“.”前的数据作为参数,并与函数括号内的参数一起合并,然后执行计算。即:函数的参数个数为类成员运算符“.”前的变量个数与函数括号内的参数个数之和。注意:只有成员函数前面的类成员数据才是该函数的参数。例如:
&&&&& (2).(3).max[].(5).min[]
上式中,2和3是max[]的参数,而max[2,3]和5是min[]的参数,即:min{max[(2),(3)],(5)}。
&&& 使用类成员运算符,函数if、while、until等函数有以下用法:
&&&&& (x).if&&&&&&&&&&&&&&&
//x为真时执行花括号内的内容
&&&&& &&&... ...
&&&&& (x).while&&&&&&&&&&&&&//x为真时循环执行花括号内的内容
&&&&& &&&... ...
&&&&& //循环执行花括号内的内容直到x为真。
&&&&& &&&... ...
&&&&& }.until(x);
&&& 类成员运算符不但可以表示类的成员关系,合理地使用该运算符也可使程序更易读。例如:类ClassA有一个成员函数ClassA_Add(a,b),可以执行类对象a和b相加,类对象a、b、c、d连续相加的表达式为:
ClassA_Add{ClassA_Add[ClassA_Add(a,b),c],d}
&&& 用运算符“.”可表示为:
a.ClassA_Add(b).ClassA_Add(c).ClassA_Add(d)
&&& 当然,以上还不是执行类对象a和b相加的最简形式,最简形式应是在oo{...,a=a+b+c+d,...}函数中实现运算符重载功能。请参考每一个类的说明。
逗号、冒号和分号是Forcal的三种等价的分隔符,增强了程序的可读性。实际上,这三者是三个等价的运算符。
Forcal表达式中如果有多个语句,可以用逗号、冒号或分号进行分隔,FORCAL将按从左到右的顺序计算各个语句,并返回最后一个语句的值。也可以将多个用逗号、冒号或分号分隔的语句放在一个括号内,FORCAL也将按从左到右的顺序计算各个语句,并返回最后一个语句的值。例如:
(:x)= x=2,x=5,x;&
//返回值为5;
(:x)={x=2,x=5,x}; //返回值为5;
(:x,y)={x=2,y=5,x=[x=x+1,y=y+1,x+y]:x};
//返回值为9;
(:x,y)={x=2,y=5,[x=x+1,y=y+1:x+y]};&&&&
//返回值为9;
虽然逗号、冒号或分号运算符是通用的,但逗号的用法很常见。冒号和分号运算符仅用在一些特殊场合,例如分隔一些不同类别的变量。
注意:一般表达式之间用分号进行分隔,故分号运算符必须放到括号内才有效。另外,不是所有的Forcal程序都支持分号运算符。由模块化编译运行库MForcal支持的程序都支持分号运算符,如下例:
(:x,y)={x=2,y=5;x=[x=x+1,y=y+1;x+y]:x};
//返回值为9;
(:x,y)={x=2,y=5,[x=x+1;y=y+1:x+y]};&&&&
//返回值为9;
&&& 再如矩阵定义及赋值:
!using[&math&];
& a=matrix{3,4 : 1,2,3,4; 5,6,7,8; 9,10,11,12},
& outm[a];
中文编程是许多人的梦想,Forcal使用Unicode字符串作为默认字符串,可很好地实现中文编程。Forcal标识符可全部使用中文,尽管Forcal软件包中的Forcal扩展动态库提供的都是英文函数,但你自己来设计这些库时,完全可以全部使用中文函数,或者提供中英文两套函数名。
&&& 例子:
两数加(加数1,加数2)=加数1+加数2;
两数加(2,3);
&&& 中文编程或许使普通人学会编程成为可能。
&&& Forcal的许多组成特征与三有缘,例如:、、、等等。
混合编程的关键是参数传递。Forcal是一种嵌入式脚本,采用自动垃圾回收与手动垃圾回收并存可在混合编程中简化脚本使用、扩大脚本使用范围并提高混合编程效率和运行效率。
&&& 设主程序语言为C/C++或delphi等,主程序中有一个对象(或结构等)A,要实现在主程序和Forcal脚本中对A的联合操作。
首先,要使主程序和Forcal都能操作对象A,对象A必须注册到Forcal系统中,可注册为两类对象,一种注册对象可被垃圾收集器回收,另一类注册对象垃圾收集器无法回收。此外,还要向Forcal注册一些操作对象A的函数。
&&& 有以下多种联合操作方式:
&&& (1)注册为垃圾收集器无法回收的对象,基本特点为:
&&& 主程序可生成对象A并注册到Forcal系统,对象A也可在脚本中由专用函数生成;
&&& 主程序可销毁对象A,Forcal脚本中也可销毁对象A,销毁可以是立即进行的,或者暂存到缓冲池中;
&&& 主程序或脚本中都可一次销毁对象A的所有实例;
&&& 主程序或Forcal脚本用户没有销毁的实例由Forcal系统最终回收。
&&& (2)注册为垃圾收集器可回收的对象,基本特点为:
&&& 主程序可生成对象A并注册到Forcal系统,对象A也可在脚本中由专用函数生成;
&&& 主程序可销毁对象A,Forcal脚本中也可销毁对象A,销毁可以是立即进行的,或者暂存到缓冲池中;
&&& 主程序或脚本中都可一次销毁对象A的所有实例;
&&& 主程序或Forcal脚本用户没有销毁的实例由Forcal系统最终回收。
&&& 主程序可按一定规则启动垃圾收集器回收垃圾对象;
&&& Forcal脚本中可立即启动垃圾收集器回收垃圾对象;
&&& 主程序可设置垃圾收集器不能启动,则脚本中的垃圾收集器也无法运行。
&&& 注:Forcal垃圾收集器采用标记清除算法。
(3)多种对象并存时,有些对象注册为垃圾收集器可回收的对象,有些对象注册为垃圾收集器不可回收的对象,各自具备各自的特点,不相互影响。
由于自动垃圾回收与手动垃圾回收并存,故无论在主程序,还是在Forcal脚本中销毁一个对象,不必担心会带来任何问题。而只采用自动垃圾回收的脚本系统,在实现复杂功能时,主程序和脚本系统接口上需费很多心思,往往会费力不讨好。
个人认为,自动垃圾回收与手动垃圾回收并存的脚本系统,至少在混合编程方面,最终会获得用户的认可。
如果你对自动垃圾回收有某种偏爱,你完全可以使用Forcal设计一个完全依赖自动垃圾回收的系统。只需按以下方法进行设计:
&&& (1)Forcal核心库没有任何动态对象,这是设计基础。
&&& (2)扩展Forcal时,C/C++或Delphi程序员不要注册销毁对象的函数。
&&& (3)Forcal脚本运行时的垃圾对象完全由垃圾收集器收集,垃圾收集器按一定算法启动即可。
版权所有& Forcal程序设计
,保留所有权利

我要回帖

更多关于 c 字符串首字母大写 的文章

 

随机推荐