mirror of https://github.com/ecmwf/eccodes.git
478 lines
12 KiB
C
478 lines
12 KiB
C
/*
|
|
* (C) Copyright 2005- ECMWF.
|
|
*
|
|
* This software is licensed under the terms of the Apache Licence Version 2.0
|
|
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
|
|
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
|
|
*/
|
|
|
|
|
|
/*
|
|
Author: B.Raoult
|
|
Modified by Enrico Fucile
|
|
*/
|
|
|
|
#include "grib_api_internal.h"
|
|
#include <math.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
|
|
#if 0
|
|
GRIB_INLINE static int strcmp(const char* a,const char* b) {
|
|
if (*a != *b) return 1;
|
|
while((*a!=0 && *b!=0) && *(a) == *(b) ) {a++;b++;}
|
|
return (*a==0 && *b==0) ? 0 : 1;
|
|
}
|
|
#endif
|
|
|
|
#ifndef NUMBER
|
|
#define NUMBER(a) (sizeof(a) / sizeof(a[0])) /* number of elem. of an array */
|
|
#endif
|
|
#ifndef MAX
|
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
#ifndef MIN
|
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
#define ABS(a) ((a) < 0 ? -(a) : (a))
|
|
#define ROUND(a) ((long)((a) + 0.5))
|
|
#define EQ(a, b) ((*(a) == *(b)) && (strcmp(a, b) == 0))
|
|
#define LT(a, b) ((*(a) < *(b)) || (strcmp(a, b) < 0))
|
|
|
|
|
|
static grib_math* readpower(grib_context* c, char** form, int* err);
|
|
static grib_math* readatom(grib_context* c, char** form, int* err);
|
|
static grib_math* readfactor(grib_context* c, char** form, int* err);
|
|
static grib_math* readterm(grib_context* c, char** form, int* err);
|
|
static grib_math* readtest(grib_context* c, char** form, int* err);
|
|
static grib_math* readlist(grib_context* c, char** form, int* n, int* err);
|
|
static grib_math* readand(grib_context* c, char** form, int* err);
|
|
static grib_math* reador(grib_context* c, char** form, int* err);
|
|
static void advance(char** form);
|
|
static char* opname(char* p, int n);
|
|
/*
|
|
static long op_eq(long a, long b) {return a == b;}
|
|
static long op_ne(long a, long b) {return a != b;}
|
|
static long op_lt(long a, long b) {return a < b;}
|
|
static long op_gt(long a, long b) {return a > b;}
|
|
static long op_and(long a, long b) {return a && b;}
|
|
static long op_or(long a, long b) {return a || b;}
|
|
static long op_ge(long a, long b) {return a >= b;}
|
|
static long op_le(long a, long b) {return a <= b;}
|
|
|
|
static long op_bit(long a, long b) {return a&(1<<b);}
|
|
static long op_bitoff(long a, long b) {return !op_bit(a,b);}
|
|
|
|
static long op_not(long a) {return !a;}
|
|
static long op_neg(long a) {return -a;}
|
|
|
|
static double op_neg_d(double a) {return -a;}
|
|
|
|
static long op_pow(long a, long b) {return grib_power(a,b);}
|
|
static long op_add(long a, long b) {return a+b;}
|
|
static long op_sub(long a, long b) {return a-b;}
|
|
static long op_div(long a, long b) {return a/b;}
|
|
static long op_mul(long a, long b) {return a*b;}
|
|
static long op_modulo(long a, long b) {return a%b;}
|
|
|
|
static double op_mul_d(double a, double b) {return a*b;}
|
|
static double op_div_d(double a, double b) {return a/b;}
|
|
static double op_add_d(double a, double b) {return a+b;}
|
|
static double op_sub_d(double a, double b) {return a-b;}
|
|
|
|
static double op_eq_d(double a, double b) {return a == b;}
|
|
static double op_ne_d(double a, double b) {return a != b;}
|
|
static double op_lt_d(double a, double b) {return a < b;}
|
|
static double op_gt_d(double a, double b) {return a > b;}
|
|
static double op_ge_d(double a, double b) {return a >= b;}
|
|
static double op_le_d(double a, double b) {return a <= b;}
|
|
|
|
static int op_eq_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) == 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
static int op_ne_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) == 0 ? 0 : 1;
|
|
return 0;
|
|
}
|
|
static int op_lt_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) < 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
static int op_gt_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) > 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
static int op_ge_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) >= 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
static int op_le_string(char* a,char* b) {
|
|
if (a && b) return strcmp(a,b) <= 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
typedef double real;
|
|
typedef int boolean;
|
|
typedef int err;
|
|
typedef real (*fop1)(real);
|
|
typedef real (*fop2)(real, real);
|
|
|
|
static void advance(char** form)
|
|
{
|
|
(*form)++;
|
|
while (isspace(**form))
|
|
(*form)++;
|
|
}
|
|
|
|
static grib_math* readatom(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p;
|
|
int i;
|
|
char buf[1024];
|
|
|
|
switch (**form) {
|
|
case '(':
|
|
advance(form);
|
|
p = reador(c, form, err);
|
|
if (**form != ')') {
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Formula: missing )");
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
}
|
|
advance(form);
|
|
break;
|
|
|
|
case '-':
|
|
p = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
p->arity = 1;
|
|
p->name = strdup("neg");
|
|
Assert(p->name);
|
|
advance(form);
|
|
p->left = readatom(c, form, err);
|
|
break;
|
|
|
|
case '!':
|
|
p = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
p->arity = 1;
|
|
p->name = strdup("neg");
|
|
Assert(p->name);
|
|
advance(form);
|
|
p->left = readatom(c, form, err);
|
|
break;
|
|
|
|
case '\0':
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Formula: syntax error");
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
return NULL;
|
|
/*NOTREACHED*/
|
|
break;
|
|
|
|
default:
|
|
i = 0;
|
|
|
|
if (**form == '\'' || **form == '"') {
|
|
char achar = *((*form)++);
|
|
while (**form && **form != achar)
|
|
buf[i++] = *((*form)++);
|
|
if (**form)
|
|
(*form)++;
|
|
}
|
|
else
|
|
while (isalpha(**form) || isdigit(**form) || **form == '.' || **form == '_')
|
|
buf[i++] = *((*form)++);
|
|
|
|
buf[i] = 0;
|
|
if (isspace(**form))
|
|
advance(form);
|
|
|
|
p = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
p->name = strdup(buf);
|
|
Assert(p->name);
|
|
p->left = 0;
|
|
p->right = 0;
|
|
|
|
switch (**form) {
|
|
case '(':
|
|
advance(form);
|
|
p->arity = 0;
|
|
p->left = readlist(c, form, &p->arity, err);
|
|
if (**form != ')') {
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Formula: missing )");
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
}
|
|
advance(form);
|
|
break;
|
|
|
|
case '[':
|
|
advance(form);
|
|
p->arity = 0;
|
|
p->left = readlist(c, form, &p->arity, err);
|
|
if (**form != ']') {
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Formula: missing ]");
|
|
*err = GRIB_INTERNAL_ERROR;
|
|
}
|
|
p->arity = -p->arity;
|
|
advance(form);
|
|
break;
|
|
|
|
default:
|
|
p->arity = 0;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
static char* opname(char* p, int n)
|
|
{
|
|
char buf[5];
|
|
strncpy(buf, p, n);
|
|
buf[n] = 0;
|
|
return strdup(buf);
|
|
}
|
|
|
|
void print_math(grib_math* m)
|
|
{
|
|
if (m) {
|
|
putchar('(');
|
|
print_math(m->left);
|
|
printf("%s", m->name);
|
|
print_math(m->right);
|
|
putchar(')');
|
|
}
|
|
}
|
|
|
|
static grib_math* readpower(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readatom(c, form, err);
|
|
|
|
while (**form == '^' || (**form == '*' && *(*form + 1) == '*')) {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
q->right = 0;
|
|
q->left = p;
|
|
q->arity = 2;
|
|
|
|
if (**form == '*') {
|
|
advance(form);
|
|
**form = '^';
|
|
}
|
|
|
|
q->name = opname(*form, 1);
|
|
advance(form);
|
|
q->right = readatom(c, form, err);
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* readlist(grib_context* c, char** form, int* n, int* err)
|
|
{
|
|
grib_math* p;
|
|
|
|
if (**form == ')')
|
|
return NULL;
|
|
|
|
p = readtest(c, form, err);
|
|
*n = 1;
|
|
|
|
while (**form == ',') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
|
|
(*n)++;
|
|
|
|
q->left = p;
|
|
|
|
advance(form);
|
|
|
|
q->right = readtest(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* readfactor(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readpower(c, form, err);
|
|
|
|
while (**form == '*' || **form == '/') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
|
|
q->arity = 2;
|
|
q->left = p;
|
|
q->name = opname(*form, 1);
|
|
|
|
advance(form);
|
|
|
|
q->right = readpower(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* readterm(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readfactor(c, form, err);
|
|
while (**form == '+' || **form == '-') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
|
|
q->arity = 2;
|
|
q->left = p;
|
|
q->name = opname(*form, 1);
|
|
|
|
advance(form);
|
|
|
|
q->right = readfactor(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* readtest(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readterm(c, form, err);
|
|
while (**form == '<' || **form == '>' || **form == '=') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
char* x = *form;
|
|
int n = 1;
|
|
|
|
q->arity = 2;
|
|
q->left = p;
|
|
|
|
advance(form);
|
|
if (**form == '=' || **form == '>') {
|
|
n = 2;
|
|
advance(form);
|
|
}
|
|
|
|
q->name = opname(x, n);
|
|
|
|
q->right = readterm(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* readand(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readtest(c, form, err);
|
|
while (**form == '&') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
char* x = *form;
|
|
int n = 1;
|
|
|
|
q->arity = 2;
|
|
q->left = p;
|
|
|
|
advance(form);
|
|
if (**form == '&') {
|
|
n = 2;
|
|
advance(form);
|
|
}
|
|
|
|
q->name = opname(x, n);
|
|
|
|
q->right = readtest(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static grib_math* reador(grib_context* c, char** form, int* err)
|
|
{
|
|
grib_math* p = readand(c, form, err);
|
|
while (**form == '|') {
|
|
grib_math* q = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
char* x = *form;
|
|
int n = 1;
|
|
|
|
q->arity = 2;
|
|
q->left = p;
|
|
|
|
advance(form);
|
|
if (**form == '|') {
|
|
n = 2;
|
|
advance(form);
|
|
}
|
|
|
|
q->name = opname(x, n);
|
|
|
|
q->right = readand(c, form, err);
|
|
|
|
p = q;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
grib_math* grib_math_clone(grib_context* c, grib_math* m)
|
|
{
|
|
grib_math* n = NULL;
|
|
if (m) {
|
|
n = (grib_math*)grib_context_malloc(c, sizeof(grib_math));
|
|
n->arity = m->arity;
|
|
n->name = strdup(m->name);
|
|
Assert(n->name);
|
|
n->left = grib_math_clone(c, m->left);
|
|
n->right = grib_math_clone(c, m->right);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
void grib_math_delete(grib_context* c, grib_math* m)
|
|
{
|
|
grib_math *left = 0, *right = 0;
|
|
left = m->left;
|
|
right = m->right;
|
|
if (m->name)
|
|
free(m->name);
|
|
grib_context_free(c, m);
|
|
if (left)
|
|
grib_math_delete(c, left);
|
|
if (right)
|
|
grib_math_delete(c, right);
|
|
}
|
|
|
|
grib_math* grib_math_new(grib_context* c, const char* formula, int* err)
|
|
{
|
|
grib_math* x = NULL;
|
|
char* f = NULL;
|
|
char* fsave = NULL;
|
|
|
|
*err = 0;
|
|
|
|
if (!formula) {
|
|
*err = GRIB_INVALID_ARGUMENT;
|
|
return NULL;
|
|
}
|
|
|
|
f = strdup(formula);
|
|
Assert(f);
|
|
fsave = f;
|
|
|
|
x = reador(c, &f, err);
|
|
if (*err != GRIB_SUCCESS)
|
|
return NULL;
|
|
|
|
if (*f) {
|
|
grib_context_log(c, GRIB_LOG_ERROR,
|
|
"grib_math_new : Part of the formula was not processed: '%s'", f);
|
|
*err = GRIB_INVALID_ARGUMENT;
|
|
return NULL;
|
|
}
|
|
|
|
free(fsave);
|
|
|
|
return x;
|
|
}
|