原文 https://www.vtscada.com/help/Content/Scripting/API/p_StyleGuide.htm
Trihedral的开发人员使用这份样式指南来创建一致的、易读的VTScada代码。如果您遵守本指南中的建议,其他人将更容易阅读您的代码,您也更容易阅读其他人的代码。

Notation标记含义:

$ 表示您必须遵守此规则
表示您应该遵守此规则,但是又一些余地
$ 表示这是一个准则

1. Comments注释

1.1. $$$
在VTScada文件的开始处,添加每行80个字符、多行的注释,用以描述模块的用途。第一行注释应该包含模块名称和隶属模块层级名称,位于等号行中间:

  1. {============================== MyService.MyModule ============================}
  2. { Description of module }
  3. {==============================================================================}
等号的数量将根据填满80个字符的要求进行改变(右花括号应该在第80列)。注释的最后一行应该在花括号中全部用等号,来标记注释的结束。<br />    注意很多现有的代码在第一行的模块名称中间使用\号。但我们正在采用.分隔号(本地作用域),来和预期的默认的作用域操作符.号保持一致。在这里混合风格会降低可读性。<br />_备注:_<br />_VTScada文件开头必须有注释;_<br />_每行80个字符;_<br />_可以有多行;_<br />_第一行内容是模块名称、.号、隶属模块名称,放在=号中间;_<br />_最后一行内容是=号。_

1.2. $$
用于描述语句动作等的整行注释(独立一行)应该在左花括号前后各有一个空格,在右花括号之前有一个空格:

 { This is a comment } 
X = 1;

1.3. $
如果您正在编辑使用一个不同注释风格的已有模块(例如,5个星号风格),为了保持一致性,可以继续使用这个风格。如果这个风格的示例不多或样式已有混合,您可以考虑修改这个已有风格,
1.4.
注释通常以大写字母开头,但是,单个或几个单词的注释可以用大写或者不用,视情况而定。
1.5.
多行注释应该使用一组花括号。 文本应左对齐。

 { This comment has multiple lines
   and should be left aligned }

1.6. $$
所有变量和参数注释应从同一列开始(最好是第31列)并在同一列结束(最好是第79列,分号在第80列)。

  System        { Provides access to system library functions                 };
  Layer         { Provides access to the application layer                    };

1.7. $$$
任何为了测试或其他临时目的而插入的代码都必须有一个包含两个连续问号的注释{ ?? },以便在代码发布之前快速定位。
1.8. $
出现在多行上的多个行内注释应该对齐,特别是模块调用中的参数注释。 最好填充空格让右花括号也对齐。

IfThen(X == Y { First two are equal       } ||
       X == Z { First and last are equal  } ||
       Y == Z { Last two are equal        },
  ...
);

2. Variables 变量和Parameters参数

2.1. $$$
在紧跟模块名称(或模块注释)的行的最左列,以左圆括号开始参数。

<
{============================== MyService.MyModule ============================}
{ 1. This is a sample module                                                   }
{==============================================================================}
MyModule
(
  { 2. Parameter section: }
)

2.2. $$$
将所有变量和参数定义缩进两个空格(除非出现在class-block类块中,在这种情况下需要额外缩进)。

(
  System        { Provides access to system library functions                 };
  Layer         { Provides access to the application layer                    };
)

2.3. $
所有变量和参数都必须有注释。
2.4. $
对变量和参数使用描述性名称(见名知意)
2.5. $
变量和参数名称必须以大写字母开头。例外是作为指针的变量或参数,例如 pResult。
2.6. $
把分号放在变量或参数声明的行内注释后边。这些与变量声明的注释有关,将在源码调试器中进行正确的高亮区段显示。
2.7. $$
在设定默认初始值时,尽可能对齐所有=号。

[
  AxisXColor          = "<FF6E7079>"  { X Axis Color                          };
  AxisXScaleLineColor = "<FF6E7079>"  { X Axis scale line color               };
]

2.8. $
可以在不同用途的变量组之间放置空行。用一个注释表示变量组的用途也很有用。
2.9. $
在参数的结尾和变量的开头之间放置空行是不必要的,当然也可以放置空行。

...
)
[
...

2.10. $
根据需要,常量可以用全大写名称来声明。
2.11. $
用作记录的数组中用于索引的常量应以 # 字符开头。
2.12. $
关键字 CONSTANT、PROTECTED、RETAINED、SHARED、MODULE 和 STRUCT 应该是大写的,尽管大小写混合或小写是可以接受的。 在模块中的所有变量声明中,大小写应该是一致的。 由于 Module模块 和 Struct结构 在代码中的表现不同,因此可以接受为这些关键字采用不同但一致的样式。
2.13. $$$
Structure结构定义必须将其字段名称缩进两个空格,并每个字段都有注释。
2.14. $
在一个全是PROTECTED受保护变量的模块中,如果有一些变量必须公开访问,您可能希望在其前面放置“{PUBLIC}”的注释,以便未来的编码人员知道这是准备公开访问的。

3. Modules模块

3.1. $
对于模块声明,尽可能把所有“Module模块”关键字在同一列中对齐。
3.2. $
带有文件名的模块声明应该在同一列中对齐文件名。
3.3. $
如果子模块超过 500 行代码,请考虑将其移动到单独的文件中。 尽可能避免使用小文件。 一边是过于冗长且难以浏览的源文件,一边是不打开几十个小文件就难以跟踪代码,应该在这之间取得一个好的平衡。
3.4. $$$
模块开头的 < 必须跟随一个注释块,来描述这个模块,请参阅“注释”章节。

<
{============================== MyService.MyModule ============================}
{ 1. This is a sample module                                                   }
{==============================================================================}

3.5. $
一个模块的结束 > 和另一个模块的开始 < 必须用空行分隔。
3.6. $
一个模块的结束尖括号必须有一个前缀注释,来表明模块结束。在结束方括号]开始花括号{之间可以有一个空行。

...
]

{ End of MyService.MyModule }
>

4. States状态

4.1. $$$
状态声明的前边必须有一个空行,但后边不能有空行。

...
]

NextState [
  If X Done;
]

4.2. $
状态名声明不能缩进。
4.3. $
状态名必须以大写字母开头。
4.4. $$$
开始状态声明的方括号必须与状态名在同一行,与状态名间隔一个空格。

5. Statements语句

5.1. $
状态中的语句必须缩进两个空格。 当您按下 TAB 键时,您的编辑器应配置为使用两个空格而不是一个制表符。
5.2. $
带有附加脚本块的“If”语句(断言条件)中,开始方括号[以及结束方括号]都要有和“If”语句一样的缩进。

{ An example of poorly written code }
HeaterOn 
[ { Begin state HeaterOn }
  If level > 40 { Monitor the level }; 
  [ { Begin script } 
    highLevel++; 
    highAlm = highLevel > 10 { Sound high level alarm }; 
  ] { End script } 
] { End state heaterOn }

5.3. $
“If”这个词必须这样大小写混合。
5.4. $
脚本块的语句应该再多缩进两个空格。嵌套在它们中语句应该持续使用这种方式,一次增加两个空格的缩进。
5.5. $
在function函数或module模块调用的左圆括号两侧,不要使用空格。如果有必要,这几个例外情况允许空格,IfElse (、IfThen (、WhileLoop ( 和 DoLoop (.
5.6. $
所有逗号后面必须跟一个空格,除非逗号出现在行尾(例如在IfThen/IfElse的条件中)。
5.7.
多个=号语句列到一起时,尽可能的将=号对齐到同一列。这在几个相关的赋值语句引用相同数组或相同结构时特别有用。它帮助强调这些代码行的相似性和差异。
5.8. $
结束语句的分号应该紧跟代码行内容,不要任何前缀空格和尾随空格。
5.9.
您的编辑器应该配置为在保存文件时自动修剪尾随空格。
5.10. $
例如 IfThen 和 IfElse 等functions函数的参数,应被视为独立语句,遵循那些缩进与逗号使用的相同规则。
5.11. $$$
一行最多只能有一个语句。
5.12. $
长赋值语句应该在大约第80列的地方换到下一行。每行应该从第一个赋值语句相同的列开始。未终止的行应该以一个操作符结束。跨越多行的语句对齐不能随意,而是要有助于代码的可读性,如本例所示。

X = Parm1 + Parm2 + Parm3 +
    Parm4 + Parm5;

5.13. $$
在使用需要坐标值的UI控件时,使用全局常量EditHt、DropHt、BtnWd 等,而不是硬编码坐标值。

6. Operators操作符

6.1. $
在= == != += -= = /= %= && & || | ^ @ < > <= >= ? : >> 和 <<(其中 & 是按位与)这些操作符的左右放一个空格。
6.2. $
不要 [ ] ++ 和 — 操作符的左右放空格。
*6.3. $$$

当使用 ++ 或 — 并且没有功能性区别时,它们应该放在变量之后,而不是之前。

I++;

6.4.
+ - / 和 % 运算符的前后最好有空格,但是在不影响清晰度的情况下可以省略。这些在复杂语句中很有帮助,但是在简单语句中会占用不必要的空间。
6.5. $
前缀操作符 ! & 和
后面不能有空格。
6.6. $
作用域操作符 \ 和 . 绝不能在它们和变量之间有空格。
6.7.
始终使用本地作用域操作符.,除非你有意将这个范围设为全局\。

MyTag.Name

6.8.
不建议使用操作符 <> 和 >< 。应该使用 != 来替代。
6.9.
不建议使用操作符 ~ 。应该使用 ! 来替代。
6.10. $$
不建议使用操作符 => 和 =<。应该使用 >= 和 <= 来替代。

7. Function calls函数调用

7.1. $
所有函数调用都以大写字母开头。
7.2. $
带有长参数或条件列表的函数可以在大约第80列的地方换到下一行。参数应该在同一列开始。在那一列换行,应该有一个平衡。跨越多行的语句有时很难阅读,然而语句不换行超出文本编辑器的可视区域也是一个问题。如果仅仅是一个小部分拆分到下一行,那么尽量将这个语句放到一行上。

MyModule(Parm1, Parm2, Parm3,
         Parm4, Parm5);

7.3. $
除了条件(如果它们有),WhileLoop、DoLoop、IfThen、IfElse、CriticalSection、Execute 和 Case 必须用分号结束所有的内部语句,而不是逗号,即使技术它们是参数。
7.4.
函数 WhileLoop、DoLoop、IfThen、IfElse、CriticalSection、Execute 和 Case不需要类似{ End WhileLoop }的结束注释,除非是在非常复杂或者特别长的情况下。现代编辑器和适当的缩进很容易让您识别这些语句的结尾。
7.5. WhileLoop & IfThen
7.5.1. $
将条件与 WhileLoop/IfThen 放在同一行。
7.5.2. $
将所有内部语句相对 WhileLoop/IfThen 缩进两个空格。
7.5.3. $$$
在单独行上用 ) 终止这个语句,将其与WhileLoop/IfThen对齐到同一列。

WhileLoop(I < N,
  ...
  I++;
);

7.6. DoLoop
7.6.1. $
在第一行开始DoLoop语句,不要带参数。
7.6.2. $
将循环的内部语句相对DoLoop缩进两个空格。
7.6.3. $$
在与DoLoop相同的列位置,用注释{ While }来结束循环,在下一行缩进两个空格跟随条件,然后下一行跟随);与DoLoop对齐到相同列。然而,把条件和{ While }放在同一行也是可以接受的。

DoLoop(
  ...
{ While } 
  !Valid(X);
);

7.7. IfElse
7.7.1. $
将条件与 IfElse 放在同一行。
7.7.2. $
如果TRUE情况需要Execute执行,Execute执行也放到第一行,它的左圆括号紧随其后(没有空格),它的右圆括号独立一行和IfElse在同一列对齐。这避免了条件主体不必要的缩进,并且使 IfElse 和 IfThen 语句在结构上非常相似。在结构中,它们所有语句都相对条件缩进两个空格并且块的结束使用与块的开头对齐。
7.7.3. $$$
FALSE 情况应该以{ Else }注释开头,与IfElse在同一列对齐。如果它需要一个Execute执行体,需要遵循之前描述的准则,除了Execute执行体和IfElse的右圆括号一起放到最后一行并且不要空格。
7.7.4. $
IfThen 可以用在 Execute执行体的位置。
7.7.5. $$
多层嵌套的 IfElse 语句,如果它们表示多层互斥选择,就都应该从相同的列位置开始。避免额外的缩进将有助于可读性。

IfElse(X,
  Y = 1;
{ Else }
  Y = 2;
);

IfElse(X == 0, Execute(
  ...
);
IfElse(X < 10, Execute(
);
{ Else } Execute(
  ...
)));

7.8. Case
7.8.1. $
将条件和 Case 放到同一行。
7.8.2.
用注释标识每个内部语句的整数值。注释应该相对Case缩进两个空格。
7.8.3.
简单的Case语句应该和它们的注释在同一行。而使用Execute执行体的Case复杂语句应该单独一行,并且缩进两个空格开始注释。
7.8.4. $
右圆括号应该独立一行,并Case在相同列对齐。

    X = Case(FirstVar,
          { 0 } A;
          { 1 } B + C;
          { 2 } 2*A + B/2 + Min(C, D%5);
        );      

    Case(SecondVar,
      { 0 - This} 
        DoThis();
      { 1 - This & That } Execute(
        DoThis();
        DoThat();
      );
      { 2 - The other thing } 
        Other();
    );

7.9. $$
所有函数调用不管是否需要参数,都应该有一对圆括号。这使得区分函数和变量更容易。例外是Invalid, Self, TRUE 和 FALSE,它们不需要圆括号。
7.10. $
如果模块不需要返回值,或者有一个valid返回值,Return()优先于Return(Invalid)使用。
7.11. $$
当 True(X) 和 False(X) 与参数一起使用时,它们需要圆括号,并且应该只有首字母大写。如果它们作为常量使用,它们应该所有字母大写不带圆括号:TRUE 和 FALSE。