歡迎訪問 Forcal程序設計

FORCAL32W.DLL V9.0 用戶指南

目  錄  [頁首]

簡單的例子
標識符
表達式和數據
常量和變量
賦值語句
算術運算符
關系運算符和邏輯運算符
逗號(冒號、分號)運算符和括號運算符
運算符及優先級
10 函數概述
11 函數的傳值調用和傳址調用
12 用表達式作為函數的參數
13 表達式的初始化及銷毀
14 表達式的完整定義及表達式句柄
15 流程控制

16 字符串
17 靜態數組
18 遞歸調用
19 模塊化編譯
20 模塊命名空間

21 二級函數命名空間
22 常量命名空間
23 訪問命名空間
24 類成員運算符(函數參數運算符)及對象賦值運算符

25 標識符解釋規則
26 二級函數
27 關鍵字
28 指針
29 運算符及函數重載
30 動態內存管理
31 錯誤處理
32
效率
33 主要技術指標

正文

1 簡單的例子  [返回頁首] [返回目錄]

      F(x,y)=x+y;       //函數定義;
     
2+F[2,3]+5;       //簡單的計算式;

    在這個例子中,分號表示一個表達式的結束,兩個反斜杠//后的內容表示注釋,本文中將一直采用這種表示和注釋方法。
    在第一個表達式中定義了一個函數 F ,小括號( )內的x,y為函數的自變量,等號后為函數體,即可執行的部分,該函數計算并返回兩個參數的和。在第二個表達式中調用了上面定義的函數 F 。
    需要注意,在一般的Forcal程序中,只計算無自變量的表達式。因此,對第一個表達式只編譯,不計算。

2 標識符  [返回頁首] [返回目錄]

    在FORCAL中,一個標識符可以用來表示一個表達式的名字,或者是一個函數的名字,或者是一個變量,或者是一個符號常量。標識符可由一個或多個字符組成,可以任意一個英文字母 、中文字符或者下劃線開頭,后面可以接英文字母、中文字符、數字或者下劃線(下劃線的使用可以增加標識符的可讀性,如first_name)。注意:英文字母的大寫和小寫是不同的,例如:count和COUNT是兩個不同的名字。下面給出一些合法的標識符:

      first    last    Addr1    top  _of_file    name23    _temp    a23e3    MyVar    您好    數1    My數

3 表達式和數據  [返回頁首] [返回目錄]

    表達式是FORCAL的編譯單元,如果沒有語法錯誤,編譯后將生成可執行的代碼。FORCAL表達式可以很簡單,例如只有一個數字;FORCAL表達式也可以很復雜,例如是一段復雜的程序。
    以下是一些簡單的表達式的例子:

      2;
      2+3;
      2+sin(3)-ln[6];

    可以給表達式起一個名字,這樣做的好處是:以后可以用函數調用的方式通過該名字調用該表達式。表達式的名字是一個標識符,必須位于表達式的開頭。例如,上面三個表達式可按如下方式定義:

      A()=2;
      B()=2+3;
      C()=2+sin(3)-ln[6];

    表達式定義的一般形式是:

      Name(a,b)={a=a+2,b=10:a+b}

    其中 Name 為表達式的名字,不可與其它已經定義的表達式名字相同,但可以缺省;如果定義了表達式名字,表達式名字后必須跟一對小括號(只能用小括號),用來定義自變量,自變量個數可以為零,也可以有任意多個,有多個自變量時,自變量間以逗號分隔;如果用小括號定義了自變量,小括號后必須跟一個等號,該等號標志表達式可執行部分的開始,等號及等號后的可執行部分均不可缺省。表達式的可執行部分由多個語句組成,多個語句之間用逗號 或冒號分隔,表達式總是返回最后一個語句的值;另外花括號不是必須的,但有了花括號后,表達式更易讀。

    用這種方式定義表達式時,實際上就是自定義了一個函數,可以在任意的表達式中使用該函數(只要給該函數起了名字),由于這個原因,我們常常將表達式說成是函數,或者說表達式就是一個函數,但反過來并不成立。
    下面是一個函數定義及使用的例子。

      相加(加數1,加數2)=加數1+加數2;    //函數定義;
      2+相加[2,3]+5;      
             //函數調用;

    以下是一些合法的表達式例子:

      2;            //常量(無參)表達式(函數);
      ()=2;         //常量(無參)表達式(函數);
      A()=2;        //常量(無參)表達式(函數),但定義了函數名字,在其它表達式中可以調用該函數;
      B(x)=2;       //有一個自變量的表達式(函數);
      C(x,y)=x+y;   //有二個自變量的表達式(函數);

    下面說一下表達式的類型和數據的類型,FORCAL表達式有三種類型:整數表達式、實數表達式和復數表達式;相應地,FORCAL中有三種基本的數據類型:整數、實數和復數。例如:

      i:2+3;    //整數表達式,在一般的Forcal程序中,整數表達式以i:開頭;
      r:2.2+3;  //實數表達式,在一般的Forcal程序中,實數表達式以r:開頭;
      c:2+3i;   //復數表達式,在一般的Forcal程序中,復數表達式以c:開頭;
      3.2+3;    //實數表達式,在一般的Forcal程序中, 缺省是實數表達式;

    FORCAL編譯器在編譯表達式時,將整數表達式中的數據都轉換成整數(64位有符號整數,范圍從-9223372036854775808~9223372036854775807);將實數表達式中的數據都轉換成實數 (64位雙精度實數,范圍大致從±1.7E-308±1.7E+308);將復數表達式中的數據都轉換成復數 (128位雙精度復數,復數的實部和虛部都是64位雙精度實數,范圍大致從±1.7E-308±1.7E+308),如果數字后有i,表示一個虛數。

    在FORCAL實數或復數表達式中,數字可以帶小數點,也可以不帶小數點,還可以用科學記數法表示數字。小數的表示非常靈活,小數點前面的零或后面的零可省,例如:5.6、5.、.6都是合法的數據表示。用科學記數法表示的數字,例如:10.3E8、2E-10等,其中用E表示以10為底的指數部分,但指數不能為小數,例如:3E5.6、8.6E-6.7不合法。

    在FORCAL整數表達式中,數字既可以是10進制數,也可以是16進制數,但數字中不能包含小數點,也不能用科學記數法表示數字。16進制整數以0x開頭,并用A~F表示10~16,例如:0x1A、0xB、0x123D等。

4 常量和變量  [返回頁首] [返回目錄]

    常量是指那些不需要程序計算的固定值。有數值常量和符號常量兩種。如100就是一個數值常量。在FORCAL中,也可以用標識符表示一個符號常量 。用函數const可以定義一個永久性符號常量或暫時性符號常量,但只有const函數被執行后,定義的常量才會起作用。如下例:

      const("aa",111);      //定義永久性常量,不可刪除
      const("bb",222,1);   
//定義暫時性常量,可以刪除

    編譯運行以上表達式,然后輸入下例代碼并執行:

      aa;                   //aa=111
      bb;                  
//bb=222
      const("aa",0,0);     
//試圖刪除永久性常量,但失敗了
      const("bb",0,0);      //刪除暫時性常量

    有些軟件會利用Forcal的輸出函數定義一些符號常量,但在這里無法給出具體的例子。

    變量是指在程序運行時,其值可以改變的量。FORCAL有五種變量,即:自變量、動態變量、靜態變量、模塊變量和全局變量。自變量、動態變量和靜態變量只能被定義該變量的表達式所訪問;模塊變量可被同一模塊的所有表達式所訪問,其他模塊的表達式無法訪問;全局變量可被所有的表達式所訪問。自變量用于向表達式傳遞參數 ,因此自變量也稱為形式參數。動態變量只在表達式執行時起作用,一旦表達式執行完畢,動態變量也隨之失效。靜態變量存在于表達式的整個生命周期,每次表達式執行完畢,靜態變量的值被保留。FORCAL在編譯表達式時,將所有靜態變量初始化為0,其余的變量均不進行初始化。

    如果表達式中的變量名與一個常量名相同,則常量名被忽略。

    在FORCAL表達式中,通常情況下,變量要先定義后使用,變量在表達式的開頭進行定義,格式如下:

      F(a,b:x,y,static,u:s,t,common,v)=
      {x=1,y=2,
       a+b+x+y+static+u+s+t+common+v
      }

    F是表達式的名字,a和b是自變量,x和y是動態變量,static和u是靜態變量,s和t是模塊變量,common和v是全局變量。自變量、動態變量和靜態變量以及模塊變量和全局變量之間用冒號分隔 ,即第一個冒號前為自變量,兩個冒號之間為動態變量和靜態變量,第二個冒號后為模塊變量和全局變量。兩個冒號之間用關鍵字static分隔動態變量和靜態變量,static之前為動態變量,static及以后變量均為靜態變量,關鍵字static只 能用在兩個冒號之間。第二個冒號后用關鍵字common分隔模塊變量和全局變量,common之前為模塊變量,common及以后變量均為全局變量,關鍵字common只能用在第二個冒號后。FORCAL中的所有變量均可缺省。以下都是合法的變量定義的例子:

      F()= ... ...          //沒有使用任何變量,稱無參表達式;
      F(::)= ... ...        //沒有使用任何變量,稱無參表達式;
      F(a,b)= ... ...       //定義了兩個自變量a和b;
      F(:x,y)= ... ...      //定義了兩個動態變量x和y;
      F(:static,u)= ... ... //定義了兩個靜態變量static和u;
      F(::s,t)= ... ...     //定義了兩個模塊變量s和t;
      F(::common,v)= ... ...//定義了兩個全局變量common和v;
      F(a,b:x,y)= ... ...   //定義了兩個自變量a和b,兩個動態變量x和y;
      F(a,b::s,t)= ... ...  //定義了兩個自變量a和b,兩個模塊變量s和t;
      F(:x,y:s,t)= ... ...  //定義了兩個動態變量x和y,兩個模塊變量s和t;

    變量的使用見下面的例子:

      F(a,b:x,y,static,u:s,t,common,v)={a=1,b=2,x=3,y=4,static=5,u=6,s=7,t=8,common=9,v=10};//函數定義及變量賦值;
      A(a,b:x,y,static,u:s,t,common,v)=a;//函數定義;
      B(a,b:x,y,static,u:s,t,common,v)=b;//函數定義;
      X(a,b:x,y,static,u:s,t,common,v)=x;//函數定義;
      Y(a,b:x,y,static,u:s,t,common,v)=y;//函數定義;
      _S(a,b:x,y,static,u:s,t,common,v)=static;//函數定義;
      U(a,b:x,y,static,u:s,t,common,v)=u;//函數定義;
      S(a,b:x,y,static,u:s,t,common,v)=s;//函數定義;
      T(a,b:x,y,static,u:s,t,common,v)=t;//函數定義;
      _C(a,b:x,y,static,u:s,t,common,v)=common;//函數定義;
      V(a,b:x,y,static,u:s,t,common,v)=v;//函數定義;
      F(11,22);//函數調用,進行變量賦值 ,返回值=10;
      A(11,22);//函數調用,返回值=11;
      B(11,22);//函數調用,返回值=22;
      X(11,22);//函數調用,返回值=隨機數值;
      Y(11,22);//函數調用,返回值=隨機數值;
      _S(11,22);//函數調用,返回值=0;
      U(11,22);//函數調用,返回值=0;
      S(11,22);//函數調用,返回值=7;
      T(11,22);//函數調用,返回值=8;
      _C(11,22);//函數調用,返回值=9;
      V(11,22);//函數調用,返回值=10;

    可以在FORCAL表達式使用未定義的模塊變量。在MForcal(MForcal是一個Forcal擴展動態庫,可對源代碼進行模塊化編譯)中,可使用編譯符mvar:通知編譯器使用未定義的模塊變量,使用編譯符unmvar:通知編譯器取消這種設置,格式如下:

      mvar:        //通知編譯器使用未定義的模塊變量
      s,t,u=5,v=6; //如果不存在同名的常量,就解釋為模塊變量
      s=1, 2+s+u;  //可以正確編譯,返回值=8
      unmvar: 
    //通知編譯器取消使用未定義的模塊變量
      2+s+u;       //編譯出錯,變量不可識別

    若要確保編譯器將未定義的標識符解釋為模塊變量,則應在前面編譯的表達式中,將該標識符明確地定義為模塊變量并至少使用一次,如下例:

      !const["v",66,1];  //創建一個常量v=66
      v;                 //v為常量,返回值=66
      mvar:              //通知編譯器使用未定義的模塊變量
      (::s,t,u,v)= s,t,u=5,v=6;
//將s,t,u,v定義為模塊變量并至少使用一次
      s=1, 2+s+u;        //s,u將解釋為模塊變量,返回值=8
      v;  
              //v將解釋為模塊變量,返回值=6

5 賦值語句  [返回頁首] [返回目錄]

    賦值語句的作用是將一個值賦給一個變量。在FORCAL中,可以用等號對變量進行賦值。例如:

      F(x)= x=5;   //函數定義,將數值5賦給變量x;
      F[2];        //函數調用,返回值為5;

    上面進行變量賦值的例子很簡單,但等號后部分可以是任意復雜的表達式。

    對象及對象成員的賦值用“.=”并最終通過函數實現,參考:類成員運算符(函數參數運算符 )及對象賦值運算符

6 算術運算符  [返回頁首] [返回目錄]

    FORCAL中共有八個算術運算符,即:+(加或正)、-(減或負)、*(乘)、/(除)、%(求模)、^(乘方)、++(自增)、--(自減)。 其中%(求模)僅在整數表達式中使用;^(乘方)僅在實數和復數表達式中使用。
    運算符*、/、%和^是雙目運算符。注意數字與變量相乘時,乘號不可省略;在進行乘方運算時,底數應為非負數 。
    運算符+、-作加、減運算時,是二元運算符,當作正、負運算時,是單目運算符。
    運算符++、--是單目運算符,僅能對變量使用。++使變量的值加1,如果++在變量之前,那么運算符在程序語句訪問該值之前執行加法運算,這時的++運算符稱為“前置自增運算符”;如果把該運算符放在變量之后,那么運算符在程序語句訪問該值之后執行加法運算,這時的++運算符被稱為“后置自增運算符”。--使變量的值減1,如果--在變量之前,那么運算符在程序語句訪問該值之前執行減法運算,這時的--運算符稱為“前置自減運算符”;如果把該運算符放在變量之后,那么運算符在程序語句訪問該值之后執行減法運算,這時的--運算符被稱為“后置自減運算符”。例如:

      (:x)= x=2,++x;    //返回值為3;
      (:x)= x=2,++x,x;  //返回值為3;
      (:x)= x=2,x++;    //返回值為2;
      (:x)= x=2,x++,x;  //返回值為3;
      (:x)= x=2,--x;    //返回值為1;
      (:x)= x=2,--x,x;  //返回值為1;
      (:x)= x=2,x--;    //返回值為2;
      (:x)= x=2,x--,x;  //返回值為1;

    如果在復數表達式中使用自增減運算符,則僅對復數的實部作運算,復數的虛部保持不變。例如:

      c:(:x)= x=2+3i,++x;  //返回值為3+3i;
      c:(:x)= x=2+3i,--x;  //返回值為1+3i;

    單目運算符的優先級比雙目運算符的優先級高,后置單目運算符的優先級比前置單目運算符的優先級高。對于同一優先級的運算,按從左到右的優先順序進行。

    注意:單目運算符-(負) 與雙目運算符^(乘方)需用括號區分計算的先后順序。例如:

      (-2)^2;      //返回值為4;
      -(2^2);      //返回值為-4;
      -2^2;        //編譯出錯;
      -(2+3)^2;    //編譯出錯;
      -sin(2+3)^2; //編譯出錯;

    算術運算符的優先級如表6-1所示。在表中,同一行中運算符優先級相同,不同行中運算符的優先級從上往下依次降低。

表6-1:算術運算符及優先級

運 算 符

說  明

++、-- 后置單目運算符,自增減運算符
+、-、++、-- 前置單目運算符,“++、--”為自增減運算符
^ 乘方
*、/、% 乘、除、求模
+、- 加、減

7 關系運算符和邏輯運算符  [返回頁首] [返回目錄]

    關系運算是對兩個值的大小進行比較,返回一個邏輯值。邏輯值只有兩個:邏輯真和邏輯假。在FORCAL中用0表示邏輯假,其他任何非0值表示邏輯真。例如:

      3>2;       //返回邏輯真;
      2>3;       //返回邏輯假;

    關系運算符共有6個:>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、==(等于)、!=(不等于)。

    邏輯值之間的運算稱邏輯運算,邏輯運算的結果仍然是一個邏輯值。有三個邏輯運算符:&(邏輯與)、|(邏輯或)、!(邏輯非)。通過表7-1給出的真值表可以掌握這三種運算。表中用1代表邏輯真,0代表邏輯假。

表7-1 真值表

p q p&q p|q !p
0 0 0 0 1
0 1 0 1 1
1 1 1 1 0
1 0 0 1 0

    在FORCAL中,僅使用復數的實部表示邏輯值,邏輯值的虛部沒有任何意義。所以,如果在復數表達式中使用關系運算符或邏輯運算符,則僅取復數的實部作運算,復數的虛部對運算結果沒有任何影響;在運算結果中,僅復數的實部有意義,虛部沒有意義,但其值為參與運算的第一個參數的虛部值。例如:

      c:2+3i>5+6i;    //返回值為0+3i;
      c:!(2+3i);     
//返回值為0+3i;
      c:2+3i==2+6i;  
//返回值為1+3i;
     
c:2+3i!=2+6i;   //返回值為0+3i;

    FORCAL的這種規定使得不能直接用==、!=運算符對兩個復數作相等或不等的比較。如果要比較兩個復數相等或者不等,應對復數的實部和虛部都進行比較,見下面的例子。

      c:(:a,b)= a=2+3i,b=2+3i,a==b&xy(a)==xy(b);     //返回值為1+3i;
      c:(:a,b)= a=2+3i,b=2+5i,a==b&xy(a)==xy(b);     //返回值為0+3i;

    在上面的例子中,xy(a)是一個復數函數,該函數用于交換復數a的實部和虛部。

    關系運算符和邏輯運算符的優先級如表7-2所示。在表中,同一行中運算符優先級相同,不同行中運算符的優先級從上往下依次降低。

表7-2 關系運算符和邏輯運算符及優先級

運 算 符

說  明

! 邏輯非
>、>=、<、<=、==、!= 關系運算符
& 邏輯與
| 邏輯或

8 逗號(冒號、分號)運算符和括號運算符  [返回頁首] [返回目錄]

    表達式中如果有多個語句,可以用逗號、冒號或分號進行分隔,FORCAL將按從左到右的順序計算各個語句,并返回最后一個語句的值。也可以將多個用逗號 、冒號 或分號分隔的語句放在一個括號內,FORCAL也將按從左到右的順序計算各個語句,并返回最后一個語句的值。例如:

      (:x)= x=2,x=5,x;                          //返回值為5;
      (:x)={x=2,x=5,x};                        
//返回值為5;
      (:x,y)={x=2,y=5,x=[x=x+1,y=y+1,x+y]:x};  
//返回值為9;
      (:x,y)={x=2,y=5,[x=x+1,y=y+1:x+y]};      
//返回值為9;

    雖然逗號、冒號或分號運算符是通用的,但逗號的用法很常見。冒號和分號運算符僅用在一些特殊場合,例如分隔一些不同類別的變量。本文中除了對冒號和分號運算符進行說明外,只使用逗號運算符。

    注意:一般表達式之間用分號進行分隔,故分號運算符必須放到括號內才有效。另外,不是所有的Forcal程序都支持分號運算符。由模塊化編譯運行庫MForcal支持的程序都支持分號運算符,如下例:

      (:x,y)={x=2,y=5;x=[x=x+1,y=y+1;x+y]:x};   //返回值為9;
      (:x,y)={x=2,y=5,[x=x+1;y=y+1:x+y]};      
//返回值為9;

9 運算符及優先級  [返回頁首] [返回目錄]

    FORCAL中的運算符及優先級如表9-1所示,在表中,同一行中運算符優先級相同,不同行中運算符的優先級從上往下依次降低。

表9-1:FORCAL運算符及優先級

運 算 符

說  明

:= 括號連接運算符,冒號前和等號后都必須是括號
( )=、[ ]=、{ }= 括號連接運算符,等號后是一個表達式
( )、[ ]、{ } 括號運算符
:: 命名空間成員訪問符
. 類成員運算符(函數參數運算符) 、變量函數調用運算符
++、-- 后置單目運算符(自增、自減)
!、+、-、++、-- 前置單目運算符(非、正、負、自增、自減)
^ 算術運算符(乘方)
*、/、% 算術運算符(乘、除、求模)
+、- 算術運算符(加、減)
>、>=、<、<=、==、!= 關系運算符(大于、大于等于、小于、小于等于、等于、不等于)
& 邏輯與
| 邏輯或
= 賦值運算符
.= 變量函數調用運算符與賦值運算符的結合,一般用于對象賦值
,、:、; 逗號、冒號、分號運算符

    括號連接運算符應用舉例:

      (1,2):=[6,5] 等價于 (1,2,6,5) 或者 [1,2,6,5]

      (1,2)=[6,5]  等價于 (1,2,[6,5])

      (1,2)=5      等價于 (1,2,5)

    括號連接運算符常用在函數調用中,例如有對數組操作的函數A,可接受變參數,使用格式如下:

      A[me,i]    //獲得數組me的第i個單元的值
      A[me,i,t]  //設置數組me的第i個單元的值為t

    將數組me的第i個單元的值加2,用函數可表示為:

      A[me,i,A(me,i)+2]

    用括號連接運算符可表示為:

      A[me,i]:=[A(me,i)+2] 或者 A[me,i]=A(me,i)+2

    再如有對對象操作的函數B,使用格式如下:

      B[me,t0,t1,...,tn]    //將對象me的值設置為t0,t1,...,tn

    用括號連接運算符可表示為:

      B[me]:=[t0,t1,...,tn]

    注意在FORCAL中,通常運算符不能連用,例如 !-2 是錯誤的,應當添加括號分隔開各個運算符,即應當寫成 !(-2) 形式。

    還有一個FORCAL運算符在表9-1中沒有列出:&(取變量的地址)。取地址運算符&只能用于(被逗號或冒號隔開的)單獨的變量,與其他運算符不發生任何關系,所以這個運算符在表9-1中沒有列出,其用法我們將在下面詳細介紹。

    類成員運算符(函數參數運算符)“.”、對象賦值運算符“.=”及命名空間成員訪問符“::”也將在下面詳細介紹。

10 函數概述  [返回頁首] [返回目錄]

    函數是FORCAL的構成模塊,是FORCAL最為重要的特性。一個函數,通過傳遞給它的參數完成一個特定的功能。通常函數都有一個名字,可通過調用函數名并傳遞參數來使用函數。所有的函數都將返回一個函數值。典型的函數調用方法如下:

      函數名(參數1,參數2,... ...)

    函數可以有零個或多個參數,但即便有零個參數,函數名后的括號也不能缺省。函數調用時,參數一定要匹配。

    在FORCAL中可以使用的函數有三種:一級函數、二級函數和自定義函數(表達式)。其中一級函數為系統內置的函數,都是單變量 或雙變量函數,運算速度快;二級函數部分為系統內置的函數,部分為軟件為提高性能擴充的函數,功能非常豐富;自定義函數實際上就是一個表達式,由用戶定義,但只有有名字的自定義函數才能被其他表達式所調用。
    實際上,FORCAL還有一類為數不多的函數,稱為流程控制函數,不過對于它們,函數的意義并不明顯,更多的是流程控制的意義,因此我們不把它們包括在上面的分類中。

    FORCAL函數有三種類型,即整數函數、實數函數和復數函數,分別對應著FORCAL的三種表達式。FORCAL規定:一級函數和二級函數只能應用在同類型的表達式中,而自定義函數可以應用在任意的表達式中,FORCAL不會為自定義函數的調用進行類型轉換,用戶可根據需要自行轉換。例如:

      i:f(a,b)=a+b;              //整數表達式定義
      f(2,3);
                    //實數表達式調用整數表達式,但未進行數據轉換
      itor{f[rtoi(2),rtoi(3)]};
  //實數表達式調用整數表達式,函數rtoi將一個實數轉換成一個整數,函數itor將一個整數轉換成一個實數,計算值是正確的

      f(a,b)=a+b;                //實數表達式定義
      i:f(2,3);                  //整數表達式調用實數表達式,但未進行數據轉換
      i:rtoi{f[itor(2),itor(3)]};//整數表達式調用實數表達式,函數rtoi將一個實數轉換成一個整數,函數itor將一個整數轉換成一個實數,計算值是正確的

    如果不同類型的表達式之間相互調用時傳遞指針數據(例如函數句柄),將不必進行類型轉換。

    如果在整數或實數表達式中調用復數自定義函數,傳遞的參數個數應是復數自定義函數的自變量個數的兩倍,即對復數自變量參數的實部和虛部都要進行賦值,且只能返回復數自定義函數的實部的值。如果在復數表達式中調用整數或實數類型的自定義函數, 則整數或實數表達式的自變量個數應為復數表達式自變量個數的兩倍,即調用時需將復數的實部和虛部傳遞給整數或實數自定義函數,但函數返回值只傳遞給復數的實部。例如:

      c:a(x,y)=x+y;    //復數自定義函數,有兩個參數;
      a(1,2,5,6);      //調用函數a時,要傳遞四個參數;
      b(x,y)=x+y;      //實數自定義函數,有兩個參數;
      c:b(1+2i);       //調用函數b時, 只傳遞1個參數;

    FORCAL中的一級函數見表10-1。

表10-1:一級函數

整數函數

整數函數說明

實數函數

實數函數說明

復數函數 復數函數說明
opp(x) 相反數函數 opp(x) 相反數函數 sin(x) 正弦函數
abs(x) 絕對值函數 sin(x) 正弦函數 cos(x) 余弦函數
not(x) 按位非函數 cos(x) 余弦函數 sqrt(x) 平方根函數
or(x,y) 按位或函數 tan(x) 正切函數 exp(x) 指數函數
and(x,y) 按位與函數 asin(x) 反正弦函數 ln(x) 自然對數函數
xor(x,y) 按位異或函數 acos(x) 反余弦函數 floor(x) 返回值的實部為不大于x的實部的最大整數,虛部不變
shl(x,i) 位左移函數,相當于C語言中的x<<i atan(x) 反正切函數 ceil(x) 返回值的實部為不小于x的實部的最小整數,虛部不變
shr(x,i) 位右移函數,相當于C語言中的x>>i sqrt(x) 平方根函數 abs(x) 絕對值函數
itor(x) 將整數類型格式轉換成實數類型格式,大數轉換時有精度損失 exp(x) 指數函數 con(x) 共軛函數
rtoi(x) 將實數類型格式轉換成整數類型格式,大數轉換時有誤差 ln(x) 自然對數函數 xy(x) 實部虛部交換函數
padd(p,i) 指針加函數,p為舊指針,i是一個整數,返回新指針為(p+i) lg(x) 常用對數函數 x0(x) 實部為0函數
ptoi(x) 將指針轉換成一個整數 sinh(x) 雙曲正弦函數,[exp(x)-exp(-x)]/2 y0(x) 虛部為0函數
itop(x) 將整數轉換成一個指針 cosh(x) 雙曲余弦函數,[exp(x)+exp(-x)]/2 itor(x) 將x的實部整數類型格式轉換成實數類型格式,大數轉換時有精度損失;虛部不變
getc(p) 獲得字符p的ASCII值,p是一個靜態單字節字符地址 tanh(x) 雙曲正切函數,[exp(x)-exp(-x)]/[exp(x)+exp(-x)] rtoi(x) 將x的實部實數類型格式轉換成整數類型格式,大數轉換時有誤差;虛部不變
setc(p,x) 設置字符p的ASCII值為x,p是一個靜態單字節字符地址,函數仍返回p abs(x) 絕對值函數 getc(p) 獲得字符p的ASCII值,p是一個靜態單字節字符地址
getw(p) 獲得寬字符p的Unicode值,p是一個靜態寬字符地址 floor(x) 返回不大于x的最大整數 setc(p,x) 設置字符p的ASCII值為x,p是一個靜態單字節字符地址,函數仍返回p
setw(p,x) 設置寬字符p的Unicode值為x,p是一個靜態寬字符地址,函數仍返回p ceil(x) 返回不小于x的最小整數 getw(p) 獲得寬字符p的Unicode值,p是一個靜態寬字符地址
getn(p) 獲得整數p的值,p是一個靜態整數地址 itor(x) 將整數類型格式轉換成實數類型格式,大數轉換時有精度損失 setw(p,x) 設置寬字符p的Unicode值為x,p是一個靜態寬字符地址,函數仍返回p
setn(p,x) 設置整數p的值為x,p是一個靜態整數地址,函數仍返回p rtoi(x) 將實數類型格式轉換成整數類型格式,大數轉換時有誤差 getn(p) 獲得復數p的值,p是一個靜態復數地址
to(p) 將臨時對象轉換為一般對象,僅用于oo函數。若在oo函數外使用該函數,或者找不到該臨時對象,將返回運行錯誤。 getc(p) 獲得字符p的ASCII值,p是一個靜態單字節字符地址 setn(p,x) 設置復數p的值為x,p是一個靜態復數地址,函數仍返回p
oofree(p) 將一般對象轉換為臨時對象,僅用于oo函數。若在oo函數外使用該函數,或者該對象不支持此類轉換,將返回運行錯誤。 setc(p,x) 設置字符p的ASCII值為x,p是一個靜態單字節字符地址,函數仍返回p    
    getw(p) 獲得寬字符p的Unicode值,p是一個靜態寬字符地址    
    setw(p,x) 設置寬字符p的Unicode值為x,p是一個靜態寬字符地址,函數仍返回p    
    getn(p) 獲得實數p的值,p是一個靜態實數地址    
    setn(p,x) 設置實數p的值為x,p是一個靜態實數地址,函數仍返回p    
    atan2(x,y) 反正切函數,求x/y的反正切值,所在象限由x和y的符號確定    
    fmod(x,y) 求x/y的余數    
    sign(x,y) 符號傳送函數,取y的符號,數值取x的絕對值,若y=0無符號傳送,返回x值    
    dim(x,y) 正差函數,當x>y時得x-y,否則返回0    
    padd(p,i) 指針加函數,p為舊指針,i是一個整數,返回新指針為(p+i)    
    to(p) 將臨時對象轉換為一般對象,僅用于oo函數。若在oo函數外使用該函數,或者找不到該臨時對象,將返回運行錯誤。    
    oofree(p) 將一般對象轉換為臨時對象,僅用于oo函數。若在oo函數外使用該函數,或者該對象不支持此類轉換,將返回運行錯誤。    

11 函數的傳值調用和傳址調用  [返回頁首] [返回目錄]

    傳值調用是把變量值拷貝到被調函數的形式參數中,函數在執行時,參數的改變不會影響到調用函數時所用的變量。
    傳址調用(也叫引用調用)是把變量的地址拷貝到被調函數的形式參數中,函數在執行時,參數的改變會影響到調用函數時所用的變量。
    通常,FORCAL是按傳值調用的,除非你用取地址運算符&(也叫引用運算符)顯示地通知FORCAL編譯器,要按傳址方式使用參數。在使用運算符&時,&只能放到(用逗號 或冒號隔開的)單獨存在的變量的前面。如下列:

      a(x,y)= x=2,y=3;
      (:x,y)= x=5,y=6,a(x,y),x; 
//傳值調用,x=5;
      (:x,y)= x=5,y=6,a(x,y),y; 
//傳值調用,y=6;
      (:x,y)= x=5,y=6,a(&x,y),x;
//傳址調用,x=2;
     
(:x,y)= x=5,y=6,a(x,&y),y; //傳址調用,y=3;

12 用表達式作為函數的參數  [返回頁首] [返回目錄]

    在函數調用時,有時候需要用表達式(即自定義函數)作為函數的參數。

    12.1 用表達式的名稱作為字符串(兩個雙引號"..."之間的內容為一個字符串)傳給函數

    例子:

      F(x,y)=sin[x]+0.8-y;       //定義二元函數;
      sum("F",1,2,0.01,2,5,0.1); //對函數F循環求和:x自1到2,增量為0.01;y自2到5,增量為0.01。

    12.2 用二級函數HFor("ForName",ForType)獲得表達式句柄(也稱為表達式指針、函數指針)傳給函數

    例子:

      i: aa(x)=x+8;                             //定義一元函數aa;
      i: (:x)=sys::call[1,HFor("aa",1),7,&x],x; //調用一元函數aa,并將參數7傳遞給該函數;sys::call是Forcal系統擴展庫FcSystem32W的一個函數 。

    一般,在函數的說明中會指定需傳遞的表達式參數的類型,或者傳遞字符串形式的表達式名稱,或者傳遞表達式的句柄。

13 表達式的初始化及銷毀  [返回頁首] [返回目錄]

    13.1 通過靜態變量初始化和銷毀數據

    通過靜態變量,Forcal表達式可以進行初始化,也可以借助專用靜態變量free進行銷毀表達式前的釋放工作(Forcal在銷毀表達式前將自動設置free=1,然后自動執行表達式)。如下例:

      f(x:y,static,d,e,free,f)=                //表達式用printff函數輸出字符串,printff是Forcal數據類型擴展庫FcData的一個函數 。
      { if{!d,printff("初始化!"),d=1},        
//注意靜態變量d使初始化僅執行一次。
        if{free,printff("銷毀!"),return(0)},
 //Forcal在銷毀表達式前將自動設置free=1,然后自動執行表達式,使銷毀僅執行一次。
       
x+1                                    //每次調用使自變量增1。
     
};
      f(0);

      f(1);
      f(2);

    為了充分發揮靜態變量free的作用,在表達式中不要對其有任何的賦值運算,以免引起混亂。另外,如果沒有將free定義為靜態變量,Forcal在銷毀表達式前將不會將其自動設置為1,也不會自動執行表達式。

    如果一個表達式中直接調用的其他表達式或二級函數被刪除,該表達式將不能運行,這樣即便在該表達式中定義了靜態變量free,在Forcal銷毀該表達式前也無法執行該表達式。如下例:

      //函數f中調用了函數a,如果函數a先于函數f被銷毀,則函數f將無法進行正常的銷毀工作。

      a(x)=x+1;

      f(x:y,static,d,e,free,f)=
      { if{!d,printff("初始化!"),d=1},        
 //注意靜態變量d使初始化僅執行一次。
        if{free,printff("銷毀!"),return(0)},
   //如果函數a先于函數f被銷毀,則函數f將無法進行正常的銷毀工作。
        a(x)
+1                                  //調用函數a。
     
};
      f(0);

      f(1);
      f(2);

    若要上面的程序正常工作,主程序在銷毀表達式時必須遵循“后進先出”的原則,即:后編譯的表達式先刪除。

    動態調用表達式或二級函數,能使上面的程序正常工作。如下例:

      //以下語句中,sys::call()是Forcal系統擴展動態庫FcSystem32W中定義的一個函數,可在運行時調用自定義函數;
     
//函數f動態調用了函數a,即便函數a先于函數f被銷毀,也不影響函數f執行正常的銷毀工作。

      i: a(x)=x+1;

      i: f(x:y,static,d,e,free,f)=
         { if{!d,printff("初始化!"),d=1},         
//注意靜態變量d使初始化僅執行一次。
           if{free,printff("銷毀!"),return(0)},
  //Forcal在銷毀表達式前將自動設置free=1,然后自動執行表達式,使銷毀僅執行一次。
           sys::call(1,HFor("a",1),x,&x),x
+1      //通過函數sys::call()動態調用函數a,使自動銷毀正常進行。因為在sys::call()執行前,不知道函數a是否存在。
        
};
     
i: f(0);
      i: f(1);
      i: f(2);

    13.2 通過函數free(p)銷毀數據

    函數free(p)可將對象p自動記錄下來,在銷毀表達式時銷毀對象p。用法舉例如下:

      i: ConstObj(:static,obj)=
         {
           if{!obj, obj=new[...].free()},
 //第一次調用函數ConstObj()時,用函數new申請一個對象obj,并用函數free()標記在銷毀表達式 時銷毀它
           obj
                            //返回對象obj
        
};
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象

    注意:函數free(p)并不立即銷毀對象p,而是在銷毀表達式時銷毀該對象。并不是所有的對象都可由函數free銷毀,這取決于主程序和Forcal擴展庫的設計,在Forcal數據類型擴展庫FcData中用函數new申請的對象都可由函數free來銷毀。函數free(p)只適合銷毀少量的數據,故不要將其放在循環中使用。

    注意:靜態變量free和函數free(p)不必同時使用,同時使用將降低效率。

    最后指出,能否進行銷毀表達式前的釋放工作,取決于主程序的設計,與主程序如何使用Forcal的輸出函數有關。即便銷毀表達式前沒有進行釋放工作,Forcal最后也將釋放所有資源,因而無需擔心太多。

14 表達式的完整定義及表達式句柄  [返回頁首] [返回目錄]

    在這里,我們總結性地給出FORCAL表達式的完整定義,以幫助用戶更好地理解FORCAL,為了定義的完整性,部分地重復了前面所敘述過的內容。FORCAL表達式的完整定義如下:

      F(a,b:x,y,static,u,free,v:s,t,common,w)=
      {x=1,y=2,[x+y,x*y],(x-y):
       a+b+x+y+static+u+s+t+common+v
      }

    F是表達式的名字,必須位于表達式的開頭,該名字必須是一個標識符。給表達式起一個名字,主要是以后可以通過該名字來調用該表達式。表達式也可以沒有名字,但這樣,在其它的表達式中將無法調用它。在FORCAL中,一般表達式的名字是唯一的,不能給兩個表達式起同一個名字(模塊內表達式的名字除外,模塊的定義將在后面介紹)。
    如果定義了表達式名字,表達式名字后必須跟一對小括號(只能用小括號),用來定義變量。變量個數可以為零,也可以有任意多個。有多個變量時,變量間以逗號或冒號分隔。用冒號隔開的變量,從前往后依次為 自變量、動態變量、靜態變量、模塊變量和全局變量,即第一個冒號前為自變量,兩個冒號之間為動態變量和靜態變量,第二個冒號后為模塊變量和全局變量。兩個冒號之間用關鍵字static分隔動態變量和靜態變量,static之前為動態變量,static及以后變量均為靜態變量,關鍵字static只 能用在兩個冒號之間。第二個冒號后用關鍵字common分隔模塊變量和全局變量,common之前為模塊變量,common及以后變量均為全局變量,關鍵字common只能用在第二個冒號后。 自變量、動態變量和靜態變量只能被定義該變量的表達式所訪問;模塊變量可被同一模塊的所有表達式所訪問,其他模塊的表達式無法訪問;全局變量可被所有的表達式所訪問。自變量用于向表達式傳遞參數 ,因此自變量也稱為形式參數。動態變量只在表達式執行時起作用,一旦表達式執行完畢,動態變量也隨之失效。靜態變量存在于表達式的整個生命周期,每次表達式執行完畢,靜態變量的值被保留。FORCAL在編譯表達式時,將所有靜態變量初始化為0,其余的變量均不進行初始化。 如果定義了靜態變量free,Forcal在銷毀表達式前將自動設置free為1,然后自動執行表達式。所有變量以及冒號均可缺省。在這個例子中,a和b是自變量,x和y是動態變量,static、u、free和v是靜態變量,s和t是模塊變量,common和w是全局變量。
    即便表達式沒有名字,也可以用一對小括號(只能用小括號)來定義變量,這時,小括號必須位于表達式的開頭。
    如果用小括號定義了變量,小括號后必須跟一個等號,該等號標志表達式可執行部分的開始,等號及等號后的可執行部分均不可缺省。
    如果表達式中的變量名與一個常量名相同,則常量名被忽略。
    表達式中可以不定義變量,這時,表達式中只有可執行部分,稱常量表達式,或者稱無參表達式。
    表達式的可執行部分任何情況下都不可缺省。
    表達式的可執行部分由多個語句組成,多個語句之間用逗號或冒號分隔,多個語句可以放在一對括號內。可執行部分中可以使用三對括號( )、[ ]和{ },括號必須成對使用。在FORCAL中,括號是一種運算符,具有一個值,即該括號內最后一個語句的值。表達式總是返回(最外層括號中)最后一個語句的值。另外,最外層的括號不是必須的,但表達式若有逗號 或冒號隔開的多個語句,有了最外層的括號后,表達式更易讀。

    用這種方式定義表達式時,實際上就是自定義了一個函數,可以在任意的表達式中使用該函數(只要給該函數起了名字),由于這個原因,我們常常將表達式說成是函數,或者說表達式就是一個函數,但反過來并不成立。

    以下都是合法的表達式定義的例子:

      2;                     //常量(無參)表達式(函數);
      ()=2;                 
//常量(無參)表達式(函數);
      (::)=2;                //常量(無參)表達式(函數);
      A()=2;                
//常量(無參)表達式(函數),但定義了函數名字,在其它表達式中可以調用該函數;
      A(::)=2;               //常量(無參)表達式(函數),但定義了函數名字,在其它表達式中可以調用該函數;
      B(x)=2;               
//有一個自變量的表達式(函數);
      (x)=23;               
//有一個自變量的表達式(函數),但沒有函數名,不能在其他表達式中調用該函數;
      F(a,b)= ... ...       
//定義了兩個自變量a和b;
      F(:x,y)= ... ...      
//定義了兩個動態變量x和y;
      F(:static,u)= ... ...  //定義了兩個靜態變量static和u;
      F(::s,t)= ... ...     
//定義了兩個模塊變量s和t;
      F(::common,v)= ... ... //定義了兩個全局變量common和v;
      F(a,b:x,y)= ... ...   
//定義了兩個自變量a和b,兩個動態變量x和y;
      F(a,b::s,t)= ... ...  
//定義了兩個自變量a和b,兩個模塊變量s和t;
      F(:x,y:s,t)= ... ...  
//定義了兩個動態變量x和y,兩個模塊變量s和t;

    FORCAL表達式可用句柄(也稱為表達式指針、函數指針)進行標識,可以使用二級函數HFor("ForName",ForType)獲得表達式的句柄。表達式句柄有很多用途,例如可以作為函數的參數、獲得表達式中的靜態字符串等等。

15 流程控制  [返回頁首] [返回目錄]

    在FORCAL中,表達式的各個語句一般是順序執行的。但是某些函數可以改變語句執行的順序,稱為流程控制函數。

    15.1 立即返回函數 return(x)

    結束計算并立即返回表達式的值為x。

    15.2 判斷函數 if(x,y1,y2,... ...,yn)

    當邏輯語句x的值為真時,依次執行語句y1,y2,... ...,yn,否則,不執行語句y1,y2,... ...,yn。
    該函數至少要有2個自變量參數,其中第一個參數為邏輯語句。
    該函數的返回值無意義。

    15.3 自定義分段函數

      which{邏輯語句1,語句1,
        邏輯語句2,語句2,
        ... ...,
        邏輯語句n,語句n,
        缺省語句
      };

    FORCAL從前往后計算并檢測邏輯語句的值,當檢測到邏輯真時,計算與此邏輯真對應的語句并返回該語句的值,如果沒有檢測到邏輯真,則計算缺省語句的值作為返回值,若此時沒有缺省語句,則產生一個運行錯誤(錯誤代碼為0)。
    該函數至少要有2個自變量參數。
    例如下式定義了一個分段函數:

      (x)=which{x>0,2*x-1,
            x*x-1
          };

    如果舍棄該函數的返回值,則該函數可以作為一個選擇計算函數使用。

    15.4 while循環函數

    while循環是“當型”循環,其特點是:先判斷條件是否成立,當條件成立時,則執行循環體,否則退出循環體,即“當條件成立時執行循環”。“當型”循環的循環體有可能一次也不執行。
    while循環函數的格式如下:

      while{x,
        y1,y2,
        ...,
        break(),
        ...,
        continue(),
        ...,
        yn
      };

    其中x為邏輯語句;y1,y2,...,break(),...,continue(), ...yn為循環體語句。當x的值為真時,依次執行循環體語句,直到x的值為假時退出循環。當執行到break()函數時,跳出while循環,執行while循環后面的語句部分;當執行到continue()函數時,返回到while循環的開始語句x處繼續執行。
    在循環體語句中,必須有能修改邏輯語句x的值的語句,使x的值為假,退出循環體,否則將產生無限循環。
    該函數至少要有2個自變量參數,其中第一個參數為邏輯語句。
    該函數的返回值無意義。
    以下是一個while循環的例子:

      (:i,k)=
      {i=0,k=0,
        while{i<=1000000,k=k+i,i++},
//當i<=1000000時,計算k=k+i,然后i++;
        k
      };

    15.5 until循環函數

    until循環是“直到型”循環,其特點是:先執行循環體,再判斷條件是否成立,當條件成立時,退出循環體,否則繼續執行循環體,即“執行循環直到條件成立”。“直到型”循環的循環體至少執行一次。
    until循環函數的格式如下:

      until{x1,x2,
        ...,
        break(),
        ...,
        continue(),
        ...,
        y
     
};

    until為先執行后判斷的循環函數。即先執行循環體語句x1,x2,...,break(),...,continue(),...,然后計算邏輯語句y的值,直到y的值為真時退出循環。當執行到break()函數時,跳出until循環,執行until循環后面的語句部分;當執行到continue()函數時,返回到until循環的開始語句x1處繼續執行。
    在循環體語句中,必須有能修改邏輯語句y的值的語句,使y的值為真,退出循環體,否則將產生無限循環。
    該函數至少要有2個自變量參數,其中最后一個參數為邏輯語句。
    該函數的返回值無意義。
    以下是一個until循環的例子:

      (:i,k)=
      {i=0,k=0,
       
until{k=k+i,i++,i>1000000}, //計算k=k+i,i++,當i>1000000時退出;
        k
      };

    注意:
    (1)break()和continue()是兩個無參函數,只能用在while和until兩個循環函數中。
    (2)FORCAL支持多線程,在多線程的程序中,如果不慎進入了無限循環,可以通過另一個線程退出。

16 字符串  [返回頁首] [返回目錄]

    在FORCAL中使用Unicode寬字符串 ,一個寬字符有2個字節,用兩個雙引號定義一個字符串,即"..."表示一個字符串。在FORCAL字符串中,還可以用反斜杠轉義字符輸入一些特殊字符,見表16-1。

表16-1 反斜杠轉義字符

\\ 反斜杠“\”
\" 雙引號“"”
\% 0
\a 警告
\b 退格
\f 換頁
\n 換行
\r 回車
\t 水平制表符
\v 垂直制表符
\& 沒有對應的字符。當該轉義字符位于字符串最前面時(例如:"\&... ..."),指示編譯器在數的邊界處存放該字符串,并影響轉義字符\[n];該轉義字符位于字符串的其他位置時不產生任何作用
\NNNNN 任意字符,NNNNN是該字符Unicode碼的10進制值,NNNNN必須是5個數字,例如NNNNN碼為9的字符,應寫成\00009
\xNNNN 任意字符,NNNN是該字符Unicode碼的16進制值,NNNN必須是兩個16進制數字(字母A到F以單個數字的形式表示10進制數的10到15),例如Unicode碼為11的字符,應寫成“\x000B”
\[n] n是一個10進制整數,轉換成n×k個空格符。 若字符串最前面沒有轉義字符\&,k=1;若字符串最前面有轉義字符\&,則在整數和實數表達式中k=4,在復數表達式中k=8,這種字符串格式可轉換為整數、實數或復數數組。例如: 任意表達式中,"\[256]" 是一個256個字符長的空格符字符串。實數表達式中,"\&\[256]" 是一個256×4個字符長的空格符字符串。

    除了表中定義的之外,FORCAL沒有定義其它的轉義字符(“\”和其他字符的組合都是非法的)。 可以看出,反斜杠“\”和雙引號“"”只能通過轉義字符輸入。
    另外,若字符串前有符號@(例如:@"...\r\n..."),將忽略轉義字符。

    例如:

      printff("hello!\r\n字符串!!!");       //用printff函數輸出字符串;
      printff(@"hello!\r\n字符串!!!");      //用printff函數輸出字符串;

    FORCAL在編譯表達式時,將同一個表達式中的字符串連續存放,同時將每一個字符串都轉換成一個整數,該整數即該字符串的首字符所在的位置,稱字符串的地址。因而,兩個相鄰字符串地址的差即前一個字符串的長度的負值。

    例如:

      (:i,j)={i="Hello Forcal !",j="end",printff(i),j-i};       //該函數返回第一個字符串的長度;

    可以用字符串標識任意類型的數據值,如前所述,字符串形式的表達式的名稱可以作為參數傳給函數,此時,該字符串標識一個表達式。

    可以用字符串存儲任意類型的數據值,如下面將要講到的靜態數組。

    Forcal字符串有二種類型:Forcal靜態字符串和Forcal動態字符串。Forcal靜態字符串即在Forcal表達式中定義的字符串,長度是固定的,不能隨意進行銷毀(但Forcal靜態字符串也并非一成不變);Forcal動態字符串由Forcal擴展動態庫FcData進行管理,可由函數new進行申請,由函數delete進行銷毀。

    Forcal靜態字符串又分為近程靜態字符串和遠程靜態字符串。近程靜態字符串僅用一個整數(該整數即字符串在表達式中的地址)就可以標識,遠程靜態字符串需由表達式句柄和一個整數進行標識 。Forcal數據擴展動態庫FcData中的函數printff可以輸出遠程靜態字符串, 如下例:

bb()="adfg";                            //定義表達式bb,函數返回一個Forcal靜態字符串地址;
printff["{1,fs}",2,HFor("bb",2),bb()];  //用函數printff輸出表達式bb中的字符串,函數HFor用于獲得表達式bb的句柄。

    由此可見,可在自定義表達式之間通過表達式句柄和字符串地址傳遞Forcal遠程靜態字符串。

    通常,涉及字符串的規范的二級函數命名將按以下約定:函數名中含有NStr(Forcal近程靜態字符串),表示需要一個Forcal靜態字符串地址參數;函數名中含有FStr(Forcal遠程靜態字符串),表示需要表達式句柄和一個Forcal靜態字符串地址參數;函數名中含有Str(Forcal動態字符串),表示需要一個FcData字符串指針參數。

    附:標準輸出函數printff簡介

    格式1:printff("hello,Forcal!");

    說明:只有一個字符串參數時,直接輸出Forcal近程靜態字符串。

    格式2:printff("aa{1,ns}\r\nbb{2,r,10.5}","hello.",sin[1.2]);

    說明:有多個參數時(參數序號以0為基數,依次為0,1,2,...),第0個參數是含格式說明的字符串,其余為要輸出的參數列表第0個字符串參數由兩部分組成,第一部分是普通字符,將被輸出;第二部分是{...}內的格式說明。格式說明有三項(前2項不可缺省),由逗號隔開,以{2,r,10.5}為例:第一項2指出要輸出printff函數的第2個參數;第二項r表示按實數格式輸出;第三項10.5表示輸出寬度為10個字符,保留5位有效數字,靠右邊輸出,若是負數表示靠左輸出。常見說明符:ns表示Forcal近程靜態字符串,fs表示Forcal遠程靜態字符串,s表示字符串指針,i表示10進制整數,x表示16進制整數,r表示實數等等。另外,i2表示2進制整數,i3表示3進制整數等等。

    需要注意,函數printff在Forcal擴展動態庫FcData中定義,詳細請參考該庫的說明。

17 靜態數組  [返回頁首] [返回目錄]

    在Forcal中定義和使用數組是通過一組函數操作靜態字符串來實現的。可以將Forcal靜態字符串轉換為數組來使用,Forcal內置了ANSI字符數組、Unicode字符數組、整數數組 、實數數組和復數數組的操作函數。

    使用數組之前,須先用轉義字符"\[n]"定義足夠的靜態空間。

    17.1 Unicode字符數組

    通過函數getw(p)和setw(p,x)操作Unicode字符數組,可用在任意表達式中。如下

i:(:i,k,str)={ str="**\[26]**",            //定義字符串str,共30個字符,這就是一個Unicode字符數組
    k=getw["a"],                          
//用函數getw獲得字符"a"的Unicode值并賦值給k
    i=0,
    (i<26).while{setw(str+2+i,k++),i++},  
//將星號之間是字符空間設置為26個英文字母
   
printff(str)                           //輸出字符數組str
};

    17.2 ANSI字符數組

    通過函數getc(p)和setc(p,x)操作ANSI字符數組,可用在任意表達式中。一個ANSI字符占1個字節,而一個Unicode字符占2個字節,故將Unicode字符地址乘以2即轉換為ANSI字符地址。如下

i:(:i,j,k,str)={ str="**\[26]**",          //定義字符串str,共30個字符,這是一個Unicode字符數組,但也可以看成是ANSI字符數組
    k=getc["a"*2],                        
//用函數getc獲得字符"a"的ASCII值(實際上與字符"a"的Unicode值相等)并賦值給k
    i=0,j=(str+2)*2,
    (i<52).while{setc(j+i,k++),i++,setc(j+i,0),i++},
//將星號之間是字符空間設置為26個英文字母,注意函數setc用了兩次,將一個寬字符的低位字節設為ASCII值,而高位字節為0
   
printff(str)                           //輸出字符數組str
};

    17.3 整數、實數及復數數組

    通過函數getn(p)和setn(p,x)操作整數、實數或復數表達式中的相關數組 ,此時字符串必須定義成"\&... ..."格式。整數 或實數表達式中,一個數占8個字節,而一個Unicode字符占2個字節,故將Unicode字符地址除以4即轉換為數組地址。復數表達式中,一個數占16個字節,故將Unicode字符地址除以8即轉換為數組地址。

    整數或實數數組的例子:

(:i,j,k,end,str)={ str="\&\[10]",          //定義字符串str,共40個字符,這是一個Unicode字符數組,但可以轉換成整數 或實數數組
    k=str/4,end=k+10,                     
//轉換成整數或實數數組地址k,end是數組末地址的下一個地址
    i=k,
    (i<end).while{setn(i,1),i++},         
//將數組的每一個元素都設為1
    i=k,j=0,
    (i<end).while{j=j+getn(i++)},         
//將數組的所有元素都加起來
    j
                                      //輸出相加后的值
};

    復數數組的例子:

c:(:m,j,k,end,str)={ str="\&\[10]",        //定義字符串str,共80個字符,這是一個Unicode字符數組,但可以轉換成 復數數組
    k=str/8,end=k+10,                     
//轉換成復數數組地址k,end是數組末地址的下一個地址
    m=k,
    (m<end).while{setn(m,1.1+1.1i),m++},   
//將數組的每一個元素都設為1
    m=k,j=0,
    (m<end).while{j=j+getn(m++)},         
//將數組的所有元素都加起來
    j
                                      //輸出相加后的值
};

18 遞歸調用  [返回頁首] [返回目錄]

    如果一個函數直接或者間接地調用了自己,稱作函數的遞歸調用。FORCAL支持函數的遞歸調用。

    為了在FORCAL中使用遞歸,需要在相應類型的表達式中設置好相應類型的堆棧。在整數表達式中用SetIntStackMax(n)進行設置,在實數表達式中用SetRealStackMax(n)進行設置,在復數表達式中用SetComplexStackMax(n)進行設置。注意n的值不能取得太大,當n取得很大時,函數遞歸調用雖不會溢出FORCAL的堆棧,但會使系統堆棧溢出,這樣會使程序運行中斷,丟失數據(作者還沒有很好的解決這個問題!希望朋友們能夠幫助解決,深表謝意。)。并不需要每次運行程序都進行堆棧的設置,如果堆棧設置的合適,可以只設置一次堆棧。

    下面就是遞歸的最簡單的例子:

      SetRealStackMax(10000);   //設置實數堆棧為10000;
      a()=a();                  //函數a遞歸地調用自己,屬于無窮遞歸調用。

    直接運行上面的表達式,將會返回一個堆棧溢出的運行錯誤。雖然溢出FORCAL的堆棧不會中斷程序的運行,但對于上面的程序,無論設置多大的堆棧都會溢出,因為函數a的遞歸定義是錯誤的。遞歸函數應當包含一條控制該函數是繼續調用其本身還是返回的語句。如果沒有這樣的語句,遞歸函數將用完分配給堆棧的所有內存空間,導致堆棧溢出錯誤。

    下面舉一個能正常遞歸調用返回的例子。

      SetRealStackMax(1000);               //設置實數堆棧為1000;
      Fact(n)=which{n<=1,1,n*Fact(n-1)};  
//階乘函數Fact的遞歸實現;
      Fact(3);                             //計算3!;
      Fact(5);                             //計算5!;
      Fact(10);                            //計算10!;
      Fact(100);                           //計算100!;

    以下是一個交叉遞歸的例子。

      i: SetIntStackMax(1000);             //設置整數堆棧為1000;
      //以下語句中,sys::call()Forcal系統擴展動態庫FcSystem32W中定義的函數,可在運行時調用自定義函數;
      i: a(x:k)=printff["a..."],if(x<1,return[x]),sys::call[1,HFor("b",1),x-1,k];
    //a(...)函數中調用了b(...)函數;
      i: b(x:k)=printff["b..."],if(x<1,return[x]),sys::call[1,HFor("a",1),x-1,k];
    //b(...)函數中調用了a(...)函數;
      i: a[10];   
//啟動遞歸程序;

19 模塊化編譯  [返回頁首] [返回目錄]

    FORCAL支持表達式的模塊化編譯。

    在用FORCAL編譯表達式時,要給該表達式指定模塊號,模塊號用一個整數進行標識。

    在FORCAL中,一個模塊由一個或多個表達式組成。模塊用一個整數標識,整數可正可負,只要絕對值相等,就屬于同一個模塊。一般用正整數表示該模塊名。模塊共有兩類,即主模塊(0#模塊)和普通模塊(其他標號的模塊)。

    同一模塊中,模塊號為負的表達式稱私有表達式,只能被本模塊的表達式 所訪問(即調用),在其他模塊中是不可見的;模塊號為正的表達式稱公有表達式或全局表達式,能被任何一個表達式所訪問。主模塊(0#模塊)中的表達式都是私有表達式。任何一個表達式,既可以訪問本模塊中的表達式,也可以訪問其他模塊中的全局表達式,如果本模塊中的一個私有表達式與其他模塊的一個全局表達式重名,將優先調用本模塊中的私有表達式。

    由以上規定可以看出,主模塊可以訪問本模塊中的表達式,也可以訪問其他模塊中的全局表達式。因此,主模塊常常用在主程序中。

    通常,可以用編譯符#MODULE##END#定義一個模塊,用編譯符~輸出模塊中的 全局表達式。另外,若表達式名稱前有編譯符!(首先解釋為立即執行編譯符,而不是邏輯非運算符),在編譯后將立即執行 ;若表達式名稱前有編譯符:,只編譯,不執行。如下例:

#MODULE#                    //定義一個子模塊
  !a()=
printff("字符串!"); //模塊私有表達式,編譯后立即執行
  f(x)= x+1;               
//模塊私有表達式
  :g()= 100;               
//模塊私有表達式,只編譯,不執行
  ~h(x)= f(x)+g()+2;       
//全局表達式
#END#                      
//子模塊定義結束


f(x)= x+5;
                  //主模塊中的私有表達式,可以使用與其他模塊中的表達式相同的名字
f[3];
                       //調用主模塊中的函數f
h[3];
                       //調用子模塊中的全局表達式

20 模塊命名空間  [返回頁首] [返回目錄]

    使用命名空間可以有效地避免函數重名問題。Forcal中可以用函數Module創建模塊命名空間,命名空間創建后,可以用函數OutFun輸出該模塊的表達式,不管是私有表達式還是公有表達式,都可以輸出。

      Module("Name":"Name1","Name2",... ...)    //創建模塊命名空間Name,繼承自"Name1","Name2",... ...

      OutFun("fun1","fun2","fun3",... ...)      //輸出模塊命名空間中的表達式"fun1","fun2","fun3",... ...

    模塊命名空間只能創建一次,可以繼承,甚至可以循環繼承,如果確實有必要。模塊命名空間是一棵樹或者是一個連通圖。

    當模塊中有表達式時,才能創建該模塊的命名空間,當該模塊中的最后一個表達式被銷毀時,將同時銷毀該命名空間。

    當為一個命名空間指定父空間(基空間)時,該父空間是否存在可以是未知的,即父空間并不一定要先于子空間而存在。

    模塊命名空間中輸出的表達式可以用命名空間成員訪問符::調用,如:Name::fun1(...)。 如果該命名空間中沒有輸出指定的表達式,而該空間的父空間中輸出了同名表達式,就會調用父空間中的同名表達式。可以連續使用訪問符::直接調用指定父空間(或該父空間的父空間)中的表達式,如:Name1::Name2::Name3::fun1(...)。 可以看出,模塊命名空間中的表達式調用規則類似于C++中的虛函數調用規則。

    由于Module和OutFun是兩個函數,為了使創建的空間及輸出函數立即可用,應在編譯完Module或OutFun所在的表達式后,立即執行該表達式。

    例子:

#MODULE#                         //定義一個子模塊
  !Module("AA");                 //創建模塊命名空間AA,該表達式編譯后將立即執行
  Set(x::xx)= xx=x;              //模塊私有表達式
  Get(::xx)= xx;                 //模塊私有表達式
  aa()= 111;                     //模塊私有表達式
  !OutFun("Set","Get","aa");     //輸出模塊命名空間中的表達式,該表達式編譯后將立即執行
#END#                            //子模塊定義結束

#MODULE#                         //定義一個子模塊
  !Module("BB","AA");            //創建模塊命名空間BB,繼承自"AA",該表達式編譯后將立即執行
  Set(x::xx)= xx=x;              //模塊私有表達式
  Get(::xx)= xx;                 //模塊私有表達式
  !OutFun("Set","Get");          //輸出模塊命名空間中的表達式,該表達式編譯后將立即執行
#END#                            //子模塊定義結束

//以下都是主模塊中的表達式

aa()= 999999;
aa();                            //調用主模塊中的表達式aa,結果為:999999

BB::aa();                        //通過模塊空間BB調用空間AA中的表達式aa,結果為:111

BB::Set(33);                     //調用模塊空間BB中的表達式Set,結果為:33
BB::Get();                       //調用模塊空間BB中的表達式Get,結果為:33

BB::AA::Set(55);                 //調用模塊空間AA中的表達式Set,結果為:55
BB::AA::Get();                   //調用模塊空間AA中的表達式Get,結果為:55
BB::Get();                       //調用模塊空間BB中的表達式Get,結果為:33
AA::Get();                       //調用模塊空間AA中的表達式Get,結果為:55

21 二級函數命名空間  [返回頁首] [返回目錄]

    為了避免二級函數重名,二級函數可以采用模塊命名空間中的命名方式,如:Fun2::Set(...),稱二級函數命名空間。是否采用二級函數命名方式,取決于提供二級函數的模塊。

    一般,二級函數名稱中不應有空格,所以可用如下方式判斷一個函數是一個二級函數,或者是一個模塊命名空間中輸出的表達式。

      name ::Set(...);                //注意::前有一空格,若編譯通過,一般是模塊命名空間中的表達式,若編譯未通過,說明是個二級函數

22 常量命名空間  [返回頁首] [返回目錄]

    為了避免常量重名,常量可以采用函數命名空間中的命名方式,如:ConstName::MyConst,稱 常量命名空間。常量命名空間可由程序或庫提供,也可用函數const創建。

    一般,常量名稱中不應有空格,否則該常量將無法正常訪問。

    例子:

      !const("aa::c1",111);    //在命名空間aa中定義永久性常量
      !const("aa::c2",222,1); 
//在命名空間aa中定義暫時性常量
      aa::c1;                  //直接訪問命名空間中的常量
      aa::c2;                 
//直接訪問命名空間中的常量
      !using("aa");           
//訪問命名空間aa
      c1;                   
  //訪問命名空間中的常量
      c2;                   
  //訪問命名空間中的常量

23 訪問命名空間  [返回頁首] [返回目錄]

    命名空間(包括模塊命名空間和二級函數命名空間)比較長時,輸入比較麻煩,使用using函數可簡化命名空間的訪問。

    執行過函數using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace",... ...)后,如果有一個命名空間中的函數NameSpace2::fun(x,y),不必寫出該命名空間,直接使用函數fun(x,y)就可以了 ;如果有一個常量命名空間中的常量ConstSpace::MyConst, 也不必寫出該命名空間,直接使用常量MyConst就可以了。 函數命名空間若與常量命名空間相同,只寫出一個即可。如下列:

      using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace");
      2+fun(5,6)+MyConst+3;

    注意:如果有一個非命名空間中的函數fun(x,y),將優先調用該函數,遇到這種情況,應使用函數的全名:NameSpace2::fun(x,y)。 如果有一個非命名空間中的常量MyConst,將優先調用該 常量,遇到這種情況,應使用常量的全名:ConstSpace::MyConst

    可使用using函數一次指定多個命名空間,當再一次調用using函數時,以前指定的命名空間將被刪除,可訪問的命名空間被重新設定。用using函數指定的命名空間僅在本模塊中起作用,換句話說,可在不同的模塊中使用using函數而互不影響。

    例子:

#MODULE#                         //定義一個子模塊
  !Module("AA");                 //創建模塊命名空間AA,該表達式編譯后將立即執行
  Set(x::xx)= xx=x;              //模塊私有表達式
  Get(::xx)= xx;                 //模塊私有表達式
  aa()= 111;                     //模塊私有表達式
  !OutFun("Set","Get","aa");     //輸出模塊命名空間中的表達式,該表達式編譯后將立即執行
#END#                            //子模塊定義結束

#MODULE#                         //定義一個子模塊
  !Module("BB","AA");            //創建模塊命名空間BB,繼承自"AA",該表達式編譯后將立即執行
  Set(x::xx)= xx=x;              //模塊私有表達式
  Get(::xx)= xx;                 //模塊私有表達式
  !OutFun("Set","Get");          //輸出模塊命名空間中的表達式,該表達式編譯后將立即執行
#END#                            //子模塊定義結束

//以下都是主模塊中的表達式

!using("BB");                    //主模塊可訪問命名空間BB

aa();                            //通過模塊空間BB調用空間AA中的表達式aa,結果為:111

Set(33);                         //調用模塊空間BB中的表達式Set,結果為:33
Get();                           //調用模塊空間BB中的表達式Get,結果為:33

BB::AA::Set(55);                 //調用模塊空間AA中的表達式Set,結果為:55
BB::AA::Get();                   //調用模塊空間AA中的表達式Get,結果為:55
BB::Get();                       //調用模塊空間BB中的表達式Get,結果為:33
AA::Get();                       //調用模塊空間AA中的表達式Get,結果為:55

24 類成員運算符(函數參數運算符 )及對象賦值運算符  [返回頁首] [返回目錄]

    若標識符后面有句點“.”,表示將該標識符聯系到一個函數,例如:a.sin();或者產生一個函數調用,例如:a.b 相當于 a(b)。若變量是顯示說明的,則通過句點將產生隱含的oset函數或oget函數調用,稱變量函數調用,例如:a.b 相當于 oget[a,b];a.b=c 相當于 oset[a,b:c]。

    在FORCAL中,任何一個數都有可能是一個類或指針,這需要在運行時才能確定,所以FORCAL編譯器把任何一個函數或表達式都看作類或指針的成員函數。盡管FORCAL32W.dll中沒有提供類或指針的概念,但FORCAL擴展動態庫FcData中定義了該概念。為了存取像類或指針等復雜數據類型時,在形式上看起來更美觀一些,FORCAL32W.dll中提供了類成員運算符“.”操作類的成員函數或指針數據。如下例:

      (:x)= x=2.3, x.sin();                //計算sin(x)。
      (:x)= x=2.3, sin.=x;                 //計算sin(x)。
      (:x)= x=2.3, sin.x;                  //計算sin(x)。

      f(x,y)= x.y.atan2().sin();          //定義函數f,計算sin(atan2(x,y))。
      (:x,y)= x=2.3,y=3.3, x.f(y);         //計算f(x,y)。
      (:x,y)= x=2.3,y=3.3, f.x.y;          //計算f(x,y)。
      (:x,y)= x=2.3,y=3.3, f[x]=y;         //計算f(x,y)。
      (:x,y)= x=2.3,y=3.3, f.x.=y;         //計算f(x,y)。
      (:x,y)= x=2.3,y=3.3, f.x=y;          //計算f(x,y)。

      "字符串也可以的".printff[];           //執行printff["字符串也可以的"];
      printff."字符串也可以的";
             //執行printff["字符串也可以的"];

      (:f,x,y)= x=2,y=3.3, f.x=y;          //因f是一個顯示說明的變量,計算oset(f,x:y)。
      (:f,x,y)= x=2,y=3, f.x.y;            //因f是一個顯示說明的變量,計算oget(f,x,y)。
      (:f,x,y)= x=2,y=3, f.x.y=f.x.y+1;    //因f是一個顯示說明的變量,計算oset[f,x,y : oget(f,x,y)+1]。

    若句點“.”沒有將標識符聯系到一個函數,則第一個句點前只能是一個類似變量的標識符,其他句點“.”前允許是常量名、變量名、字符串、括號運算符或函數。

    若句點“.”將標識符聯系到一個函數,則任一句點“.”前允許是常量名、變量名、字符串、括號運算符或函數。運算符“.”表示它前面的參數是它后面最近的函數的一個參數,所以稱為函數參數運算符,該運算符之所以也稱為類成員運算符,是因為“.”就是為了表示類的成員關系而設置的。成員函數在調用時,先把類成員運算符“.”前的數據作為參數,并與函數括號內的參數一起合并,然后執行計算。即:函數的參數個數為類成員運算符“.”前的變量個數與函數括號內的參數個數之和。注意:只有成員函數前面的類成員數據才是該函數的參數。例如:

      (2).(3).max[].(5).min[]

上式中,2和3max[]的參數,而max[2,3]和5min[]的參數,即:min{max[(2),(3)],(5)}

    使用類成員運算符,函數if、while、until等函數有以下用法:

      (x).if                //x為真時執行花括號內的內容。
      {
         ... ...
      };

      (x).while             //x為真時循環執行花括號內的內容。
      {
         ... ...
      };

      //循環執行花括號內的內容直到x為真。
      {
         ... ...
      }.until(x);

    類成員運算符不但可以表示類的成員關系,合理地使用該運算符也可使程序更易讀。例如:類ClassA有一個成員函數ClassA_Add(a,b),可以執行類對象a和b相加,類對象a、b、c、d連續相加的表達式為:

ClassA_Add{ClassA_Add[ClassA_Add(a,b),c],d}

    用運算符“.”可表示為:

a.ClassA_Add(b).ClassA_Add(c).ClassA_Add(d)

    當然,以上還不是執行類對象a和b相加的最簡形式,最簡形式應是在oo{...,a=a+b+c+d,...}函數中實現運算符重載功能。請參考每一個類的說明。

    盡管運算符“.”對程序的運行速度沒有影響,但會影響編譯速度,因而建議僅在需要的時候使用它。

25 標識符解釋規則  [返回頁首] [返回目錄]

    1)若標識符后面有括號,表示是一個函數,否則是一個變量或常量名。

    2)若標識符后面有句點“.”,表示將該標識符聯系到一個函數,例如:a.sin(x);或者產生一個函數調用,例如:a.b 相當于 a(b)。若變量是顯示說明的,則通過句點將產生隱含的oset函數或oget函數調用,稱變量函數調用,例如:a.b 相當于 oget[a,b];a.b=c 相當于 oset[a,b:c]。

    3)如果一個變量名與常量名相同,則常量名被忽略。確定變量或常量的順行是:變量、常量、常量命名空間。

    4)如果編譯器允許使用未定義的模塊變量,當遇到一個未定義的標識符時,將被解釋為模塊變量或常量。如果該常量不存在,就解釋為模塊變量。如果該常量存在,但不存在同名的模塊變量,將解釋為常量。如果常量和同名的模塊變量同時存在,將優先解釋為模塊變量。 若要確保編譯器將未定義的標識符解釋為模塊變量,則應在前面編譯的表達式中,將該標識符明確地定義為模塊變量并至少使用一次。

    5)如果是一個普通的函數名,則確定函數的順行是:變量函數、一級函數或流程控制函數、自定義表達式、二級函數、using指定的命名空間中的函數。

    6)如果是一個命名空間中的函數,確定函數的順行是:模塊命名空間、二級函數命名空間。

    7)模塊私有表達式與一個公有表達式重名時,優先調用本模塊中的私有表達式。

26 二級函數  [返回頁首] [返回目錄]

    在下面的說明中,FcErr表示相應函數的運行錯誤代碼。

    26.1 整數二級函數

    26.1.1 最大值函數 max(x1,x2,x3,... ...):

    若FcErr=1:沒有參數。

    26.1.2 最小值函數 min(x1,x2,x3,... ...):

    若FcErr=1:沒有參數。

    26.1.3 設置整數堆棧最大數目 SetIntStackMax(n):

    在使用遞歸函數之前,需要先設置一定數目的堆棧。通常n的值不能取得太大,當n取得很大時,函數遞歸調用雖不會溢出FORCAL的堆棧,但會使系統堆棧溢出,這樣會使程序運行中斷。該函數返回實際設置的堆棧數目。
    若FcErr=1:內存分配失敗;FcErr=2:在函數遞歸時使用該函數。

    26.1.4 設置常量 const("ConstStr",ConstValue)或const("ConstStr",ConstValue,bMode):

    ConstStr:常量名,要符合Forcal標識符的命名規定,否則編譯器找不到該常量。 可使用常量命名空間的方式命名,例如:"ConstName::MyConst"
    ConstValue:常量的值。當bMode為邏輯假時,不使用該值。
    bMode:指出工作方式。若缺省該參數(函數const只有兩個參數),創建一個永久性常量,無法刪除一個永久性常量,除非Forcal重新初始化。若bMode為邏輯真,創建一個暫時性常量;若bMode為邏輯假,刪除一個暫時性常量。暫時性常量保持常量的基本意義,在編譯表達式時不可改變其值,但可被const函數刪除。
    該函數返回值的意義如下:

      0:設置成功。
      1:已存在該常量。
      2:內存分配失敗。
      3:不能用空字符串作為常量名。
      4:參數太多或者太少。
      5:需用字符串指出常量名。
      6:不能刪除該常量。

    26.1.5 獲得調用其他類型表達式或其他類型二級函數時計算結果的字節值 GetCalByte(&x0,&x1):

    在整數表達式中調用實數表達式或者復數表達式之后,緊接著調用該函數,可以獲得計算結果的按字節復制來的值。由于Forcal表達式中,整數為8個字節,實數為8個字節,復數為16個字節,所以要獲得實數結果的按字節拷貝,需使用1個參數,要獲得復數結果的按字節拷貝,需使用2個參數。多余的參數被忽略,參數少將不能獲得計算結果的完整拷貝。該函數返回計算結果前8個字節表示的整數值。

    26.1.6 創建模塊命名空間 Module("NameSpace":"name1","name2",... ...):

    該函數為調用該函數的模塊創建模塊命名空間。NameSpace為空間名稱,繼承自"name1","name2",... ...。模塊命名空間可以循環繼承。模塊命名空間是一棵樹或者是一個連通圖。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:創建成功。
      1:至少需要一個參數,不能缺省模塊命名空間名稱。
      2:不能重復創建模塊命名空間,模塊命名空間只能創建一次。
      3:須用字符串指出模塊命名空間名稱。
      4:內存錯誤。
      5:該命名空間已被其他模塊使用。
      6:要創建的命名空間不能是空字符串。

    26.1.7 輸出模塊命名空間中的表達式 OutFun("fun1","fun2",... ...):

    該函數為模塊命名空間輸出表達式。模塊命名空間即調用函數OutFun的模塊的命名空間。須用字符串 參數指出表達式的名稱。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:操作成功。
      i:其他正整數:前i-1個參數操作成功,第i個參數操作失敗,其他參數未進行操作。

    26.1.8 獲得表達式的句柄 HFor("ForName",ForType,&nPara,&hModule,&bParaModify):

    ForName:表達式的名稱。可以是簡單名稱,也可以是包含模塊命名空間訪問符::(該訪問符可簡化為一個或多個:)的復雜名稱。
   
ForType:表達式的類型。如果是簡單名稱,只能取1(標識整數表達式)、2(標識實數表達式)、3(標識復數表達式)。如果名稱包含模塊命名空間訪問符::,只能取-1(標識整數表達式)、-2(標識實數表達式)、-3(標識復數表達式)。 若缺省該參數,默認為1。
   
nPara:返回表達式的參數個數。該參數可以缺省。
    hModule:返回表達式所在的模塊,模塊號保存在hModule的前4個字節中。該參數可以缺省。
    bParaModify:返回一個邏輯值,表示表達式的自定義參數在執行過程中是否可能被修改,邏輯真表示可能被修改。該參數可以缺省。

    26.1.9 訪問命名空間 using("NameSpace1","NameSpace2","NameSpace::name",... ...):

    命名空間(包括模塊命名空間、二級函數命名空間和常量命名空間)比較長時,輸入比較麻煩,使用using函數可簡化命名空間的訪問。

    執行過函數using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace",... ...)后,如果有一個命名空間中的函數NameSpace2::fun(x,y),不必寫出該命名空間,直接使用函數fun(x,y)就可以了 ;如果有一個常量命名空間中的常量ConstSpace::MyConst, 也不必寫出該命名空間,直接使用常量MyConst就可以了。 函數命名空間若與常量命名空間相同,只寫出一個即可。如下列:

      using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace");
      2+fun(5,6)+MyConst+3;

    注意:如果有一個非命名空間中的函數fun(x,y),將優先調用該函數,遇到這種情況,應使用函數的全名:NameSpace2::fun(x,y)。 如果有一個非命名空間中的常量MyConst,將優先調用該 常量,遇到這種情況,應使用常量的全名:ConstSpace::MyConst

    可使用using函數一次指定多個命名空間,當再一次調用using函數時,以前指定的命名空間將被刪除,可訪問的命名空間被重新設定。用using函數指定的命名空間僅在本模塊中起作用,換句話說,可在不同的模塊中使用using函數而互不影響。

    26.1.10 標記需自動銷毀的對象 free(p):

    函數free(p)可將對象p自動記錄下來,在銷毀表達式時銷毀對象p。函數free(p)仍然返回對象p,若標記失敗返回0。用法舉例如下:

      i: ConstObj(:static,obj)=
         {
           if{!obj, obj=new[...].free()},
 //第一次調用函數ConstObj()時,用函數new申請一個對象obj,并用函數free()標記在銷毀表達式 時銷毀它
           obj
                            //返回對象obj
        
};
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象

    注意:函數free(p)并不立即銷毀對象p,而是在銷毀表達式時銷毀該對象。并不是所有的對象都可由函數free銷毀,這取決于主程序和Forcal擴展庫的設計,在Forcal數據類型擴展庫FcData中用函數new申請的對象都可由函數free來銷毀。函數free(p)只適合銷毀少量的數據,故不要將其放在循環中使用。

    注意:靜態變量free和函數free(p)不必同時使用,同時使用將降低效率。

    26.1.11 獲得對象信息 o(p,... ...):

    p是一個對象指針,函數o(p,... ...)用于獲得對象p的信息。

    若FcErr=1:至少需要一個參數;FcErr=2:沒有為對象重載該函數。

    不是所有的對象都支持o函數,具體請查看該對象的說明。

    26.1.12 對象賦值 oset(p,... ...):

    p是一個對象指針,函數oset(p,... ...)可對對象p賦值。oset函數的調用是與等號相關聯的。

    若FcErr=1:至少需要一個參數;FcErr=2:沒有為對象重載該函數。

    不是所有的對象都支持oset函數,具體請查看該對象的說明。

    例子:設A、B是二維數組(矩陣)對象,i=2,j=3

    A(2,3)=1;    //相當于 oset[A,2,3 : 1]

    A.i.j=1;     //相當于 oset[A,i,j : 1]

    A.=A+B;      //相當于 oset[A : A+B]

    26.1.13 獲得對象的值 oget(p,... ...):

    p是一個對象指針,函數oget(p,... ...)可獲得對象p的值;p也可以是一個自定義函數的指針,此時將產生一個函數調用。oget函數的調用不與等號相關聯。

    該函數的返回值請參考對象的有關說明。若p是整數或實數函數指針,則該函數返回函數調用的值;若p是復數函數指針,則傳遞參數的個數為復數參數個數的2倍加1,最后一個參數返回復數的虛部,而該函數返回復數的實部。

    若FcErr=1:至少需要一個參數;FcErr=2:調用整數表達式時參數不匹配;FcErr=3:調用實數表達式時參數不匹配;FcErr=4:調用復數表達式時參數不匹配;FcErr=5:沒有為對象重載該函數。

    不是所有的對象都支持oget函數,具體請查看該對象的說明。

    例子1:對象指針。設A是一個二維數組(矩陣)對象,i=2,j=3

    A(2,3)=A(2,3)+1;    //相當于 oset[A,2,3 : oget(A,2,3)+1]

    A.i.j=A.i.j+1;      //相當于 oset[A,i,j : oget(A,i,j)+1]

    例子2:函數指針

    a(x)=x+2;
    (:p)= p=HFor("a"), p(3);   
//p(3)相當于oget(p,3),即調用函數a(3)

    26.1.14 垃圾收集 gc():

    立即掃描并銷毀垃圾對象,釋放所占空間。 函數返回0表示運行成功,否則表示不允許運行垃圾收集器。

    在Forcal中,一個對象用一個指針標識,在32位平臺上,一個指針是存放在一個數(整數、實數或復數)的前4個字節中,此時,我們也稱這個數為指向該對象的指針。若Forcal系統中的靜態變量、模塊變量、全局變量以及正在運行的表達式的數據區(自變量、動態變量及數據堆棧)中存在一個數指向一個對象時,該對象是有效的,否則視為垃圾對象,會被垃圾收集器所回收。

    26.1.15 設置一個對象是否可以保存子對象 SaveSubObj(p,k):

    p是一個對象指針。當k=0時,對象p將不能保存子對象,但子對象可暫時存在,在垃圾回收時將被銷毀;當k非0時,對象p將可以保存子對象,不會當作垃圾被回收。

    若FcErr=1:不能對該對象設置此屬性,該對象也不能保存子對象。

    返回值:指針p。

    說明:有些對象默認是可以保存子對象的,例如FcData中的類對象;有些對象默認是不保存子對象的,但可以用函數SaveSubObj使其能保存子對象,例如FcData中的64位整數數組、實數數組等;有些對象則無論如何都不能保存子對象。一個對象能否保存子對象,取決于該對象的設計者,請參考該對象的說明。

    26.2 實數二級函數

    26.2.1 最大值函數 max(x1,x2,x3,... ...):

    若FcErr=1:沒有參數。

    26.2.2 最小值函數 min(x1,x2,x3,... ...):

    若FcErr=1:沒有參數。

    26.2.3 取小數部分函數 modf(x,&y):

    該函數把x分解成整數和小數部分,并返回小數部分,整數部分由y返回(必須使用運算符&)。

    26.2.4 求和函數 sum("F",y1min,y1max,y1dy,y2min,y2max,y2dy,... ...):

    F為求和函數;y1min,y1max,y1dy為第一個自變量的初值、終值和參數增量[初值<終值,參數增量>0],依次類推。

    例子:

      F(x,y)=sin[x]+0.8-y;
      sum("F",1,2,0.01,2,5,0.1);

    FcErr=1:應使用字符串傳遞表達式名稱;FcErr=2:指定的表達式不存在;FcErr=3:參數個數不匹配;FcErr=4:常量表達式,無法求和;FcErr=5:內存分配失敗;FcErr=6:自變量參數非法。

    26.2.5 求積函數 pro("F",y1min,y1max,y1dy,y2min,y2max,y2dy... ...):

    用法請參見sum(),用于求積。
    FcErr=1:應使用字符串傳遞表達式名稱;FcErr=2:指定的表達式不存在;FcErr=3:參數個數不匹配;FcErr=4:常量表達式,無法求積;FcErr=5:內存分配失敗;FcErr=6:自變量參數非法。

    26.2.6 數據求和函數 DataSum("F",y11,y12,... ...,y21,y22,... ...):

    F為求和函數;y11,y12,... ...為第一組自變量數據,依次類推。

    例子:

      F(x,y)=x*y;
      DataSum["F",1,2,3,4,5,6,7,8,9,10];
//返回值為190;

      說明:對于式子F(x,y)=x*y,求x,y分別取1,2、3,4、5,6、7,8、9,10時的值的和。即求F[1,2]+F[3,4]+F[5,6]+F[7,8]+F[9,10]的值。

    若FcErr=1:應使用字符串傳遞表達式名稱;FcErr=2:指定的表達式不存在;FcErr=3:參數個數不匹配;FcErr=4:常量表達式,無法求和。

    26.2.7 數據求積函數 DataPro("F",y11,y12,... ...,y21,y22,... ...):

    用法請參見DataSum(),用于數據求積。
    若FcErr=1:應使用字符串傳遞表達式名稱;FcErr=2:指定的表達式不存在;FcErr=3:參數個數不匹配;FcErr=4:常量表達式,無法求積。

    26.2.8 設置實數堆棧最大數目 SetRealStackMax(n):

    在使用遞歸函數之前,需要先設置一定數目的堆棧。通常n的值不能取得太大,當n取得很大時,函數遞歸調用雖不會溢出FORCAL的堆棧,但會使系統堆棧溢出,這樣會使程序運行中斷。該函數返回實際設置的堆棧數目。
    若FcErr=1:內存分配失敗;FcErr=2:在函數遞歸時使用該函數。

    若FcErr=1:該函數至少使用兩個參數,或者參數不匹配;FcErr=2:應使用字符串傳遞二級函數名稱;FcErr=3:函數類型參數m非法;FcErr=4:找不到該二級函數;FcErr=5:內存分配失敗。

    26.2.9 設置常量 const("ConstStr",ConstValue)或const("ConstStr",ConstValue,bMode):

    ConstStr:常量名,要符合Forcal標識符的命名規定,否則編譯器找不到該常量。 可使用常量命名空間的方式命名,例如:"ConstName::MyConst"
    ConstValue:常量的值。當bMode為邏輯假時,不使用該值。
    bMode:指出工作方式。若缺省該參數(函數const只有兩個參數),創建一個永久性常量,無法刪除一個永久性常量,除非Forcal重新初始化。若bMode為邏輯真,創建一個暫時性常量;若bMode為邏輯假,刪除一個暫時性常量。暫時性常量保持常量的基本意義,在編譯表達式時不可改變其值,但可被const函數刪除。
    該函數返回值的意義如下:

      0:設置成功。
      1:已存在該常量。
      2:內存分配失敗。
      3:不能用空字符串作為常量名。
      4:參數太多或者太少。
      5:需用字符串指出常量名。
      6:不能刪除該常量。

    26.2.10 獲得調用其他類型表達式或其他類型二級函數時計算結果的字節值 GetCalByte(&x0,&x1):

    在實數表達式中調用整數表達式或者復數表達式之后,緊接著調用該函數,可以獲得計算結果的按字節復制來的值。由于Forcal表達式中,整數為8個字節,實數為8個字節,復數為16個字節,所以要獲得整數結果的按字節拷貝,僅需用一個參數,要獲得復數結果的按字節拷貝,需使用2個參數。多余的參數被忽略,參數少將不能獲得計算結果的完整拷貝。復制復數結果時,函數返回計算結果前8個字節表示的實數值,即復數的實部。

    26.2.11 創建模塊命名空間 Module("NameSpace":"name1","name2",... ...):

    該函數為調用該函數的模塊創建模塊命名空間。NameSpace為空間名稱,繼承自"name1","name2",... ...。模塊命名空間可以循環繼承。模塊命名空間是一棵樹或者是一個連通圖。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:創建成功。
      1:至少需要一個參數,不能缺省模塊命名空間名稱。
      2:不能重復創建模塊命名空間,模塊命名空間只能創建一次。
      3:須用字符串指出模塊命名空間名稱。
      4:內存錯誤。
      5:該命名空間已被其他模塊使用。
      6:要創建的命名空間不能是空字符串。

    26.2.12 輸出模塊命名空間中的表達式 OutFun("fun1","fun2",... ...):

    該函數為模塊命名空間輸出表達式。模塊命名空間即調用函數OutFun的模塊的命名空間。須用字符串 參數指出表達式的名稱。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:操作成功。
      i:其他正整數:前i-1個參數操作成功,第i個參數操作失敗,其他參數未進行操作。

    26.2.13 獲得表達式的句柄 HFor("ForName",ForType,&nPara,&hModule,&bParaModify):

    ForName:表達式的名稱。可以是簡單名稱,也可以是包含模塊命名空間訪問符::(該訪問符可簡化為一個或多個:)的復雜名稱。
   
ForType:表達式的類型。如果是簡單名稱,只能取1(標識整數表達式)、2(標識實數表達式)、3(標識復數表達式)。如果名稱包含模塊命名空間訪問符::,只能取-1(標識整數表達式)、-2(標識實數表達式)、-3(標識復數表達式)。 若缺省該參數,默認為2。
   
nPara:返回表達式的參數個數。該參數可以缺省。
    hModule:返回表達式所在的模塊,模塊號保存在hModule的前4個字節中。該參數可以缺省。
    bParaModify:返回一個邏輯值,表示表達式的自定義參數在執行過程中是否可能被修改,邏輯真表示可能被修改。該參數可以缺省。

    在實數表達式中,表達式句柄保存在實數的前4個字節中。

    26.2.14 訪問命名空間 using("NameSpace1","NameSpace2","NameSpace::name",... ...):

    命名空間(包括模塊命名空間、二級函數命名空間和常量命名空間)比較長時,輸入比較麻煩,使用using函數可簡化命名空間的訪問。

    執行過函數using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace",... ...)后,如果有一個命名空間中的函數NameSpace2::fun(x,y),不必寫出該命名空間,直接使用函數fun(x,y)就可以了 ;如果有一個常量命名空間中的常量ConstSpace::MyConst, 也不必寫出該命名空間,直接使用常量MyConst就可以了。 函數命名空間若與常量命名空間相同,只寫出一個即可。如下列:

      using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace");
      2+fun(5,6)+MyConst+3;

    注意:如果有一個非命名空間中的函數fun(x,y),將優先調用該函數,遇到這種情況,應使用函數的全名:NameSpace2::fun(x,y)。 如果有一個非命名空間中的常量MyConst,將優先調用該 常量,遇到這種情況,應使用常量的全名:ConstSpace::MyConst

    可使用using函數一次指定多個命名空間,當再一次調用using函數時,以前指定的命名空間將被刪除,可訪問的命名空間被重新設定。用using函數指定的命名空間僅在本模塊中起作用,換句話說,可在不同的模塊中使用using函數而互不影響。

    26.2.15 標記需自動銷毀的對象 free(p):

    函數free(p)可將對象p自動記錄下來,在銷毀表達式時銷毀對象p。函數free(p)仍然返回對象p,若標記失敗返回0。用法舉例如下:

      i: ConstObj(:static,obj)=
         {
           if{!obj, obj=new[...].free()},
 //第一次調用函數ConstObj()時,用函數new申請一個對象obj,并用函數free()標記在銷毀表達式 時銷毀它
           obj
                            //返回對象obj
        
};
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象

    注意:函數free(p)并不立即銷毀對象p,而是在銷毀表達式時銷毀該對象。并不是所有的對象都可由函數free銷毀,這取決于主程序和Forcal擴展庫的設計,在Forcal數據類型擴展庫FcData中用函數new申請的對象都可由函數free來銷毀。函數free(p)只適合銷毀少量的數據,故不要將其放在循環中使用。

    注意:靜態變量free和函數free(p)不必同時使用,同時使用將降低效率。

    26.2.16 獲得對象信息 o(p,... ...):

    p是一個對象指針,函數o(p,... ...)用于獲得對象p的信息。

    若FcErr=1:至少需要一個參數;FcErr=2:沒有為對象重載該函數。

    不是所有的對象都支持o函數,具體請查看該對象的說明。

    26.2.17 對象賦值 oset(p,... ...):

    p是一個對象指針,函數oset(p,... ...)可對對象p賦值。

    若FcErr=1:至少需要一個參數;FcErr=2:沒有為對象重載該函數。

    不是所有的對象都支持oset函數,具體請查看該對象的說明。

    例子:設A、B是二維數組(矩陣)對象,i=2,j=3

    A(2,3)=1;    //相當于 oset[A,2,3 : 1]

    A.i.j=1;     //相當于 oset[A,i,j : 1]

    A.=A+B;      //相當于 oset[A : A+B]

    26.2.18 獲得對象的值 oget(p,... ...):

    p是一個對象指針,函數oget(p,... ...)可獲得對象p的值;p也可以是一個自定義函數的指針,此時將產生一個函數調用。

    該函數的返回值請參考對象的有關說明。若p是整數或實數函數指針,則該函數返回函數調用的值;若p是復數函數指針,則傳遞參數的個數為復數參數個數的2倍加1,最后一個參數返回復數的虛部,而該函數返回復數的實部。

    若FcErr=1:至少需要一個參數;FcErr=2:調用整數表達式時參數不匹配;FcErr=3:調用實數表達式時參數不匹配;FcErr=4:調用復數表達式時參數不匹配;FcErr=5:沒有為對象重載該函數。

    不是所有的對象都支持oget函數,具體請查看該對象的說明。

    例子1:對象指針。設A是一個二維數組(矩陣)對象,i=2,j=3

    A(2,3)=A(2,3)+1;    //相當于 oset[A,2,3 : oget(A,2,3)+1]

    A.i.j=A.i.j+1;      //相當于 oset[A,i,j : oget(A,i,j)+1]

    例子2:函數指針

    a(x)=x+2;
    (:p)= p=HFor("a"), p(3);   
//p(3)相當于oget(p,3),即調用函數a(3)

    26.2.19 垃圾收集 gc():

    立即掃描并銷毀垃圾對象,釋放所占空間。 函數返回0表示運行成功,否則表示不允許運行垃圾收集器。

    在Forcal中,一個對象用一個指針標識,在32位平臺上,一個指針是存放在一個數(整數、實數或復數)的前4個字節中,此時,我們也稱這個數為指向該對象的指針。若Forcal系統中的靜態變量、模塊變量、全局變量以及正在運行的表達式的數據區(自變量、動態變量及數據堆棧)中存在一個數指向一個對象時,該對象是有效的,否則視為垃圾對象,會被垃圾收集器所回收。

    26.2.20 設置一個對象是否可以保存子對象 SaveSubObj(p,k):

    p是一個對象指針。當k=0時,對象p將不能保存子對象,但子對象可暫時存在,在垃圾回收時將被銷毀;當k非0時,對象p將可以保存子對象,不會當作垃圾被回收。

    若FcErr=1:不能對該對象設置此屬性,該對象也不能保存子對象。

    返回值:指針p。

    說明:有些對象默認是可以保存子對象的,例如FcData中的類對象;有些對象默認是不保存子對象的,但可以用函數SaveSubObj使其能保存子對象,例如FcData中的64位整數數組、實數數組等;有些對象則無論如何都不能保存子對象。一個對象能否保存子對象,取決于該對象的設計者,請參考該對象的說明。

    26.3 復數二級函數

    26.3.1 設置復數堆棧最大數目 SetComplexStackMax(n):

    在使用遞歸函數之前,需要先設置一定數目的堆棧。通常n的值不能取得太大,當n取得很大時,函數遞歸調用雖不會溢出FORCAL的堆棧,但會使系統堆棧溢出,這樣會使程序運行中斷。該函數返回實際設置的堆棧數目。
    若FcErr=1:內存分配失敗;FcErr=2:在函數遞歸時使用該函數。

    26.3.2 設置常量 const("ConstStr",ConstValue)或const("ConstStr",ConstValue,bMode):

    ConstStr:常量名,要符合Forcal標識符的命名規定,否則編譯器找不到該常量。 可使用常量命名空間的方式命名,例如:"ConstName::MyConst"
    ConstValue:常量的值。當bMode為邏輯假時,不使用該值。
    bMode:指出工作方式。若缺省該參數(函數const只有兩個參數),創建一個永久性常量,無法刪除一個永久性常量,除非Forcal重新初始化。若bMode為邏輯真,創建一個暫時性常量;若bMode為邏輯假,刪除一個暫時性常量。暫時性常量保持常量的基本意義,在編譯表達式時不可改變其值,但可被const函數刪除。
    該函數返回值的意義如下:

      0:設置成功。
      1:已存在該常量。
      2:內存分配失敗。
      3:不能用空字符串作為常量名。
      4:參數太多或者太少。
      5:需用字符串指出常量名。
      6:不能刪除該常量。

    26.3.3 獲得調用其他類型表達式或其他類型二級函數時計算結果的字節值 GetCalByte(&x0):

    在復數表達式中調用整數表達式或者實數表達式之后,緊接著調用該函數,可以獲得計算結果的按字節復制來的值。由于Forcal表達式中,整數為8個字節,實數為8個字節,復數為16個字節,所以要獲得整數或 實數結果,僅需用一個參數就可以了,多余的參數被忽略。若復制整數(或實數)結果,則整數(或實數)結果僅占復數的前8個字節,其余字節無意義,且函數返回時,整數 (或實數)結果也保存在返回值的前8個字節中(復數的實部)。

    26.3.4 創建模塊命名空間 Module("NameSpace":"name1","name2",... ...):

    該函數為調用該函數的模塊創建模塊命名空間。NameSpace為空間名稱,繼承自"name1","name2",... ...。模塊命名空間可以循環繼承。模塊命名空間是一棵樹或者是一個連通圖。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:創建成功。
      1:至少需要一個參數,不能缺省模塊命名空間名稱。
      2:不能重復創建模塊命名空間,模塊命名空間只能創建一次。
      3:須用字符串指出模塊命名空間名稱。
      4:內存錯誤。
      5:該命名空間已被其他模塊使用。
      6:要創建的命名空間不能是空字符串。

    26.3.5 輸出模塊命名空間中的表達式 OutFun("fun1","fun2",... ...):

    該函數為模塊命名空間輸出表達式。模塊命名空間即調用函數OutFun的模塊的命名空間。須用字符串 參數指出表達式的名稱。

    請參考模塊命名空間了解該函數的使用。

    該函數返回值的意義如下:

      0:操作成功。
      i:其他正整數:前i-1個參數操作成功,第i個參數操作失敗,其他參數未進行操作。

    26.3.6 獲得表達式的句柄 HFor("ForName",ForType,&nPara,&hModule,&bParaModify):

    ForName:表達式的名稱。可以是簡單名稱,也可以是包含模塊命名空間訪問符::(該訪問符可簡化為一個或多個:)的復雜名稱。
   
ForType:表達式的類型。如果是簡單名稱,只能取1(標識整數表達式)、2(標識實數表達式)、3(標識復數表達式)。如果名稱包含模塊命名空間訪問符::,只能取-1(標識整數表達式)、-2(標識實數表達式)、-3(標識復數表達式)。 若缺省該參數,默認為3。
   
nPara:返回表達式的參數個數。該參數可以缺省。
    hModule:返回表達式所在的模塊,模塊號保存在hModule的前4個字節中。該參數可以缺省。
    bParaModify:返回一個邏輯值,表示表達式的自定義參數在執行過程中是否可能被修改,邏輯真表示可能被修改。該參數可以缺省。

    在復數表達式中,表達式句柄保存在復數的前4個字節中。

    26.3.7 訪問命名空間 using("NameSpace1","NameSpace2","NameSpace::name",... ...):

    命名空間(包括模塊命名空間、二級函數命名空間和常量命名空間)比較長時,輸入比較麻煩,使用using函數可簡化命名空間的訪問。

    執行過函數using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace",... ...)后,如果有一個命名空間中的函數NameSpace2::fun(x,y),不必寫出該命名空間,直接使用函數fun(x,y)就可以了 ;如果有一個常量命名空間中的常量ConstSpace::MyConst, 也不必寫出該命名空間,直接使用常量MyConst就可以了。 函數命名空間若與常量命名空間相同,只寫出一個即可。如下列:

      using("NameSpace1","NameSpace2","NameSpace::name","ConstSpace");
      2+fun(5,6)+MyConst+3;

    注意:如果有一個非命名空間中的函數fun(x,y),將優先調用該函數,遇到這種情況,應使用函數的全名:NameSpace2::fun(x,y)。 如果有一個非命名空間中的常量MyConst,將優先調用該 常量,遇到這種情況,應使用常量的全名:ConstSpace::MyConst

    可使用using函數一次指定多個命名空間,當再一次調用using函數時,以前指定的命名空間將被刪除,可訪問的命名空間被重新設定。用using函數指定的命名空間僅在本模塊中起作用,換句話說,可在不同的模塊中使用using函數而互不影響。

    26.3.8 標記需自動銷毀的對象 free(p):

    函數free(p)可將對象p自動記錄下來,在銷毀表達式時銷毀對象p。函數free(p)仍然返回對象p,若標記失敗返回0。用法舉例如下:

      i: ConstObj(:static,obj)=
         {
           if{!obj, obj=new[...].free()},
 //第一次調用函數ConstObj()時,用函數new申請一個對象obj,并用函數free()標記在銷毀表達式 時銷毀它
           obj
                            //返回對象obj
        
};
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象
      i: ConstObj();                      //每次調用函數ConstObj(),都會得到同一個對象

    注意:函數free(p)并不立即銷毀對象p,而是在銷毀表達式時銷毀該對象。并不是所有的對象都可由函數free銷毀,這取決于主程序和Forcal擴展庫的設計,在Forcal數據類型擴展庫FcData中用函數new申請的對象都可由函數free來銷毀。函數free(p)只適合銷毀少量的數據,故不要將其放在循環中使用。

    注意:靜態變量free和函數free(p)不必同時使用,同時使用將降低效率。

27 關鍵字 [返回頁首] [返回目錄]

    在一般的編程語言中,關鍵字是事先定義的有特別意義的字,關鍵字是保留字,不能用來做標識符(如變量名) ,使用關鍵字來做變量名是一種語法錯誤,不能通過編譯。按此定義,則Forcal中沒有關鍵字。Forcal中只有常量、變量和函數。但有些符號常量、變量名或函數名使用很頻繁,可當作“關鍵字”來使用,不過不符合上述關鍵字的定義,例如:

f(return) = return(return+1);  //return是自變量,同時也是一個二級函數。
f(2);

    Forcal允許符號常量、變量和函數用同一個標識符表示,參考標識符解釋規則。但盡量避免這種用法。

    Forcal核心庫中的“關鍵字”見下表(Forcal核心庫中未定義任何符號常量,但一些Forcal擴展庫中定義的符號常量可當作“關鍵字”來使用,如FcData中定義的符號常量char、int等等。該表僅收錄Forcal核心庫中的“關鍵字”)。

關鍵字 類型 功能
static 靜態變量 定義靜態變量。
free 靜態變量、二級函數 專用靜態變量或函數,進行銷毀表達式前的釋放工作。
common 全局變量 定義全局變量。
const 二級函數 定義永久性符號常量或暫時性符號常量。
return 二級函數 結束計算并立即返回表達式的值。
if 二級函數 條件滿足時執行計算多個語句。
which 二級函數 自定義分段函數,選擇計算函數。
while 二級函數 “當型”循環函數。
until 二級函數 “直到型”循環函數。
continue 二級函數 返回while或until循環的開始。
break 二級函數 跳出while或until循環。
Module 二級函數 創建模塊命名空間。
OutFun 二級函數 輸出模塊命名空間中的表達式。
HFor 二級函數 獲得表達式的句柄。
using 二級函數 訪問命名空間。
oo 二級函數 支持運算符重載
to 一級函數 將臨時變量轉換為一般變量
oofree 一級函數 將一般變量轉換為臨時變量
o 二級函數 獲得對象信息
oset 二級函數 對象賦值
oget 二級函數 獲得對象的值

28 指針 [返回頁首] [返回目錄]

    指針是數據對象的內存地址,對象的成員函數通過指針可以操作對象,例如表達式句柄就是一個指針。Forcal擴展庫中存在很多指針對象,例如Forcal數據擴展動態庫FcData中,用函數new申請的數據對象都是指針。需要說明的是,靜態字符串地址和靜態數組地址不是指針,而是一個偏移量,但似乎也可以把它們看作指針一樣進行各種操作。

29 運算符及函數重載 [返回頁首] [返回目錄]

    在Forcal腳本中,函數oo{..., a+b, ...}中的運算符將被重載(該函數不可嵌套使用),運算符的第一操作數(例如a+b中的a)將被看作是一個指針(指向一個對象),Forcal在運算時將查找該指針的運算符重載函數,如果找到就調用該函數,否則將返回一個運行錯誤。有些重載運算符會返回一個臨時對象,甚至某些二級函數也會返回一個臨時對象,所有臨時對象在生命期結束時自動銷毀。

    所有在oo函數中產生的臨時對象的生命期不大于oo函數所在表達式運行時的生命期,即當一個表達式運行結束時,所有在該表達式中由oo函數產生的臨時對象都將被銷毀(若用函數to將臨時對象轉換為一般對象,則表達式的運行生命期結束時不會被銷毀)。

    如果某對象對運算符進行了重載,就要用到oo函數。例如:

    oo{                         //這段代碼僅說明oo函數的用法,并不能正常運行
        a=newo().oofree(),     
//申請一個對象,函數oofree將其轉換為臨時對象,由oo函數銷毀它 (一般情況下,在oo函數中生成的對象即為臨時對象,因而無需使用oofree函數)
        b=newo().oofree(),     
//申請一個對象,函數oofree將其轉換為臨時對象,由oo函數銷毀它 (一般情況下,在oo函數中生成的對象即為臨時對象,因而無需使用oofree函數)
        a+(a+b)*(a-b).show(),  
//兩個對象運算后輸出結果,產生的臨時對象由oo函數銷毀
        p=[a+(a+b)/(a-b)].to() 
//兩個對象運算后的結果由函數to轉換為一般對象,并賦值給p,可在oo函數外使用該對象并銷毀它
    }

    oo函數使用棧管理臨時對象,故如果在oo函數中存在一個循環,而在循環中又不斷生成新的對象,若不對新對象使用to函數,則只有最后一次循環的新對象被保留,其余的都將銷毀。

    oo函數中的運算符重載代碼只是為了代碼更清晰簡潔,但運行效率較低。

    在Forcal中可重載的運算符及函數見下表(實際的返回值請參考該對象的說明):

運算符 功  能 默認返回值 說  明
+ 臨時對象 雙目運算符。
- 臨時對象 雙目運算符。
* 臨時對象 雙目運算符。
/ 臨時對象 雙目運算符。
% 或 ^ 求模 或 乘方 臨時對象 雙目運算符。運算符%用在整數表達式中;運算符^用在實數表達式中。
- 臨時對象 單目運算符。
++ 前置自增 ++i 當前對象 單目運算符。
++ 后置自增 i++ 臨時對象 單目運算符。
-- 前置自減 --i 當前對象 單目運算符。
-- 后置自減 i-- 臨時對象 單目運算符。
> 大于 邏輯值 雙目運算符。
>= 大于等于 邏輯值 雙目運算符。
< 小于 邏輯值 雙目運算符。
<= 小于等于 邏輯值 雙目運算符。
== 等于 邏輯值 雙目運算符。
!= 不等于 邏輯值 雙目運算符。
& 邏輯值 雙目運算符。
| 邏輯值 雙目運算符。
! 邏輯值 單目運算符。
o{...} 重載函數 當前對象或一般對象 該函數一般用于獲得對象信息。
oset{...} 重載函數 當前對象或一般對象 該函數一般用于對象賦值。
oget{...} 重載函數 當前對象或一般對象 該函數一般用于獲得對象的值。

    注意:在Forcal腳本中無法定義運算符的重載,運算符重載是由設計該對象的程序員實現的。

30 動態內存管理 [返回頁首] [返回目錄]

    C程序員要自己管理內存的分配和回收,而Python具有垃圾自動回收的機制,Forcal的動態內存管理兼有二者的特點:既可以手動回收垃圾以提高運行效率,也可以完全依賴于Forcal的垃圾自動回收機制。通常,Forcal中用類似new的函數生成動態對象,而用類似delete的函數銷毀動態對象,這一點類似于C,用戶可以高效地管理內存;所有用戶沒有銷毀的對象,會由Forcal的垃圾收集器管理,并最終會被Forcal安全地回收,這一點類似于Python。

    Forcal核心庫中并沒有提供生成動態對象的函數,Forcal核心庫只對創建動態對象提供了良好的支持。這意味著,支持模塊可以使用C/C++、Delphi等語言創建任意的動態對象并加入Forcal系統。例如,Forcal數據類型擴展動態庫FcData就是一個能創建動態對象的功能模塊。

    在Forcal中,一個對象用一個指針標識,在32位平臺上,一個指針是存放在一個數(整數、實數或復數)的前4個字節中,此時,我們也稱這個數為指向該對象的指針。若Forcal系統中的靜態變量、模塊變量、全局變量以及正在運行的表達式的數據區(自變量、動態變量及數據堆棧)中存在一個數指向一個對象時,該對象是有效的,否則視為垃圾對象,會被垃圾收集器所回收。

    由于只要有一個指針(直接或間接)指向某對象,該對象就不會被垃圾收集器回收,故若要確保立即銷毀某對象,應使用delete之類的專用函數,而不要依賴垃圾收集器。

    Forcal的內存管理特點:(1)與C/C++類似,用戶可立即銷毀一個對象,這是推薦使用的方法;(2)被用戶忽略的垃圾將被自動回收;(3)任何時候,可手動立即啟動垃圾收集器;(4)垃圾回收是有運行開銷的,但如果用戶有效地管理了內存,垃圾回收器可以一次也不啟動。

    30.1 Forcal垃圾收集器何時啟動

    (1)用戶調用函數gc()將立即啟動垃圾收集器。

    (2)提供某對象的模塊檢測到對象太多時將自動啟動垃圾收集器。例如在FcData庫中,在使用函數new創建對象時(以FcData為基礎的庫都是直接或間接地調用new函數創建對象的),若new發現當前的對象數達到了允許的最大數,將先啟動垃圾收集器回收垃圾,再創建新的對象。一般來說,C/C++、Delphi程序員在設計動態對象時,會 用一個計數器記住生成的動態對象數目,當達到規定值時,就啟動垃圾收集器;當然,允許用戶修改對象計數器允許的最大值。

    (3)主程序可能會按一定的算法在處理器空閑時調用Forcal垃圾收集器,這取決于主程序的設計。

    注意:與其他語言的垃圾收集器不同,Forcal垃圾收集器總是立即啟動的。

    30.2 子對象與垃圾回收

    如果對象A的元素(或成員)包含了對象B,稱對象B為對象A的子對象。在垃圾回收時,若對象A有效而子對象B被回收,稱對象A是不能保存子對象的(在垃圾回收之前,子對象B可暫時保存);若只要對象A有效則子對象B就不會被回收,稱對象A是能保存子對象的。

    有些對象默認是可以保存子對象的,例如FcData中的類對象;有些對象默認是不保存子對象的,但可以用函數SaveSubObj使其能保存子對象,例如FcData中的64位整數數組、實數數組等;有些對象則無論如何都不能保存子對象。一個對象能否保存子對象,取決于該對象的設計者,請參考該對象的說明。

    以下例子中數組A中的子對象被垃圾收集器gc()銷毀了,故不能正常運行(不啟動垃圾收集器時,可以正常運行):

//array[3]用于申請存放3個變量的一維動態數組,該一維動態數組是一個FcData對象
!using["math"];        //使用命名空間math,來自于數學庫FcMath,該庫由FcData提供支持
a(:b:A)= A=array[3], A[1]=array[3], b=A[1], b[2]=333;
b(:b:A)= gc(),   
     //啟動垃圾收集器
         b=A[1], b[2];
//得到b[2]的值333

    使用函數SaveSubObj使對象A可保存子對象,程序即可正常運行:

!using["math"];
a(:b:A)= A=array[3].SaveSubObj[1], A[1]=array[3], b=A[1], b[2]=333;
b(:b:A)= gc(),
         b=A[1], b[2];

    30.3 自己管理內存

    以下程序運行時,將導致垃圾收集器多次啟動,效率較低:

//arrayinit[1,3 : 1,2,3]用于申請存放3個變量的一維動態數組并初始化,該一維動態數組是一個FcData對象
!using["math"];
main(:i,s,a,b,c)=
{
    s=0,i=0, while{++i<=10000,
//循環10000次,將多次自動啟動垃圾收集器,效率低
        a=arrayinit[1,3 : 1,2,3], b=arrayinit[1,3 : 1,2,3], c=arrayinit[1,3 : 1,2,3],
        s=s+a[0]+b[1]+c[2]
    },
    s             
//返回結果
};

    改成手動管理內存可提高運行效率:

!using["math"];
main(:i,s,a,b,c)=
{
    s=0,i=0, while{++i<=10000,
        a=arrayinit[1,3 : 1,2,3], b=arrayinit[1,3 : 1,2,3], c=arrayinit[1,3 : 1,2,3],
        s=s+a[0]+b[1]+c[2], delete[a,b,c]
//用delete函數銷毀對象a、b、c
    },
    s
};

    在設計大的程序時,大多數人對使用類似delete的函數都心存畏懼,那么,使用Forcal特有的oo函數(在oo函數中產生的動態對象會被自動銷毀)可以避免這一點,為此約定:

    1、所有生成動態對象的函數和語句都放在oo函數中,因為這些動態對象會被自動銷毀。
    2、任何自定義函數不要返回動態對象。所有需要的動態對象由調用者生成,傳給函數。

    下面是一個由oo函數自動管理動態對象的例子:

!using["math"];
Add(a,b,c,d) = oo{d.=a+b+c}, d;      
//定義一個函數,計算并返回a、b、c三個對象的和
AddSub(a,b,c,d) = oo{c.=a+b, d.=a-b};
//定義一個函數,計算并返回a、b的和c與差d,返回值無意義
main(:a,b,c,d) =
{
    oo{
        a=matrix[2,3 : 1,2,3,1,2,3], b=matrix[2,3 : 1,2,3,4,5,6],
//生成2×3矩陣并初始化
        c=matrix[2,3], d=matrix[2,3] 
//生成2×3矩陣,工作矩陣
    },
    AddSub(a,b,&c,&d),
 //調用函數AddSub,注意使用了引用參數
    outm[c], outm[d], 
 //輸出矩陣c、d
    Add(a,b,c,d).outm()
//調用函數Add,并輸出結果
};

    結果:

 2.  4.  6.
 5.  7.  9.

 0.  0.  0.
-3. -3. -3.

 4.  8. 12.
10. 14. 18.

    如果確實需要全局對象,可使用以下格式:

!using["math"];
init(::a,b) =
//全局動態對象用模塊變量或全局變量保存,這里是用模塊變量保存的。free函數指出在銷毀自定義函數init時才銷毀對象a,b
{
    a=matrix[2,3 : 1,2,3,1,2,3].free(), b=matrix[2,3 : 1,2,3,4,5,6].free()
//生成2×3矩陣并初始化
};
Add(a,b,c,d) = oo{d.=a+b+c}, d;
AddSub(a,b,c,d) = oo{c.=a+b, d.=a-b};
main(:c,d:a,b) =
{
    oo{c=matrix[2,3], d=matrix[2,3]},
    AddSub(a,b,&c,&d),
    outm[c], outm[d],
    Add(a,b,c,d).outm()
};

    結果:

 2.  4.  6.
 5.  7.  9.

 0.  0.  0.
-3. -3. -3.

 4.  8. 12.
10. 14. 18.

31 錯誤處理 [返回頁首] [返回目錄]

    錯誤有編譯錯誤和運行錯誤兩種。通常,Forcal程序總是準確定位編譯期錯誤的。若程序編譯通過,在運行時仍會發生錯誤,通常,Forcal程序總是記住并給出第一個運行錯誤的信息,錯誤信息包括運行出錯的表達式的類型和名稱(可見,給每一個表達式都起一個名字是非常重要的)、表達式所在的模塊、運行出錯的函數名、錯誤代碼等等,用戶可根據這些信息查找并修改錯誤。

    Forcal運行時使用錯誤(異常)處理的恢復模型。模塊化編譯運行庫MForcal中提供了一組函數以支持該功能:

    1、檢測輸出并清除Forcal運行錯誤:err();

    2、獲得Forcal運行錯誤:geterr(&ErrType,FunName,FunNameLen,&FunCode,&ForType,&ForHandle);

ErrType:返回運行錯誤的類型。
FunName:Forcal靜態字符串地址。返回出錯函數名。
FunNameLen:Forcal靜態字符串長度。
FunCode:返回函數錯誤代碼。
ForType:返回出錯表達式的類型。
ForHandle:返回出錯表達式的句柄,該句柄即編譯表達式時獲得的句柄。

    3、設置Forcal運行錯誤:seterr(ErrType,FunName,FunCode,ForType,ForHandle);

ErrType:設置運行錯誤的類型。
FunName:設置出錯的函數名,要求傳遞一個Forcal靜態字符串(長度小于80)。
FunCode:設置函數錯誤代碼。
ForType:設為0。
ForHandle:未使用。

    4、清除Forcal運行錯誤:clearerr();

    以下例子用函數seterr設置了一個Forcal運行錯誤,并用函數geterr捕獲了該錯誤:

f(:a,b,c,d,e)= seterr[66,"aaa",23,0,0], geterr[&a,b="\[10]",10,&c,&d,&e], printff[b];

    Forcal運行錯誤可由Forcal系統、二級函數,或者由Forcal腳本用戶進行設置,可在任意位置設置運行錯誤,同時可在任意位置捕獲該運行錯誤。運行錯誤一經設置,將始終存在,直到遇到函數clearerr()err()為止。在執行MForcal模塊的最后,將自動調用函數err()

    捕獲Forcal運行錯誤并進行處理后,可調用函數clearerr()清除運行錯誤,重啟程序代碼,通常需借助循環完成該處理過程。

32 效率 [返回頁首] [返回目錄]

    FORCAL中有以下提高效率的方法。

    1、將表達式中可以計算的部分放到括號中。

    例如,需要將表達式:

      F(x,y)=x-5-7+y

    寫成:F(x,y)=x-[5+7]+y或F(x,y)=x+[-5-7]+y。

    2、盡量使用自增減運算符++和--。

    例如要把 i=i+1 寫成 i++ 形式。

    3、until循環函數的速度比while循環函數要快。

    4、模塊變量和全局變量的訪問速度比自動變量快。

    5、盡量避免使用全局變量 ,全局變量會增加代碼維護的困難。

    6、類成員運算符“.”將降低編譯速度,對運行速度沒有影響,如果參數不是一個類,也沒有增加程序的易讀性,不要用該運算符。

    7、避免使用轉義字符"\[n]"開辟大的靜態空間,將影響編譯速度。

33 主要技術指標  [返回頁首] [返回目錄]

    1、表達式最大長度:約2G。
    2、自變量個數:不限。
    3、動態變量、靜態變量、模塊變量、全局變量個數:不限。
    4、最多可用的實數表達式:不限。
       最多可用的復數表達式:不限。
       最多可用的整數表達式:不限。
    5、表達式中最多可用的字符串數:不限。
    6、自定義外部函數個數:不限。
    7、while循環、until循環最大循環次數:不限。
    8、表達式遞歸調用最多層數:受系統堆棧和自定義堆棧大小的限制,自定義堆棧最大為2G。
    9、最多可存儲的用戶自定義數據類型:約2G。
    10、執行速度:一級函數速度約為FORTRAN(或C/C++)執行速度的50%左右;其他情況,速度稍有下降;
    11、FORCAL32W.DLL文件大小:約130K;不使用MSVC運行庫的靜態庫版本,約260K~300K。
    12、內存需求:視FORCAL運行情況而定。


版權所有© Forcal程序設計 2002-2011,保留所有權利
E-mail: [email protected]  QQ:630715621
最近更新: 2013年09月06日

福利彩票22选5走势图