2012-04-08 95 views
0

我想擴展Maple CodeGeneration [C]的分段函數處理程序(不知道爲什麼它不包括在內)。 爲此我做:擴展楓葉代碼生成中的變量名稱

with(CodeGeneration): 
with(LanguageDefinition): 

LanguageDefinition:-Define("NewC", extend="C", 
    AddFunction("piecewise", anything::numeric, 
     proc() 
      local i; 
      Printer:-Print("if(",_passed[1],"){",_passed[2],"}"); 
      for i from 3 to _npassed-2 by 2 do 
       Printer:-Print("else if(",_passed[i],"){",_passed[i+1],"}"); 
      end do; 
      Printer:-Print("else{",_passed[_npassed],"}"); 
     end proc, 
    numeric=double) 
); 

請注意,我用的,如果else語句贊成puropose case語句。 下面是一個例子代碼翻譯:

myp:=proc(x::numeric) 
    piecewise(x>1,1*x,x>2,2*x,x>3,3*x,0); 
end proc: 
Translate(myp, language="NewC"); 

輸出是

void myp (double x) 
{ 
    if(0.1e1 < x){x}else if(0.2e1 < x){0.2e1 * x}else if(0.3e1 < x){0.3e1 * x}else{0}; 
    ; 
} 

對於一個合法的C-例行我顯然需要更換大括號一樣

{x} 

的東西像

{result=x;} 

和其他類似。我可以通過修改上面的AddFunction語句中的字符串來實現這一點。但是,那麼變量名結果對於代碼生成器是不知道的,所以不會有任何聲明,也不會根據需要返回結果的值以匹配例程myp或任何更復雜的過程,其中可以分配分段結果到其他一些變量或用於計算。那麼如何在CodeGeneration例程中正確處理這個問題呢?即我怎樣才能得到一個有效的變量名等

回答

1

這樣的事情呢?

restart: 

with(CodeGeneration): 
with(LanguageDefinition): 

LanguageDefinition:-Define("NewC", extend="C", 
    AddFunction("piecewise", anything::numeric, 
     proc() 
      local i; 
      Printer:-Print("((",_passed[1],") ? ",_passed[2]); 
      for i from 3 to _npassed-2 by 2 do 
       Printer:-Print(" : (",_passed[i],") ? ",_passed[i+1]); 
      end do; 
      Printer:-Print(" : ",_passed[_npassed],") "); 
     end proc, 
    numeric=double) 
); 

myp:=proc(x::numeric) local result::numeric; 
    result := piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0); 
end proc: 

Translate(myp, language="NewC"); 

double myp (double x) 
{ 
    double result; 
    result = ((0.3e1 < x) ? 0.3e1 * x : (0.2e1 < x) ? 0.2e1 * x : (0.1e1 < x) ? x : 0) ; 
    return(result); 
} 

[編輯,添加下面的材料]

事實證明,CodeGeneration [C]不處理piecewise,但只有當optimize選項被提供。 (我將提交錯誤報告,它應該在默認情況下進行處理。)

restart: 

with(CodeGeneration): 
with(LanguageDefinition): 
myp:=proc(x::numeric) local result::numeric; 
    result:=piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0); 
end proc; 

     myp := proc(x::numeric) 
     local result::numeric; 
      result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0) 
     end proc; 

Translate(myp, language="C", optimize); 

double myp (double x) 
{ 
    double result; 
    double s1; 
    if (0.3e1 < x) 
    s1 = 0.3e1 * x; 
    else if (0.2e1 < x) 
    s1 = 0.2e1 * x; 
    else if (0.1e1 < x) 
    s1 = x; 
    else 
    s1 = 0.0e0; 
    result = s1; 
    return(result); 
} 

正如你所看到的,piecewise被翻譯上述處理到一個單獨的if(){..}塊,以分配給引入的臨時變量。隨後在Maple過程中存在調用piecewise的地方使用該臨時值。臨時宣佈。尼斯和自動。所以這可能足以讓您使用piecewise

你也問過你如何在你自己的擴展中引入和聲明這樣的臨時變量(如果我理解你的話)。繼續從上面的同一個楓樹會議,這裏有一些想法。生成未分配的全局名稱。將myp過程置於惰性形式,將新局部變量添加到該形式。然後,改變後的惰性形式被轉變回實際的程序。作爲說明,我使用了原始擴展的修改版本來處理piecewise。這一切都產生了接近可接受的東西。唯一的障礙是,轉讓聲明,

result = temporary_variable; 

是不合適的!它位於piecewise翻譯塊之前。我還沒有看到如何修復該方法。

LanguageDefinition:-Define("NewC", extend="C", 
    AddFunction("piecewise", anything::numeric, 
     proc() 
      global T; 
      local i, t; 
      t:=convert(T,string); 
      Printer:-Print(t,";\n"); 
      Printer:-Print(" if (",_passed[1], 
          ")\n { ",t," = ",_passed[2],"; }\n"); 
      for i from 3 to _npassed-2 by 2 do 
       Printer:-Print(" else if (",_passed[i],")\n { ", 
           t," = ",_passed[i+1],"; }\n"); 
      end do; 
      Printer:-Print(" else { ",t," = ",_passed[_npassed],"; }"); 
     end proc, 
    numeric=double) 
): 

T:=`tools/genglobal`('s'): 

newmyp := FromInert(subsindets(ToInert(eval(myp)),'specfunc(anything,_Inert_LOCALSEQ)', 
      z->_Inert_LOCALSEQ(op(z), 
           _Inert_DCOLON(_Inert_NAME(convert(T,string)), 
              _Inert_NAME("numeric", 
               _Inert_ATTRIBUTE(_Inert_NAME("protected", 
               _Inert_ATTRIBUTE(_Inert_NAME("protected") 
     )))))))); 

      newmyp := proc(x::numeric) 
      local result::numeric, s::numeric; 
       result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0) 
      end proc; 

Translate(newmyp, language="NewC"); 

double newmyp (double x) 
{ 
    double result; 
    double s; 
    result = s; 
    if (0.3e1 < x) 
    { s = 0.3e1 * x; } 
    else if (0.2e1 < x) 
    { s = 0.2e1 * x; } 
    else if (0.1e1 < x) 
    { s = x; } 
    else { s = 0; }; 
    return(result); 
} 

如果重新運行上面的最後三個報表(從分配到T,通過對Translate呼叫),那麼你應該可以看到使用了新的臨時變量,如S0。然後再次重複s1。等等。

也許這會給你更多的想法。乾杯。

+0

這當然是有效的,並且可能是分段函數的最佳解決方案。但是,在我需要做一些中間計算來評估C語言函數的一般情況下,我能做些什麼呢?我如何獲得有效的變量名稱? – highsciguy 2012-04-10 13:51:39