diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/seg/segparse.y | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/contrib/seg/segparse.y b/contrib/seg/segparse.y new file mode 100644 index 0000000..0dc6bb6 --- /dev/null +++ b/contrib/seg/segparse.y @@ -0,0 +1,177 @@ +%{ +/* contrib/seg/segparse.y */ + +#include "postgres.h" + +#include <float.h> +#include <math.h> + +#include "fmgr.h" +#include "utils/builtins.h" + +#include "segdata.h" + +/* + * Bison doesn't allocate anything that needs to live across parser calls, + * so we can easily have it use palloc instead of malloc. This prevents + * memory leaks if we error out during parsing. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYMALLOC palloc +#define YYFREE pfree + +static float seg_atof(const char *value); + +static int sig_digits(const char *value); + +static char strbuf[25] = { + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '\0' +}; + +%} + +/* BISON Declarations */ +%parse-param {SEG *result} +%expect 0 +%name-prefix="seg_yy" + +%union +{ + struct BND + { + float val; + char ext; + char sigd; + } bnd; + char *text; +} +%token <text> SEGFLOAT +%token <text> RANGE +%token <text> PLUMIN +%token <text> EXTENSION +%type <bnd> boundary +%type <bnd> deviation +%start range + +/* Grammar follows */ +%% + + +range: boundary PLUMIN deviation + { + result->lower = $1.val - $3.val; + result->upper = $1.val + $3.val; + sprintf(strbuf, "%g", result->lower); + result->l_sigd = Max(sig_digits(strbuf), Max($1.sigd, $3.sigd)); + sprintf(strbuf, "%g", result->upper); + result->u_sigd = Max(sig_digits(strbuf), Max($1.sigd, $3.sigd)); + result->l_ext = '\0'; + result->u_ext = '\0'; + } + + | boundary RANGE boundary + { + result->lower = $1.val; + result->upper = $3.val; + if ( result->lower > result->upper ) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("swapped boundaries: %g is greater than %g", + result->lower, result->upper))); + + YYERROR; + } + result->l_sigd = $1.sigd; + result->u_sigd = $3.sigd; + result->l_ext = ( $1.ext ? $1.ext : '\0' ); + result->u_ext = ( $3.ext ? $3.ext : '\0' ); + } + + | boundary RANGE + { + result->lower = $1.val; + result->upper = HUGE_VAL; + result->l_sigd = $1.sigd; + result->u_sigd = 0; + result->l_ext = ( $1.ext ? $1.ext : '\0' ); + result->u_ext = '-'; + } + + | RANGE boundary + { + result->lower = -HUGE_VAL; + result->upper = $2.val; + result->l_sigd = 0; + result->u_sigd = $2.sigd; + result->l_ext = '-'; + result->u_ext = ( $2.ext ? $2.ext : '\0' ); + } + + | boundary + { + result->lower = result->upper = $1.val; + result->l_sigd = result->u_sigd = $1.sigd; + result->l_ext = result->u_ext = ( $1.ext ? $1.ext : '\0' ); + } + ; + +boundary: SEGFLOAT + { + /* temp variable avoids a gcc 3.3.x bug on Sparc64 */ + float val = seg_atof($1); + + $$.ext = '\0'; + $$.sigd = sig_digits($1); + $$.val = val; + } + | EXTENSION SEGFLOAT + { + /* temp variable avoids a gcc 3.3.x bug on Sparc64 */ + float val = seg_atof($2); + + $$.ext = $1[0]; + $$.sigd = sig_digits($2); + $$.val = val; + } + ; + +deviation: SEGFLOAT + { + /* temp variable avoids a gcc 3.3.x bug on Sparc64 */ + float val = seg_atof($1); + + $$.ext = '\0'; + $$.sigd = sig_digits($1); + $$.val = val; + } + ; + +%% + + +static float +seg_atof(const char *value) +{ + Datum datum; + + datum = DirectFunctionCall1(float4in, CStringGetDatum(value)); + return DatumGetFloat4(datum); +} + +static int +sig_digits(const char *value) +{ + int n = significant_digits(value); + + /* Clamp, to ensure value will fit in sigd fields */ + return Min(n, FLT_DIG); +} + + +#include "segscan.c" |