1 /*
2   This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.
3 
4   Author: Uwe Schulzweida
5 
6 */
7 
8 #include <cstdlib>
9 #include <cassert>
10 #include <cdi.h>
11 
12 #include "cdo_options.h"
13 #include "dmemory.h"
14 #include "process_int.h"
15 #include "field.h"
16 #include "expr.h"
17 #include "expr_fun.h"
18 #include "expr_yacc.h"
19 #include "cdo_zaxis.h"
20 
21 static const char *const ExIn[] = { "expr", "init" };
22 static const char *const tmpvnm = "_tmp_";
23 static int pointID = -1;
24 static int zonalID = -1;
25 static int surfaceID = -1;
26 
27 enum
28 {
29   FT_STD,
30   FT_CONST,
31   FT_FLD,
32   FT_ZON,
33   FT_VERT,
34   FT_COORD,
35   FT_1C,
36   FT_2C,
37   FT_0
38 };
39 
40 // clang-format off
41 auto expr_func_con_var = [](auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut, auto binray_operator)
__anona30997820202(auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut, auto binray_operator) 42 {
43   if (hasMissvals)
44     {
45       if (std::isnan(mv))
46         for (size_t i = 0; i < n; ++i) vOut[i] = dbl_is_equal(vIn[i], mv) ? mv : binray_operator(cVal, vIn[i]);
47       else
48         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(vIn[i], mv) ? mv : binray_operator(cVal, vIn[i]);
49     }
50   else
51     {
52       for (size_t i = 0; i < n; ++i) vOut[i] = binray_operator(cVal, vIn[i]);
53     }
54 };
55 
56 auto expr_mul_con_var = [](auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut)
__anona30997820302(auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut) 57 {
58   if (hasMissvals)
59     {
60       if (std::isnan(mv))
61         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(cVal, 0.0) ? 0.0 : dbl_is_equal(vIn[i], mv) ? mv : binary_op_MUL(cVal, vIn[i]);
62       else
63         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(cVal, 0.0) ? 0.0 : is_equal(vIn[i], mv) ? mv : binary_op_MUL(cVal, vIn[i]);
64     }
65   else
66     {
67       for (size_t i = 0; i < n; ++i) vOut[i] = binary_op_MUL(cVal, vIn[i]);
68     }
69 };
70 
71 auto expr_div_con_var = [](auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut)
__anona30997820402(auto hasMissvals, auto n, auto mv, const auto cVal, const auto &vIn, auto &vOut) 72 {
73   if (hasMissvals)
74     {
75       if (std::isnan(mv))
76         for (size_t i = 0; i < n; ++i) vOut[i] = (dbl_is_equal(vIn[i], mv) || dbl_is_equal(vIn[i], 0.0)) ? mv : binary_op_DIV(cVal, vIn[i]);
77       else
78         for (size_t i = 0; i < n; ++i) vOut[i] = (is_equal(vIn[i], mv) || is_equal(vIn[i], 0.0)) ? mv : binary_op_DIV(cVal, vIn[i]);
79     }
80   else
81     {
82       for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(vIn[i], 0.0) ? mv : binary_op_DIV(cVal, vIn[i]);
83     }
84 };
85 
86 auto expr_func_var_con = [](auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut, auto binray_operator)
__anona30997820502(auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut, auto binray_operator) 87 {
88   if (hasMissvals)
89     {
90       if (std::isnan(mv))
91         for (size_t i = 0; i < n; ++i) vOut[i] = dbl_is_equal(vIn[i], mv) ? mv : binray_operator(vIn[i], cVal);
92       else
93         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(vIn[i], mv) ? mv : binray_operator(vIn[i], cVal);
94     }
95   else
96     {
97       for (size_t i = 0; i < n; ++i) vOut[i] = binray_operator(vIn[i], cVal);
98     }
99 };
100 
101 auto expr_mul_var_con = [](auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut)
__anona30997820602(auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut) 102 {
103   if (hasMissvals)
104     {
105       if (std::isnan(mv))
106         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(cVal, 0.0) ? 0.0 : dbl_is_equal(vIn[i], mv) ? mv : binary_op_MUL(vIn[i], cVal);
107       else
108         for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(cVal, 0.0) ? 0.0 : is_equal(vIn[i], mv) ? mv : binary_op_MUL(vIn[i], cVal);
109     }
110   else
111     {
112       for (size_t i = 0; i < n; ++i) vOut[i] = binary_op_MUL(vIn[i], cVal);
113     }
114 };
115 
116 auto expr_div_var_con = [](auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut)
__anona30997820702(auto hasMissvals, auto n, auto mv, const auto &vIn, const auto cVal, auto &vOut) 117 {
118   if (hasMissvals)
119     {
120       if (std::isnan(mv))
121         for (size_t i = 0; i < n; ++i) vOut[i] = (dbl_is_equal(vIn[i], mv) || dbl_is_equal(cVal, 0.0)) ? mv : binary_op_DIV(vIn[i], cVal);
122       else
123         for (size_t i = 0; i < n; ++i) vOut[i] = (is_equal(vIn[i], mv) || is_equal(cVal, 0.0)) ? mv : binary_op_DIV(vIn[i], cVal);
124     }
125   else
126     {
127       for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(cVal, 0.0) ? mv : binary_op_DIV(vIn[i], cVal);
128     }
129 };
130 
131 auto expr_func_var_var = [](auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut, auto binray_operator)
__anona30997820802(auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut, auto binray_operator) 132 {
133   if (hasMissvals)
134     {
135       if (std::isnan(mv1) || std::isnan(mv2))
136         for (size_t i = 0; i < n; ++i) vOut[i] = (dbl_is_equal(vIn1[i], mv1) || dbl_is_equal(vIn2[i], mv2)) ? mv1 : binray_operator(vIn1[i], vIn2[i]);
137       else
138         for (size_t i = 0; i < n; ++i) vOut[i] = (is_equal(vIn1[i], mv1) || is_equal(vIn2[i], mv2)) ? mv1 : binray_operator(vIn1[i], vIn2[i]);
139     }
140   else
141     {
142       for (size_t i = 0; i < n; ++i) vOut[i] = binray_operator(vIn1[i], vIn2[i]);
143     }
144 };
145 
146 auto expr_mul_var_var = [](auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut)
__anona30997820902(auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut) 147 {
148   if (hasMissvals)
149     {
150       if (std::isnan(mv1) || std::isnan(mv2))
151         for (size_t i = 0; i < n; ++i)
152           vOut[i] = (dbl_is_equal(vIn1[i], 0.0) || dbl_is_equal(vIn2[i], 0.0)) ? 0.0 : (dbl_is_equal(vIn1[i], mv1) || dbl_is_equal(vIn2[i], mv2)) ? mv1 : binary_op_MUL(vIn1[i], vIn2[i]);
153       else
154         for (size_t i = 0; i < n; ++i)
155           vOut[i] = (is_equal(vIn1[i], 0.0) || is_equal(vIn2[i], 0.0)) ? 0.0 : (is_equal(vIn1[i], mv1) || is_equal(vIn2[i], mv2)) ? mv1 : binary_op_MUL(vIn1[i], vIn2[i]);
156     }
157   else
158     {
159       for (size_t i = 0; i < n; ++i) vOut[i] = binary_op_MUL(vIn1[i], vIn2[i]);
160     }
161 };
162 
163 auto expr_div_var_var = [](auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut)
__anona30997820a02(auto hasMissvals, auto n, auto mv1, auto mv2, const auto &vIn1, const auto &vIn2, auto &vOut) 164 {
165   if (hasMissvals)
166     {
167       if (std::isnan(mv1) || std::isnan(mv2))
168         for (size_t i = 0; i < n; ++i) vOut[i] = (dbl_is_equal(vIn1[i], mv1) || dbl_is_equal(vIn2[i], mv2) || dbl_is_equal(vIn2[i], 0.0)) ? mv1 : binary_op_DIV(vIn1[i], vIn2[i]);
169       else
170         for (size_t i = 0; i < n; ++i) vOut[i] = (is_equal(vIn1[i], mv1) || is_equal(vIn2[i], mv2) || is_equal(vIn2[i], 0.0)) ? mv1 : binary_op_DIV(vIn1[i], vIn2[i]);
171     }
172   else
173     {
174       for (size_t i = 0; i < n; ++i) vOut[i] = is_equal(vIn2[i], 0.0) ? mv1 : binary_op_DIV(vIn1[i], vIn2[i]);
175     }
176 };
177 // clang-format on
178 
179 // clang-format off
f_float(const double x)180 static double f_float(const double x) { return (float) (x); }
f_int(const double x)181 static double f_int(const double x) { return (int) (x); }
f_nint(const double x)182 static double f_nint(const double x) { return std::round(x); }
f_rand(const double x)183 static double f_rand(const double x) { (void)x; return ((double) std::rand()) / ((double) RAND_MAX); }
f_sqr(const double x)184 static double f_sqr(const double x) { return x * x; }
f_rad(const double x)185 static double f_rad(const double x) { return x * M_PI / 180.0; }
f_deg(const double x)186 static double f_deg(const double x) { return x * 180.0 / M_PI; }
f_isMissval(const double x)187 static double f_isMissval(const double x) { (void)x; return 0.0; }
188 
pt_ngp(const paramType * const p)189 static double pt_ngp(const paramType *const p) { return p->ngp; }
pt_nlev(const paramType * const p)190 static double pt_nlev(const paramType *const p) { return p->nlev; }
pt_size(const paramType * const p)191 static double pt_size(const paramType *const p) { return p->ngp * p->nlev; }
pt_missval(const paramType * const p)192 static double pt_missval(const paramType *const p) { return p->missval; }
ts_ctimestep(const double * const data)193 static double ts_ctimestep(const double *const data) { return std::lround(data[CTIMESTEP]); }
ts_cdate(const double * const data)194 static double ts_cdate(const double *const data) { return std::lround(data[CDATE]); }
ts_ctime(const double * const data)195 static double ts_ctime(const double *const data) { return std::lround(data[CTIME]); }
ts_cdeltat(const double * const data)196 static double ts_cdeltat(const double *const data) { return data[CDELTAT]; }
ts_cday(const double * const data)197 static double ts_cday(const double *const data) { return data[CDAY]; }
ts_cmonth(const double * const data)198 static double ts_cmonth(const double *const data) { return data[CMONTH]; }
ts_cyear(const double * const data)199 static double ts_cyear(const double *const data) { return data[CYEAR]; }
ts_csecond(const double * const data)200 static double ts_csecond(const double *const data) { return data[CSECOND]; }
ts_cminute(const double * const data)201 static double ts_cminute(const double *const data) { return data[CMINUTE]; }
ts_chour(const double * const data)202 static double ts_chour(const double *const data) { return data[CHOUR]; }
203 // clang-format on
204 
205 struct func_t
206 {
207   int type;
208   int flag;
209   const char *name;    // function name
210   void (*func)(void);  // pointer to function
211 };
212 
213 // clang-format off
214 static const func_t fun_sym_tbl[] = {
215   // scalar functions
216   { FT_STD, 0, "abs",   (void (*)(void))((double (*)(double)) fabs) },  // math functions could be inlined
217   { FT_STD, 0, "floor", (void (*)(void))((double (*)(double)) floor) },
218   { FT_STD, 0, "ceil",  (void (*)(void))((double (*)(double)) ceil) },
219   { FT_STD, 0, "sqrt",  (void (*)(void))((double (*)(double)) sqrt) },
220   { FT_STD, 0, "exp",   (void (*)(void))((double (*)(double)) exp) },
221   { FT_STD, 0, "erf",   (void (*)(void))((double (*)(double)) erf) },
222   { FT_STD, 0, "log",   (void (*)(void))((double (*)(double)) log) },
223   { FT_STD, 0, "ln",    (void (*)(void))((double (*)(double)) log) },
224   { FT_STD, 0, "log10", (void (*)(void))((double (*)(double)) log10) },
225   { FT_STD, 0, "sin",   (void (*)(void))((double (*)(double)) sin) },
226   { FT_STD, 0, "cos",   (void (*)(void))((double (*)(double)) cos) },
227   { FT_STD, 0, "tan",   (void (*)(void))((double (*)(double)) tan) },
228   { FT_STD, 0, "sinh",  (void (*)(void))((double (*)(double)) sinh) },
229   { FT_STD, 0, "cosh",  (void (*)(void))((double (*)(double)) cosh) },
230   { FT_STD, 0, "tanh",  (void (*)(void))((double (*)(double)) tanh) },
231   { FT_STD, 0, "asin",  (void (*)(void))((double (*)(double)) asin) },
232   { FT_STD, 0, "acos",  (void (*)(void))((double (*)(double)) acos) },
233   { FT_STD, 0, "atan",  (void (*)(void))((double (*)(double)) atan) },
234   { FT_STD, 0, "asinh", (void (*)(void))((double (*)(double)) asinh) },
235   { FT_STD, 0, "acosh", (void (*)(void))((double (*)(double)) acosh) },
236   { FT_STD, 0, "atanh", (void (*)(void))((double (*)(double)) atanh) },
237   { FT_STD, 0, "gamma", (void (*)(void))((double (*)(double)) tgamma) },
238   { FT_STD, 0, "float",     reinterpret_cast<void (*)(void)>(&f_float) },
239   { FT_STD, 0, "int",       reinterpret_cast<void (*)(void)>(&f_int) },
240   { FT_STD, 0, "nint",      reinterpret_cast<void (*)(void)>(&f_nint) },
241   { FT_STD, 0, "rand",      reinterpret_cast<void (*)(void)>(&f_rand) },
242   { FT_STD, 0, "sqr",       reinterpret_cast<void (*)(void)>(&f_sqr) },
243   { FT_STD, 0, "rad",       reinterpret_cast<void (*)(void)>(&f_rad) },
244   { FT_STD, 0, "deg",       reinterpret_cast<void (*)(void)>(&f_deg) },
245   { FT_STD, 0, "isMissval", reinterpret_cast<void (*)(void)>(&f_isMissval) },
246 
247   // constant functions
248   { FT_CONST, 0, "ngp",     reinterpret_cast<void (*)(void)>(&pt_ngp) },      // number of horizontal grid points
249   { FT_CONST, 0, "nlev",    reinterpret_cast<void (*)(void)>(&pt_nlev) },     // number of vertical levels
250   { FT_CONST, 0, "size",    reinterpret_cast<void (*)(void)>(&pt_size) },     // ngp*nlev
251   { FT_CONST, 0, "missval", reinterpret_cast<void (*)(void)>(&pt_missval) },  // Returns the missing value of a variable
252 
253   // CDO field functions (Reduce grid to point)
254   { FT_FLD, 0, "fldmin",  reinterpret_cast<void (*)(void)>(&field_min) },
255   { FT_FLD, 0, "fldmax",  reinterpret_cast<void (*)(void)>(&field_max) },
256   { FT_FLD, 0, "fldsum",  reinterpret_cast<void (*)(void)>(&field_sum) },
257   { FT_FLD, 1, "fldmean", reinterpret_cast<void (*)(void)>(&field_meanw) },
258   { FT_FLD, 1, "fldavg",  reinterpret_cast<void (*)(void)>(&field_avgw) },
259   { FT_FLD, 1, "fldstd",  reinterpret_cast<void (*)(void)>(&field_stdw) },
260   { FT_FLD, 1, "fldstd1", reinterpret_cast<void (*)(void)>(&field_std1w) },
261   { FT_FLD, 1, "fldvar",  reinterpret_cast<void (*)(void)>(&field_varw) },
262   { FT_FLD, 1, "fldvar1", reinterpret_cast<void (*)(void)>(&field_var1w) },
263 
264   // CDO zonal functions (Reduce grid to point)
265   { FT_ZON, 0, "zonmin",  reinterpret_cast<void (*)(void)>(&zonal_min) },
266   { FT_ZON, 0, "zonmax",  reinterpret_cast<void (*)(void)>(&zonal_max) },
267   { FT_ZON, 0, "zonsum",  reinterpret_cast<void (*)(void)>(&zonal_sum) },
268   { FT_ZON, 0, "zonmean", reinterpret_cast<void (*)(void)>(&zonal_mean) },
269   { FT_ZON, 0, "zonavg",  reinterpret_cast<void (*)(void)>(&zonal_avg) },
270   { FT_ZON, 0, "zonstd",  reinterpret_cast<void (*)(void)>(&zonal_std) },
271   { FT_ZON, 0, "zonstd1", reinterpret_cast<void (*)(void)>(&zonal_std1) },
272   { FT_ZON, 0, "zonvar",  reinterpret_cast<void (*)(void)>(&zonal_var) },
273   { FT_ZON, 0, "zonvar1", reinterpret_cast<void (*)(void)>(&zonal_var1) },
274 
275   // CDO field functions (Reduce level to point)
276   { FT_VERT, 0, "vertmin",  reinterpret_cast<void (*)(void)>(&field_min) },
277   { FT_VERT, 0, "vertmax",  reinterpret_cast<void (*)(void)>(&field_max) },
278   { FT_VERT, 0, "vertsum",  reinterpret_cast<void (*)(void)>(&field_sum) },
279   { FT_VERT, 1, "vertmean", reinterpret_cast<void (*)(void)>(&field_meanw) },
280   { FT_VERT, 1, "vertavg",  reinterpret_cast<void (*)(void)>(&field_avgw) },
281   { FT_VERT, 1, "vertstd",  reinterpret_cast<void (*)(void)>(&field_stdw) },
282   { FT_VERT, 1, "vertstd1", reinterpret_cast<void (*)(void)>(&field_std1w) },
283   { FT_VERT, 1, "vertvar",  reinterpret_cast<void (*)(void)>(&field_varw) },
284   { FT_VERT, 1, "vertvar1", reinterpret_cast<void (*)(void)>(&field_var1w) },
285 
286   { FT_COORD, 0, "clon",       nullptr },
287   { FT_COORD, 0, "clat",       nullptr },
288   { FT_COORD, 0, "clev",       nullptr },
289   { FT_COORD, 0, "cdeltaz",    nullptr },
290   { FT_COORD, 0, "gridarea",   nullptr },
291   { FT_COORD, 0, "gridweight", nullptr },
292 
293   { FT_0, 0, "ctimestep", reinterpret_cast<void (*)(void)>(&ts_ctimestep) },
294   { FT_0, 0, "cdate",     reinterpret_cast<void (*)(void)>(&ts_cdate) },
295   { FT_0, 0, "ctime",     reinterpret_cast<void (*)(void)>(&ts_ctime) },
296   { FT_0, 0, "cdeltat",   reinterpret_cast<void (*)(void)>(&ts_cdeltat) },
297   { FT_0, 0, "cday",      reinterpret_cast<void (*)(void)>(&ts_cday) },
298   { FT_0, 0, "cmonth",    reinterpret_cast<void (*)(void)>(&ts_cmonth) },
299   { FT_0, 0, "cyear",     reinterpret_cast<void (*)(void)>(&ts_cyear) },
300   { FT_0, 0, "csecond",   reinterpret_cast<void (*)(void)>(&ts_csecond) },
301   { FT_0, 0, "cminute",   reinterpret_cast<void (*)(void)>(&ts_cminute) },
302   { FT_0, 0, "chour",     reinterpret_cast<void (*)(void)>(&ts_chour) },
303 
304   { FT_1C, 0, "sellevel",       nullptr },
305   { FT_1C, 0, "sellevidx",      nullptr },
306   { FT_2C, 0, "sellevelrange",  nullptr },
307   { FT_2C, 0, "sellevidxrange", nullptr },
308   // {FT_1C, 0, "gridindex", nullptr},
309 };
310 // clang-format on
311 
312 static const int NumFunc = sizeof(fun_sym_tbl) / sizeof(fun_sym_tbl[0]);
313 
314 static void
node_data_delete(nodeType * p)315 node_data_delete(nodeType *p)
316 {
317   if (p)
318     {
319       if (p->param.data)
320         {
321           Free(p->param.data);
322           p->param.data = nullptr;
323         }
324     }
325 }
326 
327 static void
node_delete(nodeType * p)328 node_delete(nodeType *p)
329 {
330   if (p)
331     {
332       if (p->type == typeVar) node_data_delete(p);
333       Free(p);
334     }
335 }
336 
337 static int
get_funcID(const char * fun)338 get_funcID(const char *fun)
339 {
340   int funcID = -1;
341   for (int i = 0; i < NumFunc; i++)
342     if (cdo_cmpstr(fun, fun_sym_tbl[i].name))
343       {
344         funcID = i;
345         break;
346       }
347 
348   if (funcID == -1) cdo_abort("Function >%s< not available!", fun);
349 
350   return funcID;
351 }
352 
353 static constexpr bool
isCompare(const int oper)354 isCompare(const int oper) noexcept
355 {
356   return (oper == LEG || oper == GE || oper == LE || oper == EQ || oper == NE || oper == GT || oper == LT);
357 }
358 
359 static void
param_meta_copy(paramType & out,const paramType & in)360 param_meta_copy(paramType &out, const paramType &in)
361 {
362   out.type = in.type;
363   out.gridID = in.gridID;
364   out.zaxisID = in.zaxisID;
365   out.datatype = in.datatype;
366   out.steptype = in.steptype;
367   out.ngp = in.ngp;
368   out.nlat = in.nlat;
369   out.nlev = in.nlev;
370   out.missval = in.missval;
371   out.nmiss = 0;
372   out.coord = 0;
373   out.hasMissvals = true;
374   out.name = nullptr;
375   out.longname = nullptr;
376   out.units = nullptr;
377   out.data = nullptr;
378 }
379 
380 static nodeType *
expr_con_con(const int oper,const nodeType * p1,const nodeType * p2)381 expr_con_con(const int oper, const nodeType *p1, const nodeType *p2)
382 {
383   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
384 
385   p->type = typeCon;
386   p->ltmpobj = true;
387 
388   auto cval1 = p1->u.con.value;
389   const auto cval2 = p2->u.con.value;
390 
391   // clang-format off
392   switch (oper)
393     {
394     case LT:   cval1 = binary_op_LT(cval1, cval2); break;
395     case GT:   cval1 = binary_op_GT(cval1, cval2); break;
396     case LE:   cval1 = binary_op_LE(cval1, cval2); break;
397     case GE:   cval1 = binary_op_GE(cval1, cval2); break;
398     case NE:   cval1 = binary_op_NE(cval1, cval2); break;
399     case EQ:   cval1 = binary_op_EQ(cval1, cval2); break;
400     case LEG:  cval1 = binary_op_LEG(cval1, cval2); break;
401     case AND:  cval1 = binary_op_AND(cval1, cval2); break;
402     case OR:   cval1 = binary_op_OR(cval1, cval2); break;
403     case '^':  cval1 = binary_op_POW(cval1, cval2); break;
404     case '+':  cval1 = binary_op_ADD(cval1, cval2); break;
405     case '-':  cval1 = binary_op_SUB(cval1, cval2); break;
406     case '*':  cval1 = binary_op_MUL(cval1, cval2); break;
407     case '/':  cval1 = binary_op_DIV(cval1, cval2); break;
408     default:   cdo_abort("%s: operator %d unsupported!", __func__, oper); break;
409     }
410   // clang-format on
411 
412   p->u.con.value = cval1;
413 
414   return p;
415 }
416 
417 static void
oper_expr_con_var(const int oper,const bool hasMissvals,const size_t n,const double mv,double * odat,const double cval,const double * idat)418 oper_expr_con_var(const int oper, const bool hasMissvals, const size_t n, const double mv, double *odat,
419                   const double cval, const double *idat)
420 {
421   // clang-format off
422   switch (oper)
423     {
424     case LT:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_LT); break;
425     case GT:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_GT); break;
426     case LE:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_LE); break;
427     case GE:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_GE); break;
428     case NE:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_NE); break;
429     case EQ:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_EQ); break;
430     case LEG: expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_LEG); break;
431     case AND: expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_AND); break;
432     case OR:  expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_OR); break;
433     case '^': expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_POW); break;
434     case '+': expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_ADD); break;
435     case '-': expr_func_con_var(hasMissvals, n, mv, cval, idat, odat, binary_op_SUB); break;
436     case '*': expr_mul_con_var(hasMissvals, n, mv, cval, idat, odat); break;
437     case '/': expr_div_con_var(hasMissvals, n, mv, cval, idat, odat); break;
438     default: cdo_abort("%s: operator %d unsupported!", __func__, oper); break;
439     }
440   // clang-format on
441 }
442 
443 static void
oper_expr_var_con(const int oper,const bool hasMissvals,const size_t n,const double mv,double * odat,const double * idat,const double cval)444 oper_expr_var_con(const int oper, const bool hasMissvals, const size_t n, const double mv,
445                   double *odat, const double *idat, const double cval)
446 {
447   // clang-format off
448   switch (oper)
449     {
450     case LT:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_LT); break;
451     case GT:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_GT); break;
452     case LE:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_LE); break;
453     case GE:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_GE); break;
454     case NE:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_NE); break;
455     case EQ:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_EQ); break;
456     case LEG: expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_LEG); break;
457     case AND: expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_AND); break;
458     case OR:  expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_OR); break;
459     case '^': expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_POW); break;
460     case '+': expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_ADD); break;
461     case '-': expr_func_var_con(hasMissvals, n, mv, idat, cval, odat, binary_op_SUB); break;
462     case '*': expr_mul_var_con(hasMissvals, n, mv, idat, cval, odat); break;
463     case '/': expr_div_var_con(hasMissvals, n, mv, idat, cval, odat); break;
464     default: cdo_abort("%s: operator %d unsupported!", __func__, oper); break;
465     }
466   // clang-format on
467 }
468 
469 static void
oper_expr_var_var(const int oper,const bool hasMissvals,const size_t n,const double mv1,const double mv2,double * odat,const double * idat1,const double * idat2)470 oper_expr_var_var(const int oper, const bool hasMissvals, const size_t n, const double mv1, const double mv2,
471                   double *odat, const double *idat1, const double *idat2)
472 {
473   // clang-format off
474   switch (oper)
475     {
476     case LT:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_LT); break;
477     case GT:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_GT); break;
478     case LE:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_LE); break;
479     case GE:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_GE); break;
480     case NE:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_NE); break;
481     case EQ:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_EQ); break;
482     case LEG: expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_LEG); break;
483     case AND: expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_AND); break;
484     case OR:  expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_OR); break;
485     case '^': expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_POW); break;
486     case '+': expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_ADD); break;
487     case '-': expr_func_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat, binary_op_SUB); break;
488     case '*': expr_mul_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat); break;
489     case '/': expr_div_var_var(hasMissvals, n, mv1, mv2, idat1, idat2, odat); break;
490     default: cdo_abort("%s: operator %d unsupported!", __func__, oper); break;
491     }
492   // clang-format on
493 }
494 
495 static nodeType *
expr_con_var(const int init,const int oper,const nodeType * p1,const nodeType * p2)496 expr_con_var(const int init, const int oper, const nodeType *p1, const nodeType *p2)
497 {
498   const auto ngp = (p2->param.ngp > 0) ? p2->param.ngp : 1;
499   const auto nlev = (p2->param.nlev > 0) ? p2->param.nlev : 1;
500   const auto nmiss = p2->param.nmiss;
501   const auto datatype = p2->param.datatype;
502   const auto missval2 = p2->param.missval;
503 
504   const auto n = ngp * nlev;
505 
506   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
507 
508   p->type = typeVar;
509   p->ltmpobj = true;
510   p->u.var.nm = strdup(tmpvnm);
511   param_meta_copy(p->param, p2->param);
512   p->param.name = p->u.var.nm;
513 
514   if (!init)
515     {
516       p->param.data = (double *) Malloc(n * sizeof(double));
517       auto odat = p->param.data;
518       const auto idat = p2->param.data;
519       auto cval = p1->u.con.value;
520       if (datatype == CDI_DATATYPE_FLT32 && isCompare(oper)) cval = (float) cval;
521 
522       oper_expr_con_var(oper, nmiss, n, missval2, odat, cval, idat);
523 
524       p->param.nmiss = array_num_mv(n, odat, missval2);
525     }
526 
527   return p;
528 }
529 
530 static nodeType *
expr_var_con(const int init,const int oper,const nodeType * p1,const nodeType * p2)531 expr_var_con(const int init, const int oper, const nodeType *p1, const nodeType *p2)
532 {
533   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
534   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
535   const auto nmiss = p1->param.nmiss;
536   const auto datatype = p1->param.datatype;
537   const auto missval1 = p1->param.missval;
538 
539   const auto n = ngp * nlev;
540 
541   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
542 
543   p->type = typeVar;
544   p->ltmpobj = true;
545   p->u.var.nm = strdup(tmpvnm);
546   param_meta_copy(p->param, p1->param);
547   p->param.name = p->u.var.nm;
548 
549   if (!init)
550     {
551       p->param.data = (double *) Malloc(n * sizeof(double));
552       auto odat = p->param.data;
553       const auto idat = p1->param.data;
554       auto cval = p2->u.con.value;
555       if (datatype == CDI_DATATYPE_FLT32 && isCompare(oper)) cval = (float) cval;
556 
557       oper_expr_var_con(oper, nmiss, n, missval1, odat, idat, cval);
558 
559       p->param.nmiss = array_num_mv(n, odat, missval1);
560     }
561 
562   return p;
563 }
564 
565 static nodeType *
expr_var_var(int init,int oper,nodeType * p1,nodeType * p2)566 expr_var_var(int init, int oper, nodeType *p1, nodeType *p2)
567 {
568   auto px = p1;
569   const auto nmiss1 = p1->param.nmiss;
570   const auto nmiss2 = p2->param.nmiss;
571   const auto missval1 = p1->param.missval;
572   const auto missval2 = p2->param.missval;
573 
574   const auto ngp1 = (p1->param.ngp > 0) ? p1->param.ngp : 1;
575   const auto ngp2 = (p2->param.ngp > 0) ? p2->param.ngp : 1;
576   auto ngp = ngp1;
577 
578   const auto nlat1 = p1->param.nlat;
579   const auto nlat2 = p2->param.nlat;
580   auto lzonal = false;
581 
582   if (ngp1 != ngp2)
583     {
584       if (ngp1 == 1 || ngp2 == 1)
585         {
586           if (ngp1 == 1)
587             {
588               ngp = ngp2;
589               px = p2;
590             }
591         }
592       else if (nlat1 == nlat2 && ngp1 > ngp2)
593         {
594           lzonal = true;
595         }
596       else
597         {
598           cdo_abort("%s: Number of grid points differ (%s[%zu] <-> %s[%zu])", __func__, p1->param.name, ngp1, p2->param.name, ngp2);
599         }
600     }
601 
602   const auto nlev1 = (p1->param.nlev > 0) ? p1->param.nlev : 1;
603   const auto nlev2 = (p2->param.nlev > 0) ? p2->param.nlev : 1;
604 
605   auto nlev = nlev1;
606   if (nlev1 != nlev2)
607     {
608       if (nlev1 == 1 || nlev2 == 1)
609         {
610           if (nlev1 == 1)
611             {
612               nlev = nlev2;
613               px = p2;
614             }
615         }
616       else
617         {
618           cdo_abort("%s: Number of levels differ (%s[%zu] <-> %s[%zu])", __func__, p1->param.name, nlev1, p2->param.name, nlev2);
619         }
620     }
621 
622   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
623 
624   p->type = typeVar;
625   p->ltmpobj = true;
626   p->u.var.nm = strdup(tmpvnm);
627 
628   param_meta_copy(p->param, px->param);
629 
630   if (p->param.steptype == TIME_CONSTANT)
631     {
632       const auto steptype1 = p1->param.steptype;
633       const auto steptype2 = p2->param.steptype;
634       if (steptype1 != TIME_CONSTANT)
635         p->param.steptype = steptype1;
636       else if (steptype2 != TIME_CONSTANT)
637         p->param.steptype = steptype2;
638     }
639 
640   p->param.name = p->u.var.nm;
641   // printf("%s %s nmiss %zu %zu\n", p->u.var.nm, px->param.name, nmiss1, nmiss2);
642 
643   if (!init)
644     {
645       p->param.data = (double *) Malloc(ngp * nlev * sizeof(double));
646 
647       for (size_t k = 0; k < nlev; k++)
648         {
649           const auto loff = k * ngp;
650           const size_t loff1 = (nlev1 > 1) ? k * ngp1 : 0;
651           const size_t loff2 = (nlev2 > 1) ? k * ngp2 : 0;
652 
653           const auto idat1 = p1->param.data + loff1;
654           const auto idat2 = p2->param.data + loff2;
655           auto odat = p->param.data + loff;
656           const size_t nmiss = (nmiss1 || nmiss2);
657 
658           if (ngp1 != ngp2)
659             {
660               if (lzonal)
661                 {
662                   const auto nlon = ngp1 / nlat1;
663                   for (size_t j = 0; j < nlat1; ++j)
664                     oper_expr_var_con(oper, nmiss, nlon, missval1, odat + j * nlon, idat1 + j * nlon, idat2[j]);
665                 }
666               else
667                 {
668                   if (ngp2 == 1)
669                     oper_expr_var_con(oper, nmiss, ngp, missval1, odat, idat1, idat2[0]);
670                   else
671                     oper_expr_con_var(oper, nmiss, ngp, missval2, odat, idat1[0], idat2);
672                 }
673             }
674           else
675             {
676               oper_expr_var_var(oper, nmiss, ngp, missval1, missval2, odat, idat1, idat2);
677             }
678         }
679 
680       p->param.nmiss = array_num_mv(ngp * nlev, p->param.data, missval1);
681     }
682 
683   return p;
684 }
685 
686 static void
ex_copy_var(int init,nodeType * p2,const nodeType * p1)687 ex_copy_var(int init, nodeType *p2, const nodeType *p1)
688 {
689   const auto copyConstValue1 = (p1->param.ngp == 0 && p1->param.nlev == 0);
690   const auto ngp1 = (p1->param.ngp > 0) ? p1->param.ngp : 1;
691   const auto nlev1 = (p1->param.nlev > 0) ? p1->param.nlev : 1;
692 
693   if (Options::cdoVerbose)
694     {
695       if (copyConstValue1)
696         cdo_print("\t%s\tcopy\t%s[N%zu][L%zu] = %s", ExIn[init], p2->param.name, p2->param.ngp, p2->param.nlev, p1->param.name);
697       else
698         cdo_print("\t%s\tcopy\t%s[N%zu][L%zu] = %s[N%zu][L%zu]", ExIn[init], p2->param.name, p2->param.ngp, p2->param.nlev,
699                   p1->param.name, p1->param.ngp, p1->param.nlev);
700     }
701 
702   const auto ngp2 = (p2->param.ngp > 0) ? p2->param.ngp : 1;
703   const auto nlev2 = (p2->param.nlev > 0) ? p2->param.nlev : 1;
704 
705   if (!copyConstValue1 && ngp2 != ngp1)
706     cdo_abort("%s: Number of grid points differ (%s[N%zu] = %s[N%zu])", __func__, p2->param.name, ngp2, p1->param.name, ngp1);
707 
708   if (!copyConstValue1 && nlev2 != nlev1)
709     cdo_abort("%s: Number of levels differ (%s[L%zu] = %s[L%zu])", __func__, p2->param.name, nlev2, p1->param.name, nlev1);
710 
711   if (!init)
712     {
713       if (copyConstValue1)
714         {
715           varray_fill(ngp2 * nlev2, p2->param.data, p1->param.data[0]);
716         }
717       else
718         {
719           array_copy(ngp2 * nlev2, p1->param.data, p2->param.data);
720           p2->param.missval = p1->param.missval;
721           p2->param.nmiss = p1->param.nmiss;
722         }
723     }
724 }
725 
726 static void
ex_copy_con(int init,nodeType * p2,const nodeType * p1)727 ex_copy_con(int init, nodeType *p2, const nodeType *p1)
728 {
729   const auto cval = p1->u.con.value;
730 
731   auto ngp = p2->param.ngp;
732   auto nlev = p2->param.nlev;
733 
734   if (Options::cdoVerbose)
735     {
736       if (ngp == 0 && nlev == 0)
737         cdo_print("\t%s\tcopy\t%s = %g", ExIn[init], p2->param.name, cval);
738       else
739         cdo_print("\t%s\tcopy\t%s[N%zu][L%zu] = %g", ExIn[init], p2->param.name, ngp, nlev, cval);
740     }
741 
742   if (ngp == 0 && nlev == 0)
743     {
744       ngp = 1;
745       nlev = 1;
746     }
747 
748   assert(ngp > 0);
749   assert(nlev > 0);
750 
751   if (!init)
752     {
753       assert(p2->param.data != nullptr);
754       varray_fill(ngp * nlev, p2->param.data, cval);
755     }
756 }
757 
758 static void
ex_copy(int init,nodeType * p2,const nodeType * p1)759 ex_copy(int init, nodeType *p2, const nodeType *p1)
760 {
761   if (p1->type == typeCon)
762     ex_copy_con(init, p2, p1);
763   else
764     ex_copy_var(init, p2, p1);
765 }
766 
767 static nodeType *
expr(const int init,const int oper,nodeType * p1,nodeType * p2)768 expr(const int init, const int oper, nodeType *p1, nodeType *p2)
769 {
770   if (p1 == nullptr || p2 == nullptr) return nullptr;
771 
772   const char *coper = "???";
773 
774   if (Options::cdoVerbose)
775     {
776       switch (oper)
777         {
778         case LT: coper = "<"; break;
779         case GT: coper = ">"; break;
780         case LE: coper = "<="; break;
781         case GE: coper = ">="; break;
782         case NE: coper = "!="; break;
783         case EQ: coper = "=="; break;
784         case LEG: coper = "<=>"; break;
785         case AND: coper = "&&"; break;
786         case OR: coper = "||"; break;
787         case '^': coper = "^"; break;
788         case '+': coper = "+"; break;
789         case '-': coper = "-"; break;
790         case '*': coper = "*"; break;
791         case '/': coper = "/"; break;
792         default: cdo_abort("Internal error, expr operator %d not implemented!\n", oper);
793         }
794     }
795 
796   nodeType *p = nullptr;
797 
798   if (p1->type == typeVar && p2->type == typeVar)
799     {
800       p = expr_var_var(init, oper, p1, p2);
801       if (Options::cdoVerbose)
802         cdo_print("\t%s\tarith\t%s[N%zu][L%zu] = %s %s %s", ExIn[init], p->u.var.nm, p->param.ngp, p->param.nlev, p1->u.var.nm,
803                   coper, p2->u.var.nm);
804     }
805   else if (p1->type == typeVar && p2->type == typeCon)
806     {
807       p = expr_var_con(init, oper, p1, p2);
808       if (Options::cdoVerbose)
809         cdo_print("\t%s\tarith\t%s[N%zu][L%zu] = %s %s %g", ExIn[init], p->u.var.nm, p->param.ngp, p->param.nlev, p1->u.var.nm,
810                   coper, p2->u.con.value);
811     }
812   else if (p1->type == typeCon && p2->type == typeVar)
813     {
814       p = expr_con_var(init, oper, p1, p2);
815       if (Options::cdoVerbose)
816         cdo_print("\t%s\tarith\t%s[N%zu][L%zu] = %g %s %s", ExIn[init], p->u.var.nm, p->param.ngp, p->param.nlev, p1->u.con.value,
817                   coper, p2->u.var.nm);
818     }
819   else if (p1->type == typeCon && p2->type == typeCon)
820     {
821       p = expr_con_con(oper, p1, p2);
822       if (Options::cdoVerbose)
823         cdo_print("\t%s\tarith\t%g = %g %s %g", ExIn[init], p->u.con.value, p1->u.con.value, coper, p2->u.con.value);
824     }
825   else
826     cdo_abort("Internal problem!");
827 
828   if (p1->ltmpobj) node_delete(p1);
829   if (p2->ltmpobj) node_delete(p2);
830 
831   return p;
832 }
833 
834 static nodeType *
ex_fun0_con(const int init,const int funcID,double * data)835 ex_fun0_con(const int init, const int funcID, double *data)
836 {
837   auto functype = fun_sym_tbl[funcID].type;
838   if (functype != FT_0) cdo_abort("Function %s not available for constant values!", fun_sym_tbl[funcID].name);
839 
840   if (Options::cdoVerbose) cdo_print("\t%s\tfunc\t%s", ExIn[init], fun_sym_tbl[funcID].name);
841 
842   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
843 
844   p->type = typeCon;
845   p->ltmpobj = true;
846 
847   if (!init)
848     {
849       double (*exprfunc)(const double *) = (double (*)(const double *)) fun_sym_tbl[funcID].func;
850       p->u.con.value = exprfunc(data);
851     }
852 
853   return p;
854 }
855 
856 static nodeType *
ex_fun_con(const int funcID,nodeType * p1)857 ex_fun_con(const int funcID, nodeType *p1)
858 {
859   const auto functype = fun_sym_tbl[funcID].type;
860   if (functype != FT_STD) cdo_abort("Function %s not available for constant values!", fun_sym_tbl[funcID].name);
861 
862   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
863 
864   p->type = typeCon;
865   p->ltmpobj = true;
866 
867   double (*exprfunc)(double) = (double (*)(double)) fun_sym_tbl[funcID].func;
868   p->u.con.value = exprfunc(p1->u.con.value);
869 
870   if (p1->ltmpobj)
871     node_delete(p1);
872   else
873     Free(p1);
874 
875   return p;
876 }
877 
878 static void
ex_fun_std(const int funcID,size_t ngp,size_t nlev,size_t nmiss,double missval,double * p1data,double * pdata)879 ex_fun_std(const int funcID, size_t ngp, size_t nlev, size_t nmiss, double missval, double *p1data, double *pdata)
880 {
881   double (*exprfunc)(double) = (double (*)(double)) fun_sym_tbl[funcID].func;
882   if (nmiss)
883     {
884       if (cdo_cmpstr(fun_sym_tbl[funcID].name, "isMissval"))
885         {
886           for (size_t i = 0; i < ngp * nlev; i++)
887             {
888               pdata[i] = DBL_IS_EQUAL(p1data[i], missval);
889             }
890         }
891       else
892         {
893           for (size_t i = 0; i < ngp * nlev; i++)
894             {
895               errno = -1;
896               pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : exprfunc(p1data[i]);
897               if (errno == EDOM || errno == ERANGE || std::isnan(pdata[i])) pdata[i] = missval;
898             }
899         }
900     }
901   else
902     {
903       for (size_t i = 0; i < ngp * nlev; i++)
904         {
905           errno = -1;
906           pdata[i] = exprfunc(p1data[i]);
907           if (errno == EDOM || errno == ERANGE || std::isnan(pdata[i])) pdata[i] = missval;
908         }
909     }
910 }
911 
912 static nodeType *
ex_fun_var(const int init,const int funcID,nodeType * p1)913 ex_fun_var(const int init, const int funcID, nodeType *p1)
914 {
915   const auto funcname = fun_sym_tbl[funcID].name;
916   const auto functype = fun_sym_tbl[funcID].type;
917   const auto funcflag = fun_sym_tbl[funcID].flag;
918 
919   const auto gridID = p1->param.gridID;
920   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
921   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
922   const auto nlat = p1->param.nlat;
923   const auto nmiss = p1->param.nmiss;
924   const auto missval = p1->param.missval;
925 
926   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
927 
928   p->type = typeVar;
929   p->ltmpobj = true;
930   p->u.var.nm = strdup(tmpvnm);
931 
932   param_meta_copy(p->param, p1->param);
933 
934   if (functype == FT_CONST)
935     {
936       p->type = typeCon;
937       double (*exprfunc)(const paramType *) = (double (*)(const paramType *)) fun_sym_tbl[funcID].func;
938       p->u.con.value = exprfunc(&p1->param);
939     }
940   else if (functype == FT_FLD)
941     {
942       p->param.gridID = pointID;
943       p->param.ngp = 1;
944     }
945   else if (functype == FT_ZON)
946     {
947       if (zonalID == -1) cdo_abort("Function %s() is only available for regular 2D grids!", fun_sym_tbl[funcID].name);
948       p->param.gridID = zonalID;
949       p->param.ngp = nlat;
950     }
951   else if (functype == FT_VERT)
952     {
953       p->param.zaxisID = surfaceID;
954       p->param.nlev = 1;
955     }
956 
957   if (!init)
958     {
959       p->param.data = (double *) Malloc(p->param.ngp * p->param.nlev * sizeof(double));
960       double *pdata = p->param.data;
961       double *p1data = p1->param.data;
962 
963       if (functype == FT_STD)
964         {
965           ex_fun_std(funcID, ngp, nlev, nmiss, missval, p1data, pdata);
966         }
967       else if (functype == FT_FLD)
968         {
969           Field field;
970           field.resize(ngp);
971           if (funcflag == 1)
972             {
973               assert(p1->param.weight != nullptr);
974               field.weightv.resize(ngp);
975             }
976 
977           double (*exprfunc)(const Field &) = (double (*)(const Field &)) fun_sym_tbl[funcID].func;
978           for (size_t k = 0; k < nlev; k++)
979             {
980               fld_field_init(field, nmiss, missval, ngp, p1data + k * ngp, p1->param.weight);
981               pdata[k] = exprfunc(field);
982             }
983         }
984       else if (functype == FT_ZON)
985         {
986           Field field1, field2;
987           field1.resize(ngp);
988           field2.resize(nlat);
989           void (*exprfunc)(const Field &, Field &) = (void (*)(const Field &, Field &)) fun_sym_tbl[funcID].func;
990           for (size_t k = 0; k < nlev; k++)
991             {
992               fld_field_init(field1, nmiss, missval, ngp, &p1data[k * ngp], nullptr);
993               field1.grid = gridID;
994               fld_field_init(field2, nmiss, missval, nlat, &pdata[k * nlat], nullptr);
995               exprfunc(field1, field2);
996               array_copy(nlat, field2.vec_d.data(), &pdata[k * nlat]);
997             }
998         }
999       else if (functype == FT_VERT)
1000         {
1001           Field field;
1002           field.resize(nlev);
1003           if (funcflag == 1) vert_weights(p1->param.zaxisID, nlev, field.weightv);
1004           double (*exprfunc)(const Field &) = (double (*)(const Field &)) fun_sym_tbl[funcID].func;
1005           for (size_t i = 0; i < ngp; i++)
1006             {
1007               for (size_t k = 0; k < nlev; k++) field.vec_d[k] = p1data[k * ngp + i];
1008               fld_field_init(field, nmiss, missval, nlev, nullptr, nullptr);
1009               pdata[i] = exprfunc(field);
1010             }
1011         }
1012       else if (functype == FT_CONST)
1013         {
1014         }
1015       else
1016         cdo_abort("Intermal error, wrong function type (%d) for %s()!", functype, funcname);
1017 
1018       p->param.nmiss = array_num_mv(p->param.ngp * p->param.nlev, pdata, missval);
1019     }
1020 
1021   if (p1->ltmpobj)
1022     node_delete(p1);
1023   else
1024     Free(p1);
1025 
1026   return p;
1027 }
1028 
1029 static nodeType *
ex_fun(const int init,const int funcID,nodeType * p1)1030 ex_fun(const int init, const int funcID, nodeType *p1)
1031 {
1032   nodeType *p = nullptr;
1033 
1034   if (p1->type == typeVar)
1035     {
1036       if (Options::cdoVerbose) cdo_print("\t%s\tfunc\t%s (%s)", ExIn[init], fun_sym_tbl[funcID].name, p1->u.var.nm);
1037       p = ex_fun_var(init, funcID, p1);
1038     }
1039   else if (p1->type == typeCon)
1040     {
1041       if (Options::cdoVerbose) cdo_print("\t%s\tfunc\t%s (%g)", ExIn[init], fun_sym_tbl[funcID].name, p1->u.con.value);
1042       p = ex_fun_con(funcID, p1);
1043     }
1044   else
1045     cdo_abort("Internal problem!");
1046 
1047   return p;
1048 }
1049 
1050 static size_t
get_levidx(const size_t nlev,const double * data,const double value,const char * funcname)1051 get_levidx(const size_t nlev, const double *data, const double value, const char *funcname)
1052 {
1053   size_t levidx;
1054 
1055   for (levidx = 0; levidx < nlev; ++levidx)
1056     if (IS_EQUAL(data[levidx], value)) break;
1057   if (levidx == nlev) cdo_abort("%s(): level %g not found!", funcname, value);
1058 
1059   return levidx;
1060 }
1061 
1062 static void
get_levidxrange(size_t nlev,const double * data,double value1,double value2,const char * funcname,size_t & levidx1,size_t & levidx2)1063 get_levidxrange(size_t nlev, const double *data, double value1, double value2, const char *funcname, size_t &levidx1,
1064                 size_t &levidx2)
1065 {
1066   long i, n = nlev;
1067   if (data[0] <= data[nlev - 1])
1068     {
1069       for (i = 0; i < n; ++i)
1070         if (data[i] >= value1) break;
1071       if (i == n) cdo_abort("%s(): lower level %g not found!", funcname, value1);
1072       levidx1 = i;
1073 
1074       for (i = n - 1; i >= 0; --i)
1075         if (data[i] <= value2) break;
1076       if (i < 0) cdo_abort("%s(): upper level %g not found!", funcname, value2);
1077       if (i < (long) levidx1) cdo_abort("%s(): level range %g to %g not found!", funcname, value1, value2);
1078       levidx2 = i;
1079     }
1080   else
1081     {
1082       for (i = 0; i < n; ++i)
1083         if (data[i] <= value2) break;
1084       if (i == n) cdo_abort("%s(): upper level %g not found!", funcname, value1);
1085       levidx1 = i;
1086 
1087       for (i = n - 1; i >= 0; --i)
1088         if (data[i] >= value1) break;
1089       if (i < 0) cdo_abort("%s(): lower level %g not found!", funcname, value2);
1090       if (i < (long) levidx1) cdo_abort("%s(): level range %g to %g not found!", funcname, value1, value2);
1091       levidx2 = i;
1092     }
1093 }
1094 
1095 static nodeType *
fun1c(int init,int funcID,nodeType * p1,double value,parseParamType * parse_arg)1096 fun1c(int init, int funcID, nodeType *p1, double value, parseParamType *parse_arg)
1097 {
1098   const auto funcname = fun_sym_tbl[funcID].name;
1099   if (p1->type != typeVar) cdo_abort("Parameter of function %s() needs to be a variable!", funcname);
1100   if (p1->ltmpobj) cdo_abort("Temporary objects not allowed in function %s()!", funcname);
1101 
1102   if (parse_arg->debug)
1103     cdo_print("\t%s\tfunc\t%s=%s(%s[N%zu][L%zu], %g)", ExIn[init], tmpvnm, funcname, p1->param.name, p1->param.ngp, p1->param.nlev,
1104               value);
1105 
1106   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
1107   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
1108   auto nmiss = p1->param.nmiss;
1109   const auto missval = p1->param.missval;
1110 
1111   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1112 
1113   p->type = typeVar;
1114   p->ltmpobj = true;
1115   p->u.var.nm = strdup(tmpvnm);
1116   param_meta_copy(p->param, p1->param);
1117   p->param.name = p->u.var.nm;
1118 
1119   if (init)
1120     {
1121       if (p1->param.longname) p->param.longname = strdup(p1->param.longname);
1122       if (p1->param.units) p->param.units = strdup(p1->param.units);
1123     }
1124 
1125   p->param.nlev = 1;
1126 
1127   const auto zaxisID = p1->param.zaxisID;
1128   const auto coordID = params_get_coord_ID(parse_arg, 'z', zaxisID);
1129 
1130   std::vector<double> data;
1131   double *pdata = nullptr;
1132 
1133   if (init)
1134     {
1135       parse_arg->coords[coordID].needed = true;
1136 
1137       data.resize(nlev);
1138       pdata = data.data();
1139       cdo_zaxis_inq_levels(zaxisID, pdata);
1140     }
1141   else
1142     {
1143       pdata = parse_arg->coords[coordID].data.data();
1144     }
1145 
1146   size_t levidx = 0;
1147   if (cdo_cmpstr(funcname, "sellevidx"))
1148     {
1149       const auto ilevidx = std::lround(value);
1150       if (ilevidx < 1 || ilevidx > (long) nlev)
1151         cdo_abort("%s(): level index %ld out of range (range: 1-%zu)!", funcname, ilevidx, nlev);
1152       levidx = (size_t) ilevidx - 1;
1153     }
1154   else if (cdo_cmpstr(funcname, "sellevel"))
1155     {
1156       levidx = get_levidx(nlev, pdata, value, funcname);
1157     }
1158   else
1159     cdo_abort("Function %s() not implemented!", funcname);
1160 
1161   if (init)
1162     {
1163       const auto level = data[levidx];
1164       const auto zaxisID2 = zaxisCreate(zaxisInqType(zaxisID), 1);
1165       zaxisDefLevels(zaxisID2, &level);
1166       p->param.zaxisID = zaxisID2;
1167     }
1168 
1169   if (!init)
1170     {
1171       p->param.data = (double *) Malloc(ngp * sizeof(double));
1172       pdata = p->param.data;
1173       const auto p1data = p1->param.data + ngp * levidx;
1174       array_copy(ngp, p1data, pdata);
1175       if (nmiss) nmiss = array_num_mv(ngp, pdata, missval);
1176       p->param.nmiss = nmiss;
1177     }
1178 
1179   if (p1->ltmpobj) node_delete(p1);
1180 
1181   return p;
1182 }
1183 
1184 static nodeType *
fun2c(int init,int funcID,nodeType * p1,double value1,double value2,parseParamType * parse_arg)1185 fun2c(int init, int funcID, nodeType *p1, double value1, double value2, parseParamType *parse_arg)
1186 {
1187   const auto funcname = fun_sym_tbl[funcID].name;
1188   if (p1->type != typeVar) cdo_abort("Parameter of function %s() needs to be a variable!", funcname);
1189   if (p1->ltmpobj) cdo_abort("Temporary objects not allowed in function %s()!", funcname);
1190 
1191   if (parse_arg->debug)
1192     cdo_print("\t%s\tfunc\t%s=%s(%s[N%zu][L%zu], %g, %g)", ExIn[init], tmpvnm, funcname, p1->param.name, p1->param.ngp,
1193               p1->param.nlev, value1, value2);
1194 
1195   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
1196   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
1197   auto nmiss = p1->param.nmiss;
1198   const auto missval = p1->param.missval;
1199 
1200   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1201 
1202   p->type = typeVar;
1203   p->ltmpobj = true;
1204   p->u.var.nm = strdup(tmpvnm);
1205   param_meta_copy(p->param, p1->param);
1206   p->param.name = p->u.var.nm;
1207 
1208   if (init)
1209     {
1210       if (p1->param.longname) p->param.longname = strdup(p1->param.longname);
1211       if (p1->param.units) p->param.units = strdup(p1->param.units);
1212     }
1213 
1214   const auto zaxisID = p1->param.zaxisID;
1215   const auto coordID = params_get_coord_ID(parse_arg, 'z', zaxisID);
1216   size_t levidx1 = 0;
1217   size_t levidx2 = 0;
1218 
1219   double *data = nullptr;
1220   if (init)
1221     {
1222       parse_arg->coords[coordID].needed = true;
1223 
1224       data = (double *) Malloc(nlev * sizeof(double));
1225       cdo_zaxis_inq_levels(zaxisID, data);
1226     }
1227   else
1228     {
1229       data = parse_arg->coords[coordID].data.data();
1230     }
1231 
1232   if (cdo_cmpstr(funcname, "sellevidxrange"))
1233     {
1234       if (value2 < value1) cdo_abort("%s(): first level index is greater than last level index!", funcname);
1235       const auto ilevidx1 = std::lround(value1);
1236       if (ilevidx1 < 1 || ilevidx1 > (long) nlev)
1237         cdo_abort("%s(): level index1 %ld out of range (range: 1-%zu)!", funcname, ilevidx1, nlev);
1238       levidx1 = (size_t) ilevidx1 - 1;
1239       const auto ilevidx2 = std::lround(value2);
1240       if (ilevidx2 < 1 || ilevidx2 > (long) nlev)
1241         cdo_abort("%s(): level index2 %ld out of range (range: 1-%zu)!", funcname, ilevidx2, nlev);
1242       levidx2 = (size_t) ilevidx2 - 1;
1243     }
1244   else if (cdo_cmpstr(funcname, "sellevelrange"))
1245     {
1246       if (value2 < value1) cdo_abort("%s(): first level is greater than last level!", funcname);
1247       get_levidxrange(nlev, data, value1, value2, funcname, levidx1, levidx2);
1248     }
1249   else
1250     cdo_abort("Function %s() not implemented!", funcname);
1251 
1252   const int nlevout = levidx2 - levidx1 + 1;
1253   p->param.nlev = nlevout;
1254 
1255   if (init)
1256     {
1257       const auto zaxisID2 = zaxisCreate(zaxisInqType(zaxisID), nlevout);
1258       zaxisDefLevels(zaxisID2, &data[levidx1]);
1259       if (zaxisInqLbounds(zaxisID, nullptr) && zaxisInqUbounds(zaxisID, nullptr))
1260         {
1261           std::vector<double> bounds(nlev);
1262           zaxisInqLbounds(zaxisID, bounds.data());
1263           zaxisDefLbounds(zaxisID2, &bounds[levidx1]);
1264           zaxisInqUbounds(zaxisID, bounds.data());
1265           zaxisDefUbounds(zaxisID2, &bounds[levidx1]);
1266         }
1267       p->param.zaxisID = zaxisID2;
1268     }
1269 
1270   if (init) Free(data);
1271 
1272   if (!init)
1273     {
1274       p->param.data = (double *) Malloc(ngp * nlevout * sizeof(double));
1275       auto pdata = p->param.data;
1276       const auto p1data = p1->param.data + ngp * levidx1;
1277       array_copy(ngp * nlevout, p1data, pdata);
1278       if (nmiss) nmiss = array_num_mv(ngp * nlevout, pdata, missval);
1279       p->param.nmiss = nmiss;
1280     }
1281 
1282   if (p1->ltmpobj) node_delete(p1);
1283 
1284   return p;
1285 }
1286 
1287 static nodeType *
coord_fun(const int init,const int funcID,nodeType * p1,parseParamType * parse_arg)1288 coord_fun(const int init, const int funcID, nodeType *p1, parseParamType *parse_arg)
1289 {
1290   const auto funcname = fun_sym_tbl[funcID].name;
1291   if (p1->type != typeVar) cdo_abort("Parameter of function %s() needs to be a variable!", funcname);
1292   if (p1->ltmpobj) cdo_abort("Temporary objects not allowed in function %s()!", funcname);
1293 
1294   const auto len = 3 + strlen(p1->u.var.nm);
1295   auto cname = (char *) Calloc(len, 1);
1296   strcpy(cname, p1->u.var.nm);
1297 
1298   // clang-format off
1299   if      (cdo_cmpstr(funcname, "clon"))       strcat(cname, ".x");
1300   else if (cdo_cmpstr(funcname, "clat"))       strcat(cname, ".y");
1301   else if (cdo_cmpstr(funcname, "clev"))       strcat(cname, ".z");
1302   else if (cdo_cmpstr(funcname, "cdeltaz"))    strcat(cname, ".d");
1303   else if (cdo_cmpstr(funcname, "gridarea"))   strcat(cname, ".a");
1304   else if (cdo_cmpstr(funcname, "gridweight")) strcat(cname, ".w");
1305   else cdo_abort("Implementation missing for function %s!", funcname);
1306   // clang-format on
1307 
1308   Free(p1->u.var.nm);
1309   p1->u.var.nm = cname;
1310 
1311   auto p = expr_run(p1, parse_arg);
1312   p->param.hasMissvals = false;
1313 
1314   if (!init)
1315     {
1316       /*
1317       size_t ngp  = p1->param.ngp;
1318       size_t nlev = p1->param.nlev;
1319       p->param.data = (double*) Malloc(ngp*nlev*sizeof(double));
1320       double *pdata  = p->param.data;
1321       double *p1data = p1->param.data;
1322 
1323       for (size_t i = 0; i < ngp*nlev; i++) pdata[i] = p1data[i];
1324       */
1325     }
1326   /*
1327   Free(cname);
1328   Free(p1);
1329   */
1330   return p;
1331 }
1332 
1333 static nodeType *
ex_uminus_var(const int init,nodeType * p1)1334 ex_uminus_var(const int init, nodeType *p1)
1335 {
1336   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
1337   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
1338   const auto nmiss = p1->param.nmiss;
1339   const auto missval = p1->param.missval;
1340 
1341   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1342 
1343   p->type = typeVar;
1344   p->ltmpobj = true;
1345   p->u.var.nm = strdup(tmpvnm);
1346   param_meta_copy(p->param, p1->param);
1347   p->param.name = p->u.var.nm;
1348 
1349   if (!init)
1350     {
1351       p->param.data = (double *) Malloc(ngp * nlev * sizeof(double));
1352       double *pdata = p->param.data;
1353       const double *p1data = p1->param.data;
1354 
1355       if (nmiss)
1356         {
1357           for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : -(p1data[i]);
1358         }
1359       else
1360         {
1361           for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = -(p1data[i]);
1362         }
1363 
1364       p->param.nmiss = nmiss;
1365     }
1366 
1367   if (p1->ltmpobj) node_delete(p1);
1368 
1369   return p;
1370 }
1371 
1372 static nodeType *
ex_uminus_con(nodeType * p1)1373 ex_uminus_con(nodeType *p1)
1374 {
1375   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1376 
1377   p->type = typeCon;
1378   p->ltmpobj = true;
1379 
1380   p->u.con.value = -(p1->u.con.value);
1381 
1382   return p;
1383 }
1384 
1385 static nodeType *
ex_uminus(const int init,nodeType * p1)1386 ex_uminus(const int init, nodeType *p1)
1387 {
1388   nodeType *p = nullptr;
1389 
1390   if (p1->type == typeVar)
1391     {
1392       if (Options::cdoVerbose) cdo_print("\t%s\tneg\t- (%s)", ExIn[init], p1->u.var.nm);
1393       p = ex_uminus_var(init, p1);
1394     }
1395   else if (p1->type == typeCon)
1396     {
1397       if (Options::cdoVerbose) cdo_print("\t%s\tneg\t- (%g)", ExIn[init], p1->u.con.value);
1398       p = ex_uminus_con(p1);
1399     }
1400   else
1401     cdo_abort("Internal problem!");
1402 
1403   return p;
1404 }
1405 
1406 static nodeType *
ex_not_var(const int init,nodeType * p1)1407 ex_not_var(const int init, nodeType *p1)
1408 {
1409   const auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1;
1410   const auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1;
1411   const auto nmiss = p1->param.nmiss;
1412   const auto missval = p1->param.missval;
1413 
1414   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1415 
1416   p->type = typeVar;
1417   p->ltmpobj = true;
1418   p->u.var.nm = strdup(tmpvnm);
1419   param_meta_copy(p->param, p1->param);
1420   p->param.name = p->u.var.nm;
1421 
1422   if (!init)
1423     {
1424       p->param.data = (double *) Malloc(ngp * nlev * sizeof(double));
1425       double *pdata = p->param.data;
1426       const double *p1data = p1->param.data;
1427 
1428       if (nmiss)
1429         {
1430           for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : unary_op_not(p1data[i]);
1431         }
1432       else
1433         {
1434           for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = unary_op_not(p1data[i]);
1435         }
1436 
1437       p->param.nmiss = nmiss;
1438     }
1439 
1440   if (p1->ltmpobj) node_delete(p1);
1441 
1442   return p;
1443 }
1444 
1445 static nodeType *
ex_not_con(const nodeType * p1)1446 ex_not_con(const nodeType *p1)
1447 {
1448   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1449 
1450   p->type = typeCon;
1451   p->ltmpobj = true;
1452 
1453   p->u.con.value = unary_op_not(p1->u.con.value);
1454 
1455   return p;
1456 }
1457 
1458 static nodeType *
ex_not(const int init,nodeType * p1)1459 ex_not(const int init, nodeType *p1)
1460 {
1461   nodeType *p = nullptr;
1462 
1463   if (p1->type == typeVar)
1464     {
1465       if (Options::cdoVerbose) cdo_print("\t%s\tnot\t! (%s)", ExIn[init], p1->u.var.nm);
1466       p = ex_not_var(init, p1);
1467     }
1468   else if (p1->type == typeCon)
1469     {
1470       if (Options::cdoVerbose) cdo_print("\t%s\tnot\t! (%g)", ExIn[init], p1->u.con.value);
1471       p = ex_not_con(p1);
1472     }
1473   else
1474     cdo_abort("Internal problem!");
1475 
1476   return p;
1477 }
1478 
1479 static void
strAddNodeInfo(char * string,size_t stringlen,nodeType * p,const char * ext)1480 strAddNodeInfo(char *string, size_t stringlen, nodeType *p, const char *ext)
1481 {
1482   const auto len = strlen(string);
1483   if (p->type == typeCon)
1484     snprintf(string + len, stringlen - len, "%g%s", p->u.con.value, ext);
1485   else
1486     snprintf(string + len, stringlen - len, "%s[N%zu][L%zu]%s", p->u.var.nm, p->param.ngp, p->param.nlev, ext);
1487 }
1488 
1489 static nodeType *
ex_ifelse(const int init,nodeType * p1,nodeType * p2,nodeType * p3)1490 ex_ifelse(const int init, nodeType *p1, nodeType *p2, nodeType *p3)
1491 {
1492   if (Options::cdoVerbose)
1493     {
1494       char strbuffer[1024];
1495       snprintf(strbuffer, sizeof(strbuffer), "\t%s\tifelse\t", ExIn[init]);
1496       strAddNodeInfo(strbuffer, sizeof(strbuffer), p1, " ? ");
1497       strAddNodeInfo(strbuffer, sizeof(strbuffer), p2, " : ");
1498       strAddNodeInfo(strbuffer, sizeof(strbuffer), p3, "");
1499       cdo_print(strbuffer);
1500     }
1501 
1502   nodeType *p0 = nullptr;
1503   nodeType *pnodes[3] = { p1, p2, p3 };
1504   for (unsigned i = 0; i < 3; ++i)
1505     if (pnodes[i]->type != typeCon)
1506       {
1507         p0 = pnodes[i];
1508         break;
1509       }
1510 
1511   if (p0 == nullptr) cdo_abort("expr?expr:expr: no data variable found!");
1512 
1513   auto missval = p0->param.missval;
1514   auto ngp = (p0->param.ngp > 0) ? p0->param.ngp : 1;
1515   auto nlev = (p0->param.nlev > 0) ? p0->param.nlev : 1;
1516   auto px = p0;
1517 
1518   size_t nmiss1 = 0;
1519   auto missval1 = missval;
1520   double *pdata1 = nullptr;
1521   size_t ngp1 = 1;
1522   size_t nlev1 = 1;
1523 
1524   if (p1->type == typeCon)
1525     {
1526       pdata1 = &p1->u.con.value;
1527     }
1528   else
1529     {
1530       nmiss1 = p1->param.nmiss;
1531       ngp1 = (p1->param.ngp > 0) ? p1->param.ngp : 1;
1532       nlev1 = (p1->param.nlev > 0) ? p1->param.nlev : 1;
1533       missval1 = p1->param.missval;
1534       pdata1 = p1->param.data;
1535 
1536       if (ngp1 > 1 && ngp1 != ngp)
1537         {
1538           if (ngp != 1) cdo_abort("expr?expr:expr: Number of grid points differ (ngp = %zu, ngp1 = %zu)", ngp, ngp1);
1539 
1540           ngp = ngp1;
1541           px = p1;
1542         }
1543 
1544       if (nlev1 > 1 && nlev1 != nlev)
1545         {
1546           if (nlev != 1) cdo_abort("expr?expr:expr: Number of levels differ (nlev = %zu, nlev1 = %zu)", nlev, nlev1);
1547 
1548           nlev = nlev1;
1549           px = p1;
1550         }
1551     }
1552 
1553   auto missval2 = missval1;
1554   double *pdata2 = nullptr;
1555   size_t ngp2 = 1;
1556   size_t nlev2 = 1;
1557 
1558   if (p2->type == typeCon)
1559     {
1560       pdata2 = &p2->u.con.value;
1561     }
1562   else
1563     {
1564       ngp2 = (p2->param.ngp > 0) ? p2->param.ngp : 1;
1565       nlev2 = (p2->param.nlev > 0) ? p2->param.nlev : 1;
1566       missval2 = p2->param.missval;
1567       pdata2 = p2->param.data;
1568 
1569       if (ngp2 > 1 && ngp2 != ngp)
1570         {
1571           if (ngp != 1) cdo_abort("expr?expr:expr: Number of grid points differ (ngp = %zu, ngp2 = %zu)", ngp, ngp2);
1572 
1573           ngp = ngp2;
1574           px = p2;
1575         }
1576 
1577       if (nlev2 > 1 && nlev2 != nlev)
1578         {
1579           if (nlev != 1) cdo_abort("expr?expr:expr: Number of levels differ (nlev = %zu, nlev2 = %zu)", nlev, nlev2);
1580 
1581           nlev = nlev2;
1582           px = p2;
1583         }
1584     }
1585 
1586   auto missval3 = missval1;
1587   double *pdata3 = nullptr;
1588   size_t ngp3 = 1;
1589   size_t nlev3 = 1;
1590 
1591   if (p3->type == typeCon)
1592     {
1593       pdata3 = &p3->u.con.value;
1594     }
1595   else
1596     {
1597       ngp3 = (p3->param.ngp > 0) ? p3->param.ngp : 1;
1598       nlev3 = (p3->param.nlev > 0) ? p3->param.nlev : 1;
1599       missval3 = p3->param.missval;
1600       pdata3 = p3->param.data;
1601 
1602       if (ngp3 > 1 && ngp3 != ngp)
1603         {
1604           if (ngp != 1) cdo_abort("expr?expr:expr: Number of grid points differ (ngp = %zu, ngp3 = %zu)", ngp, ngp3);
1605 
1606           ngp = ngp3;
1607           px = p3;
1608         }
1609 
1610       if (nlev3 > 1 && nlev3 != nlev)
1611         {
1612           if (nlev != 1) cdo_abort("expr?expr:expr: Number of levels differ (nlev = %zu, nlev3 = %zu)", nlev, nlev3);
1613 
1614           nlev = nlev3;
1615           px = p3;
1616         }
1617     }
1618 
1619   auto p = (nodeType *) Calloc(1, sizeof(nodeType));
1620 
1621   p->type = typeVar;
1622   p->ltmpobj = true;
1623   p->u.var.nm = strdup(tmpvnm);
1624 
1625   param_meta_copy(p->param, px->param);
1626   p->param.name = p->u.var.nm;
1627 
1628   if (!init)
1629     {
1630       size_t nmiss = 0;
1631 
1632       p->param.data = (double *) Malloc(ngp * nlev * sizeof(double));
1633 
1634       for (size_t k = 0; k < nlev; ++k)
1635         {
1636           const size_t loff1 = (nlev1 == 1) ? 0 : k * ngp1;
1637           const size_t loff = k * ngp;
1638           const size_t loff2 = (nlev2 == 1) ? 0 : loff;
1639           const size_t loff3 = (nlev3 == 1) ? 0 : loff;
1640 
1641           const auto idat1 = pdata1 + loff1;
1642           const auto idat2 = pdata2 + loff2;
1643           const auto idat3 = pdata3 + loff3;
1644           auto odat = p->param.data + loff;
1645 
1646           for (size_t i = 0; i < ngp; ++i)
1647             {
1648               const auto ival1 = idat1[(ngp1 > 1) ? i : 0];
1649               const auto ival2 = idat2[(ngp2 > 1) ? i : 0];
1650               const auto ival3 = idat3[(ngp3 > 1) ? i : 0];
1651 
1652               if (nmiss1 && DBL_IS_EQUAL(ival1, missval1))
1653                 odat[i] = missval1;
1654               else if (IS_NOT_EQUAL(ival1, 0.0))
1655                 odat[i] = DBL_IS_EQUAL(ival2, missval2) ? missval1 : ival2;
1656               else
1657                 odat[i] = DBL_IS_EQUAL(ival3, missval3) ? missval1 : ival3;
1658             }
1659 
1660           nmiss += array_num_mv(ngp, odat, missval1);
1661         }
1662 
1663       p->param.nmiss = nmiss;
1664     }
1665 
1666   if (p1->ltmpobj) node_delete(p1);
1667   if (p2->ltmpobj) node_delete(p2);
1668   if (p3->ltmpobj) node_delete(p3);
1669 
1670   return p;
1671 }
1672 /*
1673 static int
1674 exNode(nodeType *p, parseParamType *parse_arg)
1675 {
1676   if (!p) return 0;
1677 
1678   // node is leaf
1679   if (p->type == typeCon || p->type == typeVar || p->u.opr.nops == 0) return 0;
1680 
1681   // node has children
1682   for (int k = 0; k < p->u.opr.nops; k++) exNode(p->u.opr.op[k], parse_arg);
1683 
1684   return 0;
1685 }
1686 */
1687 
1688 static int
param_search_name(const int nparam,const std::vector<paramType> & params,const char * name)1689 param_search_name(const int nparam, const std::vector<paramType> &params, const char *name)
1690 {
1691   for (int varID = 0; varID < nparam; ++varID)
1692     {
1693       if (params[varID].isValid && cdo_cmpstr(params[varID].name, name)) return varID;
1694     }
1695 
1696   return -1;
1697 }
1698 
1699 static int
param_search_name_size(const int nparam,std::vector<paramType> & params,const char * name,size_t ngp,size_t nlev)1700 param_search_name_size(const int nparam, std::vector<paramType> &params, const char *name, size_t ngp, size_t nlev)
1701 {
1702   for (int varID = 0; varID < nparam; ++varID)
1703     {
1704       if (cdo_cmpstr(params[varID].name, name))
1705         {
1706           if (ngp == params[varID].ngp && nlev == params[varID].nlev)
1707             return varID;
1708           else if (ngp == 0 && nlev == 0)
1709             return varID;
1710           else
1711             params[varID].isValid = false;
1712         }
1713     }
1714 
1715   return -1;
1716 }
1717 
1718 static void
param_print(const char * vname,const paramType & param,const long tsID)1719 param_print(const char *vname, const paramType &param, const long tsID)
1720 {
1721   constexpr size_t maxout = 100;
1722   const auto data = param.data;
1723   for (size_t k = 0; k < param.nlev; ++k)
1724     for (size_t i = 0; i < param.ngp; ++i)
1725       {
1726         if (i < maxout || (param.ngp > maxout && i >= (param.ngp - maxout)))
1727           {
1728             if (param.steptype == TIME_CONSTANT)
1729               fprintf(stdout, "   %s[lev=%zu:gp=%zu] = %g\n", vname, k + 1, i + 1, data[k * param.ngp + i]);
1730             else
1731               fprintf(stdout, "   %s[ts=%ld:lev=%zu:gp=%zu] = %g\n", vname, tsID, k + 1, i + 1, data[k * param.ngp + i]);
1732           }
1733         else if (i == maxout)
1734           {
1735             fprintf(stdout, "   .......\n");
1736           }
1737       }
1738 }
1739 
1740 static void
add_new_constant(const char * varname,parseParamType * parse_arg,std::vector<paramType> & params,const paramType & param)1741 add_new_constant(const char *varname, parseParamType *parse_arg, std::vector<paramType> &params, const paramType &param)
1742 {
1743   const auto varID = parse_arg->nparams;
1744   if (varID >= parse_arg->maxparams) cdo_abort("Too many parameter (limit=%d)", parse_arg->maxparams);
1745 
1746   param_meta_copy(params[varID], param);
1747   params[varID].type = PARAM_CONST;
1748   params[varID].isValid = true;
1749   params[varID].ngp = 0;
1750   params[varID].nlat = 0;
1751   params[varID].nlev = 0;
1752   params[varID].missval = -9.e33;
1753   params[varID].nmiss = 0;
1754   params[varID].name = strdup(varname);
1755   parse_arg->nparams++;
1756   parse_arg->cnparams++;
1757 }
1758 
1759 static void
add_new_param(const char * varname,parseParamType * parse_arg,std::vector<paramType> & params,const paramType & param)1760 add_new_param(const char *varname, parseParamType *parse_arg, std::vector<paramType> &params, const paramType &param)
1761 {
1762   const auto varID = parse_arg->nparams;
1763   if (varID >= parse_arg->maxparams) cdo_abort("Too many parameter (limit=%d)", parse_arg->maxparams);
1764 
1765   param_meta_copy(params[varID], param);
1766   params[varID].isValid = true;
1767   params[varID].hasMissvals = param.hasMissvals;
1768   params[varID].name = strdup(varname);
1769   params[varID].nmiss = param.nmiss;
1770   if (param.units) params[varID].units = strdup(param.units);
1771   if (param.longname) params[varID].longname = strdup(param.longname);
1772   parse_arg->nparams++;
1773   parse_arg->cnparams++;
1774 }
1775 
1776 static nodeType *
expr_run_type_com(nodeType * p,parseParamType * parse_arg)1777 expr_run_type_com(nodeType *p, parseParamType *parse_arg)
1778 {
1779   const auto init = parse_arg->init;
1780   auto &params = parse_arg->params;
1781 
1782   const auto cname = p->u.com.cname;
1783   const auto vname = p->u.com.vname;
1784   if (parse_arg->debug) cdo_print("\tstatement\t\t%s(%s)", cname, vname);
1785 
1786   auto varID = param_search_name(parse_arg->nparams, params, vname);
1787   if (varID == -1) cdo_abort("Variable %s not found, needed for statement %s(%s)!", vname, cname, vname);
1788 
1789   if (init)
1790     {
1791       if (cdo_cmpstr(cname, "remove")) params[varID].remove = true;
1792     }
1793   else
1794     {
1795       if (cdo_cmpstr(cname, "print")) param_print(vname, params[varID], std::lround(params[parse_arg->tsID].data[0]));
1796     }
1797 
1798   return nullptr;
1799 }
1800 
1801 static nodeType *
expr_run_type_con(nodeType * p,parseParamType * parse_arg)1802 expr_run_type_con(nodeType *p, parseParamType *parse_arg)
1803 {
1804   if (parse_arg->debug) cdo_print("\tpush\tconst\t%g", p->u.con.value);
1805   return p;
1806 }
1807 
1808 static int
expr_run_type_var_grid(const char * vnm,int coord,parseParamType * parse_arg)1809 expr_run_type_var_grid(const char *vnm, int coord, parseParamType *parse_arg)
1810 {
1811   auto &params = parse_arg->params;
1812 
1813   const auto len = strlen(vnm);
1814   auto varname = strdup(vnm);
1815   varname[len - 2] = 0;
1816   const auto varID = param_search_name(parse_arg->nparams, params, varname);
1817   if (varID == -1) cdo_abort("Coordinate %c: variable >%s< not found!", coord, varname);
1818 
1819   const auto nvarID = parse_arg->nparams;
1820   if (nvarID >= parse_arg->maxparams) cdo_abort("Too many parameter (limit=%d)", parse_arg->maxparams);
1821 
1822   const auto coordID = params_get_coord_ID(parse_arg, coord, params[varID].gridID);
1823   parse_arg->coords[coordID].needed = true;
1824   const auto units = parse_arg->coords[coordID].units.data();
1825   const auto longname = parse_arg->coords[coordID].longname.data();
1826 
1827   params[nvarID].isValid = true;
1828   params[nvarID].coord = coord;
1829   params[nvarID].hasMissvals = false;
1830   params[nvarID].name = strdup(vnm);
1831   params[nvarID].missval = params[varID].missval;
1832   params[nvarID].gridID = params[varID].gridID;
1833   params[nvarID].zaxisID = parse_arg->surfaceID;
1834   params[nvarID].steptype = TIME_CONSTANT;
1835   params[nvarID].ngp = params[varID].ngp;
1836   params[nvarID].nlat = params[varID].nlat;
1837   params[nvarID].nlev = 1;
1838   if (units) params[nvarID].units = strdup(units);
1839   if (longname) params[nvarID].longname = strdup(longname);
1840   parse_arg->nparams++;
1841   parse_arg->cnparams++;
1842 
1843   free(varname);
1844 
1845   return nvarID;
1846 }
1847 
1848 static int
expr_run_type_var_zaxis(const char * vnm,int coord,parseParamType * parse_arg)1849 expr_run_type_var_zaxis(const char *vnm, int coord, parseParamType *parse_arg)
1850 {
1851   auto &params = parse_arg->params;
1852 
1853   const auto len = strlen(vnm);
1854   auto varname = strdup(vnm);
1855   varname[len - 2] = 0;
1856   const auto varID = param_search_name(parse_arg->nparams, params, varname);
1857   if (varID == -1) cdo_abort("Coordinate %c: variable >%s< not found!", coord, varname);
1858 
1859   const auto nvarID = parse_arg->nparams;
1860   if (nvarID >= parse_arg->maxparams) cdo_abort("Too many parameter (limit=%d)", parse_arg->maxparams);
1861 
1862   const auto coordID = params_get_coord_ID(parse_arg, coord, params[varID].zaxisID);
1863   parse_arg->coords[coordID].needed = true;
1864   const auto units = parse_arg->coords[coordID].units.data();
1865   const auto longname = parse_arg->coords[coordID].longname.data();
1866 
1867   params[nvarID].isValid = true;
1868   params[nvarID].coord = coord;
1869   params[nvarID].hasMissvals = false;
1870   params[nvarID].name = strdup(vnm);
1871   params[nvarID].missval = params[varID].missval;
1872   params[nvarID].gridID = parse_arg->pointID;
1873   params[nvarID].zaxisID = params[varID].zaxisID;
1874   params[nvarID].steptype = TIME_CONSTANT;
1875   params[nvarID].ngp = 1;
1876   params[nvarID].nlev = params[varID].nlev;
1877   if (units) params[nvarID].units = strdup(units);
1878   if (longname) params[nvarID].longname = strdup(longname);
1879   parse_arg->nparams++;
1880   parse_arg->cnparams++;
1881 
1882   free(varname);
1883 
1884   return nvarID;
1885 }
1886 
1887 static nodeType *
expr_run_type_var(nodeType * p,parseParamType * parse_arg)1888 expr_run_type_var(nodeType *p, parseParamType *parse_arg)
1889 {
1890   const auto init = parse_arg->init;
1891   const auto &params = parse_arg->params;
1892 
1893   const auto vnm = p->u.var.nm;
1894   auto varID = param_search_name(parse_arg->nparams, params, vnm);
1895   if (varID == -1 && init)
1896     {
1897       const auto len = strlen(vnm);
1898       if (len > 2 && vnm[len - 2] == '.')
1899         {
1900           const auto coord = vnm[len - 1];
1901           if (coord == 'x' || coord == 'y' || coord == 'a' || coord == 'w')
1902             {
1903               varID = expr_run_type_var_grid(vnm, coord, parse_arg);
1904             }
1905           else if (coord == 'z' || coord == 'd')
1906             {
1907               varID = expr_run_type_var_zaxis(vnm, coord, parse_arg);
1908             }
1909         }
1910     }
1911 
1912   if (varID == -1)
1913     {
1914       cdo_abort("Variable >%s< not found!", vnm);
1915     }
1916   else if (init)
1917     {
1918       if (varID < parse_arg->nvars1 && !parse_arg->needed[varID]) parse_arg->needed[varID] = true;
1919     }
1920 
1921   param_meta_copy(p->param, params[varID]);
1922   p->param.coord = params[varID].coord;
1923   p->param.hasMissvals = params[varID].hasMissvals;
1924   p->param.name = params[varID].name;
1925   p->param.longname = params[varID].longname;
1926   p->param.units = params[varID].units;
1927   p->ltmpobj = false;
1928 
1929   if (!init)
1930     {
1931       p->param.data = params[varID].data;
1932       p->param.nmiss = params[varID].nmiss;
1933     }
1934 
1935   if (parse_arg->debug)
1936     {
1937       if (p->param.ngp == 0 && p->param.nlev == 0)
1938         cdo_print("\tpush\tvar\t%s", vnm);
1939       else
1940         cdo_print("\tpush\tvar\t%s[N%zu][L%zu]", vnm, p->param.ngp, p->param.nlev);
1941     }
1942 
1943   return p;
1944 }
1945 
1946 static nodeType *
expr_run_type_fun1c(nodeType * p,parseParamType * parse_arg)1947 expr_run_type_fun1c(nodeType *p, parseParamType *parse_arg)
1948 {
1949   const auto init = parse_arg->init;
1950 
1951   const auto funcID = get_funcID(p->u.fun1c.name);
1952   const auto functype = fun_sym_tbl[funcID].type;
1953 
1954   if (functype == FT_1C)
1955     {
1956       auto fnode = expr_run(p->u.fun1c.op, parse_arg);
1957       const auto value = p->u.fun1c.value;
1958       return fun1c(init, funcID, fnode, value, parse_arg);
1959     }
1960   else
1961     {
1962       cdo_abort("Syntax error in call to %s(), check number of parameter!\n", p->u.fun1c.name);
1963     }
1964 
1965   return nullptr;
1966 }
1967 
1968 static nodeType *
expr_run_type_fun2c(nodeType * p,parseParamType * parse_arg)1969 expr_run_type_fun2c(nodeType *p, parseParamType *parse_arg)
1970 {
1971   const auto init = parse_arg->init;
1972 
1973   const auto funcID = get_funcID(p->u.fun2c.name);
1974   const auto functype = fun_sym_tbl[funcID].type;
1975 
1976   if (functype == FT_2C)
1977     {
1978       auto fnode = expr_run(p->u.fun2c.op, parse_arg);
1979       const auto value1 = p->u.fun2c.value1;
1980       const auto value2 = p->u.fun2c.value2;
1981       return fun2c(init, funcID, fnode, value1, value2, parse_arg);
1982     }
1983   else
1984     {
1985       cdo_abort("Syntax error in call to %s(), check number of parameter!\n", p->u.fun2c.name);
1986     }
1987 
1988   return nullptr;
1989 }
1990 
1991 static nodeType *
expr_run_type_fun(nodeType * p,parseParamType * parse_arg)1992 expr_run_type_fun(nodeType *p, parseParamType *parse_arg)
1993 {
1994   const auto init = parse_arg->init;
1995   const auto &params = parse_arg->params;
1996 
1997   const auto funcID = get_funcID(p->u.fun.name);
1998   auto functype = fun_sym_tbl[funcID].type;
1999 
2000   auto fnode = expr_run(p->u.fun.op, parse_arg);
2001 
2002   if (functype == FT_COORD)
2003     {
2004       return coord_fun(init, funcID, fnode, parse_arg);
2005     }
2006   else if (functype == FT_0)
2007     {
2008       const auto vartsID = parse_arg->tsID;
2009       return ex_fun0_con(init, funcID, params[vartsID].data);
2010     }
2011   else
2012     {
2013       functype = fun_sym_tbl[funcID].type;
2014       const auto funcflag = fun_sym_tbl[funcID].flag;
2015       if (functype == FT_FLD && funcflag == 1)
2016         {
2017           const auto coordID = params_get_coord_ID(parse_arg, 'w', fnode->param.gridID);
2018           if (init)
2019             parse_arg->coords[coordID].needed = true;
2020           else
2021             fnode->param.weight = parse_arg->coords[coordID].data.data();
2022         }
2023       auto rnode = ex_fun(init, funcID, fnode);
2024       // if (fnode->ltmpobj) node_delete(fnode);
2025       // Free(fnode);
2026       return rnode;
2027     }
2028 }
2029 
2030 static nodeType *
expr_run_type_opr(nodeType * p,parseParamType * parse_arg)2031 expr_run_type_opr(nodeType *p, parseParamType *parse_arg)
2032 {
2033   const auto init = parse_arg->init;
2034   auto &params = parse_arg->params;
2035 
2036   // clang-format off
2037   switch (p->u.opr.oper)
2038     {
2039     case '=':
2040       {
2041         auto rnode = expr_run(p->u.opr.op[1], parse_arg);
2042 
2043         const auto varname2 = p->u.opr.op[0]->u.var.nm;
2044 
2045         if (parse_arg->debug)
2046           {
2047             if (rnode && rnode->type == typeVar && rnode->param.ngp > 0 && rnode->param.nlev > 0)
2048               cdo_print("\tpop\tvar\t%s[N%zu][L%zu]", varname2, rnode->param.ngp, rnode->param.nlev);
2049             else
2050               cdo_print("\tpop\tconst\t%s", varname2);
2051           }
2052 
2053         // auto varID = param_search_name(parse_arg->nparams, params, varname2);
2054         auto varID = param_search_name_size(parse_arg->nparams, params, varname2, rnode->param.ngp, rnode->param.nlev);
2055         if (init)
2056           {
2057             if (varID >= 0)
2058               {
2059                 // printf("  found %s\n", varname2);
2060                 if (varID < parse_arg->nvars1)
2061                   {
2062                     if (rnode->param.nlev > 0 && params[varID].nlev != rnode->param.nlev)
2063                       cdo_abort("The number of layers must not change (name=%s layers: in=%zu out=%zu)!", params[varID].name,
2064                                params[varID].nlev, rnode->param.nlev);
2065 
2066                     params[varID].select = true;
2067                     parse_arg->needed[varID] = true;
2068                   }
2069                 else if (params[varID].coord)
2070                   cdo_abort("Coordinate variable %s is read only!", varname2);
2071                 /*
2072                   else
2073                   cdo_warning("Variable %s already defined!", varname2);
2074                 */
2075               }
2076             else if (rnode && rnode->type == typeCon)
2077               {
2078                 add_new_constant(varname2, parse_arg, params, rnode->param);
2079               }
2080             else if (p->u.opr.op[1]->type != typeCon)
2081               {
2082                 add_new_param(varname2, parse_arg, params, rnode->param);
2083               }
2084           }
2085         else
2086           {
2087             if (varID < 0) cdo_abort("Variable >%s< not found!", varname2);
2088 
2089             if (params[varID].coord) cdo_abort("Coordinate variable %s is read only!", varname2);
2090             param_meta_copy(p->param, params[varID]);
2091             p->param.name = params[varID].name;
2092             p->param.data = params[varID].data;
2093             p->ltmpobj = false;
2094 
2095             ex_copy(init, p, rnode);
2096             params[varID].nmiss = p->param.nmiss;
2097           }
2098 
2099         if (rnode && rnode->ltmpobj)
2100           {
2101             node_delete(rnode);
2102             rnode = nullptr;
2103           }
2104         // else Free(rnode);
2105         break;
2106       }
2107     case UMINUS: return ex_uminus(init, expr_run(p->u.opr.op[0], parse_arg));
2108     case NOT:    return ex_not(init, expr_run(p->u.opr.op[0], parse_arg));
2109     case '?':    return ex_ifelse(init, expr_run(p->u.opr.op[0], parse_arg), expr_run(p->u.opr.op[1], parse_arg),
2110                                   expr_run(p->u.opr.op[2], parse_arg));
2111     default:     return expr(init, p->u.opr.oper, expr_run(p->u.opr.op[0], parse_arg), expr_run(p->u.opr.op[1], parse_arg));
2112     }
2113   // clang-format on
2114 
2115   return nullptr;
2116 }
2117 
2118 nodeType *
expr_run(nodeType * p,parseParamType * parse_arg)2119 expr_run(nodeType *p, parseParamType *parse_arg)
2120 {
2121   pointID = parse_arg->pointID;
2122   zonalID = parse_arg->zonalID;
2123   surfaceID = parse_arg->surfaceID;
2124 
2125   if (!p) return nullptr;
2126 
2127   // clang-format off
2128   switch (p->type)
2129     {
2130     case typeCom:     return expr_run_type_com(p, parse_arg);
2131     case typeCon:     return expr_run_type_con(p, parse_arg);
2132     case typeVar:     return expr_run_type_var(p, parse_arg);
2133     case typeFun1c:   return expr_run_type_fun1c(p, parse_arg);
2134     case typeFun2c:   return expr_run_type_fun2c(p, parse_arg);
2135     case typeFun:     return expr_run_type_fun(p, parse_arg);
2136     case typeOpr:     return expr_run_type_opr(p, parse_arg);
2137     }
2138   // clang-format on
2139 
2140   return nullptr;
2141 }
2142