定义

计算变量,是对一次变量进行数学或逻辑计算,计算的结果作为变量的值。

计算变量的值根据数据类型的不同,可以是小数/整数

计算变量是采用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','中文'

操作数的函数/操作符定义

(这些操作符和函数的字符,在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
    •  按位取反运算,~
      • 示例:~tag1
    • 非运算符,!
      • 示例:!tag1
  • 指数函数:log,log10,exp
  • 位运算符:&,^
    • 这几个单目算数运算,会将操作数的值先变为整数,取非后再返回double
    •  &,AND运算
      • tag1&tag2
    • ^,异或运算
      • 示例:tag1^tag2
    • | 或运算
      • 示例:tag1|tag2
  • 位移运算 >> <<
    • >>,右移运算
      • 如: tag1>>3
    • <<,左移运算
      • 如:tag1 << 3
  •  逻辑运算符:&&,||
    • 这几个单目算数运算,会将操作数的值先变为整数,取非后再返回double
    •  &&,逻辑与运算
      • tag1&&tag2
    • ||,逻辑或运算
      • 示例:tag1||tag2
  • 算数比较运算,>,<, >=, <=,!=,<>,==
    • 返回1或者0
    • > 大于,如:tag1>tag2
    • < 小于,如:tag1<tag2
    • >= 大于等于,如:tag1>10
    • <= 小于等于,如:tag1<10
    • != 不等于,如:tag1!=10
    • <> 不等于,如:tag1!=10
    • ==,等于,如:tag1==10
  • 其他运算符
    • %,取模运算符,tag1%16,得到余数
    • fmod,返回余数,和取模运算符类似,不过这个是对小数进行操作。
      • 如fmod(tag1,2.5)
  • 四则运算符
    • 返回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)


示例

  1. 目标:
    1. 红叉绿箭指示状态,其中红叉(停止)、直行(绿箭)是2个不同的点的地址,其值分别为1或0。
    2. 我们需要将这两个点配置为一个计算点,用1个点的值表示当前是红叉还是绿箭,而不是2个点。该点的值应有三个状态,分别为:
      1. 黑屏
      2. 红叉
      3. 绿箭
      4. 红叉且绿箭(逻辑上不应该存在的状态)
  2.  对象模式下配置
    1. 红叉绿箭类名:车道指示器
    2. 该类的属性 
      1. 绿箭,BOOL类型, 值为1,0
      2. 红叉,BOOL类型, 值为1,0
      3. 红叉绿箭,int8类型,表示当前的红叉绿箭状态
        1. 属性地址:SELF.绿箭*2+SELF.红叉*1      . SELF表示对象本身
        2. 值含义:
          1. 0-→当前是黑屏
          2. 1--→当前是红叉
          3. 2-→当前是绿箭
          4. 3--->逻辑上不应该同时出现红叉和绿箭
    3. 对象。如车道指示器车道指示器11N
      1. 绿箭地址:M150.0,eview实际对象属性:车道指示器11N.绿箭,值为:1,0
      2. 红叉地址:M150.1,eview实际对象属性:车道指示器11N.红叉,值为:1,0
      3. 红叉绿箭,不需要配置对象地址,因为地址和类地址相同。
      4. eview实际对象属性:车道指示器11N.红叉绿箭,值的含义见上面,可能为0,1,2,3
  3. 设备模式下配置
    1. 一级变量名(直接读取自设备的变量)
      1. 车道指示器11N.绿箭,BOOL类型, 值为1,0,地址:M150.0
      2. 车道指示器11N.红叉,BOOL类型, 值为1,0,地址:M150.1
    2. 二级变量
      1. 车道指示器11N.红叉绿箭,int8类型, 地址:车道指示器11N.绿箭*2+车道指示器11N.红叉*1
      2. 可见,该二级变量等于2个一级变量的运算值。值含义:
        1. 0-→当前是黑屏
        2. 1--→当前是红叉
        3. 2-→当前是绿箭
        4. 3--->逻辑上不应该同时出现红叉和绿箭


  • 无标签