summaryrefslogtreecommitdiffstats
path: root/contrib/seg/segparse.y
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/seg/segparse.y177
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"