跳到內容

Pascal 程式設計/入門

來自華夏公益教科書,開放的書籍,開放的世界

在本章中,你將學習

  • Pascal 原始碼檔案的結構
  • 基本術語

所有程式設計任務都需要一個原始碼檔案,在 Pascal 中稱為 program。一個 program 原始碼檔案由編譯器翻譯成可執行應用程式,你可以執行它。讓我們看看一個最小的 program 原始碼檔案

program nop;
begin
	{ intentionally empty }
end.
  1. 第一行 program nop; 表示該檔案是 Pascal 程式的原始碼檔案。
  2. beginend 標記一個框架。在接下來的內容中,我們將詳細解釋這一點。
  3. { intentionally empty } 是一個 註釋。註釋將被編譯器忽略,因此不會以任何方式影響可執行程式的外觀或行為。
  4. 最後一個點 . 在最後一個 end 後告訴編譯器程式原始碼檔案的結束位置。
Note 如果你覺得這本書的節奏讓你難以理解,華夏公益教科書 程式設計基礎 可能更適合你。

為了啟動你的程式,你需要編譯它。

首先,複製上面顯示的程式。我們建議你實際輸入這些示例,而不是複製貼上程式碼。將檔案命名為 nop.pasnop 是程式的名稱,副檔名 .pas 幫助你識別 原始碼 檔案。

完成後,告訴編譯器你已經選擇編譯程式了

如果你使用的是 FPC,在控制檯中輸入 fpc,後跟一個指向原始碼檔案的(相對或絕對)檔名路徑
FPC 輸入:
fpc nop.pas
結果
Target OS: Linux for x86-64
Compiling nop.pas
Linking nop
4 lines compiled, 0.1 sec
如果沒有輸入錯誤,成功的編譯看起來像這樣(一些資料可能會有所不同)。在當前目錄中,將會有一個名為 nop 的新檔案。這是你可以啟動的可執行程式。


如果你使用的是 GPC,在控制檯中輸入 gpc,後跟一個指向原始碼檔案的(相對或絕對)檔名路徑
GPC 輸入:
gpc nop.pas
結果
如果沒有輸入錯誤,gpc 不會報告任何錯誤,但將會有一個(預設情況下)名為 a.out 的新檔案。


最後,你可以透過你的 OS 提供的其中一種方法來執行程式。例如,在控制檯中,你只需輸入可執行檔案的名稱:./nop(其中 ./ 指的是 Unix 類環境中的當前工作目錄)。由於此程式(有意地)沒有做任何事情,你不會注意到任何(明顯的)變化。畢竟,程式名稱 nop無操作 的縮寫。

Note 程式需要為每個平臺編譯。 平臺 指的是 OSOS 版本以及使用的微處理器體系結構和製造。只有當所有這些指標都匹配時,你才能將可執行檔案複製到另一臺計算機並執行它。否則,它可能會失敗。現代 OSs 可以阻止你執行不相容的程式(在一定程度上)。

計算機說話

[編輯 | 編輯原始碼]

恭喜你編寫了第一個 Pascal 程式!公平地說,這個程式沒什麼用處,對吧?作為一個小步驟,讓我們讓計算機說話(比喻地)並向世界介紹自己

program helloWorld(output);
begin
	writeLn('Hello world!');
end.

程式頭

[編輯 | 編輯原始碼]

你會注意到第一個區別在第一行。不僅程式名稱發生了變化,而且還有 (output)。這是一個程式 引數。實際上,它是一個列表。在這裡,它只包含一項,但一般形式是 (a, b, c, d, e, ) 等等。程式引數指定了 OS 需要向程式提供的一個外部實體,以便程式能夠按預期執行。我們將在後面詳細介紹,但現在我們需要知道有兩個 特殊 程式引數:inputoutput。這些引數象徵著與 OS 互動的預設方式。通常,如果你在控制檯中執行程式,output 是控制檯的顯示。

寫入控制檯

[編輯 | 編輯原始碼]

下一個區別是 writeLn('Hello world!')。這是一個語句。語句是一個例程呼叫。例程名為 writeLnWriteLn 有(可選)引數。引數是,同樣,以逗號分隔的列表,用括號括起來。

例程

[edit | edit source]

例程是可重用的程式碼片段,可以反覆使用。例程 writeLn,縮寫為 write line,將所有提供的引數寫入目標,然後是一個“換行符”(一些使游標移動到下一行的魔法)。然而,這裡目標是不可見的。這是因為它是可選的,可以省略。如果省略,目標將變為 output,因此我們的控制檯輸出。如果我們想要明確命名目標,我們必須寫 writeLn(output, 'Hello world!')WriteLn(output, 'Hello world!')writeLn('Hello world!')完全相同的。缺少的可選引數將自動插入,但它減輕了程式設計師的輸入負擔。

為了使用一個例程,我們寫它的名稱,作為一個語句,後面跟著引數列表。我們在上面第 2 行做了這件事。

Note 例程需要在使用之前定義。

然而,例程 writeLn 作為 Pascal 語言的組成部分被定義。在接下來的章節中,我們將學習定義我們自己的例程。

字串字面量

[edit | edit source]

引數 'Hello world!' 是一個所謂的字串字面量。字面量意味著,你的程式將按原樣使用這個字元序列,不會以任何方式解釋它,並將它傳遞給例程。一個 string 字面量由打字機(直線)撇號分隔。

保留字

[edit | edit source]

與之相反,單詞 programbeginend(以及你在程式碼示例中以粗體顯示的許多其他單詞)是所謂的保留字。它們傳達了關於如何解釋和構建可執行程式的特殊含義。你只能在特定的地方寫它們。

Note 但是,你可以string 字面量 'program'。字串分隔符“停用”瞭解釋。

行為

[edit | edit source]
現在,我們知道原始碼包含什麼,建立一個新的檔案 helloWorld.pas,複製原始碼(透過手動輸入),編譯並執行它

程式碼:

program helloWorld(output);
begin
	writeLn('Hello world!');
end.

輸出:

Hello world!
程式將在控制檯上列印 Hello world!沒有直引號,在一個單獨的行上。這不是很棒嗎?
“救命!我只看到終端視窗開啟又關閉!”
在這種情況下,試試這個程式
program helloWorld(input, output);
begin
	writeLn('Hello world!');
	readLn();
end.
更改的行已突出顯示。額外的 readLn() 將使你的程式停頓,因此程式不被認為是完成的。在你按下 ↵ Enter 後,終端視窗應該再次關閉。

順便說一下,這種型別的程式是“Hello world”程式類別的一個例子。它們用於演示任何程式語言的原始碼檔案需要滿足的最低要求。更多示例請參見 WikiBook“計算機程式設計”中的 Hello world(並欣賞 Pascal 與其他程式語言相比的簡單性)。

註釋

[edit | edit source]

我們已經看到了寫註釋的選項。註釋的目的是作為程式設計師的提醒。

註釋語法

[edit | edit source]

Pascal 將大括號定義為註釋分隔符:{ comment }(空格用於視覺引導,沒有意義)。左大括號開啟開始註釋,右大括號關閉註釋。

Note 在註釋“內部”,你不能使用註釋結束符作為文字的一部分。第一個出現的正確結束符將是註釋的結束。

然而,當 Pascal 被開發時,並非所有計算機系統都擁有鍵盤上的大括號。因此,使用括號和星號的雙字母組合也變得合法:(* comment *)

這樣的註釋被稱為塊註釋。它們可以跨越多行。Delphi 引入了另一種註釋風格,行註釋。它們以兩個斜槓 // 開始,包含當前行結束之前的所有內容。

Delphi、FPC 以及 GPC 都支援所有三種註釋風格。

有用的註釋

[edit | edit source]

好的註釋是一種“藝術”。

註釋應該解釋不明顯的資訊
program nop;
begin
	{ intentionally empty }
end.


寫註釋時,堅持使用一種自然語言。在接下來的章節中,你將看到許多“好的”註釋(除非它們清楚地展示了以下內容)。

術語

[edit | edit source]

熟悉以下術語(即右側以註釋形式列印的術語)

program demo(input, output);     // program header
                                 // ───────────────────────────────────┐
const                            // ────────────────────┐              │
  answer = 42;                   // constant definition ┝ const-section│
                                 // ────────────────────┘              │
type                             // ────────────────────┐              │
  employee = record              // ─┐                  │              │
      number: integer;           //  │                  │              │
      firstName: string;         //  ┝ type definition  │              │
      lastName: string;          //  │                  ┝ type-section │
    end;                         // ─┘                  │              │
                                 //                     │              │
  employeeReference = ^employee; // another type def.   │              │
                                 // ────────────────────┘              ┝ block
                                 //                                    │
var                              // ────────────────────┐              │
  boss: employeeReference;       // variable declaration┝ var-section  │
                                 // ────────────────────┘              │
                                 //                                    │
begin                            // ────────────────────┐              │
  boss := nil;                   // statement           │              │
  writeLn('No boss yet.');       // another statement   ┝ sequence     │
  readLn();                      // another statement   │              │
end.                             // ────────────────────┘              │
                                 // ───────────────────────────────────┘

請注意,每個常量和型別定義,以及每個變數宣告都進入專門的部分。保留字 consttypevar 充當標題。

一個序列也稱為複合語句。定義、宣告和序列的組合稱為。定義和宣告是可選的,但序列是必需的。序列可以為空,正如我們在上面已經證明的那樣,但這通常不是這種情況。

不用擔心,定義宣告之間的區別將在後面解釋。現在你應該知道和認識

註釋可以包含註釋嗎?嘗試編寫一個測試程式來找出答案!混合使用各種註釋分隔符,看看混合使用它們會發生什麼。
是/否。雖然你可以在註釋內部開始另一個註釋,但終止字元將標記註釋的結束。以下情況不會造成問題
program commentDemo;
begin
	{ (* Hello { { { }
	(* (* { (* Foo }
	{ (* Bar *)

第一個註釋結束字元標記整個註釋的結束,無論它以{還是(*開頭。這意味著,這裡編譯器會報錯

	{ start (* again? } *)

行註釋不受此影響,因為它們沒有顯式的結束分隔符。這將編譯透過,不會報錯

	// *) } { (*
end.
是/否。雖然你可以在註釋內部開始另一個註釋,但終止字元將標記註釋的結束。以下情況不會造成問題
program commentDemo;
begin
	{ (* Hello { { { }
	(* (* { (* Foo }
	{ (* Bar *)

第一個註釋結束字元標記整個註釋的結束,無論它以{還是(*開頭。這意味著,這裡編譯器會報錯

	{ start (* again? } *)

行註釋不受此影響,因為它們沒有顯式的結束分隔符。這將編譯透過,不會報錯

	// *) } { (*
end.


writeLn(注意缺少引數列表)的作用是什麼?
WriteLn在沒有提供任何引數的情況下,會將一個空行列印到預設目標,即output
WriteLn在沒有提供任何引數的情況下,會將一個空行列印到預設目標,即output


編寫一個program,演示這一點(或類似的功能)
     ####     ####
   ######## ########
  ##     #####     ##
  ##       #       ##
  ##      ILY      ##
   ##   sweetie   ##
    ###         ###
      ###     ###
        ### ###
          ###
           #
一個可接受的實現可能如下所示
program valentine(output);
begin
	writeLn('     ####     ####');
	writeLn('   ######## ########');
	writeLn('  ##     #####     ##');
	writeLn('  ##       #       ##');
	writeLn('  ##      ILY      ##');
	writeLn('   ##   sweetie   ##');
	writeLn('    ###         ###');
	writeLn('      ###     ###');
	writeLn('        ### ###');
	writeLn('          ###');
	writeLn('           #');
end.

注意,程式引數列表(第一行)只列出了output。注意,雖然程式碼中的空格數量無關緊要,但它們在字串文字中很重要。

維基百科上有更多關於ASCII 藝術的資訊。
一個可接受的實現可能如下所示
program valentine(output);
begin
	writeLn('     ####     ####');
	writeLn('   ######## ########');
	writeLn('  ##     #####     ##');
	writeLn('  ##       #       ##');
	writeLn('  ##      ILY      ##');
	writeLn('   ##   sweetie   ##');
	writeLn('    ###         ###');
	writeLn('      ###     ###');
	writeLn('        ### ###');
	writeLn('          ###');
	writeLn('           #');
end.

注意,程式引數列表(第一行)只列出了output。注意,雖然程式碼中的空格數量無關緊要,但它們在字串文字中很重要。

維基百科上有更多關於ASCII 藝術的資訊。
下一頁: 變數和常量 | 上一頁: 入門
主頁: Pascal 程式設計
華夏公益教科書