定义
计算变量,是对一次变量进行数学或逻辑计算,计算的结果作为变量的值。
计算变量的值根据数据类型的不同,可以是小数/整数
计算变量是采用C++的yacc和lex,结合自己代码进行实现
- lex和yacc定义了操作符和函数
- 定义在sosource\common\exprcalc\lexyacc\lex.l,定义了函数的名称
- syntex.y定义了操作数的个数,变量名称、数字、字符串的解析方法、运算规则等
- 使用GenCode.bat,生成对应的C++文件lexer.cpp,parser.cpp,parser.h,根据GenCode.bat的注释,复制到上级目录下
- 在ExprCalc.cpp中,定义了各个操作符和函数的实现方法
- 如果想要增加其他的方法,则按照此实现
计算变量表达式格式
数字和变量、字符串定义
- 数字定义
- 连续的0到9和.号组成的字符串,会解析为数字。1,2,3,4,5,6,7,8,9,0,.
- 不支持十六进制的A,B,C,D,E
- 示例:1.99,200
- 变量定义
- 由大小写英文字母、中文开头,中间可以包含数字0-9的连续字符串,被识别为变量
- 不能以数字0-9开头,否则会被识别为数字
- 如:tag1、Object1.Prop1
- 字符串定义
- 包含在两个单引号之间的内容,被识别为字符串
- 如:'abcdefg','中文'
- 特殊变量定义
- self.name,表示对象的名称。示例:self.温度,如果对象为温度计1,属性未温度,则self温度会被替换为‘温度计1’
- self,表示对象的名称,和self.name相同。
- self.param1,表示对象配置的参数1,这个可根据需要进行配置,如param1配置为"device1",以此时device.self.param1.connstatus就指代:device.device1.connstatus,以此时device.self.param1.enableconnect就指代:device.device1.enableconnect
- self.param2,表示对象配置的参数2
- self.param3,表示对象配置的参数3
- self.param4,表示对象配置的参数4
函数/操作符定义
(这些操作符和函数的字符,在lex.l中定义)
- 三角函数:sin,cos,tan,asin,acos,atan。
- 返回值为双精度小数。如果变量值质量为BAD,则返回0.0
- sin,如:sin(tag1)
- cos,如:cos(tag1)
- tan,如:tan(tag1)
- asin,如:asin(tag1)
- acos,如:acos(tag1)
- atan,如:atan(tag1)
- 绝对值函数:abs
- 函数名称 不区分大小写,建议使用小写。
- 返回值为双精度小数。如果变量值质量为BAD,则返回0.0
- 示例:abs(tag1)
- 优先级运算运算符:(,)
- 括号运算符,会先计算括号内的表达式,再作为一个整体计算之后的表达式
- 单目位算数运算:!,~
- 这几个单目算数运算,会将操作数的值先变为整数,取非后再返回double
- 按位取反运算,~
- 非运算符,!
- 指数函数:log,log10,exp
- 位运算符:&,^
- 这几个单目算数运算,会将操作数的值先变为整数,取非后再返回double
- &,AND运算
- ^,异或运算
- | 或运算
- 位移运算 >> <<
- 逻辑运算符:&&,||
- 这几个单目算数运算,会将操作数的值先变为整数,取非后再返回double
- &&,逻辑与运算
- ||,逻辑或运算
- 算数比较运算,>,<, >=, <=,!=,<>,==
- 返回1或者0
- > 大于,如:tag1>tag2
- < 小于,如:tag1<tag2
- >= 大于等于,如:tag1>10
- <= 小于等于,如:tag1<10
- != 不等于,如:tag1!=10
- <> 不等于,如:tag1!=10
- ==,等于,如:tag1==10
- 其他运算符
- %,取模运算符,tag1%16,得到余数
- fmod,返回余数,和取模运算符类似,不过这个是对小数进行操作。
- 四则运算符
- 返回double类型的值
- +,加,如:tag1+1
- -,减,如:tag1-1
- *,乘,如:tag1*3
- /,除,如:tag1/5
- 指数运算符
- exp,返回e 的x 次幂的值。如:exp(tag1),如tag1值为1,则返回2.71828
- pow,pow(tag1,5),返回tag1的值得5次幂
- ln,返回自然对数。如log(tag1),返回以e为底的自然对数
- log,返回以10为底的对数。如log10(tag1)
- sqrt,求平方根,如:sqrt(tag1)
- 统计运算符
- 统计2个或3个变量的最大值。
- 如果有质量为BAD的点,则该点不参与运算。如果所有点质量都为BAD,则返回0
- max,取两个值得最大值。如:max(tag1,tag2)
- min,取两个值得最大值。如:min(tag1,tag2)
- avg,取两个值得最大值。如:avg(tag1,tag2)
- max3,取两个值得最大值。如:max3(tag1,tag2,tag3)
- min3,取两个值得最大值。如:min3(tag1,tag2,tag3)
- avg3,取两个值得最大值。如:avg3(tag1,tag2,tag3)
- 问号冒号运算符:?:
- 格式:expr1?expr2:expr3
- expr1返回值不为0,则返回值为expr2,否则返回值为expr3
- 修改数据类型函数
- bool,数据类型改为0或1。如:bool(tag1)
- int,数据类型改为int,如:int(tag1)
- string, 数据类型改为string,如:string(tag1)
示例
- 目标:
- 红叉绿箭指示状态,其中红叉(停止)、直行(绿箭)是2个不同的点的地址,其值分别为1或0。
- 我们需要将这两个点配置为一个计算点,用1个点的值表示当前是红叉还是绿箭,而不是2个点。该点的值应有三个状态,分别为:
- 黑屏
- 红叉
- 绿箭
- 红叉且绿箭(逻辑上不应该存在的状态)
- 对象模式下配置
- 红叉绿箭类名:车道指示器
- 该类的属性
- 绿箭,BOOL类型, 值为1,0
- 红叉,BOOL类型, 值为1,0
- 红叉绿箭,int8类型,表示当前的红叉绿箭状态
- 属性地址:SELF.绿箭*2+SELF.红叉*1 . SELF表示对象本身
- 值含义:
- 0-→当前是黑屏
- 1--→当前是红叉
- 2-→当前是绿箭
- 3--->逻辑上不应该同时出现红叉和绿箭
- 对象。如车道指示器车道指示器11N
- 绿箭地址:M150.0,eview实际对象属性:车道指示器11N.绿箭,值为:1,0
- 红叉地址:M150.1,eview实际对象属性:车道指示器11N.红叉,值为:1,0
- 红叉绿箭,不需要配置对象地址,因为地址和类地址相同。
- eview实际对象属性:车道指示器11N.红叉绿箭,值的含义见上面,可能为0,1,2,3
- 设备模式下配置
- 一级变量名(直接读取自设备的变量)
- 车道指示器11N.绿箭,BOOL类型, 值为1,0,地址:M150.0
- 车道指示器11N.红叉,BOOL类型, 值为1,0,地址:M150.1
- 二级变量
- 车道指示器11N.红叉绿箭,int8类型, 地址:车道指示器11N.绿箭*2+车道指示器11N.红叉*1
- 可见,该二级变量等于2个一级变量的运算值。值含义:
- 0-→当前是黑屏
- 1--→当前是红叉
- 2-→当前是绿箭
- 3--->逻辑上不应该同时出现红叉和绿箭