本栏目将对《AFSim 2.9中文参考手册》进行持续更新,欢迎关注交流!
对本书全文和AFSIM其它资料感兴趣的伙伴,可联系作者领取~
全部内容索引请看 ⬇️⬇️⬇️
《AFSim 2.9中文参考手册》-CSDN博客编辑https://blog.csdn.net/henggesim/article/details/145566384
概述
Scripts为用户提供了一种基于仿真中发生的事件执行复杂指令集的方法。其语言类似于C#和Java,对于具备基本编程技能的人来说应该很熟悉。它是块结构化的,包含熟悉的声明、赋值和流程控制语句,允许用户检查和操作仿真环境。
Scripts本质上是由脚本编译器生成的指令列表,该编译器理解脚本语言语法并将其翻译为适当的指令。一旦编译,Scripts可以在脚本上下文(执行上下文)中执行,该上下文负责解释脚本的指令并提供脚本与应用程序(即仿真)层之间的接口。在WSF中,执行上下文被链接形成树结构,允许子上下文继承其父上下文定义的Scripts。
基本类型
Script有四种基本类型。基本类型在赋值给变量和传递给函数时被复制。基本类型包括:

int:32位整数,例如:int prime5 = 11;
bool:布尔值,‘true’或‘false’,例如:bool isTrue = true;
double:双精度浮点值,例如:double gravity = 9.8;
string:字符字符串,例如:string text = "Hello World";
基本类型支持多种运算符。‘int’和‘double’都支持基本算术和比较运算:
// 算术运算 ( +, -, *, / )
double abc = (5 + 2.5) / 2.0 - 1.0;
// 算术赋值: ( +=, -=, *=, /= )
abc += 5.0; // abc加5
// 比较运算 ( >, >=, <, <=, ==, != )
bool isPositive = abc > 0.0;
‘string’支持比较运算符和‘+’作为连接:
string alphabet = "alphabet";
string zoo = "zoo";
bool trueVal = alphabet < zoo;
string combine = alphabet + " " + zoo;
‘bool’支持比较运算符:
bool trueVal = true != false;
Script类
所有其他类型称为Script类。这些类型通过引用复制。可用的类型很多,详见Script Types:
// 定义一个非基本类型的变量。
// 在这个例子中,val没有值,是'null'。
Vec3 val;
// 创建一个新的Vec3值
Vec3 val2 = Vec3();
// 调用返回值的静态方法的示例。
Vec3 val3 = Vec3.Construct(1,2,3);
方法
方法是存在于Script类上的函数。方法可以是静态的或非静态的。静态方法可以在没有脚本对象的情况下调用,例如:
Vec3.Construct(1,2,3);
非静态方法必须在有效对象上调用,例如Magnitude():
Vec3 v = Vec3.Construct(1,2,3);
double length = v.Magnitude();
在无效对象上调用非静态方法会导致运行时错误:
Vec3 v;
v.Magnitude(); // 产生错误,v未初始化,因此为'null'
可以这样测试对象的有效性:
if (v) {
double length = v.Magnitude();
}
Scripts
用户定义的函数称为‘Scripts’。通常Scripts具有以下语法:
script <type> <script-name>([<variable-declaration-list>])
<script-commands...>
end_script
Scripts可以调用在相同上下文中定义的其他Scripts或在父上下文中定义的Scripts。例如:
script bool global_script()
writeln("Global script called");
return true;
end_script
platform plat WSF_PLATFORM
script void local_script()
writeln("Local script");
end_script
// on_initialize是不同脚本语法的示例。
on_initialize
// 调用全局脚本,任何地方都可以访问
global_script();
// 调用本地脚本,仅在此平台上可访问
local_script();
// 要调用稍后定义的脚本,必须使用'extern'声明它
extern bool global_later(double);
global_later(123.0);
end_on_initialize
end_platform
script bool global_later(double value)
writeln("global_later(", value, ")");
end_script
platform plat2 WSF_PLATFORM
// 此平台无法直接访问'plat'上的Scripts
//
script void call_plat1()
// 找到上面定义的平台
WsfPlatform plat = WsfSimulation.FindPlatform("plat");
// 这里,'.'操作符不能用于调用'plat'上的local_script()
// '->'操作符允许访问其他对象,但这种访问在启动时不检查。
plat->local_script();
// 如果出错,会在运行时发出错误。
// 这会导致运行时错误:
// plat->bad_script();
end_script
end_platform
全局变量
全局变量允许从多个Scripts中存储和访问值。当定义全局变量时,它仅对其父上下文全局。例如,在平台上定义全局变量仅允许从该特定平台访问该变量。有多种定义全局变量的方法:
// 在平台外的'script_variables'块中定义的变量始终是全局的。
// 'x'是真正的'全局'变量,任何地方都可以使用
script_variables
double x = 1.0;
end_script_variables
platform plat WSF_PLATFORM
// y是仅对位于'plat'上的Scripts可用的全局变量
script_variables
double y = x;
end_script_variables
script void test()
// 全局变量可以像常规变量一样使用
y += x;
// 全局变量也可以在任何脚本中使用'global'关键字定义:
global double z = y;
end_script
end_platform
script void test2()
// 找到上面定义的平台
WsfPlatform plat = WsfSimulation.FindPlatform("plat");
// '->'操作符可用于访问属于对象的变量。
plat->y -= x;
end_script
静态变量
静态变量是只有一个实例并且只初始化一次的变量:
script void test_static()
// 在这个例子中,x在第一次调用此脚本时初始化为1.0。
// x的值在对test_static()的调用之间保持不变。
// 这将输出1234...每次调用test_static()时输出一个数字。
static double x = 1.0;
write(x);
x += 1;
end_script
类型转换
Casting是将一个值从一种类型转换为另一种类型。转换的语法为(<type>)value。基本类型之间可以自由转换:
int five = (int) 5.5;
string fivePointFive = (string)5.5;
在非基本类型之间进行转换是允许的,但用户应谨慎操作:
WsfMessage msg = GetControlMessage();
((WsfControlMessage)msg).SetResource("my_resource");
运算符
- .:用于调用脚本类对象上的方法,或脚本类上的静态方法。
- ->:用于调用对象上的用户定义脚本,以及获取/设置对象上的用户定义脚本变量。
- +:用于数值相加和字符串连接。
- -:用于数值相减,例如:1 - 1。
- *:用于数值相乘,例如:2 * 2。
- /:用于数值相除,例如:4 / 2。
- >:用于大于比较,例如:1 > 0。
- >=:用于大于或等于比较,例如:1 >= 1。
- <:用于小于比较,例如:0 < 1。
- <=:用于小于或等于比较,例如:0 <= 1。
- ==:用于等于比较,例如:1 == 1。
- !=:用于不等于比较,例如:1 != 0。
- !:布尔非运算,例如:true == !false。
- ():用于表达式的优先级,例如:(1+1)*2 == 4。
- (<type>):类型转换运算符。
- =:赋值运算符,例如:double x = 2.0;。
详细信息
这是脚本语法的详细文档。
- 符号说明:
- 尖括号(< >)用于标记类别。
- 方括号([ ])用于标记可选项。
- 花括号({ })用于标记重复项。
- 单引号(‘ ‘)用于标记字面量。
- 粗体文本表示保留字。
注意:完整的语言语法可以在Scripting Language Grammar中找到。
命令模板
脚本使用以下序列定义:
script <type> <script-name>([<variable-declaration-list>])
<script-commands>
end_script
这种结构允许用户定义和执行复杂的指令集,利用脚本语言的语法和功能来操控仿真环境。
语言描述
该语言由以下构造组成:
<identifier> 标识符
标识符表示变量或函数的名称。标识符以字母(大写或小写)开头,后跟零个或多个字母、数字(0-9)或下划线(‘_’)。标识符是区分大小写的。因此,标识符‘x1’和‘X1’表示不同的变量。有效标识符的示例:
- i
- X1
- aLongIdentifier
- x_2
<type> 类型
每个变量都有一个‘类型’,定义了它可以包含的数据类型。数据主要有两种类型:<basic_type> 和 <complex_type>。所有类型都派生自一个称为Object的‘基’类型。
Object:所有其他类型都兼容的‘基’类型。
例如:
Object myObject;
myObject = 'hello';
myObject = 19;
<basic_type> 基本类型
脚本语言的类型与大多数现代编程语言提供的类型相匹配:
- int
- double
- bool
- string
<complex_type> 复杂类型
这些是更复杂的类型,通常由几个基本类型或其他复杂类型组成,通常包括可以访问和操作类型内数据的函数。复杂类型不能在脚本中定义;它们是在C++中定义并导出以供脚本使用。复杂类型的完整列表可在Script Types部分找到。
<storage-type> 存储类型
当变量被声明时(见下文),内存存储类型要么是隐式的,要么是显式设置的。默认情况下(如果未指定存储类型),变量被认为是自动的,意味着它们是在当前<block>的内存空间中创建的。这也意味着它们仅在当前<block>及其内部嵌套的<block>中可用。除了自动变量,还有全局变量和静态变量。全局变量在全局内存中分配,并在所有脚本中可用。静态变量的工作方式与自动变量相同,只是它们的内存(及其当前值)在对给定脚本的调用之间被保留。
<expression> 表达式
表达式是任何导致单个值的内容。
例如:
10 * 3
('platform-1' == platform.Name()) && (5 < mX)
Foo()
mX
MATH.Pi()
(9.99 >= 1.0)
1.23
<expression-list> 表达式列表
以逗号分隔的<expression>列表。
<cast> 类型转换
表达式可以使用类型转换操作转换为另一种类型。在某些情况下这是必要的(参见Script Types部分中的Iterator、ArrayIterator和MapIterator)。
'(' <type> ')' <expression>
例如:
Object obj = 'my string';
string str = (string)obj;
int i = 99;
double d = (double)i;
WsfMessage msg = GetControlMessage();
((WsfControlMessage)msg).SetResource('my_resource');
<statement> 语句
语句定义为以下之一:
<variable-declaration> 变量声明
每个变量必须在使用前声明。变量可以简单地声明,也可以声明并赋值。变量声明如下:
[<storage_type>] <type> <identifier> ';'
[<storage_type>] <type> <identifier> = <expression> ';'
前者的示例:
int i;
static j;
WsfSensor thisSensor;
后者的示例:
int i = 0;
global double x = 10.0 * i;
string s = 'Hello, world';
WsfSensor thisSensor = PLATFORM.Sensor('this_sensor');
<variable-assignment> 变量赋值
简单值、复杂表达式和脚本/函数返回值可以使用赋值运算符赋值给变量。
<variable> = <expression> ;
例如:
int x;
x = 10;
<if-else> 条件语句
if-else语句允许用户根据一个或多个计算为布尔值的表达式选择要执行的语句。第一个解析为true的条件执行其<block>中包含的语句。
if '(' <expression> ')' <block> { else if '(' <expression> ')' <block> } [else <block>]
例如:
string name = 'platform-1';
if (name == 'platform-2')
{
print('Found platform-2');
}
else if (name == 'platform-1')
{
print('Found platform-1');
}
else
{
print('Couldn\'t find platform 1 or 2');
}
<while-loop> 循环语句
while语句允许用户基于计算为布尔值的表达式进行迭代。迭代继续,直到表达式解析为false。
while '(' <expression> ')' <block>
例如:
int i = 0;
while (i < 10)
{
print('i is ', i);
i = i + 1;
}
<do-while-loop> do-while循环
do-while语句允许用户基于计算为布尔值的表达式进行迭代。迭代继续,直到表达式解析为false。do-while和while循环之间的区别在于条件在do-while循环的底部检查,这保证至少进行一次迭代。
do <block> while '(' <expression> ')'
例如:
int i = -1;
do
{
i = i + 1;
print('i is ', i);
}
while (i < 10)
<for-loop> for循环
for语句允许用户基于计算为布尔值的表达式进行迭代。迭代继续,直到表达式解析为false。此外,它提供了声明循环计数器和增量操作的空间。
for '(' [<variable-declaration>] ';' [<expression-list>] ';' [<expression-list>] ')' <block>
例如:
for (int i = 0; i < 10; i = i + 1)
{
print('i is ', i);
}
<foreach-loop> foreach循环
foreach循环允许用户迭代容器中的元素,同时提供对键和值的访问。
foreach '(' [<variable-declaration> ':'] <variable-declaration> in <expression> ')' <block>
例如:
Map<string, double> myMap = Map<string, double>();
myMap['a'] = 1.1;
myMap['b'] = 2.2;
// 如果声明了两个循环变量(用冒号分隔),第一个必须是键,第二个必须是数据。
foreach (string aKey : double aData in myMap)
{
print('key, data ', aKey, ', ', aData);
}
// 如果声明了一个循环变量,它必须是数据。
foreach (double aData in myMap)
{
Print('data ', aData);
}
<break> 跳出循环
break语句允许用户跳出当前块。
break ';'
例如:
while (true)
{
if (true)
{
break;
}
}
<continue> 继续循环
continue语句允许用户忽略循环中的其余语句并跳到循环的顶部。
continue ';'
例如:
for (int i = 0; i < 10; i = i + 1)
{
if (i == 5)
{
continue;
}
}
<return> 返回值
return语句允许用户从脚本/函数调用中返回一个值。
return <expression> ';'
例如:
double Multiply(double aA, double aB)
{
return aA * aB;
}
<block> 代码块
代码块是:
-
- 零个或多个语句被script和end_script包围
- 零个或多个语句被花括号包围
前者的示例:
script void my_script()
int i = 1;
print('i = ', i);
end_script
后者的示例:
if (true)
{
int i = 1;
print('i = ', i);
}
<function-declaration> 函数声明
函数可以在脚本中使用以下语法声明。函数只能在脚本中声明。如果需要一个对所有脚本都可用的函数,将其定义为脚本。
<type> <identifier> '(' [<variable-declaration-list>] ')' <block>
例如:
double Magnitude(double aDx, double aDy)
{
return MATH.Sqrt(aDx*aDx + aDy*aDy);
}
注意:MATH是一个系统变量,所有脚本都可以使用它,提供对各种基于数学的实用程序的访问。