ShoneSharp语言(S#)的设计和使用介绍
系列(10)— 富家子弟“语句“不炫富
作者:Shone
声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp。
摘要: 语句是过程式编程语言的基础构造,对应于程序命令,通常按照指定顺序执行。S#语句与C#语句基本相同,如有var, eval, if, switch, for, foreach, do, while, return, continue, break, load, using等语句。C/C++/Java/JavaScript等语言爱好者很容易上手。
软件: S#语言编辑解析运行器13.6.24,运行环境.NET 4.0,绿色软件,单个EXE直接运行,无副作用。网盘下载链接为https://pan.baidu.com/s/1nv1hmJn
今天继续介绍S#的语句功能,请使用最新软件13.6.24版运行本文示例。
语句是过程式编程语言的基础构造,对应于程序命令,通常按照指定顺序执行。语句执行顺序通常也称为“控制流”。
S#语句的语法与C#基本上相同,为了突出S#的表达能力做了部分精简,如删去事件、委托、属性修改、异步等,因为S#是面向表达的动态语言,不需要开发成为另一个C#。
S#语句就像来自C#大家族是富家子弟,平常比较低调不炫富,主要使用公式就可满足要求,需要时也可以写出像C#一样复杂的大块逻辑代码。S#语句也适合于有C / C++ / Java / JavaScript等C类风格编程语言爱好者上手试用。
一、基本语句
(1)声明语句:声明引入新的变量,并为变量赋值。
var 变量名 = 变量值公式;
var变量声明语句例如:
var a = 10; //声明数值变量,若未定义则新声明一个,否则修改已定义变量 var f = func(x, y)=>(x+y)/2; //声明函数变量
func 函数(参数序列) = 变量值公式;
func函数声明语句例如:
func f(x, y) = (x+y)/2; //显式声明函数变量,与上面var声明等价,但更直观 func f(x=10, y=20) = (x+y)/2; //显式声明函数变量,带缺省值
(2)表达式语句:用于调用函数、对象方法、或修改变量值的语句。
表达式;
例如:
Funcxxx(); //执行函数调用 xxx.Methodxxx(); //执行对象的方法调用 (x+y)/2; //其他任意表达式加;也是合法语句,通常用于求值语句
变量名 符号 变量值公式;
例如:
x += 10; x -= 10; x *= 10; x /= 10; x /%= 10; x %= 10; x ^= 10; x += 10; x++; x--;
(3)返回值语句:用于返回结果值的语句。
return 结果值公式;
(4)跳转继续语句:用于跳转并继续循环体控制流的语句,即继续循环。
continue;
(5)跳转结束语句:用于跳转并结束循环体控制流的语句,即跳出循环。
break;
二、语句块
语句块可以是单个语句,也可以由{}包围的一个到多个语句序列。
单语句
{ 语句系列 }
语句块通常用于复合语句中,并通过语句块可以形成复杂的嵌套语句结构。
三、求值语句
与其他语言不同,S#多了一个求值语句,即独立的带{}的语句块。
求值语句用于按照顺序执行对应控制流并最终返回一个结果值的语句。执行时遇到return语句则结束控制流并返回该语句结果,如果没有return语句则执行到最后一个语句再返回最有一个语句的计算结果。例如:
{ var x = 10; var y = 20; (x + y) / 2; } //计算结果为最后一个语句值,即15
另一个带return语句例子:
{ var x = 10; var y = 20; if(x<y) return 50; return (x+y)/2; } //计算结果为第一个return语句值,即50
细心的观众可能会发现求值语句与eval()公式功能类似,都是设置局部变量,返回一个结果值,只不过支持更多语法结构和组合,功能更强。求值语句还可以直接嵌套在公式中使用,这时需要加上eval关键字,例如:
5 + eval{var x=5; return 2*x;} //计算结果15
三、复合语句
(1)选择语句:用于进行条件判断并选择执行对应控制流的语句。
if(条件公式) 语句块1
if(条件公式) 语句块1 else 语句块2
选择语句先计算条件公式并进行判断,如果为真则执行语句块1,否则执行语句块2。例如:
{ var a=15; var b=0; if(b<a) b=a; if(a<10) a+=100; else a-=10; return a+b; } //计算结果20
(2)分支语句:用于多路分支比较判断并选择执行对应控制流的语句。
switch(数据公式) { 分支语句系列 缺省语句 }
分支语句写法是:case 分支公式: 语句系列
缺省语句写法是:default: 语句系列
分支语句先计算数据公式,然后对分支语句的每个分支进行测试,如果等于某个分支公式值,则执行该分支语句,否则执行缺省语句。注意case语句块的最后一个语句通常是break;例如:
{ var a = 2; var x = 0; switch( a ) { case 1 : x = 10; break; case 2 : x = 20; break; default: x = 30; break; } return x; } //计算结果20
(3)循环语句:用于循环进行条件判断并执行对应控制流的语句。
for(变量赋值语句; 循环条件公式; 步长赋值语句) 循环体语句块
例如:
{ var a = [ 10 , 20 , 30 ]; var x = 0; for(var i = 0 ; i < 3 ; i++ ) { x += 2*a[ i ]; } return x; } //计算结果120
foreach(var 变量名 in 数组或列表公式) 循环体语句块
例如:
{ var a = [ 10 , 20 , 30 ]; var x = 0; foreach(var b in a ) { x += 2 * b; } return x; } //计算结果120
while(循环条件公式) 循环体语句块
例如:
{ var a = [ 10 , 20 , 30 ]; var x = 0; var i=0; while(i < 3) { x += 2*a[ i ]; i++; } return x; } //计算结果120
do循环体语句块 while(循环条件公式);
例如:
{ var a = [ 10 , 20 , 30 ]; var x = 0; var i=0; do { x += 2*a[ i ]; i++; }while(i<3); return x; } //计算结果120
四、函数定义语句
func 函数名称(形参序列) 函数体语句块
带参数的函数定义语句,例如:
{ func f(x) { return 2 * x; } , var g = f(5); //直接调用,g结果10 var a = f; a(5); //变量传递后间接调用,结果10 }
func 函数名称(形参赋值序列) 函数体语句块
带参数及缺省值的函数定义语句,例如:
{ func f(x=1) { return 2 * x; } , var g = f(x=5); //直接调用,g结果10 var a = f; a(x=5); //变量传递后间接调用,结果10 }
func 函数名称() 函数体语句块
无参函数的定义语句,例如:
{ func f() { return 2 * PI; } , var g = f(); //直接调用,g结果6.2831853071795862 var a = f; a(); //变量传递后间接调用,结果6.2831853071795862 }
五、整合语句
(1)动态加载.NET程序集:动态加载指定的.NET dll到当前程序域中,后续语句就可以通过全名直接调用该dll公开的方法。
load 文件名称字符串;
假如你已经用C#编写了一个叫AddIn.dll的.NET程序集,包含有一个名叫Shone的类及相关方法如下:
using System; namespace MyAddIn { /// <summary> /// 示例扩展 /// </summary> public class Shone { /// <summary> /// 测试函数,返回两个数值和的一半 /// </summary> public static double Mid(double d1, double d2) { return (d1 + d2) / 2; } } }
那么你就可以执行以下S#语句调用其中.NET方法进行计算了:
{ load 'C:HjxAddIn.dll'; //加载.NET dll文件 var a=10; var b=20; MyAddIn.Shone.Mid(a,b); //计算结果15 }
通过这种方式可以非常轻易地进行扩展,一些复杂的计算或逻辑处理直接用.NET写成dll,使用S#调用即可。如果你有C++代码的.NET包装dll,那么你也可以通过这种动态加载,从而间接调用C++代码。
事实上S#默认就动态加载了.NET的system.dll,因此System命名空间中的很多方法可以直接调用。例如:
{ var a = PI/3; var b = 60; System.Math.Cos(a)+cos(b); //计算结果0.5+0.5=1 } //注意:.NET的Cos方法参数为弧度,系统cos函数参数为角度
这会很酷炫,很像Python可作为胶水语言,只是S#天生就与.NET无缝融合在一起。
(2)使用命名空间:在当前变量堆栈上引用.NET命名空间的子命名空间、或类型中的所有成员,后续语句就可以不用全名直接调用该dll公开的方法。
using 命名空间或类型名称;
如上述例子可以通过using语句简化写成如下:
{ load 'C:HjxAddIn.dll'; //加载.NET dll文件 using System.Math; using MyAddIn.Shone; var a=10; var b=20; Mid(a,b)+Cos(PI/3); //计算结果15.5 }
注意使用上using语法与C#类似,但背后原理差别很大,其实S#中命名空间、类型、方法以及函数都看成变量了,优点是动态性和灵活性更大,缺点是类型推导难了,也容易出现重名,这就是硬币的两面性。
六、语句综合示例
下面举一个比较复杂的语句例子:
{ var str = ""; for(var i = 0 ; i < 5 ; i++ ) { for(var j = 4 ; j > i ; j-- ) { str += " "; } for(var t = 0 ; t <= i ; t++ ) { str += "*"; } for(var p = 0 ; p <= i - 1 ; p++ ) { str += "*"; } str += " "; } return str; }
//输出结果*的三角堆字符串,看起来效果如下
*
***
*****
*******
*********
七、待扩展
很多语言的学习都是从输出Hello开始的,其实S#现在就有该功能,不信写下如下句子:
{ System.Console.Write("您好!"); }
是不是和C#的入门程序很像。只不过是Write方法的返回值为null,"您好!"被写到控制台中,目前看不到,后面我会想办法打开控制台,需要时可以随时看到控制台内容。
八、展望
语句其实是为后面更复杂的代码模块——“类”使用的,有待后续分解。
目前而言,语句通过eval{}可以嵌入到前述的公式中,就可以形成很多语言难以达到的灵活性和复杂性了。
不知您对S#的语句能力评价如何?
声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp。
软件: S#语言编辑解析运行器13.6.24,运行环境.NET 4.0,绿色软件,单个EXE直接运行,无副作用。网盘下载链接为https://pan.baidu.com/s/1nv1hmJn