author: Kevin Lynx email: zmhn320#163.com date: 3.6.2009
语言特性
在正式讨论实现细节前明确下这个脚本语言的一些语言特性,基本上可以让我们预见将
来会遇到哪些难题。总的来说,它(脚本)将同我们平时接触的如lua一样的脚本语言:拥
有一般的编程语言特性,如变量、各种控制流程、也许还有函数,另一方面它还应该和它的
宿主语言结合,如作为一个库被用进C,这还涉及到给这门语言设计一种插件方式,最好能
通过独立的解释程序让脚本载入一些插件运行。
以下在描述我写的这个脚本语言时,将以kl表示它的名字,以方便描述。
代码块:
首先从整体风格上,kl如同C语言一样被划分为函数块,如:
function func1()
{
}
function func2()
{
}
...
kl支持以{}隔离代码块,但是这并不意味着kl有多个独立的局部堆栈,如同C语言一样。
这些细节暂不讨论。本节描述的所有内容你都不必深究,因为我只要求你对kl有个感性上的
认识。
函数块之外没有可执行的语句(statement)。那么你可能会想到程序的入口点也许会是
main。事实上从kl提供的库来看,并没有这种硬性要求。但是,kl的独立解释程序是这样要
求的。
变量:
kl允许你在任何地方使用一个变量。变量不需要事先定义,任何地方出现一个合
法的标识符时,就意味着kl内部会增加这个变量,并给予初值。变量也没有静态类型,也不
会固定为某一类型。就一门最简单的语言来看,我觉得数据类型无非就是字符串和数字类型
。
所以,kl的变量在某一时刻必然是数字,或者字符串。在脚本里,你无法获知一个变量
的类型,事实上也没这个必要。说变量拥有一个类型属性,倒不如说值(value)有一种类型
属性。
当字符串值与数字值参与运算时,如1+"a",其运算结果将自动转换为字符串,也就是
"1a"。
一个只有标识符的语句(statement)通常意味着你想定义一个变量。这种无聊的手段通
常被用于定义全局变量。
运算符:
kl支持一般的C语言风格的算术、比较、逻辑运算符。例如加减乘除、大于小于、逻辑
与逻辑或。
作用域:
kl脚本里只有两个作用域:全局的和局部的。
位于所有函数块外的变量处于全局作用域;位于函数内的变量处于局部作用域,位于函
数块内的代码块变量,还是处于局部作用域。
当局部作用域内出现一个全局里的同名变量时,优先取局部作用域里的变量。这同C语
言一样。
控制语句if:
if的语法同C语言一样,如:
if( a > 10 )
{
}
else
{
}
if( a > 10 )中的a>10被我成为条件语句,所有条件语句,包括下面的while,都不能
为字符串。例如if( "a" )将被视为非法语句。(我为什么要这样考虑?- -!)
控制语句while:
c-like while:
while( a > 10 )
{
}
很遗憾,我暂时没有加入对for的支持。因为我觉得既然有了while,有了循环控制,在
没有更多无聊时间的前提下,我没有必要加入for。
函数:
很遗憾,函数的定义和调用和C语言有点不一样。这是因为kl没有变量类型,那就意味
着函数定义如果和C语言一样,就会出现语法歧义,如:
func( a )
{
}
就会和函数调用func(a)出现混淆。所以,我加入了function关键字。定义函数的语法
为:
function func( a, b )
{
}
如你所见,函数支持参数传递,当然也支持return a;返回值。kl是简陋的,因为它没
有指针之类的概念,所以你无法为函数传递一块数据。当然,kl也不能像lua一样让函数可
以返回多个值。
函数调用的语法相对熟悉:
func( 1, 3 );
数组:
从一开始我就没考虑为kl加入数组。事实证明加入数组是一个不明智的做法。数组的支
持让代码在很多地方变得脏乱。无论如何,kl后来支持一维数组了。为了让代码保持那么一
点点的干净,我甚至为定义数组加入dim的关键字。这意味着,在kl里,数组和一般的变量
总有点不一样:变量无需定义,数组却必须事先定义。
数组的长度不支持动态扩充。如果支持,我得让kl内部更好地去管理内存。
数组元素的类型没有硬性的规定,这意味着a[0] = 1; a[1] = "a";是允许的。
语言特性上就描述这些,在本节末尾我决定贴一段kl计算阶乘的代码:
/* fac.kl */
function main()
{
n = input( "%d" );
print( "fac(" + n + ") = " + fac( n ) );
}
function fac( n )
{
if( n == 1 )
{
return 1;
}
else
{
return fac( n - 1 ) * n;
}
}