65.9K
CodeProject 正在变化。 阅读更多。
Home

Twiggery 脚本语言

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (14投票s)

2010年7月31日

LGPL3

13分钟阅读

viewsIcon

70394

downloadIcon

1082

Twiggery 脚本语言

引言

Twiggery 是一种小巧但有用的脚本语言。一个完整的 Twiggery 系统由一个编译器和一个虚拟机组成。而且,它比任何其他脚本语言都更容易将脚本与宿主程序(C++、Java、C# 等)结合,最精简的 TVM 实现源代码不超过 25KB。

背景

编写游戏是很有趣的!原因很简单,因为在游戏中你可以编写各种不同类型的子系统,无论是渲染器、声音系统、AI 还是游戏逻辑代码;在所有这些类型的编程中,你都可以解决各种挑战。在很多情况下,使用脚本是将游戏代码与主引擎隔离的理想方式。在 PC 平台、MAC 和游戏机上,有许多强大且成熟的脚本语言供开发人员选择,如 Lua、Python、Ruby 等。但在 J2ME 手机等移动平台上,开发人员没有选择,这就是为什么创建了这种优秀的脚本语言。你将了解 Twiggery 脚本语言是什么以及它是如何工作的;Twiggery 的最佳用途是将其用作手机脚本语言;当然,你还将了解一些编译器理论。你甚至可以研究一个完整的 Twiggery 虚拟机是如何开发的!如果你热爱编程,特别是编写游戏,我相信你会乐于了解更多关于这种小巧的脚本语言。祝你玩得开心!

如何使用 Twiggery 编程

基本语法

关键词

Twiggery 中只有 17 个关键字,如下所示

  • function
  • if
  • elseif
  • else
  • for
  • to
  • step
  • while
  • do
  • break
  • continue
  • return
  • not
  • true
  • false

每个单词的含义将在后面的部分介绍。

Twiggery 是一种区分大小写的语言,也就是说,“function” 是一个关键字,表示脚本函数的头部,而 Function FUNCTION 在语法上与“function”不同。

运算符

Twiggery 中有 15 个运算符,如下所示

类型

词汇

描述

示例

赋值

=

给变量赋值

pi = 3.14: pi 是 3.14

数值

计算

+

将一对值相加

r = 2 + 3: r 是 5

-

用一个值减去另一个值

r = 5 – 2: r 是 3

*

将两个值相乘

r = 3 * 7: r 是 21

/

将一个值除以另一个值

r = 18 / 3: r 是 6

%

取模运算

r = 10 % 3: r 是 1

数值

比较

<

小于

c = 1 < 2: c 是 true

>

大于

c = 1 > 2: c 是 false

<=

小于或等于

c = 1 <= 2: c 是 true

>=

大于或等于

c = 1 >= 1: c 是 true

==

等于

c = 4 == 5: c 是 false

~=

不等于

c = 4 ~= 5: c 是 true

布尔值

运算

“与”逻辑

参见“运算符”

“或”逻辑

not

“非”逻辑

关键字“false”表示一个表达式的结果为 false,它等同于 C 语言中的数字零;而“true”表示 true 或非零。“false”或“true”是数字比较或布尔运算的结果值。

关键字“and”、“or”和“not”也是运算符。请参阅 Twiggery 运算 优先级 表。

信号强度 操作 (Operation)
1 * / %
2 + -
3 < > <= >= ~= ==
4 not
5 and or
6 =

级别 1 的优先级最高,级别 6 的优先级最低。级别高的运算先于级别低的运算执行。公式从左到右处理;同一级别的运算以相同方式处理。括号‘(‘和‘)’成对使用,以处理它们之间的公式;例如 5 * (1 + 2) % 4 返回值 3。

注释

编译器除了跳过注释外,不会做任何事情。但这并不意味着注释不重要,注释在代码注释中起着重要作用,可以为代码阅读者提供很多信息。

Twiggery 注释以字符 ‘ 开头,以行尾结束。‘ 之后的所有内容都将被跳过。如下所示

' Welcome to Twiggery Scripting Language. This line is a comment.
function main() {
  output("Hello, Twiggery!"); ' Output a string. This is also a comment.
} 

变量与运算

数据类型

Twiggery 中有三种数据类型:数字、布尔和字符串。

数字是一种基本数据类型。Twiggery 只有一个数字类型;它以 32 位存储,并始终定义为 IEEE754 标准浮点类型。其范围是 3.402823e+38 ~ 1.401298e-45。

布尔可以被赋值为“true”或“false”这两个值之一。在 Twiggery 中,布尔在 32 位中存储和处理方式与数字类似;数值零表示“false”,所有非零值表示“true”。

字符串是通过不同 TVM 编码语言中的本机字符串类型实现的。字符串只能用作函数的参数。例如:output("Twiggery");

你可以在 Twiggery 中进行数字和布尔计算、比较和赋值,如下所示

' assignment 
 pi = 3.14; 
' remote function call, input a value into 'r' 
 input ( r );  
 ' calculation  
 s  = pi * r * r; 
' compare two value and assignment the result to a boolean 
 t = 1 < 2; ' t is true 
 f = 1 == 2; ' f is false 
' two simple variables 
 a = 1; 
 b = 0; 
' boolean operation between a numeric and a boolean const 
 b1 = a or false; ' b1 is true 
 b2 = not b and true; ' b2 is true 

脚本中的每个变量都是全局的,也就是说,你可以在任何地方、任何时间访问任何变量。变量类型声明不是必需的,因为 Twiggery 是一种弱类型语言,如果你想使用一个变量,只需写下来即可。

数字计算

编程语言的主要目的是数据处理,而数据处理的主要目的是数值计算。

有五种数字计算运算。这很简单,所以更多的解释会让你感到厌烦。你可以像下面一样使用 +、-、*、/、% 作为加、减、乘、除和取模运算

 s = v0 * t + (1 / 2) * 9.8 * t * t;
 m = 10 % 3; ' m is 1 

数字比较

这些运算比较两个数字并返回布尔值,它们根据比较公式是否相等来输出“true”或“false”。任何比较只能产生“true”或“false”之一。Twiggery 数字比较如下所示。

比较 示例 描述(结果为 true)
< ex1 < ex2 ex1 小于 ex2
> ex1 > ex2 ex1 大于 ex2
<= ex1 <= ex2 ex1 小于或等于 ex2
>= ex1 >= ex2 ex1 大于或等于 ex2
== ex1 == ex2 ex1 等于 ex2
~= ex1 ~= ex2 ex1 不等于 ex2

布尔运算

布尔是一种特殊的表示数字的方式,所以 支持布尔 和数字比较。“true”被当作 处理,“false”被当作零处理。

控制 Twig 执行会使用布尔值作为其条件。稍后将显示更多详细信息。

字符串

Twiggery 最初设计为一种 JavaME 嵌入式脚本语言,仅用于简单的逻辑控制和数字处理。因此,字符串操作不是它的强项。

在某些用法中,字符串类型的值只能作为远程函数参数传递。例如,将字符串“Hello”传递给标准输出函数“output”,字符串将显示在标准控制台上。

函数

如你所见,在当前版本的 Twiggery 中,每个脚本源文件只有一个函数。与其他复杂的编程语言不同,Twiggery 是一种小巧且易于嵌入的脚本,因此其设计理念是“用更少的代码做更多的事”。

每个 Twiggery 脚本源文件只包含一个无参数函数。执行流程从函数的第一行开始。多函数调用和进入点函数参数支持可能在后续版本中可选。

执行结构

我们称 Twiggery 为脚本语言而不是公式处理器,因为它像其他编程语言一样有三种执行结构:顺序、条件和循环流。在本节中,你将学习如何使用它们。

与 C/C++/Java/C# 等类似,Twiggery 的作用域由花括号 {} 的位置决定,语句以分号; 结束。花括号必须成对使用。允许但 Constructors(不推荐)在一行中编写多个语句。

顺序流

顺序流语句一行接一行编写,并按编写顺序执行。例如,测试如下代码。

function main() {
 ' Now let's do some calculating.
  pi = 3.1415926; ' Step 1: Assign p to variable pi
  r = input(); ' Step 2: Input a value to variable r
  s = pi * r * r; ' Step 3: Calculate area of a circle
  output( s); ' Step 4: Output the result
} 

如你所见,每个 Twiggery 脚本源文件只包含一个“function”。在步骤1 中,将一个浮点数值 3.1415926 赋值给名为 pi 的变量;在步骤 2 中,我们调用一个标准的远程函数“input”从用户输入(控制台或输入框…)获取一个值并将其设置为变量 r;在步骤 3 中,我们进行一个你知道的计算:S =pR2;最后,结果区域“s”在最后一步 4 中显示。

开始使用 Twiggery 很容易,不是吗?

if-elseif-else

标准的“if” twig 遵循如下语法

if( expression) {
   twig_body;
}

如果公式表达式的结果为“true”或非零,则执行子 twig“twig_body”;否则,它将跳转到此“if”块后面的下一个 twig。

twig body 包含一个或多个子 twig。例如

n =  input();
if( n % 400 == 0 or ( n % 4 == 0 and  n % 100 ~= 0)) {
   output("leap year");
}

Twiggery 中没有“最佳路径”。这意味着“or”后面的公式会每次都计算。因此,即使在本示例中“ n % 400 ==0”true ;“n % 100 ~= 0”也将在任何情况下被处理。

允许在“if” twig 后直接追加最多一个“else” twig。此外,“if-elseifelse”结构在复杂的条件 twig 中非常有用。“elseif”和“else”在“if-elseifelse”结构中都是可选的。如下所示

c = input(); ' Input a variable.
if( c == 1) { ' If the variable "c" equals to "1"...
  output("Uno"); ' Call a system function to output something.
} elseif(c == 2) {
  output("Dos");
} elseif(c == 3) {
  output("Tres");
} else {
  output(c);
} 

在此示例中,第二个条件“c == 2”仅在“c”不等于 1 时确定,第三个条件类似。最后一个“output(c)”仅在“c”不等于 12 3 时执行。

for, while 和 do-while 循环

if-elseifelse” twig 只能为 Twiggery 提供跳过能力。在本节中,你将学习一些有用的具有重复能力的 twig。

有三种重复 twig:“for-to-step”、“while”和“do-while”。

for” twig 被视为固定步长循环。如下所示

 n = 1; ' Initialize "n" with value "1".
 e = 10;
for( i = 1 to e step 1) { ' A loop.
   n  = n * i;
 }
 output ( n );  ' Output n!

在此示例中,变量“i" 从 1 计数到 e(即 10),循环步长为 1。这意味着 twig body“n = n * I”被处理 10 次。循环步长的默认值为 1,因此此 twig 头部也可以写成“for(i = 1 to e)”。

有时我们不知道循环需要多少步。为此,动态变量循环是必要的。Twiggery 中有两种不固定循环:“while”和“do-while”循环。

while”和“do-while” twig 实际上是条件循环。它们会在“if” twig 中一旦条件为 true 就跳转到 twig body 执行;并且在“while”和“do-while”中,twig body 会一遍又一遍地执行,直到循环条件不再为真;这两个循环的区别在于,如果条件为 false,则“while” twig body 不会被处理,但无论条件值如何,“do-while” twig body 至少会运行一次,这是因为在“while”中是在 twig body 之前判断循环条件,而在“do-while”中是在 twig body 之后判断。例如

 a = 0;
while( a <= 5) {
  ' Execute inside if loop condition is true
   output ( a );
   a = a + 1;
 }
 b  = 0;
do  {
  ' Execute inside at least once whether loop condition is true or false
  output(b);
  b = b + 1;
} while(b <= 5)

break, continue 和 return

Twiggery 中的“break”用于中断当前循环并继续执行其后的程序。它与 C 编程语言相同。它总是通过外部条件触发(通常通过“if” twig 测试)来中断当前循环。“break”可以用于“for”、“while”和“do-while” twig。

 num =  input();
 count =  num / 2;
while( count > 0) {
  if( num %  count == 0) {
     output( count, " is the largest factor of ",  num);
    break;
  }
   count =  count - 1;
}

此脚本将找出给定数字“num”的最大因子。我们迭代所有可能的数字,并使用“count”作为循环变量,按降序拒绝所有不能被“num”整除的数字。然后,第一个能被“num”整除的数字就是我们要找的,如果我们找到了,就不需要再执行循环了,我们只需使用“break”退出循环。

Twiggery 中的“continue”与其他编程语言没有区别。它可以用于“for”、“while”和“do-while”,类似于“break”。“while”和“do-while”是条件循环,“for”是迭代循环。是否执行循环的下一个周期在遇到“continue”时也取决于循环类型的需求;当循环不满足条件时,它将正常终止。如下所示

 valid = false;
 count = 3;
while( count > 0) {
  it = input();
  if(it == 123) {
    valid = true;
    break;
  }
  if(not valid) {
    output("Invalid");
    count = count - 1;
    continue;
  } else {
    break;
  }
}

有时我们想完全跳出整个函数并退出脚本执行,“return”就是为此而设计的;“return”仅用于执行此操作,但不能将值返回给外部调用者。如下所示

for( i = 0 to 10) {
   n =  input();
  if( i %  n ~= 0) {
    return;
  }
}

如果“i % n ~= 0”为 true ,程序将毫无疑问地直接终止。

输入和输出

如果没有输入和输出,我们无法使用编程语言进行任何操作,只能进行内部处理。在 Twiggery 中,有一个标准的输入函数和一个输出 函数 input函数不接受任何参数并返回一个数字值;“output”函数至少接受一个数字或字符串格式的参数,并将其输出到标准流(Windows 上的消息框、控制台上的行打印等)。

历史

  • 2010年8月12日 - 版本:0.5.2.44
    • 为 C# TVM 添加 try-catch 以直接加载和运行字节码
    • 为脚本文本框添加拖放支持
    • Java TVM 中的字节码加载错误修复
  • 2010年7月28日 - 版本:0.5.1.43
    • 音频插件错误修复
    • 为 Core 插件添加数组支持
    • 为所有 TVM 添加动态多参数支持
    • 在普通公式中接受函数调用
    • 负号错误修复
  • 2010年7月3日 - 版本:0.4.2.38
    • 脚本内部异常错误修复
  • 2010年6月24日 - 版本:0.4.1.36
    • 添加插件加载过程窗口
    • 关联“.twg”和“.tad”文件
    • 添加新的 Core 插件
    • 为 CodeLeaf 添加自动补全提示
    • 条件表达式解析错误修复
    • 为 Graphics 插件添加一些新界面
  • 2010年6月18日 - 版本:0.4.0.30
    • 修改 Graphics 插件:将画布图像放在 PictureBox 中,而不是直接放在窗体上
    • 添加关键字 'do' 和 'do-while' twig 支持
    • 添加负号支持
    • 重新配置 Graphics 插件
  • 2010年6月16日 - 版本:0.3.5.28
    • 在 RAM 框中显示堆单元使用情况
    • 在标准函数 'input' 和 'output' 中接受多参数
    • 如果两个操作数的寻址模式都是 AM_STK,则交换它们
    • TASM 列表框项数错误修复
    • 添加字符串类型插件函数参数支持
    • 修改 Graphics 插件:创建 Canvas,绘制 Sprites,获取 KeyDown
    • 修改 Audio 插件:C# 源代码格式插件,播放 *.wav 文件
    • 修改 IO 插件:打开、关闭、写入、读取文件
    • 如果获取操作数失败,将参数推回堆栈
    • 'if-elseif-else' 块编译错误修复
    • 将默认的 'for' 循环步长参数值设为 1
    • 将返回值获取为格式 'a = input();'
    • 重新配置异常消息
    • 添加使用插件的新示例脚本
    • 在函数参数中将 'true'、'false' 转义为 '1'、'0'。
  • 2010年6月12日 - 版本:0.2.3.25
    • 添加已编译程序集 DLL 和 C# 源代码插件支持
    • 在 TVM 执行中使用 'v is t' 而不是 'v.GetType() == typeof(t)'。
  • 2010年6月9日 - 版本:0.1.2.24
    • 'if-elseif-else' 跳转指令编译错误修复
  • 2010年2月24日 - 版本:0.1.0.20
    • 首次发布版本。完整的编译器和虚拟机
© . All rights reserved.