1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
/* CForm: convert MathPiper objects to C/C++ code. */
/* version 0.3 */
/* Changelog
0.1 CForm() derived from TeXForm() v0.4. Have basic functionality. Do not allow list manipulation, unevaluated derivatives, set operations, limits, integrals, Infinity, explicit matrices. Complex numbers and expressions are handled just like real ones. Indexed symbols are assumed to be arrays and handled literally. No declarations or prototypes are supplied. Function definitions are not handled. Sum() is left as is (can be defined as a C function).
0.2 Fix for extra parens in Sin() and other functions; fixes for Exp(), Abs() and inverse trig functions
0.3 Fix for indexed expressions: support a[2][3][4]
0.3.1 Fix for CForm(integer): add a decimal point
0.4 Support While()[]. Added IsCFormable. Use Concat() instead of Union() on lists.
0.4.1 Support False, True
0.4.2 Changed it so that integers are not coerced to floats any more automatically (one can coerce integers to floats manually nowadays by adding a decimal point to the string representation, eg. 1. instead of 1).
*/
/* To do:
0. Find and fix bugs.
1. Chop strings that are longer than 80 chars?
2. Optimization of C code?
*/
RuleBase("CForm",{expression});
RuleBase("CForm",{expression, precedence});
Function ("CFormBracketIf", {predicate, string})
[
Check(IsBoolean(predicate) And IsString(string), "CForm internal error: non-boolean and/or non-string argument of CFormBracketIf");
If(predicate, ConcatStrings("( ", string, ") "), string);
];
/* Proceed just like TeXForm()
*/
// CFormMaxPrec should perhaps only be used from within this file, it is thus not in the .def file.
CFormMaxPrec() := 60000; /* This precedence will never be bracketed. It is equal to KMaxPrec */
100 # CForm(_x) <-- CForm(x, CFormMaxPrec());
/* Replace numbers and variables -- never bracketed except explicitly */
110 # CForm(x_IsInteger, _p) <-- String(x);
111 # CForm(x_IsZero, _p) <-- "0.";
112 # CForm(x_IsNumber, _p) <-- String(x);
/* Variables are left as is, except some special ones */
190 # CForm(False, _p) <-- "false";
190 # CForm(True, _p) <-- "true";
200 # CForm(x_IsAtom, _p) <-- String(x);
/* Strings must be quoted but not bracketed */
100 # CForm(x_IsString, _p) <-- ConcatStrings("\"", x, "\"");
/* Replace operations */
/* arithmetic */
/* addition, subtraction, multiplication, all comparison and logical operations are "regular" */
LocalSymbols(cformRegularOps) [
cformRegularOps := { {"+"," + "}, {"-"," - "}, {"*"," * "},
{"/"," / "}, {":="," = "}, {"=="," == "},
{"="," == "}, {"!="," != "}, {"<="," <= "},
{">="," >= "}, {"<"," < "}, {">"," > "},
{"And"," && "}, {"Or"," || "}, {">>", " >> "},
{ "<<", " << " }, { "&", " & " }, { "|", " | " },
{ "%", " % " }, { "^", " ^ " },
};
CFormRegularOps() := cformRegularOps;
]; // LocalSymbols(cformRegularOps)
/* This is the template for "regular" binary infix operators:
100 # CForm(_x + _y, _p) <-- CFormBracketIf(p<OpPrecedence("+"), ConcatStrings(CForm(x, OpLeftPrecedence("+")), " + ", CForm(y, OpRightPrecedence("+")) ) );
*/
/* unary addition */
100 # CForm(+ _y, _p) <-- CFormBracketIf(p<OpPrecedence("+"), ConcatStrings(" + ", CForm(y, OpRightPrecedence("+")) ) );
/* unary subtraction */
100 # CForm(- _y, _p) <-- CFormBracketIf(p<OpPrecedence("-"), ConcatStrings(" - ", CForm(y, OpRightPrecedence("-")) ) );
/* power's argument is never bracketed but it must be put in braces. */
100 # CForm(_x ^ _y, _p) <-- CFormBracketIf(p<=OpPrecedence("^"), ConcatStrings("pow(", CForm(x, CFormMaxPrec()), ", ", CForm(y, CFormMaxPrec()), ")" ) );
100 # CForm(if(_pred)_body, _p) <-- "if (":CForm(pred,60000):") ":CForm(body);
100 # CForm(_left else _right, _p) <-- CForm(left):" else ":CForm(right);
LocalSymbols(cformMathFunctions) [
cformMathFunctions :=
{
{"Sqrt","sqrt"},
{"Cos","cos"},
{"Sin","sin"},
{"Tan","tan"},
{"Cosh","cosh"},
{"Sinh","sinh"},
{"Tanh","tanh"},
{"Exp","exp"},
{"Ln","log"},
{"ArcCos","acos"},
{"ArcSin","asin"},
{"ArcTan","atan"},
{"ArcCosh","acosh"},
{"ArcSinh","asinh"},
{"ArcTanh","atanh"},
{"Max","max"},
{"Min","min"},
{"Abs","fabs"},
{"Floor","floor"},
{"Ceil","ceil"},
{"!","factorial"}
};
CFormMathFunctions() := cformMathFunctions;
]; // LocalSymbols(cformMathFunctions)
/* Precedence of 120 because we'd like to process some special functions like pow() first */
120 # CForm(expr_IsFunction, _p)_(NrArgs(expr)=2 And Contains(AssocIndices(CFormRegularOps()), Type(expr)) ) <--
CFormBracketIf(p<OpPrecedence(Type(expr)), ConcatStrings(CForm(Listify(expr)[2], OpLeftPrecedence(Type(expr))), CFormRegularOps()[Type(expr)], CForm(Listify(expr)[3], OpRightPrecedence(Type(expr))) ) );
/* Sin, Cos, etc. and their argument is always bracketed */
120 # CForm(expr_IsFunction, _p) _
(NrArgs(expr)=1 And Contains(AssocIndices(CFormMathFunctions()), Type(expr)) ) <--
ConcatStrings(CFormMathFunctions()[Type(expr)], "(", CForm( Listify(expr)[2], CFormMaxPrec()),")" );
/* functions */
/* Unknown function, precedence 200. Leave as is, never bracket the function itself and bracket the argumentPointer(s) automatically since it's a list. Other functions are precedence 100 */
CFormArgs(list_IsList) <--
[
Local(i,nr,result);
result:="";
nr:=Length(list);
For (i:=1,i<=nr,i++)
[
result:=result:CForm(list[i]);
If (i<nr, result:=result:", ");
];
result;
];
200 # CForm(_x, _p)_(IsFunction(x)) <--
[
ConcatStrings(Type(x), "(", CFormArgs(Tail(Listify(x))),")" );
];
/* Complex numbers */
100 # CForm(Complex(0, 1), _p) <-- "I";
100 # CForm(Complex(_x, 0), _p) <-- CForm(x, p);
110 # CForm(Complex(_x, 1), _p) <-- CForm(x+Hold(I), p);
110 # CForm(Complex(0, _y), _p) <-- CForm(Hold(I)*y, p);
120 # CForm(Complex(_x, _y), _p) <-- CForm(x+Hold(I)*y, p);
/* Some special functions: Mod */
100 # CForm(Mod(_x, _y), _p) <-- CFormBracketIf(p<OpPrecedence("/"), ConcatStrings(CForm(x, OpPrecedence("/")), " % ", CForm(y, OpPrecedence("/")) ) )
;
/* Indexed expressions are never bracketed */
// the rule with [ ] seems to have no effect?
//100 # CForm(_x [ _i ], _p) <-- ConcatStrings(CForm(x, CFormMaxPrec()), "[", CForm(i, CFormMaxPrec()), "]");
100 # CForm(Nth(_x, _i), _p) <-- ConcatStrings(CForm(x, CFormMaxPrec()), "[", CForm(i, CFormMaxPrec()), "]");
LocalSymbols(cindent) [
cindent:=1;
NlIndented():=
[
Local(result);
// carriage return, so needs to start at the beginning of the line
result:=
"
";
Local(i);
For(i:=1,i<cindent,i++)
[
result:=result:" ";
];
result;
];
CIndent() :=
[
(cindent++);
"";
];
CUndent() :=
[
(cindent--);
"";
];
]; // LocalSymbols(cindent)
CFormStatement(_x) <-- CForm(x) : ";" : NlIndented();
120 # CForm(_x,_p)_(Type(x) = "Prog") <--
[
Local(result);
result:=CIndent():"{":NlIndented();
ForEach(item,Tail(Listify(x)))
[
result:=result:CFormStatement(item);
];
result:=result:"}":CUndent():NlIndented();
result;
];
120 # CForm(For(_from,_to,_step)_body,_p) <--
"for(" : CForm(from,CFormMaxPrec()) : ";"
: CForm(to,CFormMaxPrec()) : ";"
: CForm(step,CFormMaxPrec()) : ")"
: CIndent() : NlIndented()
: CFormStatement(body) : CUndent();
120 # CForm(While(_pred)_body, _p) <--
"while(" : CForm(pred,CFormMaxPrec()) : ")"
: CIndent() : NlIndented()
: CFormStatement(body) : CUndent();
//////////////////////////////////////////////////
/// IsCFormable
//////////////////////////////////////////////////
LocalSymbols(CFormAllFunctions) [
/// predicate to test whether an expression can be successfully exported to C code
/// interface with empty extra function list
// need the backquote stuff b/c we have HoldArg now
IsCFormable(_expr) <-- `IsCFormable(@expr, {});
// need to check that expr contains only allowed functions
IsCFormable(_expr, funclist_IsList) <--
[
Local(bad'functions);
bad'functions := Difference(`FuncList(@expr), Concat(CFormAllFunctions, funclist));
If(Length(bad'functions)=0,
True,
[
If(InVerboseMode(),
Echo(Concat({"IsCFormable: Info: unexportable function(s): "}, bad'functions))
);
False;
]
);
];
HoldArgNr("IsCFormable", 1, 1);
HoldArgNr("IsCFormable", 2, 1);
/// This is a list of all function atoms which CForm can safely handle
CFormAllFunctions := MapSingle(Atom, Concat(AssocIndices(CFormMathFunctions()), AssocIndices(CFormRegularOps()),
// list of "other" (non-math) functions supported by CForm: needs to be updated when CForm is extended to handle new functions
{
"For",
"While",
"Prog",
"Nth",
"Mod",
"Complex",
"if",
"else",
"++",
"--",
}
));
]; // LocalSymbols(CFormAllFunctions)
|