Ada 程式設計/基礎
語言的 語法 的一個常見示例是 Hello world 程式。這是一個簡單的 Ada 實現
withAda.Text_IO;procedureHelloisbeginAda.Text_IO.Put_Line("Hello, world!");endHello;
with 語句將包 Ada.Text_IO 新增到程式中。此包包含在每個 Ada 編譯器中,幷包含文字輸入/輸出所需的所有功能。with 語句使 Ada.Text_IO 的宣告可供過程 Hello 使用。這包括在 Ada.Text_IO 中宣告的型別、Ada.Text_IO 的子程式以及 Ada.Text_IO 中為公開使用而宣告的所有其他內容。在 Ada 中,包可以用作工具箱。Text_IO 為在一個易於訪問的模組中進行文字輸入和輸出提供了一組工具。以下是包 Ada.Text_IO 的部分概述
packageAda.Text_IOistypeFile_Typeislimitedprivate; -- more stuffprocedureOpen(File :inoutFile_Type; Mode : File_Mode; Name : String; Form : String := ""); -- more stuffprocedurePut_Line (Item : String); -- more stuffendAda.Text_IO;
接下來在程式中我們宣告一個主過程。Ada 主過程不需要被命名為 "main"。任何簡單的名稱都可以,這裡就是 Hello。編譯器可能允許將過程或函式用作主子程式。 [1]
對 Ada.Text_IO.Put_Line 的呼叫將文字 "Hello World" 寫入當前輸出檔案。
with 子句使包的內容 透過選擇可見:我們需要用其完整包名 Ada.Text_IO 為 Text_IO 包中的過程名 Put_Line 新增字首。如果你需要更頻繁地使用包中的過程,則需要某種捷徑。有兩個選擇
透過重新命名包,可以為任何包名提供一個更短的別名。[2] 這減少了打字量,同時保留了一些可讀性。
withAda.Text_IO;procedureHelloispackageIOrenamesAda.Text_IO;beginIO.Put_Line("Hello, world!"); IO.New_Line; IO.Put_Line("I am an Ada program with package rename.");endHello;
Theuse 子句使包的所有內容對宣告它的作用域直接可見。use 可以放在本地或全域性(見下文)。與重新命名一樣,這減少了打字量,同時保留了一些可讀性。
withAda.Text_IO;procedureHelloisuseAda.Text_IO;beginPut_Line("Hello, world!"); New_Line; Put_Line("I am an Ada program with package use.");endHello;
use 可以用於包,並以以下形式使用use type 用於型別。use type 僅使給定型別的 運算子 直接可見,但不包括型別上的任何其他操作。
使用use 子句在任何作用域之外都會使包的所有內容對整個編譯單元直接可見。它允許更少的打字,但會降低可讀性,並可能導致名稱衝突。
withAda.Text_IO;useAda.Text_IO;procedureHelloisbeginPut_Line("Hello, world!"); New_Line; Put_Line("I am an Ada program with package use.");endHello;
有了這麼多選擇,需要考慮在什麼情況下使用哪個選擇。一個建議的“經驗法則”
你可能還有更簡單的規則(例如,始終use 包 Ada 及其子包,永不use 任何其他內容)。
Ada 開發早期另一個規則是全域性use 用於所有包,除非發生名稱衝突。
有關如何在各種編譯器上構建“Hello, world!”程式的資訊,請參閱構建章節。
Ada 初學者經常會問,像“Hello, world!”這樣簡單的程式怎麼會產生這麼大的可執行檔案。原因與 Ada 無關,通常可以在使用的編譯器和連結器選項中找到 - 或者更確切地說,是未使用的選項。
Ada 編譯器 - 或者一般來說好的編譯器 - 的標準行為不是建立最佳程式碼,而是為了易用性而最佳化。這樣做是為了確保一個“開箱即用”的系統,從而不會因不必要的複雜性而嚇跑潛在的新使用者。
您可以在下載示例程式的同時下載的 GNAT 專案檔案,使用更最佳化的編譯器、繫結器和連結器選項。如果您使用這些選項,“Hello, world!”將變得小很多。
32K ./Linux-i686-Debug/hello_world_1 8.0K ./Linux-i686-Release/hello_world_1 36K ./Linux-x86_64-Debug/hello_world_1 12K ./Linux-x86_64-Release/hello_world_1 1.1M ./Windows_NT-i686-Debug/hello_world_1.exe 16K ./Windows_NT-i686-Release/hello_world_1.exe 32K ./VMS-AXP-Debug/hello_world_1.exe 12K ./VMS-AXP-Release/hello_world_1.exe
為了比較,一個簡單的 gnat make 編譯的大小
497K hello_world_1 (Linux i686) 500K hello_world_1 (Linux x86_64) 1.5M hello_world_1.exe (Windows_NT i686) 589K hello_world_1.exe (VMS AXP)
值得一提的是,使用 GNAT/MSVC 7.1/GCC(C) 編譯的 hello_world(Ada、C、C++)在給定可比的最佳化和連結器方法的情況下,都產生大小大致相同的可執行檔案。
準備好識別 Ada 的一些重要特性,這些特性對於學習其語法和語義至關重要,將會有所幫助。
在所有控制結構和模組結構中都存在一種梳狀格式。請參閱以下示例以瞭解梳狀格式。您不必理解這些示例的作用 - 只需查詢佈局中的相似之處即可。
ifBoolean expressionthenstatementselsifBoolean expressionthenstatementselsestatementsendif;
whileBoolean expressionloopstatementsendloop;
forvariableinrangeloopstatementsendloop;
declaredeclarationsbeginstatementsexceptionhandlersend;
procedureP (parameters :inouttype)isdeclarationsbeginstatementsexceptionhandlersendP;
functionF (parameters :intype)returntypeisdeclarationsbeginstatementsexceptionhandlersendF;
packagePisdeclarationsprivatedeclarationsendP;
genericdeclarationspackagePisdeclarationsprivatedeclarationsendP;
genericdeclarationsprocedureP (parameters :inouttype);
請注意,分號始終用於終止語句和宣告;空行(或單獨的分號)不是有效的語句:空語句是
null;
型別和子型別之間存在重要的區別:型別由一組值及其操作給出。子型別由型別和一個約束給出,該約束限制了值集。值始終屬於一種型別。物件(常量和變數)屬於子型別。這概括、澄清並系統化了一種關係,例如Integer 和 1..100 之間的關係,這種關係在Pascal 的語義中是特殊處理的。
約束型別和無約束型別之間存在重要的區別。無約束型別具有一種或多種自由引數,這些引數會影響其大小或形狀。約束型別固定了這些引數的值,因此確定了其大小和形狀。簡單來說,物件必須屬於約束型別,但形式引數可以是無約束型別(它們採用任何相應實際引數的約束)。這解決了 Pascal 中陣列引數的問題(以及其他問題)。
在Pascal 或C 中的值必須是靜態的(例如,陣列的下標邊界),但在 Ada 中它們可以是動態的。但是,在動態求值無法允許合理實現的某些情況下(例如,在設定浮點型別的精度位數時),需要靜態表示式。
Ada 一直支援介面和機制的分離。您可以在包的格式中看到這一點,它將包的宣告與其主體分開;以及在私有型別的概念中,其在 Ada 資料結構方面的表示在包含其定義的作用域之外是不可訪問的。
大多數 Ada 專家潛伏在Usenet 新聞組 comp.lang.ada(英語)和fr.comp.lang.ada(法語)中;可以使用新聞閱讀器或透過眾多網路介面中的一個來訪問它們。這是所有與 Ada 相關問題的地方。
這些新聞組中的人願意提供幫助,但不會為學生完成作業;他們不會發布作業的完整答案。相反,他們會為學生提供指導,讓他們自己找到答案。
有關更多線上資源,請參閱本華夏公益教科書介紹中的外部連結部分。
