跳轉到內容

軟體工程師手冊/語言詞典/PLI

來自 Wikibooks,開放世界中的開放書籍

這是維基百科條目

PL/I 是一種完整的過程式語言。

執行入口點

[編輯 | 編輯原始碼]

程式的入口點指定為OPTIONS(MAIN),在過程語句中,例如

 tree: procedure options (main);

列特性

[編輯 | 編輯原始碼]

沒有列特性。

通用語法

[編輯 | 編輯原始碼]

賦值示例

a = b*(c-d);

在這個數值賦值語句中,dc 中減去,結果乘以 b 的值,然後儲存到變數 a 中。

s = t || u;

在這個字串賦值示例中,字串 u 連線到字串 t 的末尾,組合字串儲存到字串變數 s 中。

注意:使用編譯時選項,連線運算子|| 可以替換為另一對符號,以相容現有的 PL/I 程式,通常使用!!

每個註釋以/* 開頭,以 */ 結尾。註釋可以跨越多行。

/*
 * this is a long comment.
 */

變數宣告

[編輯 | 編輯原始碼]

宣告不是強制性的,儘管大多數 PL/I 編譯器提供一個編譯器選項來強制宣告,而一些子集編譯器則要求宣告每個變數。

要將 i 宣告為二進位制

declare i fixed binary;

要將 i 宣告為二進位制並將其初始值設定為 0

declare i fixed binary initial (0);

要將變數宣告為十進位制,

declare D fixed decimal;
declare E fixed decimal (10,4);

第一個宣告是儲存在十進位制格式中的整數 D,第二個是能夠儲存十位數字且小數點後有 4 位數字的變數 E。要初始化 E,請編寫

declare E fixed decimal (10,4) initial (123456.7891);

請注意,諸如 0.1 之類的值是精確儲存的。

要定義一個浮點變數

declare f float;

使用單精度硬體;和雙精度

declare float decimal (15);

和擴充套件精度

declare float decimal (18);

(PC 的典型宣告)。數字 15 和 18 表示將儲存的小數位數。(雖然值實際上以二進位制形式儲存,但小數精度比以二進位制形式指定精度更容易記住。)要指定一個複數變數,只需在宣告中包含單詞 COMPLEX,因此

DECLARE C FLOAT DECIMAL (15) COMPLEX;
C = 5.2+8i;

賦值包括複數常數 5.2+8i,其中 5.2 是實部,8 是虛部。

基數(二進位制或十進位制)、範圍(定點或浮點)和模式(實數或複數)的算術資料屬性可以按任何順序出現,精度屬性(例如 (15))不能是第一個屬性。

以下定義是等效的,最後一個除外。

declare   number       fixed binary (15) real;
declare   number       binary fixed (15) real;
declare   number       binary fixed real (15);
declare   number       binary fixed (15);      /* because real is the default value of mode */
declare   number (15)  binary fixed real;      /* defines 15 numbers with default precision */

要宣告一個具有圖片屬性的變數

declare p picture ('9999v.999');

將變數 P 描述為具有 7 位十進位制數字,小數點後有三位數字。小數點儲存在儲存器中。字母 V 指示實際小數點的位置。對於歐洲,規範可以包含逗號

declare p picture ('9999v,999');

要將變數 S 宣告為字元字串

declare S character(10);

字串 S 可以精確儲存 10 個字元。

要將變數 V 宣告為能夠儲存最多 100 個字元的字元字串

declare V character (100) varying;

簡單的賦值

V= 'abc';

V 包含三個字元 abc

V = 'friendly';

V 包含 8 個字元 friendly

PL/I 也允許位字串

declare b bit(10);

允許儲存長度為 10 的位字串。賦值語句

b = '1011110010'b;

按給定順序儲存位。此類位字串可以像字元字串一樣進行搜尋等。

可以宣告資料結構或聚合

declare 1 name,
          2 first_name   character (10),
          2 surname      character (15);

陣列透過上述方法之一以及維度資訊來宣告

declare x(10) float;

指定了一個包含十個元素的陣列,x(1)x(10)。預設下界為 1。要指定不同的下界

declare y(0:15) float;

聲明瞭一個包含 16 個元素的陣列 Y(0) 到 Y(15),其中元素為浮點型。

多維陣列透過逗號分隔維度來宣告

declare   M ( 2 , 4:5 )   fixed binary (15)

定義了一個包含 4 個元素的二維陣列:M (1, 4)M (1, 5)M (2, 4)M (2, 5)

為了處理以兩位數年份和四位數年份給出的日期,這些日期可能在同一個程式中混合使用,可以使用 DATE 屬性。

declare d date ('YY'); [more to come]

關鍵字 DECLAREINITIAL 可以縮寫為 DCLINIT,許多屬性也可以縮寫。

屬性 縮寫
BINARY BIN
DECIMAL DEC
CHARACTER CHAR
VARYING VAR
PICTURE PIC
POINTER PTR

輸出語句

[編輯 | 編輯原始碼]
put list ('Hello world!');
put skip list ('Hello world!');

第一個示例將 Hello world! 寫入標準輸出(螢幕或印表機或檔案)。這些單詞在該行上任何已有的輸出之後列印。第二個示例在列印之前開始新的一行(單詞 SKIP)。

方法宣告/實現

[編輯 | 編輯原始碼]

描述方法/函式/過程是如何宣告和實現的。以下示例是一個包含函式的完整 PL/I 程式。

/* A program to calculate the area of a triangle, */
/* given two sides and an included angle. */
d: procedure options (main);
        declare (b, c, angle) float;
        put list ('Today is ', date());
        put skip list ('Please type the lengths of two sides, and an angle');
        get list (b, c, angle);
        put skip list ('The two sides are', b, c, 'and the angle is', angle, 'degrees');
        put list ('Area of triangle=', area(b, c, angle));

area: procedure (b, c, angle) returns (float);
        declare (b, c, angle) float;
        return (b*c*sin(angle)/2);
end area;
end d;

上述程式包含了一些典型的列表定向形式的輸入和輸出語句。第一個PUT語句列印日期。第二個請求讀者輸入三個值,表示某個三角形的引數。第三個回顯輸入作為確認。最後一個PUT語句包含一個函式引用area(b, c, angle),它呼叫了該函式。計算完成後,當前的PUT語句列印該面積。函式AREA的定義包括一個PROCEDURE語句,該語句列出了從呼叫程式所需的引數,即bcangle。這些引數在下一條語句(DECLARE)中定義。PROCEDURE語句還說明了要返回給呼叫程式的結果型別,即浮點值。這由RETURNS (FLOAT)表示。RETURN語句包含用於計算三角形面積的公式。然後它將控制權返回給呼叫程式。RETURN語句通常包含變數的名稱,但也可以包含表示式(如本例所示)。

作用域

[編輯 | 編輯原始碼]

PL/I 變數的作用域限制在宣告它們的程式中。作用域擴充套件到該程式中包含的任何程式(當然,除了任何程式中出現相同名稱的新宣告)。

如果未宣告變數,則該變數的作用域為整個程式。同樣,如果宣告(對於同名變數)出現在從屬(使用變數)的一個或多個塊中,則作用域將從包含宣告的塊中排除。

PL/I 有兩種型別的塊。一種是用於子程式和函式的PROCEDURE塊。另一種是BEGIN塊(BEGIN; ... END;)。BEGIN塊的行為類似於PROCEDURE塊,但BEGIN塊沒有引數,也不必有標籤。它以正常的順序執行進入,而PROCEDURE塊只能透過執行CALL語句或函式引用來執行。

條件語句:IF..THEN..ELSE

[編輯 | 編輯原始碼]

考慮條件語句的兩個示例

if a = b then c = d;
if a > b then c = d; else c = e;

第一個示例說明了一個可選執行的語句c = d;

第二個示例顯示了兩個可選執行的語句,第一個在a > b時執行,第二個在a <= b時執行;

當需要有條件地執行多個語句時,使用語句括號doend

if a > b then
   do; p = q; r = s; end;

多分支條件:SELECT

[編輯 | 編輯原始碼]

select 組提供多分支評估,它可以用以下兩種語法方案之一編寫

  1. SELECT ( var_or_expr ); WHEN ( val_1 ) unit_1; .... OTHERWISE unit_other; END;
  2. SELECT ; WHEN ( expr_1 ) unit_1; .... OTHERWISE unit_other; END;

方案型別 1 的 select 組具有以下形式

SELECT ( var_or_expr );
   WHEN ( val_1 ) unit_1;
   ....
   WHEN ( val_n ) unit_n;
   OTHERWISE      unit_other;
END;

var_or_exprval_II = 1..n)可以是變數或表示式。

unit_II = 1..n)和unit_other可以是單個語句或 do 組。

select 組的評估方式為(虛擬碼)

Evaluate var_or_expr and store it to the variable TEMP.
For I = 1 to n:
   Evaluate val_I,
   if the result equals TEMP: Execute unit_I and leave the select-group.
Execute unit_other.

OTHERWISE 子句(可以縮寫為OTHER)是可選的,但如果省略此子句並且沒有任何val_I等於TEMP,則會發生執行時錯誤。

WHEN 子句可以包含多個值,例如

SELECT ( my_char );
   WHEN ( '0' , '2' , '4' , '6' , '8' )
      put skip list ( 'character is an even digit' );
   WHEN ( '1' , '3' , '5' , '7' , '9' )
      put skip list ( 'character is an odd digit' );
   OTHERWISE
      put skip list ( 'character is no decimal digit' );
END;

方案型別 2 的 select 組具有以下形式

SELECT;
   WHEN ( expr_1 ) unit_1;
   ....
   WHEN ( expr_n ) unit_n;
   OTHERWISE       unit_other;
END;

expr_II = 1..n)可以是邏輯表示式或邏輯變數。
unit_II = 1..n)和 unit_other 可以是單個語句或 do 組。

select 組的評估方式為(虛擬碼)

For I = 1 to n:
   if expr_I is true: Execute unit_I and leave the select-group.
Execute unit_other.

一個示例

SELECT;
   WHEN ( a > b ) DO; call use_as_max ( a ); put skip list ( 'max = a' ); END;
   WHEN ( b > a ) DO; call use_as_max ( b ); put skip list ( 'max = b' ); END;
   OTHERWISE      ; /* clause with empty statement to avoid run time error if a = b */
END;

迴圈語句

[編輯 | 編輯原始碼]

迴圈語句的基本形式為

do k = 1 to 10;
   >>body<<
end;

迴圈體執行十次,控制變數k取值從 1 到 10。迴圈退出時,k的值會增加 1,即 11。迴圈擴充套件到下一個END語句。迴圈語句的變體有

do k = 1 to n by 2;
do k = 20 to 1 by -1;

可以使用多個迭代規範

do k = 1 to 10, 20 to 100 by 5, 120 to 200 by 20;

其中迴圈將執行,控制變數k取值從 1 到 10,然後 20、25、30、35、... 100、120、140、160、180 和 200。

有條件終止的迴圈使用WHILE結構

do while (a > b);

此類迴圈執行零次或多次,測試在迴圈開始時執行。

do until (a > b);

上述語句指定的迴圈至少執行一次,測試在迴圈結束時執行。

在以下示例中,使用REPEAT指定控制變數值的異常變化。

do k = 1 repeat k*i until (k > 1000);

在這種情況下,控制變數k取值 1、2、4、8、16,依此類推,直到k大於 1000。

REPEAT形式

do next = head repeat next > link until (link = null);

可用於遍歷連結列表。

WHILEUNTIL可以組合使用

do while ( W ) until ( U ); ... end;
do until ( U ) while ( W ); ... end;

(兩個示例是等效的,即語句中WHILEUNTIL的順序無關緊要)

DO I = ...後面可以跟WHILEREPEAT或兩者

do I = 1 to 5 while ( W ); ... end;
do I = 1 to 5 until ( U ); ... end;
do I = 1 to 5 while ( W ) until ( U ); ... end;
do I = 1 to 5 until ( U ) while ( W ); ... end;

(最後兩個示例是等效的)

評估順序

do I = 3 to 9 by 2 while ( W ) until ( U );
   ... some_statements ...
end;
put skip list ( 'I am ready' );

評估方式為

  1. 令 I 為 3
  2. 如果 I > 9 則轉到 [7]
  3. 如果 W 為假則轉到 [7]
  4. ...一些語句...
  5. 如果 U 為真則轉到 [7]
  6. 令 I 為 I + 2 並轉到 [2]
  7. put skip list ( 'I am ready' );

另一個示例:以下語句指定 do 組必須執行八次,I 的值分別為 1、3、5、9、18、36、9、18。

do I = 1 to 5 by 2,                      /* 1  3  5 */
       9 repeat 2 * I until ( I > 20 ),  /* 9 18 36 */
       9 repeat 2 * I while ( I < 21 );  /* 9 18    */

布林值

[編輯 | 編輯原始碼]

在 PL/I 中,bit (1) 字串表示單個布林值

  • '1'B 解釋為True
  • '0'B 解釋為False

Bit (1) 字串可以在條件和迴圈語句中用作布林表示式。

declare   my_bit   bit (1);
   my_bit = ( 1 < 2 );   /* now my_bit has the value '1'B */
   my_bit = ( 2 < 1 );   /* now my_bit has the value '0'B */
   .....
   if my_bit then
      put skip list ( 'value of my_bit is true' );
   else
      put skip list ( 'value of my_bit is false' );
   do while ( my_bit );
      .....
   end;

布林運算子可用於計算新值

  • 字首運算子¬用作邏輯NOT
  • 中綴運算子&用作邏輯AND
  • 中綴運算子|用作邏輯OR
declare   bit_a    bit (1);
declare   bit_b    bit (1);
declare   result   bit (1);
   result = ¬ bit_a;           /* result = '1'B if and only if bit_a is '0'B */
   result =   bit_a & bit_b;   /* result = '1'B if and only if both bit_a and bit_b are '1'B */
   result =   bit_a | bit_b;   /* result = '0'B if and only if both bit_a and bit_b are '0'B */

注意:使用編譯時選項,NOT運算子和OR運算子可能會被替換為其他符號,為了與現有的 PL/I 程式相容,通常^用作NOT!用作OR

錯誤處理/恢復

[編輯 | 編輯原始碼]

PL/I 提供錯誤檢測和錯誤處理。檢測到的錯誤包括

  • 浮點溢位和下溢;
  • 定點溢位;
  • 除以零;
  • 下標越界錯誤;
  • 子字串違規;
  • 字串截斷。
  • 一般錯誤。

使用者可以允許系統報告錯誤並執行預設操作,或者使用者可以指定在檢測到給定錯誤時要執行的計算操作。

事件(包括錯誤)稱為條件

要檢測條件,必須首先啟用它。如果啟用了條件並且發生了相應的條件,則會執行相應的ON單元(如果使用者提供)。

考慮以下程式碼

on overflow snap go to restart;
a = b * c;
...
restart:

如果產品b*c超過允許的最大值,則會引發OVERFLOW條件,並執行OVERFLOWON單元。此處的ON單元是最簡單的(go to)之一,僅將控制權轉移到標記為RESTART的語句(在該語句中,程式可能處理下一組值)。

關鍵字SNAP導致正在執行的程式列印錯誤訊息,以及發生錯誤的語句編號。

以下是一個更一般的示例

(SUBSCRIPTRANGE):
a: procedure;
 declare x(10) float;
 declare (i, k) fixed binary;

 ON SUBSCRIPTRANGE SNAP BEGIN; PUT DATA (K); STOP; END;
 get list (k);
 do i = 1 to k;
    x(i) = 0;
 end;
end a;

在本例中,錯誤檢測和處理部分以大寫顯示。下標檢查由條件字首SUBSCRIPTRANGE啟用(在PROCEDURE語句之前用括號括起來)。在執行任何語句之前,必須執行ON語句,該語句建立發生下標錯誤時要執行的操作。接下來執行的語句是輸入語句GET,它讀取一個值,例如12。進入迴圈,並初始化x的十個值。在嘗試初始化x(11)時,會引發SUBSCRIPTRANGE條件,並導致執行ON單元BEGIN; PUT DATA (K); STOP; END;SNAP導致列印錯誤訊息以及語句號,然後執行BEGIN塊中的語句,即PUT DATA語句,它列印K = 11。然後程式STOP。一些特定的條件是

OVERFLOW 指數溢位
UNDERFLOW 指數下溢
FIXEDOVERFLOW 定點溢位
SIZE 定點溢位
ZERODIVIDE 被零除
SUBSCRIPTRANGE 下標越界錯誤
STRINGRANGE 子字串錯誤
STRINGSIZE 字串截斷
ENDFILE 檔案結束
ENDPAGE 頁面結束
ATTENTION 鍵盤請求

提供了一些條件來處理日常事件,例如檔案結束和頁面結束。例如,在每一頁的頂部列印頁碼

ON ENDPAGE PUT PAGE LIST('Page', Page_no);

檢測輸入檔案IN的結束,並轉移到命名語句

ON ENDFILE(IN) go to next;

程式設計師可以發明自己的條件,並可以發出訊號。

提供SIGNAL語句用於在程式測試期間測試給定的ON單元(錯誤處理程式)。例如,SIGNAL ZERODIVIDE;要引發名為RANGE的使用者定義條件,將使用語句SIGNAL CONDITION(RANGE);

<列出此語言本機提供的容器或容器列表的引用。如果容器不是該語言的本機功能,請列出整合容器的方法。>

演算法

[編輯 | 編輯原始碼]

垃圾回收

[編輯 | 編輯原始碼]

任何垃圾回收都是自動的。所有具有automatic屬性或使用automaticautobuiltin分配的變數都會在宣告它們的塊結束時從儲存器中刪除。所有分配的儲存器(ALLOC語句或alloc builtin)都會在程式結束時從儲存器中刪除。

物理結構

[編輯 | 編輯原始碼]

標準函式庫都是自動提供的;無需執行任何操作即可訪問它們,例如指定目錄或使用INCLUDE語句等。

  • 源程式可以用大寫或小寫編寫。除了字串之外,大小寫之間沒有區別。
  • 可變字串(用屬性VARYING宣告)類似於C的char。

對於完全等效的版本,在Enterprise PL/I for z/OS中,可以使用屬性VARYINGZ,其中字串以零結尾。

如果沒有屬性VARYING,則字串為固定長度。此類字串始終儲存指定數量的字元。因此,

DECLARE S CHARACTER(8);
S = 'abc';

儲存八個字元,即abc後跟五個空格,而

declare V character(8) varying;
V = 'abc';

需要10位元組的儲存空間:2位元組用於V的實際長度,8位元組用於字元。後一種功能使得賦值成為可能

V = V || 'dog';

它將單詞dog追加到已儲存在V中的內容(在本例中最多8個字元,當然)。

Content of V after V = 'abc';:
+---+---+---+---+---+---+---+---+---+---+
|   3   | a | b | c | ? | ? | ? | ? | ? |   /* "?" means: value is undefined */
+---+---+---+---+---+---+---+---+---+---+
          1   2   3   4   5   6   7   8     /* index of character */
Content of V after V = V || 'dog';:
+---+---+---+---+---+---+---+---+---+---+
|   6   | a | b | c | d | o | g | ? | ? |   /* "?" means: value is undefined */
+---+---+---+---+---+---+---+---+---+---+
          1   2   3   4   5   6   7   8     /* index of character */
declare i fixed binary;

等效於C的int

declare i fixed binary (31);

等效於C的long int

declare i fixed binary (63);

等效於C的long long int

  • 十進位制算術,因為它固定點,需要小心。

提供內建函式ADDSUBTRACTMULTIPLYDIVIDE,使程式設計師能夠指定每個結果的精度。因此,它們有助於避免溢位。對於十進位制定點除法,強烈建議使用DIVIDE函式。因此,要將A除以B,其中A的精度為(10,5)B的精度為(6),推薦的形式為

declare A fixed decimal (10,5), B fixed decimal(6), C fixed decimal (10,5);
A = 12345.67891; b = 98765;
C = divide(A, B, 10, 5);

DIVIDE引用中,引數10和5分別指示結果A/B具有總共十位數字,小數點後有5位數字。然後將此值儲存在C中。IBM PL/I允許最多31位十進位制數字用於定點運算。

  • 在執行PL/I程式時,在初始過程語句上使用條件字首SIZESTRINGRANGESTRINGSIZESUBSCRIPTRANGE,如下所示
(SIZE, STRINGRANGE, STRINGSIZE, SUBSCRIPTRANGE):
trial: procedure options (main);

這使得可以檢查定點溢位,以及字串和下標的範圍檢查和截斷。

  • 陣列的下界預設為1,而不是0。
  • 整數(無論是十進位制、二進位制還是混合)的除法可能會產生具有比例因子的定點結果。因此,9/2產生4.5000000,這與產生整數4的Fortran不同。如果需要整數結果,可以使用TRUNCDIVIDE,例如:TRUNC(9/2)或更一般地 - DIVIDE(J, K, 31),後者為二進位制整數結果提供31位的精度。或者,將二進位制整數變數宣告為具有最大精度(通常為31位)將確保兩個此類整數變數相除的結果將產生整數結果。

網路參考

[編輯 | 編輯原始碼]
  • [1] IBM手冊:用於MVS和VM的PL/I
  • [2] IBM手冊:用於z/OS的Enterprise PL/I

書籍和文章

[編輯 | 編輯原始碼]
  • J. K. Hughes,PL/I結構化程式設計,第3版,Wiley,1986年。(初學者到專業人士;商業應用)
  • R. Reddy和C. Ziegler,PL/I:結構化程式設計和問題解決,West,1986年,ISBN 0-314-93915-6。(初學者到高階)
  • R. A. Barnes,程式設計師的PL/I,North-Holland,1979年。(專業)
  • G. F. Groner,PL/I在技術應用中的程式設計,按需印刷書籍,密歇根州安阿伯,1971年。(專業)
  • M. E. Anderson,程式設計師的PL/I,Prentice-Hall,1973年。(專業)
  • D. R. Stoutemyer,工程與科學的PL/I程式設計,Prentice-Hall,1971年。(專業)
  • E. Sturm,Das neue PL/I(für PC、Workstations和Mainframe),第5版,Vieweg-Verlag,2002年。

另請參閱

[編輯 | 編輯原始碼]
華夏公益教科書