發信人: jinna.bbs@csie.nctu.edu.tw (吉娜), 看板: mud
標  題: lpc (1) -- 自由軟體
發信站: 交大資工鳳凰城資訊站 (Fri May 24 19:57:02 1996)
轉信站: cyeebbs1!sunss105.cc.cycu!news.ncu!news.cc.nctu!news.csie.nctu!phoenix

1996年1月4日
                             LPC Basics
                     Written by Descartes of Borg
                            23 april 1993


                            介紹
               如何使用本手冊與本手冊內容簡介

    我最近看過很多人在 USENET 上要求 LPC 手冊. 此外, 在我的 MUD 上的巫師們
也都在抱怨沒有 LPC 的說明手冊的缺憾. 所以我決定親自寫有關 LPC 的手冊. 在進
一步閱讀之前, 你心裡最好有一個底: LPC 是非常容易學的語言, 而且也確實也有它存在
的重要性. 我是在 1991 年開始玩 MUD 的,在一個月的時間裡, created an unimpressive
area
and musician's guild on the original Bates College MUD called Orlith.
之後, 我搬去洛山磯一年內都沒有接觸到 MUD 或者任何電腦. 大約在 1992 年六月
我回到網際網路的世界, 而且當 Igor 的巫師. 同年九月, 我開始寫 Nightmare 來
自己用, 後來決定把它公開是.




                               LPC Basics
                     Written by Descartes of Borg
                            23 april 1993

                          Translated by Hanzo


                        第二章  LPC 的資料種類

    現在, 你應該了解在 LPC 之中的物件 (objesct) 是由函式 (function)
  所組成. 而且那些函式放置的順序是無所謂的. 遊戲本身使用那些物件的方
  法是把那些物件檔案讀進記憶體, 需要用到時再呼叫 (call) 那些函式.
  如果你沒有任何程式設計的經驗, 你可以不知道函式是甚麼, 或者什麼叫做
  呼叫一個函式. 即使是有程式設計經驗的人, 你也會對一個新加入的物件中
  的函式如何被遊戲呼叫感到詫異. 在回答這些問題以前, 你需要知道資料種
  類的概念. 這是最無聊但也是最關鍵性的題目. 有 90% 的錯誤 (除了 {}
  () :) 放錯位子之外) 跟不瞭解 LPC 資料種類有關. 所以忍受這章無聊的
  課題, 因為一旦你瞭解了, 你會發現程式寫起來容易得多了.

    你可能已經知道電腦看不懂人類使用的文字和數字. 電腦只知道簡單的零
  與一. 為了要執行你寫程式的目標, 那些指令必須從文字數字改成零與一.

    不論你使用任何語言, 你會有變數 (variable) 可以操作. 那些變數在記
  憶體中儲存資料 (data). 例如: 有個變數 x, 在程式中你可以使用敘述
  (statement) 像
     x = 65
  來設定一個值給 x. 設定了 x 的值之後, 你可以把 x 的值顯示在銀幕上:
     write(x+"\n");   (附注: \n 是一個換行的符號)
  或者可以設定值給其他的變數:
     y = x + 5;
  但是問題是電腦不知道 65 是什麼, 對電腦而言, 二進位的 65 是:
     00000000000000000000000001000001
  可是電腦中 "A" 的預設值也是:
     00000000000000000000000001000001
  所以當你告訴電腦 write(x+"\n"); 之時, 必須告訴電腦你要的到底是 65
  還是 "A".

  這就是資料的種類. 在 LPC 中, 以上的例子需要先行被定義, 像:
     int x;
  這就告訴了電腦有關資料的種類, 所以在以上的例子中, x 就是 65 而不是
  其它種類的資料.

    剛剛提到的就是很基本的普通資料種類. 這一章的目的是要介紹 LPC 的資
  料種類. 大致來說, 資料種類是遊戲的執行程式 (driver) 用來決定一個值
  在記憶體中使用及存在的方式.

    所有的 LPMud 執行程式包含以下的資料種類:
  int , string, object, int *, string *, mixed *, void
    有的執行程式有下列的資料種類:
  float, mapping, float *, mapping *, function, enum, struct, char

  基本的資料種類:
    最基本的資料種類是常見的 void. void 沒有任何種類的值. 以 LPC 代號
  的觀點來看, 最基本的兩種資料種類是 int 跟 string.  int 是整數, 例如:
  1, 17, -42, 0, -10000023 都是 int.  string 是一個或多個文字. 例如:
  "a", "We are borg", "-42", "This is a string" 都是 string. string
  一定要被放在 "" 之間. 所以執行程式在碰到 -42 和 "-42" 時, 可以分辨
  它們的不同之處, 就像 x 是一個變數, "x" 是一個文字一般.

    當你決定要使用一個變數之時, 在執行任何步驟之前, 必須讓執行程式知道
  此變數是屬於何種資料種類, 然後才能被正確的使用和執行. 如何讓執行程式
  知道變數的資料種類呢? 只需要把資料種類放在變數之前即可. 這個步驟稱為
  "變數宣告" (declaring the variable). 例如:

  void add_two_and_two()
  {
    int x;
    int y;

    x = 2;
    y = x + x;
  }

    在函式的開頭, 你就告訴值行程式有兩個整數的變數. 宣告的重要性不只是
  讓執行程式知道如何使用那些值, 而且也可以幫助執行程式更有效的使用記憶
  體. 宣告之後, 執行程式就準備足夠的記憶體來儲存 int, 但是卻不夠儲存像
  string, obj 的資料 (因為它們需要較大的記憶體空間). 當執行程式把記憶
  體預留好以及知道如何操作之後, 就可以直接用代號來使用.

    我們現在只說明 int, string, void 三種, 把其它的資料種類留到以後再
  詳加說明.

  結論:
    執行程式需要知道每一個變數的種類以及如何操作它們的值. 最簡單的 lpc
  資料種類是 int, void, string. 變數種類不能是 void(有 mixed 可以讓驅
  動程式不檢查型態) 只有的函式可以是 void. 因為不同種類的變數需要不同
  大小的記憶體空間, 以及不同的操作方式 (例如: +,-,*,/ ...) , 因此對執
  行程式而言有不同的意義. 例如:  5+5, 執行程式知道這是加法的操作, 所以
  你得到 10. 如果你打 "a"+"b",執行程式知道這是連接兩個文字串, 所以你會
  得到 "ab". 但是若資料種類不對, 極有可能得到錯誤的結果. 例如: "5"+5,
  執行程式會把它當成都是文字串來相連, 所以你的到的結果是: "55". 如果你
  本來所要的答案是 10, 那你就得到了錯誤的答案了.


                        LPC Basics
                Written by Descrates of Borg
                        23 April 1993
                     Translated by Hanzo

                第三章  函數 (Functions)

          現在，你知道物件 (objects) 是由函數所組成。物件與遊戲的
        其他部份以呼叫函數 (call function) 的方式互動。你也知道變
        數 (Variables) 與其最基本的三種LPC資料型態 void, int 與
        string。若你不完全了解這些，你需要複習第一章和第二章。

          LPC 的函數就像數學的函數一樣，需要輸入值與輸出計算結果。
        有些語言像 Pascal 的程序 (procedure) 和函數 (function)的構

        想 (concept)是不同的，但是在 LPC 中是沒有分別的。在 Pascal
        中稱為程序 (procedure)，在 LPC 中稱為 type void 的函數 (a
        function of type void)。這是指一個函數不會輸出一的有用的值。
        最平常的函數像以下的例子:

        void do_nothing() { }

        這個函數沒有輸入值，不執行指令，也沒有輸出任何有效值。


        有效的函數必須包含三個部份:

        (1) 宣告 (the declaration)
        (2) 定義 (the definition)
        (3) 呼叫 (the call)

        函數與變數相同，都必須做宣告 (declare)。宣告可以使驅動程式知
        道幾件事: (1)此函數將會傳回 (return) 何種函數資料。 (2)有幾
        個輸入值以及它們的種類。
        更為常用的函數輸入值稱為"參數" (parameter) 。而從現在起，所
        有的函數輸入值將被稱為函數之參數。

        定義 (definition) 是一個能告訴驅動程式這個被定義的函數將如何
        處理它的輸入值的代號。

        呼叫 (call) 是從別的程式輸入一個代號來使用一個已定義的完整函
        數。

        以下是一個函數的例子:

        void write_vals();       /* 這通常是宣告 */
        int add(int x, int y);   /* 開始輸入物件的代號 */

        void write_vals() {      /* 這個函數的定義 */
            int x;               /* write_vals().  寫入 x 的值 */

            x = add(2, 2);       /* 呼叫 add(). 送出 add() 函數所
                                        需的輸入值 */
            write(x+"\n");       /* 傳回變數 x 的值 */
        }

        int add(int x, int y) {  /* add() 的定義，需要兩個整數輸
                                        入值 */
            return x + y;        /* 把執行的結果傳回呼叫此函數的
                                        函數 */
        }

        函數呼叫的順序和代號的排列順並不需要一致，但是函數的宣告必
        須放在此函數的定義之前而且必須放在每一個呼叫此函數的函數之
        前。

        現在你應該成功的了解一個函數的組成結構了。了解你要呼叫的函
        數的傳回資料的種類是十分重要的。如果你把一個函數的傳回的文
        字資料指定到一個並宣告為整數的變數，最後得到的一定是錯誤的
        執行結果。你曾注意到一些你以前看不懂的代號是函數嗎？例如:
        this_player(), write(), say(), this_object() 等.
        事實上，在上面提到的 write_val() 函數中，包函兩個"呼叫"。
        第一個是由你自己定義的 add() 。第二的是由驅動程式定義的
        write()。驅動程式 (driver)已經替你將 write() 宣告和定義完
        畢。你只須要呼叫它出來用即可。此類的函數稱為 efuns，efuns
        是 everywhere function 的縮寫。efuns 定義在遊戲驅動程式的
        C 之中。因為如此，所以呼叫 efuns 比呼叫設計者自行創造的函
        數要快一些，而且呼叫的方式計完全相同。但在使用 efuns 之前
        必須注意兩件事:
        (1)efuns 函數的傳回資料的種類 (2)efuns 函數所需要的參數。
        大部份的 mud都會有以下的其中之一:
          最常見: 在叫做 /doc/efun 的子目錄中。在其中宣告和描述放
        在此目錄中的 efuns。
          此外: 一個叫 man 或 help 的指令可供使用。若你鍵入 man
        write 或 help write，就可以得到在 /doc/efun 中的資料。
        你可以看到 write() 函數如下:

        void write(string|int)

        這表示一個正確的呼叫 write() 沒有傳回資料，而需要一個字串
        或是整數當作輸入值。

        在函數中，定義的說明放置的順序是非常重要的。例如在以上的
        write_vals() 的函數中，若想得到正確的 write() 輸出值，那個
        把 add() 傳回資料指定到 x 的說明必須放在呼叫 write() 的說
        明之前。換而言之，雖然函數可以不同置於檔案之中。但是在函數
        的定義中，定義的說明必須按照它們被執行的先後順序放置。

        最後還有一點補充是有關於傳回資料的。把資料傳回到一個函數的
        簡單方法是在欲執行的函數中加入此說明:
                return value;
        其中的 value 是指一個能夠符合此函數宣告之任何型態的變數或
        常數。

        總結:
        LPC 的物件檔案是由許多函數所組成。而函數是由三部份組成: (1)
        宣告 (2) 定義 (3) 呼叫。函數的定義可以用任何方式出現在物件檔
        案之中除了你不能把這個函數定義在別的函數之中。函數的宣告必須
        出現在函數的定義和任何對此函數的呼叫之前。每次需要用到一個函
        數之時，可用呼叫的方式來執行那個函數。函數的定義是由一系列有
        順序的代號 (code) 所組成，順序如下:
        (1) 函數的送回資料型態。
        (2) 函數的名字。
        (3) 參數列。
        (4) 一個開始的符號 "{" 表示所有的指令從此符號之後開始。
        (5) 說明、表示和呼叫其他的函數。
        (6) 一個結束的符號 "}" 表示所有的指令從此符號之後結束。

        以下是一個簡單而完整的函數的例子:
        void do_nothing() { }
        說明 (instruction) : 指示驅動程式要做的事。
        表示 (expression)  : 有關於數值的說明，像 "a==b"
        呼叫 (call)        : 所有的函數呼叫的順序必須符合你所要執行
                             的順序。

        每一個遊戲的驅動程式中，都有一些預先設定好的函數稱為 efuns。
        你可以在大部份的 mud 的 /doc/efun 目錄中找到詳細資料。有的
        mud 站有特別的巫師 help 或 man 指令供線上查詢使用。使用這些
        efuns 必須遵守已經被定義在 efuns 中的方式。例如參數的數量和
        形態或傳回資料的形態等等。

        注意:
        有的 mud 驅動程式不要求作函數的宣告。有些甚至不需要你指定函
        數的傳回資料形態。但不論如何，想要省略宣告或傳回資料形態的定
        義是不明智的。因為:
        (1) 方便別人(包括你自己在內)讀你寫的函數。
        (2) 容易找到在你的程式中，有由於資料形態不符造成的錯誤。
        (3) 這是公認的一種好的函數寫作方式。

        另外，efuns 在各個驅動程式中的設定大致相同。另外，還有類似的
        函數群稱為 simul efuns (simulated efuns)。simul efuns 就會隨
        著 mudlib 的不同而不同。simul efuns 是被定義在 LPC 中的特殊物
        件稱為 simul_efun.c 的檔案中。每個好的 mudlib 對其 simul_funs
        都會有充份的說明文件。有的 mud 會將部份的 efuns 從驅動程式中
        搬到 mudlib 中而變成 simul_efuns。但對一個程式設計者而言並沒
        有差異。我之所以特別指出這點是因為有的人在他 mud 站的 efun
        中找不到 write() 而是在 simul_efun 之中。若一切正常，write()
        在大部份的 mud 中將是一個 simul_efun。

--
