词汇元素也叫词位被用于描述语言结构的句法
正则表达式符号:
符号 含义
ID=re 在正则表达式中ID被定义为re
| 替代
re? 出现re的次数为0或者1次
re* 出现re的次数为0或者更多次
re+ 至少出现一次
(re) 分组
[chars] 匹配chars中含有的任何字符
[x-y] 字符串集范围从x到y
抽象句法符号:
符号 含义
::= 被定义为
| 替换
[[X]] X至多出现一次
{{X}} X出现0次或多次
{{X}}+ X至少出现一次
((X|Y)) 分为X组或者Y组
abc 关键词终端符号abc
INTEGER 终端符号以外的关键词
xyz 非终端符号
^:a:int32^n: 定义一个整形长度为n的数组a
词位
SCADE能用几种符号去描述值。整形能被写为二进制、八进制、十六进制值和与一些表达式混合使用。它被当做前缀或者无类型。
非十进制整形字符被当做无符(通常被当做负数)。浮点型用十进制或者科学计数符号表示。字符被描述为标准的ASCII码。
DIGIT2 =[0-1]
DIGIT8 =[0-7]
DIGIT10 =[0-9]
DIGIT16 =[a-f][A-F][0-9]
INTEGER2 =0b DIGIT2+ #二进制
INTEGER8 =0 DIGIT8+ #八进制
INTEGER10 =0 | ([1-9]DIGIT10*) #十进制
INTEGER16 =0x DIGIT16+#十六进制
INTEGER =INTEGER2|INTEGER8|INTEGER10|INTEGER16
TYPED_INTEGER= INTEGER(_i|_ui)(8|16|32|64)#定义整形的长度和类型
EXPONENT =[eE][+-]? DIGIT10+;#科学计数法
FLOAT =DIGIT10+.DIGIT10*EXPONENT?|DIGIT10*.DIGIT10+EXPONENT?#浮点类型
TYPED_FLOAT=FLOAT(_f32|_f64)#定义浮点类型的字节长度
LETTER =_|[a-z]|[A-Z]#字母
ALPHANUMERIC=DIGIT10|LETTER#字母数字组合
WORD =LETTER ALPHANUMERIC* #单词是字符与字母与数字组合
CHARACTER=ALPHNUMERIC|SPACE|[!"$#&'()*+,-./:;<=>?@[]\^`|{}~]#
字符
CHAR='CHARACTER'|'\x DIGIT16 DIGIT16';
ID=WORD;
NAME='WORD;
符号列表
<> <= >= << >> = < > () [] {} -> :: .. ; , . : ^ @ # _ | + - * /
$符号被作为操作的名字。
字首操作符
PREFIXOP ::=$+$|$-$|$*$|$/$|$mod$|$=$|$+$|$<>$|$<$|$>$|$<=$|$>=$|$@$|$times$|$and$|$or$|$xor$|$land$|$lor$|$lxor$|
$lsl$|$lsr$|+$|-$|not$|$or$|lnot$|reverse$
关键字列表
abstract,actived,and,assume,automation,bool,case,char,clock,const,default,do
,else,elseif,emit,end,enum,every,flase,fby,final,flatten,float,float32,float64,fold,foldi,foldw,foldwi,function,
guarantee,group,if,imported,initial,int8,int16,int32,int64,integer,is,land,lnot,lor,lsl,lsr,last,let,
make,map,mapfold,mapfoldi,mapfoldw,mapfoldwi,mapi,mapw;
mapwi,match,merge,mod,node,not,numeric,of,onreset,open,or,package,parameter,pre,private,probe,public,
restart,resume,returns,reverse,sensor,sig,signed,specialize,state,synchro,
tel,them,times,transpose,true,type,uint8,uint16,uint32,uint64,unless,unsigned,until,var,
when,where,with,xor
注意关键词:onreset,abstract,parameter被保留但未被使用
注释:
单行注释开始用“--”
多行注释开始“\*”,结束“*\”
程序
pragma ::=#progma CHARACTER*#end|#ALPHANUMERIC+
程序和包
path ::=ID{{::ID}}
path_id ::=[[path ::]]ID
package_decl ::=package[[visibility]] ID {{decls}} end;
七中顶级申明:
decls ::=open path;
package_decl
group_block
type_block
const_block
sensor_block
usr_op_decl
一个包不能被打开多次,即使是不同的路径。一个包不能打开本身。
例子:
申明一个合格的路径:
package
P1
const foo :int16 =3;
end;
package P2
const bar : int16=4;
end;
const foobar : int16=P1::foo+P2::bar;
算法解析:打开指令将包括Q::R包进行申明而不是P::R包,由于这是第一次出现的R中的封装结构选自B开始
package P
package R
...
end;
end;
package Q
package R
...
end;
package S
open R
...
end;
end;
安装包中的申明不是相对的:
package P1
open P1;
const
iC1: T1 =2;
package P1
type
T1=int32;
end;
end;
错误源于打开多次申明:识别码foo被用作常量和类型名为foo的发生冲突通过打开指令。
package P1
type foo =int16;
end
open P1;
const foo:bool =true;
一个打开的包中的子包不能使用open指令。P2包中的第二个申明在这个程序是有效的,因为P1中的P2不可见:
package P1
package P2
...
end;
end;
open P1;
package P2
...
end;
正在打开的包是不可及:申明的P1包下被打开的P2包是不被考虑的,当打开后者。常量foo不被识别在foobar的定义中,出现一个错误:
package P1
package P2
const foo:int32 =0;
end;
open P2;
const bar:int32=foo+1;
end;
open P1;
const foobar:int32=foo*2;
属性
一些申明可能会给可见和可用的属性目标,
visiblity ::=private|public#可视化
external ::=imported;#外部
interface_status ::=[[visiblity]][[external]]#接口状态
一个包内的类型、组、常量、用户操作被严格隐藏在。
可视化规则:
公共的——默认状态;申明的变量可以在任何地方使用
私有的——被严格限制的;申明的变量只能在包的内部和它的子包内使用。私有变量出现在一个打开的包中不能与当前申明的包相互作用:没有名称冲突可能发生
SCADE不是一个通用的语言。一个SCADE程序倾向于嵌入到一个通用的程序中,通用程序是免费的,特别的,简单的输入和显示输出的SCADE程序。
一个申明被申明为imported类型通过使用关键词前缀imported。
例子
1.私有的可视化状态:类型 t不能识别在P1包外。这个程序有个错误:
package P1
type private t=int64;#自定义一个int64类型的量:t
const c:t=0;#给常量c赋0值
end;
open P1;
const d:t=c+1;#在包P1外,t类型不可识别
2.imported类型申明
package ForeignArithmetics
type imported ForeignCplx;
function imported plusCplx(x,y:ForeignCplx) return (z:ForeignCplx);
function teiceCplx(x:ForeignCplx) return (y:ForeignCplx);
y=pulsCplx(x,x);
end;
类型申明
类型申明通常被用户用来创建新的用户数据类型;
type_block ::type{{type_decl;}}
type_decl ::=interface_status ID [[=type_def]] [[ is numeric_kind]]
type_def ::=type_expr|enum{ID{{,ID}}
numeric_kind ::=numeric|float|integer|signed|unsigned
一个类型快开始的关键词TYPE,几个类型被申明只能使用type一次。
结构类型:
type t={lbl1:int32,lbl2:bool,lbl3:{lbl4:int32,lbl5:float32}};
const c:t={lbl1:1,lbl2:true,lbl3:{lbl4:2,lbl5:0.5}};
const d:int32=c.lbl1;
组申明
建立组对象的方法:
group_block ::=group{{group_decl;}}
group_deck ::=[[visibility]]ID=group_expr;
一个组块开始的关键词:group。几个组申明只能有一个关键词:group。一个组可以被用作一个类型在组中,不能被用作衣
常量类型、传感器、定义申明。
只能通过用户定义的操作符来进行操作。多态类型的操作的限制范围如下:
时态:pre,->,fby,when,merge.
控制:if(不为条件论证)case (不为条件论证)
组表达式
group_expr=(type_expr{{,type_expr}})
一个组表达式有非空的类型表达式列表组成。任何类型都能被用作组表达式。一个有效的组识别码可以被用作组的表达式。
例子:
1.组申明
group
G1=(int32,bool);
G2=(bool,G1);
2.组不能被定义成一个新类型和一个传感器。下面组的定义是不正确的:
group
G=...
type
T1=G^n;
sensor
S:G;
3.一个变量的识别码可以用带有G的申明:
group G=(int32,int16,bool);
node ex(e:G;...) returns (s:int32;...)
...
tel;
4.组通常是平的:
group
G0=(int32,bool);
G1=(int32,G0);
function f1(x:int32;y:int32;z:bool) returns(r:G1)
r=(x,y,z);
function f2(v:G1) returns(a:int32;b:int32;c:bool)
a,b,c=f1(v);
5.组通常被用作管理多个输出操作:
function f(a,b:int32;c:bool) returns(x,y:int32)
function g(a,b:int32) returns(x:int32)
6.列表中的表达式包含基于不同时钟的流:
function N(x:int32;clock h:bool) returns(y:int32 when h;z:bool)
let
y,z=(x when h,true);
tel;
而一组类型的对象不能。下面的例子有个问题:
group G=(int32,bool);
function N(x:int32;clock h:bool) returns (y:G)#一组对象不行
let
y=(x when h,true);
tel;
全局流
全局流是可在当前上下文的任何用户操作的一个流程。这个流可以使常量(关键词:const)或者变量(关键字:sensor)。
常量
const_block ::=const{{const_decl;}}
const_decl ::=interface_status ID:type_expr [[=expr]]
每个常量申明必须用分号结束。
一个imported类型的常量申明必须给以类型:type,而不能有定义部分。一个非imported类型的常量申明必须有定义的类型和定义部分。
例子都是错误:
1.一个imported的常量不能有定义部分:
type imported t;
const c:t=2.0;
2.一个imported类型的常量不能被当做静态表达式,用type申明或者用一个数字的索引:
const imported C:int32;
type T=int32^C;
3.无效静态表达式:
const c:int32 = if true then 0 else 1;
const d:int32 =0->1;
const e:bool =true;
const f:int32= 1 when e;
传感器
sensor_block ::=sensor{{sensor_decl;}}
sensor_decl ::ID{{,ID}}:type_expr;
传感器可以是任何类型(除了type变量)但不能是组类型。传感器在用户操作中被当做时钟。
传感器时时刻刻被应用在每个节点。为了保证SCADE的语义,在传感器流中的值一定要保持不变在整个时钟周期内。
例子:
1.传感器申明:
sensor temp:float32;
node gradient() returns(diff:float32)
let
diff =0.0->temp-pre temp;
tell;
2.传感器重载:这个程序不是很好的类型
sensor s:int16;
function Main(s:bool) returns (b:int16) b=s;
用户定义操作
用户定义是面向过程语言提供最基本的句法。它们允许重用之前在Model中定义的操作。
用户定义操作:
user_op_decl ::=op_kind interface_status ID[[size_decl]]
params returns params{{where_decl}}[[spec_decl]]
op_kind ::function|node
size_decl ::=<<[[ID{{,ID}}]]>>
params ::=([[var_decls{{;var_decls}}]])
where_decl ::where TYPEVAR{{,TYPEVAR}}nemeric_kind
spec_decl ::=specialize path_id
opt_body ::=;|equation;[[singnal_block]][[local_block]]
let{{equation;}} tel[[;]]
信号是本地变量需要使用关键词sig;本地变量被介绍需要使用关键词var;
方程中的每个输入、大小、本地变量至少被使用一次。
信号至少被发射和获取一次。
一个函数不能引用通过方程操作的值,节点可以,它只能使用当前值。
例子
1.相同的变量名多次出现:
node ex1(x:int16;x:bool) returns(y:float64)...;
2.由于一个输入变量和一个变量大小冲突导致错误:
node ex2<<n>>(n:int32) returns(p:int32)...;
3. 输入变量的类型是输出变量导致冲突:
function ex3(x:'T) returns(p:int32);
4.给出的函数:
function ex4(clock h:bool;y,z:int16) returns (o1:int16;o2:bool)
let
o1=merge(h;y when h;z when not h);
o2=(y>z);
tel;
5.给出的节点:
node ex5(clock h:bool;y:int32 when h)
returns (o1:int32 when h last=0 when h)
let
activate if y>0 when h
then o1=y;
else
returns ..;
tel;
变量申明
变量可以在几处地方申明:作为输入和输出的参数在节点申明中;作为一定范围内的本地变量:
var_decls ::=var_id{{,var_id}}:type_expr[[when_decl]][[default_decl]][[last_decl]]
var_id ::=[[clock]][[probe]]ID
when_decl ::=when clock_expr
default_decl ::=default=expr
last_decl ::=last=expr
var_id的特别之处:
clock:这种类型的变量类型一般在简单的其他流中申明。它大部分在时钟和状态机中使用。
probe:工具相关的指令,确保该变量的名称将在编译过程中被保留
这些属性的顺序是相关的:clock属性在probe属性之前
申明组的识别码被作为一个表达式除了带有clock标志的识别码。这种类型的申明通常跟在一个时钟表达式when_decl之后。
例子:
1.无效变量作为时钟:
(x:bool;y:int32 when x) 修改后 (clock x:bool;y:int32 when y)
2. 无效的默认表达式:在第一次循环必须被定义:
(x:int32;y:int 32 default=pre(x))
3.时钟分析错误:
(clock h:bool;y:int default=1 when h last=0 when not h)
时钟表达式:
通过时钟表达式来定义频率。
clock_expr ::=id
|not id (id match patter)
PS:时钟表达式只能通过when操作符和第一个为activate命令操作。
例子:
1.有效的时钟表达式:
type t=enum{incr,stdby,ecr};
function Sample(clock h:bool;clock k:t;x:int32) returns(y,z:int32)
let
activate when k match
|incr :y=x+1;
|stdby :y=x;
|decr :y=x-1;
returns y;
z=merge(h;x when h;x when not h);
tel;
2.无效的时钟表达式:
clock h:bool;
var k:int32;
var x:bool when k;
var y:bool when h match Blue;
var z:bool when pre h;
申明范围:
data_def ::=equation;
|scope
scope ::=[[signal_block]][[local_block]][[eqs]]
signal_block ::=sig ID{{,ID}};
local_block ::=var{{var_decls;}};
eqs ::let {{equation;}}tel;
一个范围是一组通过let-tel关键词包围的方程,可能之前通过本地变量申明。
信号是本地变量它的申明通过特殊关键字sig。信号识别码不能被直接使用在方程内部。
它们只在申明中出现。没有信息类型被请求作为一个信号申明,一个信号通常作为一个boolen流使用。
一个信号总是能很好的定义在它第一次活动的瞬间。
本地变量通过var关键词被申明。在一些时钟申明的识别码专属于当前环境的这些时钟。
方程部分定义方程、时钟快、状态机、信号释放。每一个在范围内申明的本地变量必须准确的出现一次在方程的左边或者在时钟块或者状态机的返回状态中。
每个本地变量至少被使用一次在这些方程中。信号至少要发射和捕捉一次。
例子:
1.无效的信号识别码重载:
node ex1(x:int16) returns(y:float64)
sig x;
let
...
tel;
2.有效的信号识别码重载:
const c:int32=0;
function ex2(x:bool) returns (y:int32)
sig c;
let
...
tel;
3.无用的本地变量:
node ex3(x:int8) returns(y:int8)
var z:int8 last=0;
let
z=2*pre(x)+1;
y=x-pre(x);1
tel;
函数体
输出和本地变量在函数体必须有个精确的定义。这种定义可以是一个唯一的方程亦或者时钟控制器或机器状态的几个行为状态。
在本地函数中的申明必须被发射一次或者几次。
方程:
方程允许定义联系一个输入或着本地识别码的数据流表达式。这种表达式在每个周期都会被评估,通过输入/输出和当前/之前的值去认定识别码分配给这个识别码。
方程可以被申明为数据流或者控制流通过解决问题。
方程 ::=simple_equation
|spec_equation
|emission
|control_block return
simple_equation ::=lhs=expr
lhs ::()
|lhs_id{{,lhs_id}}
spec_equation ::=assume ID:expr
| guarantee ID:expr
control_block ::=state_machine
|clocked_block
emission ::=emit emission_body
emission_body ::=NAME[if expr]
|(NAME{{,NAME}}) [[if expr]]
return ::=returns returns_var
return_var ::={{ID,}}((ID|..))
例子:
1.aussume识别码的重载阻止之前识别码的使用:
const c:int32 =0;
node ex(x:int32;b:bool) returns(y:int32)
let
assume c:true;
y=if b then x else c->pre y;
tel;
2.因果分析错误:x 和 y定义互斥
emit 's if x;
x=if y>0 then false else true->pre(x);
activate if x
then y=1;
else y=if 's then 0 else 0->pre(y);
returns y;
条件模块:
在当前循环中,当控制流依赖一个可计算条件时,条件模块是一个方便的表达方法。
clock_block ::=active [[id]]((if_block|match_block))
if_block ::=if expr then ((data_def|if_block))
else ((data_def|if_block))
match_block ::=when expr match{{|patterm:data_def}}+
if_block分支能包含另一个if_block或者a sope 申明;match_block分支只能包含一个scope申明。
一个结果模块的任何分支可以为空。
例子:
1.条件必须是布尔型或者枚举类型。下面节点有个错误:
node ex1(x:int16) returns(y:int16)
let
activate when x match
| 0:y=0;
|_:y=1;
returns ..;
tel;
2.定义变量必须在一个分支中有个定义。在下面的例子中,o2没有定义:
node ex2(i:bool) returns(o1,o2:int64)
let
activate Act if i
then o1=1;
else o1=2;
returns o1,o2;
tel;
3.条件块是可以嵌套的。注意:最后分支的else是空的:
type Tenum=enum{red,blue,pink,purple};
node ex3(eI1:Tenum;iI2:int32) returns(i01:int32 last=0)
let
activate when eI1 match
|red:var iV1:int32;
let
iV1=10+last 'i01;
i01=iV1+iI2;
tel;
|blue:
let
activate if iI2>0
then i01=iI2*iI2;
else i01=-iI2+last'i01;
returns i01;
tel;
|pink:i01=100->pre i01 -1;
|purple:
returns i01;
tel;
4.下面的例子通过变量y说明一个错误的因果:
type T=enum{a,b,c};
node ex(x:T) returns (y:T last=b)
let
activate when y match
|a:y=a->pre(y);
|b:y=x;
|c;
returns ..;
tel
5.一个结果分支可以为空。定义的流必须有个last或者一个好的初始化default申明:
node ex(i:int32) returns(o:int32 last=0)
let
activate if i>0
then o=i;
else
returns o;
tel
数据:
i:-2 1 1 -2 2 1 -1 2 ...
o:0 1 1 1 2 1 1 2 ...
6.一个结果分支可以为空。定义的流必须有个last或者一个好的初始化default申明:
function ex(i:int32) returns(o:int32 default=4)
let
activate if i>0
then o=i;
else
returns o;
tel
数据:
i:-2 1 1 -2 2 1 -1 2 ...
o: 4 1 1 4 2 1 4 2 ...
PS:SCADE中如果出现多个语句不用{}用let..tel把语句括起来。
状态机
状态机提供关于联合控制和数据流信息在一个model更好的阐述。
state_machine ::=automaton[[ID]]{{state_decl}}
state_decl ::=[[initial]][[final]]state ID
[[unless{{transition;}}+]] data_def
[[until{{transition;}}[[synchro[[action]]fork;]]]]
transition ::=if expr arrow
arrow ::=[[actions]]fork
fork ::=target
|if expr arrow{{elsif_fork}}[[else_fork]] end
elsif_fork ::=elsif expr arrow
else_fork ::=else arrow
target ::=restart ID
|resume ID
actions ::=do{[[emit]]emission_body
{{;[[emit]]emission_body}}}
|do data_def
任何状态都被打上initial标签,不必是第一个状态。但只有一个和唯一状态必须有此标签。任何状态都能被标记final标签,甚至最初的一个。
然而,当没有synchro马上转型存在当前automaton中,这个标签是没有用的时候:
按关键字unless引入强转变的可能是空列表;
一个可能空的scope申明
按关键字until引入弱转换可能是空列表;
强和弱的转换能导致相同的状态在它们出现时候。一个状态任然可能是空的。一个synchro转换可能出现在弱转换列表中。
弱转换在函数体中的scope中的本地变量和信号申明中提及,而强转换不允许。
当一个synchro转换在当前状态发生时,出现这种状态的所有状态机必须至少有一个final属性的标签。
如果这些状态机中的一个没有一个final状态,synchro转换将不被执行。相反,如果没有状态机出现这种状态,这个synchro转换同样不被执行。
当一个无效的转换用restart指定一个目标状态时,这是这个状态被重启
1.如果这个转换是强的,这时目标状态中弱部分和the body被重启在同一个循环,然它的强部分将在下一循环重启。
2.如果这个转换是弱的,这个目标状态的所有状态将被重启在当前循环
相反,当目标状态用resume指定时,内部如果有的话,状态被保持。
例子:
1.第一个例子显示在automaton中的所有语法:强和弱机制,restart和resume,在状态和本地过度中flows的定义:
node StateMachine1(bI1:bool) returns (b01:bool default=true;
i02:int16 default=0;
b03:bool default=false)
let
automaton SM1
initial state ST1
unless if bI1 resume ST2;#强转换
sig
sig1;
var
iV1:int16;
let
iV1=10;
emit ’sig1;
b01=’sig1;
i02=iV1->pre i02 +2
tel
state ST2
sig
sig1;
var
bV1:bool;
until if true do let emit ’sig1;#弱转换
bV1=’sig1;--弱转换不能再内部进行定义
b03=bV1;
restart ST1;
returns ..;
tel
2.这个例子说明:命名规则中的一些规则允许去重载一个ID:
type
SM1=uint16;
node StateMachine2(iI1:int32) returns(i01:int32)
let
automaton SM1
initial state ST1
sig
SM1;
var
ST1:int32;
let
ST1=iI1;
emit 'SM1;
i01=ST1+(if 'SM1 then 1 else 0);
tel
returns ..;
tel
3.在下面例子里有个逻辑错误在automaton的左侧:在状态ST1中声明的变量bV2可以被用在若转换的条件中,但不能被用在它不识别的状态ST2中。
相反,在状态机ST2中的强转换能提及bV1。bV1是在状态之间共享的变量。bV1可以定义在ST1中也可以定义在ST2中。
node StateMachine31(iI1:int32) returns(i01:int32)
var bV1:bool;
let
automaton SM1
initial state ST1
var bV2:bool;
let
bV2=false->not pre bV2;
bV1=iI1<>0;
i01=iI1*2;
tel
until if bV1 and bV2 restart ST2;
state ST2
unless if bV1 resume ST1;
return ..;
tel
node StateMachine32(iI1:int32) returns(i01:int32)
var bV1:bool;
let
automaton SM1
initial state ST1
var bV2:bool;
let
bV2=false->not pre bV2;
bV1=iI1<>0;
i01=iI1*2;
tel
until if bV1 and bV2 restart ST2;
state ST2
unless if last 'bV1 resume ST1;
return ..;
tel
4.这个例子说明default申明的作用:当控制器是没有定义变量的状态机,default表达式被执行。
node StateMaChine(iI1:int16;bI2:b00l)
returns (i01:int16 default =10;i02:int16 default=5*i01)
let
automaton SM1
initial state ST1
unless if bI2 resume ST2;
let
i01=iI1;
tel
until if true restart ST2;
state ST2
let
i02=0->pre i01+iI1;
tel
until if true restart ST1;
returns ..;
tel
数据:
iI1: 1 1 1 2 0 ...
bI2:false false ture false ture
Active: S1 S2 S2 S1 S2
i01: 1 10 10 2 10
i02: 5 0 11 10 10
5.变量i01不能在ST1转换和ST2的body中被定义。在状态机中变量的定义和在转换中变量的定义必须是独有的:
node StateMachine(iI1:int32;bI2:bool)
returns (i01,i02:int32)
let
automaton
initial state ST1
unless if bI2 do i01=iI1+1; restart ST2;
until if true do i01=10; restart ST2;
state ST2
unless if bI2 do i02=0;restart ST1;
i01=0;
until if true do i02=-10;restart ST1;
returns ..;
tel
6.当进入一个automaton的状态时禁止用变量获取外部的clock,这里是iI1和i01,这时过滤操作才被执行。甚至,bI2的时钟状态丢失,本地变量iV1被锁在一个无效的时钟识别码:
node StateMachine(iI1:int32 when bI2;clock bI2:bool)
returns(i01:int32 when bI2)
let
automaton
initial state ST1
var iV1:int32 when bI2;
let
iV1=(0 when bI2)->pre iV1+1 when bI2;
i01=iI1->pre iV1;
tel
until if bI2 restart ST1;
returns i01;
tel
7.在一个状态机或者转换的scope中的变量不能再这个scope外使用。如下:在弱状态几种申明的变量bV1,变量bV1不能作为转换的条件。注意:一旦不能跳出它,state ST2将进入死循环:
node StateMachine(iI1:int16)
returns(i01:int16)
let
automaton SM1
initial state ST1
let
i01=iI1*2;
tel
until if bV1 do
var bV1:bool;
let
bV1=iI1>10;
tel
restart ST2;
state ST2;
returns ..;
tel
8.如下面的例子:由于缺乏定义和default申明,当状态ST2是激活状态,变量i02被保持。
PS:通过弱restart转换输入状态,但同时初始化即使没有做last申明这个变量。的确,一个restart转换不要求为变量做last申明通过last操作符。
它评估调用的最后一个值如常,restart转换只有->和fby操作来初始化值。
初始化可能有个错在一个强转换从ST1到ST2的案例中。的确,全局初始化被要求在初始化状态
node StateMachine(iI1:int32;bI2:bool)
returns(i01:int32;i02:int32)
let
automation
initial state ST1
let
i01=iI1;
i02=iI1*2;
tel
until if bI2 restart ST2;
state ST2
let
i01=1-> -iI1;
tel
until if true restart ST1;
returns ..;
tel
9.restart转换是异步的。当从ST1的restart转换进入ST2,这条流中的状态都要重启。当进入这个状态时,在状态ST2_2中变量z的值被编译。这个例子相反
ST2状态机中的本地变量,在restart转换后,ST2重启。这个缺乏last申明变量将导致一个初始化错误。甚至,automaton A2也被重启,所以它选中的状态是
它的初始化状态ST2_1和y的计算结果是它的最后的值,因为在该状态y没有明确定义。下一循环ST2_2被激活,y在是0,因为这将是第一次被自重新激活。
node N() returns(x,y:int32 last=0)
let
automaton A
initial state ST1
let
tel
until if true restart ST2;
state ST2
var z:int32 last=2;
let
automaton A2
initial state ST2_1
let
z=3+last'z;
x=last'x+1;
tel
until if x mod 2=0 returns ST2_2;
state ST2_2
let
x=last'z-1;
y=0->pre z -1;
tel
until if true resume ST2_2;
returns ..;
tel
until if true resume ST1;
returns ..;
tel
数据:
Active:ST1
ST2_2
ST1
ST2_1
ST1
ST2_2
ST1
ST2_1
...
x: 0
1
1
2
2 1 1 2
y: 0 0 0 0 0 4 4 4 ...
z: 2 5 5 5 ...
表达式:
表达式是Cade语言的基本块。表达式允许流的联合仅仅通过申明在一个周期内应该做什么:
expr ::= id_expr
|
atom
|
list_expr
|
tempo_expr
|
arith_expr
|
relation_expr
|
bool_expr
|
array_expr
|
struct_expr
|
mixed_constructor
|
switch_expr
|
apply_expr
表达式应该是一个有效的ID,这个ID可能代表了一个常定义操作是量流或者是变量流,atoms属于Scade中的基本数据类型变量,带有用户定义的
操作符是表达式的一个分支。
基本表达式:
ID
id_expr ::=
path_id
|
NAME
一个路径ID必须参照在同一一级目录下包中的有效ID。当ID没有通过合格的路径,它可能属于一个本地scope(input,output,local变量,除了signals ID)或者一个全局scope(constant,sensor)。
一个名字是前面带有单引号的ID。当一个last的原始ID在外部出现时,这个ID不许参照一个属于local scope的有效的信号ID。当在一个last原始ID下使用时,这个ID 必须参照任意一个input、local、signal
、output变量属于本地scope。
例子:
下面的例子说明:last和pre之间在语义中的不同:
---------------------------------------------------------------------------------------
pre的使用
---------------------------------------------------------------------------------------
node UpDownPre() returns(x:int16)
let
automaton SSM
initial state UP
let
x=0->pre(x)+1;
tel
until if(x>=3) resume Down;
state Down
let
x=2->pre(x)-1;
tel
until if(x<=-3) resume Up;
returns x;
tel
---------------------------------------------------------------------------------------
last使用
---------------------------------------------------------------------------------------
node UpDownLast() returns(x:int16)
let
automaton SSM
initial state UP
let
x=0->last'x+1;
tel
until if(x>=3) resume Down;
state Down
let
x=2->last'x-1;
tel
until if(x<=-3) resume Up;
returns x;
tel
数据:
UpDownPre()
: 0 1
2 3 2 -1 -2 -3 4 -4 5 -5 6 -6 7...
UpDownLast(): 0 1 2 3 2 -1 -2 -3 -2 -1 0 1 2 3 2...
--------------------------------------------------------------------------------------------
Atoms:
atom ::=
bool_atom
|
CHAR
|
INTERGER
|
FLOAT
|
TYPED_INTERGER
|
TYPED_FLOAT
bool_atom ::= true
| false
Atoms被唯一定义的,不能由任何变量ID重载。被单引号包围的字符是signal标志(digits,letters,usual keys)。
按照通常的Numerical atoms是一个数字序列。
布尔型的atoms通常用作true和false 。
例子:
1.十进制字符用float类型的:
function correct_incr(i:float64) returns(o:float64)
o=i+1;
2.带有float类型的十六进制字面:
function incorrect_incr(i:float64) returns(o:float64)
o=i+0x1;
3.不正确不受约束字面:
function incorrect(i:float64) returns(o:float64)
o=if 6>7 then i else 0.0;
4.不在整数范围的数字:
function incorrect_range(i:int8) returns(o:int8)
o=i+128;
List:列表
list_expr
::=(list)
list
::=[[expr{{,expr}}]]
例子:
1.结构相等不能再表达式列表中使用。下面有个错误例子:
node ex1(x,y:int64) returns(z:int64)
let
z=0->if(x,y)=(pre x,pre y)
then pre x+last'y
else 0;
tel
2.用户operators能被表达式列表很好的使用:
group G=(int64,int64,bool);
function f(a,b:int64;c:bool) returns(x,y:int64)...;
function g(a,b:int64) returns(x:int64)...;
node ex(c:bool;a,b:int64;...) returns(s,t:int64;...)
var 1:G;
let
l=(a+b,a-b,c);
s,t=if c then f(1) else (0,g(f(b,a,not c)));
...
tel
连续操作:
暂存的原始操作是连续操作:它们的语义依靠流中之前的值。确实,它们的operators不能被用在non imported常量申明的表达式的申明。
tempo_expr
::=
pre expr
| expr->expr
| fby(list;expr;list)
| expr times expr
| expr when clock_expr
| merge(expr;list{{;list}})
动态Semantics:
pre:
-----------------------------------------
a
| a1 a2 a3 a4 ...
-----------------------------------------
pre a
| nulll a1 a2 a3 a4 ...
-----------------------------------------
->:
-----------------------------------------
a
| a1 a2 a3 a4 ...
-----------------------------------------
b
| b1 b2 b3 b4 ...
-----------------------------------------
a->b
| a1 b2 b3 b4
-----------------------------------------
fby(b;n;a)=a->pre(b;n-1;a):
-----------------------------------------
fby(b;1;a)
| a1 b1 b2 b3 ...
-----------------------------------------
fby(b;2;a) | a1 a1 b1 b2 ...
-----------------------------------------
fby(b;3;a)
| a1 a1 a1 b1...
-----------------------------------------
times:if then else
(x when h)=no value if h=false|x if true:
-----------------------------------------
x
| x1 x2 x3 x4 x5
-----------------------------------------
h | F T T F T
-----------------------------------------
x when h
| x2 x3 x5
-----------------------------------------
merge:
-----------------------------------------------------------------------------
h
| T T F T F F ...
-----------------------------------------------------------------------------
a | a1 a2 a3 a4 a5 a6 ...
-----------------------------------------------------------------------------
b
| b1 b2 b3 b4 b5 b6 ...
-----------------------------------------------------------------------------
a when h
| a1 a2 a4 ...
-----------------------------------------------------------------------------
b when not h
| b3 b5 b6 ...
-----------------------------------------------------------------------------
merge(h;a when h;b when not h)| a1 a2 b3 a4 b5 b6 ...
------------------------------------------------------------------------------
组合操作:
bool_expr ::= not expr
| expr bin_bool_op expr
| #(list)
bin_bool_op ::=and | or |xor
xor:一样为假,不一样为真;
算术操作:
arith_expr ::= unary_arith_op_expr
| expr bin_arith_op expr
| (expr:type_expr)
unary_arith_op ::= - | + | lnot
bin_arith_op ::= + | - | * | / | mod | land | lor | lxor | lsl |lsr
逻辑运算符:
relation_expr ::= expr bin_relation_op expr
bin_relation_op::= = | <> | < | > | <= | >=
.=. :逻辑等:在任意类型的值之间
.<>.:逻辑不等:在任意类型的值之间
.<=.:数字间的小于等于
.<. :数字间的小于
.>=.:数字间的大于等于
.>. :数字间的大于