2012-04-08 90 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