ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 鲁班编程语言 电子书籍 第2章(转)

鲁班编程语言 电子书籍 第2章(转)

原创 Linux操作系统 作者:WebSnap 时间:2019-01-11 15:21:04 0 删除 编辑
鲁班编程语言 电子书籍 第2章(转)
http://project.soft114.com/lubankit/index_chinese.html

2. 脚本鲁班

In the beginner's mind there are many possibilities,
in the expert's mind there are few.
- Shunryu Suzuki, Zen Master


这一章讲述基本的鲁班顺序执行语句构造, 包括变量, 常数, 表达式和语句. 看完这一章就可以用鲁班写一般的脚本程序了. 已经掌握C++/JAVA的朋友, 用五分钟就可以看完这章. 因为鲁班的语句和表达式和C++/JAVA基本相似, 需要看的只是鲁班扩展和不同的部分. 而那部分也是很简单, 一看即明的.

2.1 第一个鲁班程序
学习一个新的语言的最有效的办法莫过于看看程序例子. 好的语言总是以一个”世界, 你好”程序例子开始. 鲁班也不例外. 下面是鲁班的”世界, 你好”程序.
std::println(obj=”Hello, World”);
把以上代码敲进一个叫”helloworld.lbn”的文件里. 然后在你的操作系统命令行敲以下命令.
Mycomputer > luban helloworld.lbn
Hello, world!
这个鲁班程序有一点象C的”HELLOWORLD”程序. 里面代码做的事就是调用一个叫做”std::println”的鲁班部件, 调用时把字串”Hello, World”设置到一个叫”obj”的输入属性上. 程序的执行结果是在终端上印出”Hello, World”字串.

2.2 鲁班脚本基本结构
鲁班的脚本程序是由一系列的鲁班语句或表达式构成. 这些语句和表达式之间用分号隔开. 换行和空白字符会被忽略. 这样的结构和C++/JAVA是一样的. 以下是一个简单的鲁班脚本程序.
X=1;
Y=2;
Z=X+Y;
std::println(obj=Z);
把以上程序输入到一个叫”oneplustwo.lbn”的文件里然后在命令行打入以下命令:
Mycomputer > luban oneplustwo.lbn
3
从以上程序可以看出鲁班脚本程序的大概样子.


2.3 常数, 变量和表达式
鲁班的表达式和C++/JAVA基本一样. 由常数,变量和操作符组成. 以下列举表达式的基本构造. 列举大致按运算的优先级排练.
常数本身是一种表达式. 鲁班的常数有如下几种.
3.1415; 2; “Hello”; ‘a’; ‘ ’;true; false;
变量也是表达式. 鲁班变量起名规则和C语言一样, 如下都是合法的变量名.
varx; _varx_; v123;
数据类型对象建造及部件建造.
[ 1,2,3, x, y, z, a+b ]; // 数组建造
{ “one”: 1, “two” : 2 }; // 字典建造
{ “one”, “two” }; //集合建造
double(“3.1415”); //双精度浮点数建造
std::file(“mydatafile”, ‘r’); // 打开文件
mynamespace::mycomponentX(); //部件建造
mynamespace::mycomponetX( prp1 = 100 ); // 部件类型调用
容器类型成员访问, 对象成员函数调用, 部件属性访问, 部件调用.
mymap[“one”]; // 字典查找
x[1] = y[2]; // 字典或数组成员读取及赋值
mymap.remove(“one”); // 对象成员函数调用
linevector = allines.split(‘ ’); //对象成员函数调用, 分解字串
mycalculator( input1=1.1, input2=2.2); // 部件对象调用
单目操作符运算,
++i; --i; i++; i--; // 操作会改变变量i的值
y = -x; // 变量x值不变, 运算结果赋予y
常见算术类操作, 加减乘除及求余数
1+2; 10.0*3.0; 50%3; 50/3; “Hello, “+”world!”;
数据类型检查操作
objx isa string; // 检查objx是否字串类型
typeof(objx) == string; // 检查objx是否字串类型
相等关系及顺序关系检查
x == y; x != y; x > y; x < y; x >= y; x <= y;
逻辑表达式
true or false; x and y; not true; not a and not b;
三元条件表达式
x > y ? x: y;
赋值表达式
x = 1.23; x += 1; x[index] = 2; x.property = 3; x*=2; x/=3; x=y=z;
以上表达式中有一些构造包括类型检查和部件调用表达式在以后章节中还会讲述.


2.4 鲁班顺序执行语句
鲁班的顺序执行语句和C/C++/JAVA基本一样. 只是加了几个鲁班自己的语句. 以下列举所有的鲁班顺序执行语句.
赋值语句: 赋值语句也是表达式, 在此再列为语句.
x = 1; x += 1; x[index] = 2; x.property = 3; x*=2; x/=3; x=y=z=1;
条件语句
if ( a>b )
result=a;
条件否则语句
if ( a>b )
result = a;
else
result = b;
条件循环语句
while ( x < 100 ) ++ x;
步进循环语句
for( i=0; i<100; ++i)
std::console().writeline(vec[i]);
for(;;); // 死循环
枚举循环语句
foreach( key, value in themap )
std::console().writeline(key, ‘ ‘, value);
跳出循环语句
for( i=0; ; i++)
if ( i>100 ) break;
继续循环语句, 跳回循环起始点
for( i=0; ; i++)
if ( i<=100 )
continue;
else
break;
空白语句
;
结束语句,终止一个脚本或部件的执行
finish;
等待语句: 等待所有启动的线程结束
wait;
特指等待语句: 等待和等待变量相关的线程结束
waitfor x,y,z;
撤消语句: 撤消所有启动的线程并等待它们结束
cancel;
以上线程有关的语句细节在后面有叙述.
组语句. 把一个或多个语句用花括号包起来, 就成为一个组语句.
{ x = 1; y = 2; z = x+y; }
if ( z == 3 ) { z = z-3; x =0; y =0; }
多个属性设置语句, 一次设置一个部件的多个属性值.确具体的细节再部件定义一章还有讲述
Xcomponent.(prp1=1, prp2=2, prp3=3);
注解语句. 鲁班的注解语句与C++/JAVA一样
// one comment
/* another comment */


2.5 鲁班数据类型
鲁班语言提供一系列最常用的数据类型给用户. 这些类型包括整数, 双精度浮点数, 字串, 逻辑类型, 字符类型, 数组, 字典, 集合. 以下逐一介绍它们.


2.5.1 整数和双精度浮点数
整数和双精度浮点数是两个不同的数据类型. 但是它们可以自由混合使用. 运算规则和C语言一样. 整数的类型关键字是int, 浮点数类型关键字是double.
10/3; // 结果为整数 3
10.0/3.0; //结果为浮点数 3 3.333333…
10/3.0; //结果为浮点数 3 3.333333… 浮点数混合整数, 结果为浮点数
0 == 0.0; // 结果为true, 浮点数与整数可混合比较
2 > 0.1; //结果为true, 浮点数与整数可混合比较
x=1.23456789;
y=x.format(“.4”); // 按指定格式将浮点数转化为字串, 保留小数点后4位
// 结果为 “1.2346”
z = int(x); // z = 1, 将浮点数转化为整数
xstring = “1.23456E7”;
xdouble = double(xstring); // x = 1.23456x10^7将字串转化为浮点数


2.5.2 逻辑类型
逻辑类型很简单, 只能是真或者假两种值. 逻辑类型的关键字是bool, true, false. 逻辑类型可用于逻辑表达式. 逻辑表达式操作符有”或”, “与”, “非”三种, 对应关键字or, and, not. 鲁班的条件及循环语句里的条件表达式的运算结果必须是逻辑类型. 否则鲁班会终止当前部件的执行. 这一点和C语言不一样. C会把整数类型隐含转换为逻辑类型, 而鲁班不做隐含转换. 从整数到逻辑类型的转换要有明确的代码. 以下是例子.
truth = true or false; // 结果为true
truth2 = bool(1); // truth2 = true
truth3 = bool(13); // truth3 = true
fiction = bool(0); // fiction = false
truth4 = truth and truth2 and truth3 or fiction; // truth4 = true

熟悉C语言的用户仍然可以使用C风格的逻辑操作符, 用&& || ! 来代替and, or, not.


2.5.3 字符类型
字符类型等同于C语言里的单字节字符. 以下是一些字符类型操作例子. 字符类型关键字是char.
for( onechar =’a’; onechar <= ‘z’; ++onechar)
std::print(obj=onechar);
运行以上鲁班程序会在屏幕上印出abcdefghijklmnopqrstuvwxyz二十六个字母.
NinetySeven = int (‘a’); // NinetySeven = 97, 字符转换为ASCII整数
Lettera = char(97); // Lettera=’a’, 整数ASCII转换为字符


2.5.4 字串类型
字串类型关键字是string. 以下是一个比较完整的例子.
s = “Hello”; c = s[1]; // c=‘e’ 左起第二个字符
s = “Hello”; s[0] = ‘h’; // s 变成 “hello”
s = “Hello”; foreach( c in s ) std::console().write( c ); // 在屏幕上印出 Hello
s = “Hello”*2; // result =“HelloHello”
s = -“Hello”; // result = “olleH”
s = “Hello” + “World”; // result=“HelloWorld”
// below are member function examples
// SPLIT ! 类似于PERL的最常用的split函数
s = “Hello World”; words = s.split( ); // 将字串分解成数组,空格为分割符
// words = [“Hello”, “World”]
// 去除头尾空白
s = “ Hello”;
s.trimfront(); // 去开头空白s = “Hello”
s = “Hello ”;
s.trimback(); //去结尾空白 s=“Hello”
//查找子字串
s=”Hello”;
index=s.find(“Hell”); // index = 0, “Hello”开头是”Hell”
index2=s.find(“Hell”,2); // index = null, 查找失败,
// 从”Hello”的左起第三个字符起没有”Hell”字串
index3=s.find(“Heaven”); // index3 = null 查找失败
truth=s.contains(“Hell”); // truth = true “Hello”包含”Hell”
// 读取子字串
sub=s.substr(2,3); // sub=”ll” 子字串从序号2到3

// 改变字串内容
s=”Hello”;
s.replace(“Hell”, “Heaven”); // s=“Heaveno”将字串内的”Hell”换成”Heaven”
s.lower(); // s=“heaveno” 变小写
s.upper(); // s = “HEAVENO” 变大写
s.remove(6); // s=”HEAVEN”, 删除序号 6字符’o’
s.remove(“A”); // s=”HEVEN”; 删除所有字符’A’
s.insert(1, “A”); // s=”HEAVEN”; 在序号1插入字符’A’
s.clear(); // s=”” 清除所有内容


2.5.5 数组,字典和集合
数组类型的关键字是vector. 以下是操作代码举例.
x = 1; y=2; z=3; v = [x,y,z,4]; // v = [ 1,2,3,4]
v[0] = 10; // v = [10,2,3,4]
total = 0; foreach( element in v ) total += element; // total =10+2+3+4=19
v.sort(); // v= [2,3,4,10] 排序
v.append(11); //v=[2,3,4,10,11] 添加元素到结尾
v2 = v+ [11,12,13]; // v2= [2,3,4,10,11,12,13] 合并
v2.remove(0); // v2 become [3,4,10,11,12,13] 删除序号0元素
v2.removeobj(10); // v2 become [3,4,11,12,13] 删除所有值为10的元素
v3 = [ v2,v2]; // v3 是二维数组 = [[3,4,11,12,13], [3,4,11,12,13]]
//栈类操作, 压入和弹出( push and pop)
x=[1,2];
x.pushfirst(0); // x =[0,1,2] 压入开头
x.pushlast(3); // x=[0,1,2,3] 压入结尾
y=x.popfirst(); // y=0, x=[1,2,3]; 弹出开头
z=x.poplast(); // y=3, x=[1,2] 弹出结尾
字典类型的关键字是map. 字典里的查找关键字项不能重复.以下是代码举例.
x=1; y=2; z = 3;
word2number = { “one” : x, “two” : y, “three” : z }; //构造字典
word2number[“four”] = 4; // 插入或替换字典元素
word2nubmer.remove(“one”); // 删除字典元素”one”
word2number.insert(“two”,2.0); // 字典内容不变, 因为”two”已在字典里
union = word2number + { “five”:5, “six”:6}; // 字典合并
foreach(key,val in word2number )
std::console().writeline(key,’ ‘,val); // 枚举字典内所有关键字及元素值
emptymap = {:}; // 构造空白字典
集合类型的关键字是set. 集合里的元素不能重复.集合是等同于只有关键字的字典.以下是代码举例.
oneset = { 1, “hello”, 3.14 }; //构造集合
another = { 1,2}; //构造集合
union = oneset + another; // union = { 1,2,”hello”,3.14} 合并集合
minus = oneset – another ; // minus = { “hello”, 3.14}, 删除集合共同元素
joint = oneset – minus; // joint = {1}, 结果等于oneset和another的交集
foreach( val in oneset )
std::console().writeline(val); // 枚举集合所有元素
emptyset = {}; //构造空白集合
数组,字典和集合相互转换举例:
oneset = { 1,2,3}; onevec = vector(oneset); // 集合到数组
keyvec=[‘a’,’b’]; valvec = [‘A’,’B’];
onemap = map(keyvec, valvec); // 两个数组构造一个字典


2.6 鲁班数据类型通用操作
此节讲述通用于不同鲁班类型的操作.
2.6.1 类算术操作
简单的说,通用的算术操作符象加减乘除都适用于一般的鲁班数据类型.但是同样的运算不同的数据类型有不同的结果.这一点和面向对象模型里的操作符重载一致.如果操作符不适用被操作对象,结果会是错误类型.以下是举例.
// + 加法运算
numtwo = 1 + 1; // numtwo = 2
stroneone = “1” + “1”; // stroneone = “11”
vec = [1]+[1]; // vec = [ 1, 1]
s = { 1 } + { 1 }; // s = {1}, 合并集合
m = { 1:10 }+{ 2:20}; // m = { 1:10, 2:20 }, 合并字典
err = “1” + 1; // err = error,错误, 整数和字串不能相加
err2 = true + false; // err = error错误, 逻辑类型不能相加
// - 减法运算
zero = 1 – 1; // zero = 0
varset = { 1,2,3} – { 3,4,5 }; // varset = {1,2}删除集合共同元素
err = [1]-[1]; // err = error, 错误, 数组类型不能相减

// - 求负运算
x = -100; // x = -100
vec = - [ 1,2,3]; // vec =[3,2,1] 数组求负等于颠倒顺序
str = - “abc”; // str = “cba” 字串求负等于颠倒顺序
truth = -false; // truth = true逻辑类型求负等于颠倒真假
err = - ‘a’; // err = error, 错误, 字符类型不能求负
// * 乘法运算
x = 2*2; // x = 4
str = “ab”*2; // str = “abab” 字串乘整数等于自我复制
vec = [1,2]*2; // vec = [1,2,1,2] 数组乘整数等于自我复制
// 除法运算 / 只适用于数字
x = 100/3; // x = 33 integer division
xfloat = 100.0/3.0; // xfloat = 33.3333…. float number
// 求余运算 %只适用于整数
xmod = 100 % 3 ; // xmod = 1
// ++ 加1或者求下一个对象
x = 0;
y = ++x; // x=1, y=1, x值增加1赋予y
z = y++; // z =1; y =2; y赋予z然后y值增加1
x = ‘a’;
++x; // x= ‘b’ ‘a’ 的下一个是 ‘b’
--运算符只是++的逆反. 另外一些运算加赋值操作符有以下例子说明.
x += 10; // 等同于 x = x+10;
x -= 10; // 等同于 x = x-10;
x /= 10; // 等同于 x = x/10;
x *= 10; // 等同于 x = x*10;
x %= 10; // 等同于 x = x%10;
需要指出的是, 运算加赋值操作符比等同的运算再赋值要快很多. 因为步骤简化了.
可以看出, 鲁班的算术运算操作和C基本一样, 只是扩展了把非数值类型也包括进来.


2.6.2 枚举循环语句(foreach)
枚举循环语句适用于容器类型, 包括数组, 字典, 集合和字串类型. 将枚举循环用于非容器类型会导致鲁班终止执行当前部件代码. 如下举例:
X = 3.1415;
foreach( y in x ) // 错误! 程序在此终止
std::println(obj=y);

以下是一个正确的枚举循环语句例子.
foreach( x in [10,20,30] ) std::println(obj=x);
以上代码执行会在屏幕上印出10,20,30 每个数字一行.


2.6.3 通用成员函数
所有的鲁班数据类型都有成员函数可以调用.具体的鲁班数据类型定义自己的成员函数. 但是以下成员函数适用于全部或者部分数据类型.
allfuncs()成员函数. 返回所有成员函数名及调用方式.
x = [];
funcmap = x.allfuncs();
foreach( funcname, funcdesc in funcmap)
std::console().writeline(funcname, ‘ ‘, funcdesc);
以上程序在屏幕上印出所有数组类型的成员函数的名字和说明.
hash()成员函数, 当对象被加入字典或集合时此函数被调用来决定存放序号.
x = “hello”;
h = x.hash(); // default value 0
invoke()成员函数, 是鲁班反映机制的一部分. 用于动态调用成员函数
x = “hello”;
h = x.invoke(“hash”);
以上代码的执行结果与直接调用hash()成员函数一样.
serialize()成员函数将对象转换为串行字串.
x = { “one”:1, “two”:2 };
xs = x.serialize();
// 以下代码将串行字串恢复为对象.
samex = std::des(stream=xs).obj;
if ( samex == x )
std::println(obj=”hey, it works”);
以上代码会在屏幕上印出”hey, it works”. 一个小技巧是当把字串恢复成对象时需要调用一个标准部件”std::des”. 把串行字串放到”stream”输入属性端, 然后从”obj”输出端取出恢复的对象.
以下成员函数只适用于字符串和容器类型.
size()成员函数: 返回容器内元素个数或字符串长度.
x = [10,20,30]; s = x.size(); // s=3 x内有3个元素
contains()成员函数: 检查容器内是否含有指定元素, 或字符串是否有指定子字符串.
x = [10,20,30]; has20 = x.contains(20); // has20=true x内有元素20
h=”Hello”; hasHell=h.contains(“Hell”); // hasHell=true h含有子串”Hell”
clear()成员函数: 清除容器所有元素或字符串内所有字符.
x = [10,20,30]; x.clear(); // x = [];
h=”Hello”; h.clear(); // h=””;
最后需要指出的是, 所有成员函数调用, 如果出错, 都会返回错误类型对象.


2.7 空值null和错误类型error
空值null是一个特别的常数值, 由关键字null代表. 空值null可以象一般的常数一样用在表达式里, 就象如下例子.
thisarray = [ null, null ]; //定义一个数组有两个空值元素
空值null的特别之处有两点. 首先所有变量和部件属性在没有被赋值之前都是空值null. 第二是空值null不属于任何类型.
错误类型error是一个特别的类型. 所有鲁班表达式和操作当错误发生时都会返回错误类型值. 在错误类型对象上施加任何操作都会依然返回错误类型. 鲁班代码也可以直接构造错误类型对象. 以下是例子.
errval = 1/0; // 产生一个被零除错误
if ( errval isa error )
std::console().writeline(errval);
expliciterr = error(“Hey, I am a born error”);
std::console().writeline(expliciterr);
运行以上代码会在屏幕上印出:
ERROR: Error for +-*/% operation: Divided by zero
ERROR: Hey, I am a born error


2.8 高级鲁班脚本技术: 多线程并行及协调
多线程并行及协调是鲁班语言的一部分. 在鲁班语言里启动线程和等待线程非常简单, 就如下例所示
myjobs::dothis(arg=100) & // 启动一个线程运行myjobs::dothis
myjobs::dothat(arg =200) & //启动另一个线程运行myjobs::dothat
{ c.doOne(); d.doTwo(); } & // 把花括号里的语句放在一个线程里启动运行
wait; // 等待所有的线程结束
你也可以选择性地等待线程结束. 鲁班线程可以用线程相关变量来辨别. 鲁班线程相关变量定义为线程代码中最后一个赋值语句的左变量. 以下例子说明怎样用线程相关变量来辨别和等待鲁班线程.
x = y.domagic() & // 启动一个线程, 相关变量x
a = b.dogood() & //启动另一个线程, 相关变量a
waitfor x; //等待线程x结束
{ x = y.domagic(); a = b.dogood(); } & //启动一个线程, 相关变量a
{ c = d.doevil(); f = g.wastetime(); } & //启动一个线程, 相关变量f
waitfor f; //等待线程f结束
对于多个鲁班线程操作的同一个变量, 鲁班保证任何时间只有一个线程在操作同一个变量. 这样可以保证变量内的对象的完整性不至于被多线程同时操作破坏.
另一个问题是如果鲁班脚本结束时怎样处理其他可能正在运行的子线程. 鲁班的处理办法是等待所有的子线程结束才退出. 就象有一个wait语句在结尾一样.
另一个线程相关的语句是cancel语句, 用来取消所有已启动的线程.

2.9 线程陷阱举例
例子一:
for(i=0;i<10000:++i) { x += i; } &
以上貌似简单的程序几乎可以肯定会失败. 因为它会试图启动10000个线程. 很少有机器可以在一个进程内启动10000个线程. 要把一个循环放入一个线程的正确写法是如下:
{ for(i=0;i<10000:++i) { x += i; } } &
例子二:
for( i=1; i<=10; ++i )
{
std::println(obj=i) &
}
第一眼看起来, 上面程序应该在屏幕上印出1,2,3,4,5,6,7,8,9,10每个数一行. 实际上以上程序只保证印出十个一到十的数. 但究竟是哪十个数顺序怎样则不确定. 具体原因是这样. 这个程序会启动十个线程来打印变量”i”的内容, 由主线程循环改变变量”i”的内容, 每次改变后启动一个线程. 这十加一个线程的执行顺序是不确定的. 所以不一定会印出1,2,3,4,5,6,7,8,9,10顺序. 小测验: 这个程序会印出1,1,1,1,1,1,1,1,1,1十个”1”吗?
怎样更好处理类似问题在后面章节还有讲述.


2.10 鲁班简单的世界: 一切都是对象
鲁班与其他面向对象语言象C++/JAVA的一大区别是鲁班没有指针(pointer)和位址(reference)类型. 所有变量都只能存储对象本身. 每次赋值都等同与一个新的对象. 就如以下代码所示:
a = [1,2,3];
b = a; // b 得到一个新的对象
b += [4,5]; // b = [1,2,3,4,5] a = [1,2,3] b,a现在不同值
鲁班的”一切都是对象”设计主要是为了简单性. 增加位址类型会增加对用户的难度. 另外一个很重要的理由是简单对象传递让鲁班部件之间的交互变得更简单和具有可变性, 比如说可以网络远程调用. 细节以后章节会有叙述.

http://project.soft114.com/lubankit/index_chinese.html

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10797429/viewspace-101675/,如需转载,请注明出处,否则将追究法律责任。

下一篇: Linux驱动入门(转)
请登录后发表评论 登录
全部评论

注册时间:2008-01-04

  • 博文量
    45
  • 访问量
    29636