protel语法和语义
1)注释 – comments
注释是以%开头的,跟随其后面的内容都是注释。例如
% this is a comment
5 -> X; % Comment can appear on the same line as code.
注意:它不支持块注释
2)标识符 – identifiers
标识符以字母或特殊字符开头:a-z,A-Z,$,_。剩下部分可以使字母,数字或特殊字符:a-z,A-Z,0-9,$,_。它不区分大小写,除了字符串内容。(注意,实际上有效的标识符中的特殊字符就只有两种:$,_)
3)数字 – numbers
可用十进制或十六进制标识整数。十六进制的前缀是’#’。负数前缀是’-‘,且不可与十六进制联合使用。标准PROTEL中不存在浮点数。
4)字符串 – character strings
字符串是被单引号所括起来的字符序列,例如:
‘Dog’
‘#@09asn’
‘You can’’ make me!’
在PROTEL中,字符串不是原始类型。实际上等价于该字符串中每个字符所对应的ASCII数值。例如,’dog’等价于{100,111,103}。单个字符也同样,’A’ = #41。
5)数值范围 – numeric range
最基本的数据类型是数值范围。PROTEL中的原子数据类型,包括CHAR,DIGIT和INT都是源自于该基本类型。数值范围表示形式如下:{m TO n},m和n都是整型且m<=n。PROTEL分配这些变量且采用字对齐方式。
例如,CHAR采用如下方式定义,它被不同于正常的整数所解释,需要8bits(1 byte):
{0 TO 255} % 00000000 to 11111111 in binary
DIGIT 需要4 bits(1 nibble):
{0 TO15} % 0000 to1111 binary
INT需要16 bits(2 bytes, 或1 word):
{-32768 TO 32767} % 1000000000000000 to 111111111111111
% 0000000000000000 to 0111111111111111
6)符号范围 – symbolic range
实际上等价于C中的枚举类型,例如:
{morning,noon,afternoon,evening,midnight,night}等价于{0 TO 5}
预定义的符号范围是BOOL,{false,true}
7)简单变量 – simple variables
变量的声明采用关键字’DCL’,语法如下:
DCL varuable_name variable_type;
例如:
DCL my_integer INT; %my_integer is an integer {-32768 to 32767}
DCL my_digit DIGIT; %my_digit is a digit {0 to 15}
DCL my_number {0 TO 80}; %my_number is a numric range, variable requiring 7 bits
注意:PROTEL很少有native类型。INT和DIGIT也不是该类型。native类型包括bool,$int,$uint,$universal_ptr和很少的其他。
8)常量和初始化变量 – constants & initializing variables
常量声明类似于变量,但有一个额外关键字’IS’和一个常量值;而初始化变量是采用关键字’INIT’来代替’IS’。
例如,常量:
DCL my_int_const INT IS 9; %declare constant with value 9
DCL always_false BOOL IS false; %declare constant with value false
% 5 -> my_int_const; %illegal,my_int_const is a constant
初始化变量:
DCL my_int_var INT INIT 9; %declares variable initialized to 9
5 -> my_int_var; %legal,the value of my_int_var can be changed.
9)用户自定义类型 – user-defined types
用户自定义类型是采用关键字’TYPE’,语法如下:
TYPE type_name type_definition;
例如,INT,DIGIT,CHAR和BYTE的定义如下:
DCL minint {-32768 TO -32768} IS -32768;
DCL maxint {32767 TO 32767} IS 32767;
TYPE INT {minint TO maxint}
TYPE DIGIT {0 TO 15};
TYPE CHAR {0 To 255};
TYPE BYTE {0 TO 255};
从而可以采用上述类型来声明变量:
DCL my_1st_int INT;
10)赋值 – assignment
采用向后赋值方式,即从左往右,语法如下(->是赋值符号):
value -> variable; % 6 -> my_integer;
赋值操作返回左侧的值,故下面操作是合法的:
6 -> my_integer -> my_other_integer;
11)数学运算符
PROTEL没有传统的优先级计算规则(即没有乘除比加减优先),它的计算方式是从左往右,唯一的优先级规则就是一元操作高于二元操作[如负号]。如果要改变正常顺序,则只有使用圆括号。有+,-,*,/和MOD(求模)
例如:
DCL x INT;
6 + 7 -> x; % x = 13
5 + 2 * 3 -> x; % x = 21, NOT 11!
12 / 3 -> x; % x = 4
5 / 3 -> x; % x = 1
5 MOD 3 -> x; % x = 2
12)逻辑操作符 – logical operators
类似于算术操作符,计算也是从左到右,一元高于二元;没有传统的优先级,需要时则加上圆括号来提升优先级:
^ not 非
= equal 等于
& and 与
^= not equal 不等于
| or 或
< less than 小于
! xor 异或
> greater than 大于
<= less than or equal 小于或等于
>= greater than or equal 大于或等于
例如:
DCL b BOOL;
6 = 7 -> b; % b = false
^(5 = 2) -> b; % b = true
5 < 2 & true = false -> b; % b = true! A<B&C=D is treated like
% ((A<B)&C)=D, not (A<B)&(C=D)
true & (16 < 19) -> b; % b = true
(4*3) = (2*6) -> b; % b = true
12 >= 13 -> b; % b = false
13)比特移位操作符 – bit shift operators
移位操作运算符,规则如下:
<< bit shift to the left
>> bit shift to the right
例如:
DCL x {0 TO 15} INIT 3; % x = 0011 (x is a 4 bit variable)
x << 1 -> x; % x = 0110 = 6 (this is a one way to multiply by 2)
x << 2 -> x; % x = 1000 = 8 (a bit was lost in the overflow)
x >> 1 -> x; % x = 0100 = 4 (this is one way to integer divide by 2)
x >> 3 -> x; % x = 0000 = 0 (a bit was lost in the underflow)
14)STRUCT
关键字’STRUCT’用来定义结构体,类似于C中的关键字’struct’。语法如下:
TYPE struct_name
STRUCT
variable_name variable_type,
variable_name variable_type,
%......
variable_name variable_type %注意,没有逗号
ENDSTRUCT;
例如,定义一个笛卡尔坐标系,坐标类型如下:
TYPE coordinate_type % notice the 'TYPE' keyword
STRUCT % beginning of the structure definition
x INT, % notice the comma
y INT % no comma for the final field
ENDSTRUCT; % notice the semicolon
然后声明该类型的一个变量:
DCL current_coordinate coordinate_type;
可以通过句号’.’来访好结构体成员:
9 -> current_coordinate.x; % notice that current_coordinate
20 -> current_coordinate.y; % is a VARIABLE
也可以通过使用中括号和逗号来初始化该结构变量的成员值:
{9, 20} -> current_coordinate;
DCL constant_coordinate coordinate_type IS {9, 20};
DCL initialized_coordinate coordinate_type INIT {9, 20};
一个STRUCT是字对齐的,这就意味着结构体的成员将被比特对齐来适应到一个或多个字中去(1 word = 2 bytes = 4 nibbles = 16 bits)。因为这个原因,则在结构体中可能有“废弃的空间”。
注意:PLS程序”lister”可以用来检查结构体的内存布局。
TYPE branches {marketing,research,development};
TYPE regional_office
STRUCT
region_id {0 to 30}, % 5 bits
office_id {0 to 50}, % 6 bits
building_id CHAR, % 8 bits
branch branches, % 2 bits
number_of_employees {0 to 255} % 8 bits
ENDSTRUCT;
则regional_office结构体在内存中的布局如下(灰色为浪费的空间)
然而可以通过重新安排结构体来减少空间的浪费:
TYPE branches {marketing,research,development};
TYPE regional_office
STRUCT
building_id CHAR, % 8 bits
number_of_employees {0 to 255}, % 8 bits
region_id {0 to 30}, % 5 bits
office_id {0 to 50}, % 6 bits
branch branches, % 2 bits
ENDSTRUCT;
15)PACK
关键字’PACK’可以被用来为特殊变量,类型或范围指定可使用的bit范围。’PACK’不会压缩类型空间,仅仅扩展它。’PACK’可被用来强迫对齐,如在byte[‘PACK(8)’]或字[‘PACK(16)’]边界上对齐,或为将来的扩展保留空间。
type nibble {0 TO 15}; % nibble is 4 bits wide
type nibble PACK(4) {0 TO 15}; % nibble is 4 bits wide
% (PACK doesn't do anything)
type big_nibble PACK(6) {0 TO 15}; % big_nibble is 6 bits wide
type my_bool PACK(16) {true,false}; % my_bool is 16 bits wide
16)表 – TABLE
‘TABLE’用来创建数组或List。语法如下:
TABLE [lower_bount TO upper_bound] OF element_type;
低位都是从0开始的。
如创建含有5个整数的数组:
DCL my_table TABLE [0 To 4] OF INT; %this is a table of 5 INT’s
创建结构体的数组:
TYPE coordinate % define coordinate
STRUCT % data type
x int,
y int
ENDSTRUCT;
DCL my_coords TABLE [0 TO 4] OF coordinate; % create table of coordinates
访问某个元素的时候需要带上下标[],如
256 -> my_table[3]; % 4th element of my_table = 256
4 -> my_coords[2].x; % x coordinate of the 3rd element = 4
5 -> my_coords[2].y; % y coordinate of the 3rd element = 5
{2,3} -> my_coords[1]; % x,y coordinates of the 2nd element = 2,3
初始化所有元素:
{0, 2, 4, 5, 1} -> my_table; % dropping the []'s refers to the whole table
{{0,0},{1,2},{3,3},{4,1},{9,21}} -> my_coords;
如何创建多维数组:
DCL my_2D_array TABLE [0 to 20] of TABLE [0 to 20] OF INT;
4 -> my_2D_array[2][5]; % legal assignment
17)DESC
‘DESC’是指针,像使用TABLE一样使用。内在地,一个DESC包含一个指向某个表元素的指针和一个说明了元素个数的数值(即该表的大小)。外在形式上,它非常像一个通用表,只是数组的边界可动态设定。需要注意的是,只是为指针和数值分配内存,而没有为即将要指向的表分配内存。
语法如下:
DESC [optional_bounds] OF element_type;
注意:范围很少被指定的,如果给定了边界,则最低位应该为0。
DCL my_list DESC OF INT; % initially this points to nothing (NIL)
% no memory has be allocated for a table at this point
一个DESC可能有NIL值,这意味着没有分配表或者指向表。除非很清楚指定边界,否则DESC的下界总是0,上界则是元素个数-1。
举例如下:
TYPE string_type DESC of CHAR;
TYPE char_table TABLE [0 to 5] of CHAR;
DCL my_string string_type;
DCL my_char_tab char_table;
'carol' -> my_string; %% my_string = 'carol';
'n' -> my_string[2]; %% my_string = 'canol';
'a' -> my_string[3]; %% my_string = 'canal';
'PROTEL' -> my_char_table; %% my_char_table = 'PROTEL';
DESC my_char_tab -> my_string; %% my_string = 'PROTEL';
'r' -> my_string[1]; %% my_string = 'PrOTEL';
%% my_char_table = 'PrOTEL';
DESC my_char_tab[0 to 2] -> my_string; %% my_string = 'PrO';
'o' -> my_string[2]; %% my_string = 'Pro';
%% my_char_table = 'ProTEL';
[]被用来访问DESC的成员。DESC有两种用法:作为类型和作为操作符。作为操作符的时候,DESC返回一个指向一片table的descriptor(指针)。因为descriptor像一个指针,所以对DESC内容的操作会影响到被其指向的表。
18)表和DESC的赋值
考虑如下例子:
TYPE string_type DESC of CHAR;
TYPE char_table TABLE [0 to 5] of CHAR;
DCL my_table1, my_table2 char_table;
DCL my_desc1, my_desc2 string_type;
'abcde' -> my_table1;
my_table1[] -> my_table2[]; % case 1
my_table1 -> my_table2; % case 2
DESC my_table1 -> my_desc1;
DESC my_table2 -> my_desc2;
my_desc1[] -> my_desc2[]; % case 3
my_desc1 -> my_desc2; % case 4
case1和case2实现的都是相同的事情,两者都是把第一个表的内容写到第二个表中去(此时两个表都含有’abcde’)。case3和case4则不同,case3和前面case一样,因为第一个指针指向的表的内容被写进到第二个指针所指向的表中去(my_desc1指向my_table1,它的内容为 'abcde'.因此,'abcde'被写进my_desc2所指向的表,所以my_table2包含内容为'abcde'.)。对于case4,第二个指针指向了正被第一个指针所指向的表,因此,my_desc1和my_desc2都指向了my_table1。对于case3,对my_desc2内容的修改会影响到my_table2;对于case4,
对my_desc2内容的修改会影响到my_table1(当然也会影响到my_desc1)
19)UPB,TDSIZE
UPB用来获取TABLE或DESC的上界;
TDSIZE用来获取TABLE或DESC的元素个数
20)PTR
关键字’PTR’定义了指针。可以定义一个指向任何数据类型或变量的指针。必须使用’@’来解除指针参照(实际上就是取得指针所指向内存中包含的值)。指针包含了绝对内存地址。值为’NIL’的指针表示其未指向任何内存。’PTR’可被用于获取某个变量的绝对地址。
TYPE int_pointer PTR TO INT; % int_pointer is a pointer to INT
DCL x_pointer int_pointer;
DCL x,y INT;
5 -> x;
PTR x -> x_pointer; % assigns the address of x to x_pointer
x_pointer@ -> y; % assigns value pointed to by x_pointer to y, so y = 5
21)OVLY
‘OVLY’用于覆盖数据(实际上类似于C中的联合结构union)。被覆盖的两个或多个数据片是那些在内存中占用相同空间的数据片。覆盖仅存在于struct或area中。它可用来节省内存空间,前提是不同的数据片不可以同时存在。例如:
TYPE being_type PACK(4) {god,mortal};
TYPE credit_card
STRUCT
name TABLE [0 TO 3] of char,
OVLY being_type
{god}:
god_limit {0 TO 255}
{mortal}:
mortal_limit {0 TO 64000}
ENDOVLY,
being_status being_type
ENDSTRUCT;
为该结构的实例分配内存,DCL someones_credit_card credit_card;
注意:OVLY说明了一片内存可以用不同方式进行解释的原因。与把某种数据结构转换成另外一种结构类似。设置’mortal_limit’的值为255则会导致’god_limit’域的值也为255。相反,把255赋给’god_limit’,则’mortal_limit’有一半空间为空。
另外一个需要注意的是,在该例子中,OVLY类型并未阻止对覆盖的特殊部分进行访问。例如,有个类型为’being_type’的域’being_status’,类似于”tag field”,来决定覆盖的哪一部分被使用了。
21)AREA
‘AREA’被用来创建PROTEL area数据结构。它用来创建带有可扩展空间的数据结构,以及创建新的area数据结构,叫做 AREA refinements,继承了’father’ area数据结构的性质;类似于C++中类的继承????
为area分配的内存总数是在初始化声明的时候被设置的,以bit为单位。
关键字UNRESTRICTED意味着该area可能在它被声明的模块之外被refined。
参见例子:
TYPE father_area UNRESTRICTED AREA (32) % allocate 32 bits
father_id byte % for this area
ENDAREA;
TYPE son_area UNRESTRICTED AREA REFINES father_area
son_id byte
ENDAREA;
TYPE grandson_area AREA REFINES son_area
grandson_id byte
ENDAREA;
TYPE granddaughter_area AREA REFINES son_area
granddaughter_id byte
ENDAREA;
各个类型的内存布局如下:
22)SET
‘SET’用来创建逻辑上的set,这些set是基于某些集合的语义范围的。最大有16个元素。
23)BIND
‘BIND’用来为变量创建本地标识符,用于
重命名变量
加快那些经常不得不被解除参照的变量的处理
例如,假定基于某些复杂的数据类型创建了一个表:
DCL my_table TABLE [0 TO 9] of globitty_goop;
BIND often_used_var TO my_table[0].subitem.subsubitem;
% often_used_var now points to my_table[0].subitem.subsubitem
% Use often_used_var as much as you want without having to
% dereference it everytime you use it. Direct access!!
24)BIND…AS
‘AS’关键字被用在带有BIND的联合体中来访问AREA refinement。
25)CAST
‘CAST’被用来动态更改变量的类型。例如:
TYPE days {mon,tues,wed,thurs,fri,sat,sun};
DCL today days;
DCL day_number int;
mon -> today; % today = mon
CAST today as int -> day_number; % day_number = 0
26)IF
逻辑’IF…THEN…’语句的语法如下:
IF logical_condition
THEN
true_body;
ENDIF;
IF logical_condition
THEN
true_body;
ELSE
false_body;
ENDIF;
IF logical_condition1
THEN
true_body1;
ELSEIF logical_condition2 %% ELSEIF is not supported by old compiler.
THEN
true_body2;
ENDIF;
IF logical_condition1
THEN
true_body1;
ELSEIF logical_condition2
THEN
true_body2;
ELSE
false_body;
ENDIF;
27)CASE
‘CASE’用来创建一个case语句块,类似于C的’switch’语句;但不需要’break’。
例如:
DCL x DIGIT;
CASE x IN
{0}:
begin$('x is zero');
end$();
{1,2,3,4,5,6,7,8,9,10}:
begin$('x is between 1 and 10');
end$();
OUT
begin$('x is out of range');
end$();
ENDCASE;
28)SELECT
‘SELECT’类似于CASE,只是更慢,使用更少内存。
DCL x DIGIT;
SELECT x IN
{0}:
begin$('x is zero');
end$();
{1000000}:
begin$('x is 1000000');
end$();
OUT
begin$('x is not what we want');
end$();
ENDSELECT;
注意:当范围非常大的时候使用SELECT。否则,CASE通常是更好的选择。
29)DO
‘DO’通常用于FOR和WHILE循环结构中。它可以创建无限循环。
例如:
DO
% Statements here will execute over and over and over and ...
ENDDO;
FROM 10 DOWN TO 0
DO
% Statements here will execute 11 times.
ENDDO;
FROM 0 UP TO 10
DO
%% Statements here will execute 11 times.
ENDDO;
TYPE days_of_week {Sunday, Monday, Tuesday, Wednesday,Thursday, Friday, Saturday};
OVER days_of_week
DO
%% Statements here will execute 7 times.
ENDDO;
30)FOR
‘FOR’循环是通过增加关键字’FOR’和一个循环计数变量来完成的。可通过BY增加该循环计数UP TO或DOWN TO到某个值。”DOWN TO”循环效率比较好。
FOR i FROM 10 DOWN TO 0 BY 1
DO
typeint('count = &$',i);
ENDDO;
begin$('Counting up by twos!');
end$();
FOR i FROM 0 UP TO 10 BY 2 DO
typeint('count = &$',i);
ENDDO;
FOR today OVER days_of_week
DO
%% Statements here will execute 7 times.
ENDDO;
31)WHILE
修饰DO循环语句。
例如:
DCL i int;
begin$('Counting down!');
end$();
10 -> i;
WHILE i >= 0
DO
typeint('count = &$',i);
i - 1 -> i;
ENDDO;
FOR i FROM 0 UP TO 99 WHILE some_condition
DO
%% Iterate while some_condition is TRUE, to a maximum 100 times.
ENDDO;
32)PROC
过程(procedure)使用关键字’PROC’来定义;可以有返回值也可以没有。’RETURNS’用于指定返回值的类型;’RETURN’用于返回语句。在一个过程中可能有多个’RETURN’语句。
例如:
DCL do_nothing PROC() IS
BLOCK
% normally you would do something here
ENDBLOCK do_nothing;
DCL always_returns_true PROC() RETURNS bool IS
BLOCK
% always replies in an affirmative voice
return true;
ENDBLOCK always_returns_true;
33)PROC: DEFAULT, UPDATES AND REF PARAMETER PASSING
给过程(PROCEDURE)传递参数的方式有三种:传值,更新和引用。
默认的传送机制是传值。即在过程中创建本地变量,然后用被传进来的值初始化它。本地变量可能在过程中被修改,但是不会影响到原来参数值(即实参)。
假如想传送一个需被过程更新的变量,则在过程定义中为该参数使用关键字UPDATE。使用UPDATE传进来的参数必须是有效的存储位置。例如,把PTR操作符应用到那些通过UPDATE传进来的事物。
REF传送机制只能以只读方式访问该参数。注意,假如REF参数是DESC或PTR,则REF不能防止修改那些参数指向的东西。如果要预防,可使用关键字VAL,如
PROC some_proc (REF p PTR TO VAL int)
例子:
DCL add PROC( x int, ref y int, updates sum int ) IS
BLOCK
x + y -> sum; % sum is updated
0 -> x; % legal, but only the local copy is changed
% 0 -> y; % illegal, because y is read-only
ENDBLOCK add;
DCL main PROC() IS ENTRY;
DCL main PROC() IS
BLOCK
DCL i INT INIT 5;
DCL j INT INIT 6;
DCL new_sum INT;
...
add(i,j,new_sum); % after this executes, new_sum = 11, i = 5, j = 6
...
ENDBLOCK main;
34)PROC: PROCEDURE TYPES & VARIABLES
可以定义过程的类型和声明过程的参数。
例如:
TYPE generic_proc PROC( x int ) returns BOOL;
DCL compare_proc generic_proc;
DCL b BOOL;
DCL is_less_than_10 generic_proc IS
BLOCK
RETURN ( x < 10 ); % returns TRUE if x < 10 and FALSE otherwise
ENDBLOCK is_less_than_10;
is_less_than_10 -> compare_proc;
compare_proc(3) -> b; % b = true
35)ENTRY
‘ENTRY’用于把某个过程当作’main’函数供某个特殊的模块使用。与C不同的是,PROTEL允许自己指定一个’main’函数。
36)FORWARD
‘FORWARD’关键字通常用在模块的接口部分,来为其他模块声明一个过程而不指定实现的详细部分。FORWARD声明部分定义了过程的部分类型,但是过程的实现是在模块的实现部分完成的,该模块包含了FORWARD的声明部分。
如在接口模块中指定:
DCL add PROC ( x int, y int ) RETURNS INT IS FORWARD;
在该模块其他地方,实现了该add过程的实现部分。如果上述声明没有出现在接口部分里,那么其他模块就不可以使用该过程。然而,’add’仍然可在实现了它的部分中被调用,就像该部分的子部分一样。举例:
DCL add PROC ( x int, y int ) RETURNS INT IS
BLOCK
RETURN x + y;
ENDBLOCK add;
37)BLOCK AND SCOPING
关键字’BLOCK’和’ENDBLOCK’用于指示代码独立块的起始和终结,包括过程的起始和终止。假如需要在某片代码内声明新的变量或变量类型,也可使用BLOCK。
注意:类型,声明和bind在过程中只能立刻跟在明显的或隐含的BLOCK之后,就是说,不可以出现在创建它们的block任何其他可执行语句后。
例如,假定有个使用table的函数,不想为表分配空间,除非必须要:
DCL my_dummy_proc PROC ( ) IS
BLOCK
DCL table_size INT;
% calculate table size, et al....
BLOCK
DCL my_table TABLE[table_size];
% do something with the table...
ENDBLOCK;
% do some other things...
ENDBLOCK my_dummy_proc;
面向对象的PROTEL:OO PROTEL
1)类
定义:
TYPE queue_of_$longint
CLASS REFINES $object
queue DESC OF $longint,
number_of_entries,
first_valid_entry,
last_valid_entry $longint
OPERATIONS
add METHOD (UPDATES; item $longint),
remove METHOD (UPDATES) RETURNS $longint,
is_empty METHOD (REF) RETURNS bool,
is_full METHOD (REF) RETURNS bool,
initialize METHOD (UPDATES; initial_size $longint)
ENDCLASS;
类的类型不可能定义在PERPROCESS部分
声明:
DCL x queue_of_$longint; %% a class instance variable
子类化/继承
使用关键字REFINES来精炼另外一个类。任何一个类都必须refine内建的所有类的根类:$OBJECT
TYPE sorted_queue_of_$longint
CLASS REFINES queue_of_$longint
%% all class datas are inherited from queue_of_$longint
OPERATIONS
{overriding}:
add,
%% remove, is_empty, is_full and initialize are
%% inherited from queue_of_$longint
ENDCLASS;
单态和多态类别
DCL yield_sign PTR TO triangle;
DCL traffic_sign PTR TO ANY shape; %% traffic_sign can be type SHAPE’s descendent.
抽象类:
TYPE container_for_$longint
ABSTRACT CLASS REFINES $object
...
OPERATIONS
...
ENDCLASS
类数据属性:
TYPE my_class
CLASS REFINES $object
{Readable}:
a_readable_int INT;
...
ENDCLASS;
# <default>: object的派生类对隐藏数据有读和写的权利,object的客户不可以访问隐藏域,除非它们是相同级别的类别。
# Aligned: 未使用
# Blocking: 未使用
# Exclusive: 用于声明对于除了声明类,所有其他都是完全隐藏的数据。
# Protected: 定义一个类变量,存在于PROTECTED数据段中。
# Readable: object的派生类对Readable域有读和写的权限,客户有读权限。
# Scratch: 未使用
# Shared: 定义一个类变量,存在于SHARED数据段中。
# Writable: Object的派生类和客户都有读和写的权限。
# Writeblocking: 未使用
方法:
定义和实现:
%% See section “Class” for methods’ definition
IN queue_of_$longint DCL is_full METHOD IS
BLOCK
% Implementation code
ENDBLOCK ;
方法属性:
TYPE my_class
CLASS REFINES queue_of_$longint
OPERATIONS
{Overriding}:
add,
...
{}:
...
ENDCLASS;
# Overriding: 受影响的方法都继承于一些超类,但在该类中被赋予新的实现体。
# Abstract: 受影响的方法在该类中没有实现体。
# Class: 受影响的方法是类方法。只需提供类的类型而不需要该类的实例存在就可以访问(实际上就是java中的static方法)。
# Create: 受影响的方法是特殊的用户定义的用来动态生成对象的方法。
# Exclusive:受影响的方法只能被定义它的类所访问。
# Fixed: 受影响的方法不可以被子类覆写。
# Hidden: 受影响的方法不可被该类的客户所看见,但是对于该类的所有方法以及它的子类而言都是可见的。
Extern(External Methods): 该方法的实现是在不同的模块中,这些模块来自于它们的定义。
检查语句:Inspect statement
类似于CASE或SELECT,但用于类上。
INSPECT x IN
{class1}: %% x is identical to class1
%% some code
{ANY class2}: %% x is identical to class2 or a subclass of class2
%% some code
OUT
%% some code
ENDINSPECT;
=> 操作符:
It is used in the inspect statement to bind a new name to the inspected expression. Looks like the BIND ... AS... statement.
INSPECT my_shape IN
{circle => my_circle}: %% my_circle has the type circle
%% some code
{ANY polygon => my_poly}: %% my_poly has the type ANY polygon
%% some code
OUT
%% some code
ENDINSPECT
构造函数和析构函数:
在PROTEL2中,构造函数和析构函数分别由在$object,named construct和destruct的预定义方法所实现,它们被派生且可以被覆写。
Automatic invocation
# Local variable: 对于任何被声明为本地变量的对象,当该变量被声明时,其构造函数自动被调用,当对象离开其范围时,析构函数自动被调用。
# Global variable: 对于全局变量,构造函数和析构函数从来不会被自动调用,假如适当的话,必须由程序员手动调用。