%{ /* contrib/seg/segparse.y */ #include "postgres.h" #include #include #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 SEGFLOAT %token RANGE %token PLUMIN %token EXTENSION %type boundary %type 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"