Blame ce_expr.yy

Packit a4aae4
Packit a4aae4
// -*- mode: c++; c-basic-offset:4 -*-
Packit a4aae4
Packit a4aae4
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
Packit a4aae4
// Access Protocol.
Packit a4aae4
Packit a4aae4
// Copyright (c) 2002,2003 OPeNDAP, Inc.
Packit a4aae4
// Author: James Gallagher <jgallagher@opendap.org>
Packit a4aae4
//
Packit a4aae4
// This library is free software; you can redistribute it and/or
Packit a4aae4
// modify it under the terms of the GNU Lesser General Public
Packit a4aae4
// License as published by the Free Software Foundation; either
Packit a4aae4
// version 2.1 of the License, or (at your option) any later version.
Packit a4aae4
// 
Packit a4aae4
// This library is distributed in the hope that it will be useful,
Packit a4aae4
// but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a4aae4
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a4aae4
// Lesser General Public License for more details.
Packit a4aae4
// 
Packit a4aae4
// You should have received a copy of the GNU Lesser General Public
Packit a4aae4
// License along with this library; if not, write to the Free Software
Packit a4aae4
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit a4aae4
//
Packit a4aae4
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
Packit a4aae4
 
Packit a4aae4
// (c) COPYRIGHT URI/MIT 1995-1999
Packit a4aae4
// Please read the full copyright statement in the file COPYRIGHT_URI.
Packit a4aae4
//
Packit a4aae4
// Authors:
Packit a4aae4
//      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
Packit a4aae4
Packit a4aae4
/*
Packit a4aae4
  This is the parser for the DODS constraint expression grammar. The parser
Packit a4aae4
  calls various `helper' functions defined by the DAP classes which either
Packit a4aae4
  implement the operations (in the case of relational ops) or store
Packit a4aae4
  information (in the case of selection operations). 
Packit a4aae4
Packit a4aae4
  jhrg 9/5/95
Packit a4aae4
*/
Packit a4aae4
Packit a4aae4
%code requires {
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#include <cassert>
Packit a4aae4
#include <cstdlib>
Packit a4aae4
#include <cstring>
Packit a4aae4
Packit a4aae4
#include <iostream>
Packit a4aae4
#include <sstream>
Packit a4aae4
#include <iterator>
Packit a4aae4
#include <string>
Packit a4aae4
#include <stack>
Packit a4aae4
Packit a4aae4
//#define DODS_DEBUG
Packit a4aae4
Packit a4aae4
#include "debug.h"
Packit a4aae4
#include "escaping.h"
Packit a4aae4
Packit a4aae4
#include "DDS.h"
Packit a4aae4
#include "ConstraintEvaluator.h"
Packit a4aae4
Packit a4aae4
#include "BaseType.h"
Packit a4aae4
Packit a4aae4
#include "Byte.h"
Packit a4aae4
#include "Int16.h"
Packit a4aae4
#include "UInt16.h"
Packit a4aae4
#include "Int32.h"
Packit a4aae4
#include "UInt32.h"
Packit a4aae4
#include "Float32.h"
Packit a4aae4
#include "Float64.h"
Packit a4aae4
#include "Str.h"
Packit a4aae4
#include "Url.h"
Packit a4aae4
#include "Array.h"
Packit a4aae4
#include "Structure.h"
Packit a4aae4
#include "Sequence.h"
Packit a4aae4
#include "Grid.h"
Packit a4aae4
Packit a4aae4
#include "Error.h"
Packit a4aae4
Packit a4aae4
#include "util.h"
Packit a4aae4
#include "parser.h"
Packit a4aae4
#include "ce_parser.h"
Packit a4aae4
#include "expr.h"
Packit a4aae4
#include "RValue.h"
Packit a4aae4
Packit a4aae4
using std::cerr;
Packit a4aae4
using std::endl;
Packit a4aae4
using namespace libdap ;
Packit a4aae4
Packit a4aae4
#define EVALUATOR(arg) (static_cast<ce_parser_arg*>(arg)->get_eval())
Packit a4aae4
#define DDS(arg) (static_cast<ce_parser_arg*>(arg)->get_dds())
Packit a4aae4
Packit a4aae4
// #define YYPARSE_PARAM arg
Packit a4aae4
Packit a4aae4
int ce_exprlex(void);		/* the scanner; see expr.lex */
Packit a4aae4
Packit a4aae4
void ce_exprerror(ce_parser_arg *arg, const string &s); 
Packit a4aae4
void ce_exprerror(ce_parser_arg *arg, const string &s, const string &s2;;
Packit a4aae4
void no_such_func(ce_parser_arg *arg, const string &name);
Packit a4aae4
void no_such_ident(ce_parser_arg *arg, const string &name, const string &word);
Packit a4aae4
Packit a4aae4
int_list *make_array_index(value &i1, value &i2, value &i3;;
Packit a4aae4
int_list *make_array_index(value &i1, value &i2;;
Packit a4aae4
int_list *make_array_index(value &i1;;
Packit a4aae4
int_list_list *make_array_indices(int_list *index);
Packit a4aae4
int_list_list *append_array_index(int_list_list *indices, int_list *index);
Packit a4aae4
Packit a4aae4
void delete_array_indices(int_list_list *indices);
Packit a4aae4
bool bracket_projection(DDS &table, const char *name, int_list_list *indices);
Packit a4aae4
Packit a4aae4
void process_array_indices(BaseType *variable, int_list_list *indices); 
Packit a4aae4
void process_grid_indices(BaseType *variable, int_list_list *indices); 
Packit a4aae4
void process_sequence_indices(BaseType *variable, int_list_list *indices);
Packit a4aae4
Packit a4aae4
/* Replace these with method calls. jhrg 8/31/06 */
Packit a4aae4
bool is_array_t(BaseType *variable);
Packit a4aae4
bool is_grid_t(BaseType *variable);
Packit a4aae4
bool is_sequence_t(BaseType *variable);
Packit a4aae4
Packit a4aae4
BaseType *make_variable(ConstraintEvaluator &eval, const value &val;;
Packit a4aae4
bool_func get_function(const ConstraintEvaluator &eval, const char *name);
Packit a4aae4
btp_func get_btp_function(const ConstraintEvaluator &eval, const char *name);
Packit a4aae4
proj_func get_proj_function(const ConstraintEvaluator &eval, const char *name);
Packit a4aae4
Packit a4aae4
template<class arg_list, class arg_type>
Packit a4aae4
arg_list make_fast_arg_list(unsigned long vector_size_hint, arg_type arg_value);
Packit a4aae4
Packit a4aae4
template<class arg_list, class arg_type>
Packit a4aae4
arg_list make_fast_arg_list(arg_list int_values, arg_type arg_value);
Packit a4aae4
Packit a4aae4
template<class t, class T>
Packit a4aae4
rvalue *build_constant_array(vector<t> *values, DDS *dds);
Packit a4aae4
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
%require "2.4"
Packit a4aae4
Packit a4aae4
%parse-param {ce_parser_arg *arg}
Packit a4aae4
%name-prefix "ce_expr"
Packit a4aae4
%defines
Packit a4aae4
%debug
Packit a4aae4
%verbose
Packit a4aae4
Packit a4aae4
%union {
Packit a4aae4
    bool boolean;
Packit a4aae4
    int op;
Packit a4aae4
    char id[ID_MAX];
Packit a4aae4
    
Packit a4aae4
    libdap::dods_byte byte_value;
Packit a4aae4
    libdap::dods_int16 int16_value;
Packit a4aae4
    libdap::dods_uint16 uint16_value;
Packit a4aae4
    libdap::dods_int32 int32_value;
Packit a4aae4
    libdap::dods_uint32 uint32_value;
Packit a4aae4
    libdap::dods_float32 float32_value;
Packit a4aae4
    libdap::dods_float64 float64_value;
Packit a4aae4
    
Packit a4aae4
    libdap::byte_arg_list byte_values;
Packit a4aae4
    libdap::int16_arg_list int16_values;
Packit a4aae4
    libdap::uint16_arg_list uint16_values;
Packit a4aae4
    libdap::int32_arg_list int32_values;
Packit a4aae4
    libdap::uint32_arg_list uint32_values;
Packit a4aae4
    libdap::float32_arg_list float32_values;
Packit a4aae4
    libdap::float64_arg_list float64_values;
Packit a4aae4
    
Packit a4aae4
    libdap::value val;               // value is defined in expr.h
Packit a4aae4
Packit a4aae4
    libdap::bool_func b_func;
Packit a4aae4
    libdap::btp_func bt_func;
Packit a4aae4
Packit a4aae4
    libdap::int_list *int_l_ptr;
Packit a4aae4
    libdap::int_list_list *int_ll_ptr;
Packit a4aae4
    
Packit a4aae4
    libdap::rvalue *rval_ptr;
Packit a4aae4
    libdap::rvalue_list *r_val_l_ptr;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
%token <val> SCAN_STR
Packit a4aae4
Packit a4aae4
%token <id> SCAN_WORD
Packit a4aae4
Packit a4aae4
%token <op> SCAN_EQUAL
Packit a4aae4
%token <op> SCAN_NOT_EQUAL
Packit a4aae4
%token <op> SCAN_GREATER
Packit a4aae4
%token <op> SCAN_GREATER_EQL
Packit a4aae4
%token <op> SCAN_LESS
Packit a4aae4
%token <op> SCAN_LESS_EQL
Packit a4aae4
%token <op> SCAN_REGEXP
Packit a4aae4
Packit a4aae4
%token <op> SCAN_STAR
Packit a4aae4
Packit a4aae4
%token <op> SCAN_HASH_BYTE
Packit a4aae4
%token <op> SCAN_HASH_INT16
Packit a4aae4
%token <op> SCAN_HASH_UINT16
Packit a4aae4
%token <op> SCAN_HASH_INT32
Packit a4aae4
%token <op> SCAN_HASH_UINT32
Packit a4aae4
%token <op> SCAN_HASH_FLOAT32
Packit a4aae4
%token <op> SCAN_HASH_FLOAT64
Packit a4aae4
Packit a4aae4
%type <boolean> constraint_expr projection proj_clause proj_function
Packit a4aae4
%type <boolean> array_projection selection clause bool_function arg_length_hint
Packit a4aae4
%type <id> array_proj_clause name
Packit a4aae4
%type <op> rel_op
Packit a4aae4
Packit a4aae4
%type <int_l_ptr> array_index
Packit a4aae4
%type <int_ll_ptr> array_indices
Packit a4aae4
Packit a4aae4
%type <rval_ptr> r_value id_or_const array_const_special_form array_projection_rvalue
Packit a4aae4
%type <r_val_l_ptr> r_value_list arg_list
Packit a4aae4
Packit a4aae4
%type <byte_value> fast_byte_arg
Packit a4aae4
%type <byte_values> fast_byte_arg_list
Packit a4aae4
Packit a4aae4
%type <int16_value> fast_int16_arg 
Packit a4aae4
%type <int16_values> fast_int16_arg_list
Packit a4aae4
Packit a4aae4
%type <uint16_value> fast_uint16_arg 
Packit a4aae4
%type <uint16_values> fast_uint16_arg_list
Packit a4aae4
Packit a4aae4
%type <int32_value> fast_int32_arg 
Packit a4aae4
%type <int32_values> fast_int32_arg_list
Packit a4aae4
Packit a4aae4
%type <uint32_value> fast_uint32_arg 
Packit a4aae4
%type <uint32_values> fast_uint32_arg_list
Packit a4aae4
Packit a4aae4
%type <float32_value> fast_float32_arg 
Packit a4aae4
%type <float32_values> fast_float32_arg_list
Packit a4aae4
Packit a4aae4
%type <float64_value> fast_float64_arg 
Packit a4aae4
%type <float64_values> fast_float64_arg_list
Packit a4aae4
Packit a4aae4
%code {
Packit a4aae4
/* This global is used by the rule 'arg_length_hint' so that the hint can 
Packit a4aae4
   be used during the paraent rule's parse. See fast_int32_arg_list. */
Packit a4aae4
unsigned long arg_length_hint_value = 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
constraint_expr: /* empty constraint --> send all */
Packit a4aae4
         {
Packit a4aae4
             DBG(cerr << "Mark all variables" << endl);
Packit a4aae4
		     DDS(arg)->mark_all(true);
Packit a4aae4
		     $$ = true;
Packit a4aae4
		 }
Packit a4aae4
         /* projection only */
Packit a4aae4
         | projection
Packit a4aae4
		 /* selection only --> project everything */
Packit a4aae4
         | '&' { DDS(arg)->mark_all(true); } selection
Packit a4aae4
         { 
Packit a4aae4
		     $$ = $3;
Packit a4aae4
		 }
Packit a4aae4
         | projection '&' selection
Packit a4aae4
         {
Packit a4aae4
		     $$ = $1 && $3;
Packit a4aae4
		 }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
projection: proj_clause
Packit a4aae4
         | proj_clause ',' projection
Packit a4aae4
         {
Packit a4aae4
		     $$ = $1 && $3;
Packit a4aae4
		 }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
proj_clause: name 
Packit a4aae4
         {
Packit a4aae4
		     BaseType *var = DDS(arg)->var($1);
Packit a4aae4
		     if (var) {
Packit a4aae4
			     DBG(cerr << "Marking " << $1 << endl);
Packit a4aae4
			     $$ = DDS(arg)->mark($1, true);
Packit a4aae4
			     DBG(cerr << "result: " << $$ << endl);
Packit a4aae4
		     }
Packit a4aae4
		     else {
Packit a4aae4
			     no_such_ident(arg, $1, "identifier");
Packit a4aae4
		     }
Packit a4aae4
		}
Packit a4aae4
        | proj_function
Packit a4aae4
        {
Packit a4aae4
		    $$ = $1;
Packit a4aae4
		}
Packit a4aae4
		| array_projection
Packit a4aae4
        {
Packit a4aae4
		    $$ = $1;
Packit a4aae4
		}
Packit a4aae4
        | array_const_special_form
Packit a4aae4
        {
Packit a4aae4
            Array *array = dynamic_cast<Array*>($1->bvalue(*DDS(arg)));
Packit a4aae4
            if (array) { 
Packit a4aae4
                /* When the special form appears here (not as a function argument)
Packit a4aae4
                set send_p so the data will be sent and add it to the DDS. This 
Packit a4aae4
                streamlines testing (and is likely what is intended). */
Packit a4aae4
                
Packit a4aae4
                array->set_send_p(true);
Packit a4aae4
                DDS(arg)->add_var_nocopy(array);
Packit a4aae4
                
Packit a4aae4
                return true;
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                ce_exprerror(arg, "Could not create the anonymous vector using the # special form");
Packit a4aae4
                return false;
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* The value parsed by arg_length_hint is stored in a global variable by that rule
Packit a4aae4
   so that it can be used during the parse of fast_byte_arg_list. */
Packit a4aae4
Packit a4aae4
/* return a rvalue */
Packit a4aae4
array_const_special_form: SCAN_HASH_BYTE '(' arg_length_hint ':' fast_byte_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_byte, Byte>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_INT16 '(' arg_length_hint ':' fast_int16_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_int16, Int16>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_UINT16 '(' arg_length_hint ':' fast_uint16_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_uint16, UInt16>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_INT32 '(' arg_length_hint ':' fast_int32_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_int32, Int32>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_UINT32 '(' arg_length_hint ':' fast_uint32_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_uint32, UInt32>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_FLOAT32 '(' arg_length_hint ':' fast_float32_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_float32, Float32>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_const_special_form: SCAN_HASH_FLOAT64 '(' arg_length_hint ':' fast_float64_arg_list ')'
Packit a4aae4
        {
Packit a4aae4
            $$ = build_constant_array<dods_float64, Float64>($5, DDS(arg));
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* Here the arg length hint is stored in a global so it can be used by the 
Packit a4aae4
   function that allocates the vector. The value is passed to vector::reserve(). */
Packit a4aae4
   
Packit a4aae4
arg_length_hint: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              if (!check_int32($1))
Packit a4aae4
                  throw Error(malformed_expr, "$<type>(hint, value, ...) special form expected hint to be an integer");
Packit a4aae4
                   
Packit a4aae4
              arg_length_hint_value = atoi($1);
Packit a4aae4
              $$ = true;
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_byte_arg_list: fast_byte_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<byte_arg_list, dods_byte>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_byte_arg_list ',' fast_byte_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<byte_arg_list, dods_byte>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_byte_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtol($1, 0, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_int16_arg_list: fast_int16_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<int16_arg_list, dods_int16>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_int16_arg_list ',' fast_int16_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<int16_arg_list, dods_int16>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_int16_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtol($1, 0, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_uint16_arg_list: fast_uint16_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<uint16_arg_list, dods_uint16>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_uint16_arg_list ',' fast_uint16_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<uint16_arg_list, dods_uint16>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_uint16_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtoul($1, 0, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_int32_arg_list: fast_int32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<int32_arg_list, dods_int32>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_int32_arg_list ',' fast_int32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<int32_arg_list, dods_int32>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_int32_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtol($1, 0, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_uint32_arg_list: fast_uint32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<uint32_arg_list, dods_uint32>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_uint32_arg_list ',' fast_uint32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<uint32_arg_list, dods_uint32>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_uint32_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtoul($1, 0, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_float32_arg_list: fast_float32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<float32_arg_list, dods_float32>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_float32_arg_list ',' fast_float32_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<float32_arg_list, dods_float32>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_float32_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtof($1, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* return an int_arg_list (a std::vector<int>*) */
Packit a4aae4
fast_float64_arg_list: fast_float64_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<float64_arg_list, dods_float64>(arg_length_hint_value, $1);
Packit a4aae4
          }
Packit a4aae4
          | fast_float64_arg_list ',' fast_float64_arg
Packit a4aae4
          {
Packit a4aae4
              $$ = make_fast_arg_list<float64_arg_list, dods_float64>($1, $3);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
fast_float64_arg: SCAN_WORD
Packit a4aae4
          {
Packit a4aae4
              $$ = strtod($1, 0);
Packit a4aae4
          }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
proj_function:  SCAN_WORD '(' arg_list ')'
Packit a4aae4
	    {
Packit a4aae4
		    proj_func p_f = 0;
Packit a4aae4
		    btp_func f = 0;
Packit a4aae4
Packit a4aae4
		    if ((f = get_btp_function(*(EVALUATOR(arg)), $1))) {
Packit a4aae4
			    EVALUATOR(arg)->append_clause(f, $3);
Packit a4aae4
			    $$ = true;
Packit a4aae4
		    }
Packit a4aae4
		    else if ((p_f = get_proj_function(*(EVALUATOR(arg)), $1))) { 
Packit a4aae4
		        DDS &dds = dynamic_cast<DDS&>(*(DDS(arg)));
Packit a4aae4
			    BaseType **args = build_btp_args( $3, dds );
Packit a4aae4
			    (*p_f)(($3) ? $3->size():0, args, dds, *(EVALUATOR(arg)));
Packit a4aae4
			    delete[] args;
Packit a4aae4
			    $$ = true;
Packit a4aae4
		    }
Packit a4aae4
		    else {
Packit a4aae4
			    no_such_func(arg, $1);
Packit a4aae4
		    }
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
selection:	clause
Packit a4aae4
		| selection '&' clause
Packit a4aae4
                {
Packit a4aae4
		    $$ = $1 && $3;
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
clause:		r_value rel_op '{' r_value_list '}'
Packit a4aae4
                {
Packit a4aae4
		    if ($1) {
Packit a4aae4
			EVALUATOR(arg)->append_clause($2, $1, $4);
Packit a4aae4
			$$ = true;
Packit a4aae4
		    }
Packit a4aae4
		    else
Packit a4aae4
			$$ = false;
Packit a4aae4
		}
Packit a4aae4
		| r_value rel_op r_value
Packit a4aae4
                {
Packit a4aae4
		    if ($1) {
Packit a4aae4
			rvalue_list *rv = new rvalue_list;
Packit a4aae4
			rv->push_back($3);
Packit a4aae4
			EVALUATOR(arg)->append_clause($2, $1, rv);
Packit a4aae4
			$$ = true;
Packit a4aae4
		    }
Packit a4aae4
		    else
Packit a4aae4
			$$ = false;
Packit a4aae4
		}
Packit a4aae4
		| bool_function
Packit a4aae4
                {
Packit a4aae4
		    $$ = $1;
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
bool_function: SCAN_WORD '(' arg_list ')'
Packit a4aae4
	       {
Packit a4aae4
		   bool_func b_func = get_function((*EVALUATOR(arg)), $1);
Packit a4aae4
		   if (!b_func) {
Packit a4aae4
		       no_such_func(arg, $1);
Packit a4aae4
		   }
Packit a4aae4
		   else {
Packit a4aae4
		       EVALUATOR(arg)->append_clause(b_func, $3);
Packit a4aae4
		       $$ = true;
Packit a4aae4
		   }
Packit a4aae4
	       }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* This rule does not check SCAN_WORD nor does it perform www escaping */
Packit a4aae4
r_value: id_or_const
Packit a4aae4
		| SCAN_WORD '(' arg_list ')'
Packit a4aae4
		{
Packit a4aae4
		    btp_func func = get_btp_function((*EVALUATOR(arg)), $1);
Packit a4aae4
		    if (func) {
Packit a4aae4
			    $$ = new rvalue(func, $3);
Packit a4aae4
		    } 
Packit a4aae4
		    else { 
Packit a4aae4
			    no_such_func(arg, $1);
Packit a4aae4
		    }
Packit a4aae4
		}
Packit a4aae4
        | array_const_special_form
Packit a4aae4
        {
Packit a4aae4
            $$ = $1;
Packit a4aae4
        }
Packit a4aae4
        | array_projection_rvalue
Packit a4aae4
        {
Packit a4aae4
            $$ = $1;
Packit a4aae4
        }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
r_value_list:	r_value
Packit a4aae4
		{
Packit a4aae4
		    if ($1)
Packit a4aae4
			    $$ = make_rvalue_list($1);
Packit a4aae4
		    else
Packit a4aae4
			    $$ = 0;
Packit a4aae4
		}
Packit a4aae4
		| r_value_list ',' r_value
Packit a4aae4
        {
Packit a4aae4
		    if ($1 && $3)
Packit a4aae4
			    $$ = append_rvalue_list($1, $3);
Packit a4aae4
		    else
Packit a4aae4
			    $$ = 0;
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
arg_list: r_value_list
Packit a4aae4
          {  
Packit a4aae4
		      $$ = $1;
Packit a4aae4
	      }
Packit a4aae4
          | /* Null, argument lists may be empty */
Packit a4aae4
          { 
Packit a4aae4
		      $$ = 0; 
Packit a4aae4
	      }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
id_or_const: SCAN_WORD
Packit a4aae4
		{ 
Packit a4aae4
		    BaseType *btp = DDS(arg)->var(www2id($1));
Packit a4aae4
		    if (btp) {
Packit a4aae4
                btp->set_in_selection(true);
Packit a4aae4
                $$ = new rvalue(btp);
Packit a4aae4
		    }
Packit a4aae4
		    else {
Packit a4aae4
			    value new_val;
Packit a4aae4
			    string name_tmp;
Packit a4aae4
			    if (check_int32($1)) {
Packit a4aae4
			        new_val.type = dods_int32_c;
Packit a4aae4
			        new_val.v.i = atoi($1);
Packit a4aae4
			    }
Packit a4aae4
			    else if (check_uint32($1)) {
Packit a4aae4
			        new_val.type = dods_uint32_c;
Packit a4aae4
			        new_val.v.ui = atoi($1);
Packit a4aae4
			    }
Packit a4aae4
			    else if (check_float64($1)) {
Packit a4aae4
			        new_val.type = dods_float64_c;
Packit a4aae4
			        new_val.v.f = atof($1);
Packit a4aae4
			    }
Packit a4aae4
			    else {
Packit a4aae4
			        new_val.type = dods_str_c;
Packit a4aae4
				// The 'new' here was used because www2id() modifies the
Packit a4aae4
				// std::string arg in place but 'value' holds a string*.
Packit a4aae4
			        // new_val.v.s = new string(www2id($1));
Packit a4aae4
				// I replcaed this with a local tmp to avoid the dynamic
Packit a4aae4
				// allocation and the need to call delete. This was part of
Packit a4aae4
				// the fix for ticket 2240. jhrg 7/30/14
Packit a4aae4
				name_tmp = $1;
Packit a4aae4
				name_tmp = www2id(name_tmp);
Packit a4aae4
				new_val.v.s = &name_tmp;
Packit a4aae4
			    }
Packit a4aae4
			    BaseType *btp = make_variable((*EVALUATOR(arg)), new_val);
Packit a4aae4
			    $$ = new rvalue(btp);
Packit a4aae4
		    }
Packit a4aae4
		}
Packit a4aae4
        | SCAN_STR
Packit a4aae4
                {
Packit a4aae4
                    if ($1.type != dods_str_c || $1.v.s == 0 || $1.v.s->empty())
Packit a4aae4
                        ce_exprerror(arg, "Malformed string", "");
Packit a4aae4
                        
Packit a4aae4
                    BaseType *var = DDS(arg)->var(www2id(*($1.v.s)));
Packit a4aae4
                    if (var) {
Packit a4aae4
                        $$ = new rvalue(var);
Packit a4aae4
                    }
Packit a4aae4
                    else {
Packit a4aae4
                        var = make_variable((*EVALUATOR(arg)), $1); 
Packit a4aae4
                        $$ = new rvalue(var);
Packit a4aae4
                    }
Packit a4aae4
		    // When the scanner (ce_expr.lex) returns the SCAN_STR token type
Packit a4aae4
		    // it makes a local copy of the string in a new std::string object
Packit a4aae4
		    // that we must delete. Fix for a bug report by Aron.Bartle@mechdyne.com
Packit a4aae4
		    // See ticket 2240. jhrg 7/30/14
Packit a4aae4
		    delete $1.v.s;
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* this must return an rvalue. It should run bracket_projection() 
Packit a4aae4
   and then return the BaseType of the Array wrapped in a RValue
Packit a4aae4
   object. */
Packit a4aae4
array_projection_rvalue : name array_indices
Packit a4aae4
                {
Packit a4aae4
                    if (!bracket_projection((*DDS(arg)), $1, $2))
Packit a4aae4
                      no_such_ident(arg, $1, "array, grid or sequence");
Packit a4aae4
                    
Packit a4aae4
                    // strncpy($$, $1, ID_MAX-1);
Packit a4aae4
                    // $$[ID_MAX-1] = '\0';
Packit a4aae4
Packit a4aae4
                    DDS(arg)->mark($1, true);
Packit a4aae4
                    $$ = new rvalue(DDS(arg)->var($1));
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_projection : array_proj_clause
Packit a4aae4
                {
Packit a4aae4
                    $$ = (*DDS(arg)).mark($1, true);
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
                
Packit a4aae4
array_proj_clause: name array_indices
Packit a4aae4
                {
Packit a4aae4
                    //string name = www2id($1);
Packit a4aae4
                    if (!bracket_projection((*DDS(arg)), $1, $2))
Packit a4aae4
                      no_such_ident(arg, $1, "array, grid or sequence");
Packit a4aae4
                    
Packit a4aae4
                    strncpy($$, $1, ID_MAX-1);
Packit a4aae4
                    $$[ID_MAX-1] = '\0';
Packit a4aae4
                }
Packit a4aae4
                | array_proj_clause name
Packit a4aae4
                {
Packit a4aae4
                    string name = string($1) + string($2);
Packit a4aae4
                    strncpy($$, name.c_str(), ID_MAX-1);
Packit a4aae4
                    $$[ID_MAX-1] = '\0';
Packit a4aae4
                }
Packit a4aae4
                | array_proj_clause name array_indices
Packit a4aae4
                {
Packit a4aae4
                    string name = string($1) + string($2);
Packit a4aae4
                    if (!bracket_projection((*DDS(arg)), name.c_str(), $3))
Packit a4aae4
                      no_such_ident(arg, name.c_str(), "array, grid or sequence");
Packit a4aae4
Packit a4aae4
                    strncpy($$, name.c_str(), ID_MAX-1);
Packit a4aae4
                    $$[ID_MAX-1] = '\0';
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
name:           SCAN_WORD
Packit a4aae4
                { 
Packit a4aae4
                    strncpy($$, www2id($1).c_str(), ID_MAX-1);
Packit a4aae4
                    $$[ID_MAX-1] = '\0';
Packit a4aae4
                }
Packit a4aae4
                | SCAN_STR
Packit a4aae4
                {
Packit a4aae4
                    if ($1.type != dods_str_c || $1.v.s == 0 || $1.v.s->empty())
Packit a4aae4
                        ce_exprerror(arg, "Malformed string", "");
Packit a4aae4
                        
Packit a4aae4
                    strncpy($$, www2id(*($1.v.s)).c_str(), ID_MAX-1);
Packit a4aae4
		    // See comment about regarding the scanner's behavior WRT SCAN_STR.
Packit a4aae4
		    // jhrg 7/30/14
Packit a4aae4
                    delete $1.v.s;
Packit a4aae4
Packit a4aae4
                    $$[ID_MAX-1] = '\0';
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
array_indices:  array_index
Packit a4aae4
                {
Packit a4aae4
		    $$ = make_array_indices($1);
Packit a4aae4
		}
Packit a4aae4
                | array_indices array_index
Packit a4aae4
                {
Packit a4aae4
		    $$ = append_array_index($1, $2);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/*
Packit a4aae4
 * We added [*], [n:*] and [n:m:*] to the syntax for array projections.
Packit a4aae4
 * These mean, resp., all the elements, elements from n to the end, and
Packit a4aae4
 * from n to the end with a stride of m. To encode this with as little 
Packit a4aae4
 * disruption as possible, we represent the star with -1. jhrg 12/20/12
Packit a4aae4
 */ 
Packit a4aae4
array_index:
Packit a4aae4
Packit a4aae4
'[' SCAN_WORD ']'
Packit a4aae4
{
Packit a4aae4
    if (!check_uint32($2))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($2) + "' is not a valid array index.");
Packit a4aae4
    value i;
Packit a4aae4
    i.type = dods_uint32_c;
Packit a4aae4
    i.v.i = atoi($2);
Packit a4aae4
    $$ = make_array_index(i);
Packit a4aae4
}
Packit a4aae4
|   '[' SCAN_STAR ']'
Packit a4aae4
{
Packit a4aae4
    value i;
Packit a4aae4
    i.type = dods_int32_c;
Packit a4aae4
    i.v.i =-1;
Packit a4aae4
    $$ = make_array_index(i);
Packit a4aae4
}
Packit a4aae4
|'[' SCAN_WORD ':' SCAN_WORD ']'
Packit a4aae4
{
Packit a4aae4
    if (!check_uint32($2))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($2) + "' is not a valid array index.");
Packit a4aae4
    if (!check_uint32($4))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($4) + "' is not a valid array index.");
Packit a4aae4
    value i,j;
Packit a4aae4
    i.type = j.type = dods_uint32_c;
Packit a4aae4
    i.v.i = atoi($2);
Packit a4aae4
    j.v.i = atoi($4);
Packit a4aae4
    $$ = make_array_index(i, j);
Packit a4aae4
}
Packit a4aae4
|'[' SCAN_WORD ':' SCAN_STAR ']'
Packit a4aae4
{
Packit a4aae4
    if (!check_uint32($2))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($2) + "' is not a valid array index.");
Packit a4aae4
    value i,j;
Packit a4aae4
    i.type = dods_uint32_c;
Packit a4aae4
    j.type = dods_int32_c;  /* signed */
Packit a4aae4
    i.v.i = atoi($2);
Packit a4aae4
    j.v.i = -1;
Packit a4aae4
    $$ = make_array_index(i, j);
Packit a4aae4
}
Packit a4aae4
| '[' SCAN_WORD ':' SCAN_WORD ':' SCAN_WORD ']'
Packit a4aae4
{
Packit a4aae4
    if (!check_uint32($2))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($2) + "' is not a valid array index.");
Packit a4aae4
    if (!check_uint32($4))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($4) + "' is not a valid array index.");
Packit a4aae4
    if (!check_uint32($6))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($6) + "' is not a valid array index.");
Packit a4aae4
    value i, j, k;
Packit a4aae4
    i.type = j.type = k.type = dods_uint32_c;
Packit a4aae4
    i.v.i = atoi($2);
Packit a4aae4
    j.v.i = atoi($4);
Packit a4aae4
    k.v.i = atoi($6);
Packit a4aae4
    $$ = make_array_index(i, j, k);
Packit a4aae4
}
Packit a4aae4
| '[' SCAN_WORD ':' SCAN_WORD ':' SCAN_STAR ']'
Packit a4aae4
{
Packit a4aae4
    if (!check_uint32($2))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($2) + "' is not a valid array index.");
Packit a4aae4
    if (!check_uint32($4))
Packit a4aae4
        throw Error(malformed_expr, "The word `" + string($4) + "' is not a valid array index.");
Packit a4aae4
    value i, j, k;
Packit a4aae4
    i.type = j.type = dods_uint32_c;
Packit a4aae4
    k.type = dods_int32_c;
Packit a4aae4
    i.v.i = atoi($2);
Packit a4aae4
    j.v.i = atoi($4);
Packit a4aae4
    k.v.i = -1;
Packit a4aae4
    $$ = make_array_index(i, j, k);
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
rel_op:		SCAN_EQUAL
Packit a4aae4
		| SCAN_NOT_EQUAL
Packit a4aae4
		| SCAN_GREATER
Packit a4aae4
		| SCAN_GREATER_EQL
Packit a4aae4
		| SCAN_LESS
Packit a4aae4
		| SCAN_LESS_EQL
Packit a4aae4
		| SCAN_REGEXP
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
// All these error reporting function now throw instances of Error. The expr
Packit a4aae4
// parser no longer returns an error code to indicate and error. 2/16/2000
Packit a4aae4
// jhrg.
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
ce_exprerror(ce_parser_arg *, const string &s)
Packit a4aae4
{
Packit a4aae4
    string msg = "Constraint expression parse error: " +s;
Packit a4aae4
    throw Error(malformed_expr, msg);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void ce_exprerror(ce_parser_arg *, const string &s, const string &s2)
Packit a4aae4
{
Packit a4aae4
    string msg = "Constraint expression parse error: " + s + ": " + s2;
Packit a4aae4
    throw Error(malformed_expr, msg);    
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void no_such_ident(ce_parser_arg *arg, const string &name, const string &word)
Packit a4aae4
{
Packit a4aae4
#if 0
Packit a4aae4
    string msg = "No such " + word + " in dataset";
Packit a4aae4
    ce_exprerror(arg, msg , name);
Packit a4aae4
#endif
Packit a4aae4
    string msg = "Constraint expression parse error: No such " + word + " in dataset: " + name;
Packit a4aae4
    throw Error(no_such_variable, msg);    
Packit a4aae4
    
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void no_such_func(ce_parser_arg *arg, const string &name)
Packit a4aae4
{
Packit a4aae4
    ce_exprerror(arg, "Not a registered function", name);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/* If we're calling this, assume var is not a Sequence. But assume that the
Packit a4aae4
 name contains a dot and it's a separator. Look for the rightmost dot and
Packit a4aae4
 then look to see if the name to the left is a sequence. Return a pointer
Packit a4aae4
 to the sequence if it is otherwise return null. Uses tail-recursion to
Packit a4aae4
 'walk' back from right to left looking at each dot. This way the sequence
Packit a4aae4
 will be found even if there are structures between the field and the
Packit a4aae4
 Sequence. */
Packit a4aae4
static Sequence *
Packit a4aae4
parent_is_sequence(DDS &table, const string &n)
Packit a4aae4
{
Packit a4aae4
    string::size_type dotpos = n.find_last_of('.');
Packit a4aae4
    if (dotpos == string::npos)
Packit a4aae4
        return 0;
Packit a4aae4
Packit a4aae4
    string s = n.substr(0, dotpos);
Packit a4aae4
Packit a4aae4
    // If the thing returned by table.var is not a Sequence, this cast
Packit a4aae4
    // will yield null.
Packit a4aae4
    Sequence *seq = dynamic_cast<Sequence*> (table.var(s));
Packit a4aae4
    if (seq)
Packit a4aae4
        return seq;
Packit a4aae4
    else
Packit a4aae4
        return parent_is_sequence(table, s);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool bracket_projection(DDS &table, const char *name, int_list_list *indices)
Packit a4aae4
{
Packit a4aae4
    BaseType *var = table.var(name);
Packit a4aae4
    Sequence *seq; // used in last else-if clause
Packit a4aae4
Packit a4aae4
    if (!var)
Packit a4aae4
        return false;
Packit a4aae4
Packit a4aae4
    if (is_array_t(var)) {
Packit a4aae4
        /* calls to set_send_p should be replaced with
Packit a4aae4
         calls to DDS::mark so that arrays of Structures,
Packit a4aae4
         etc. will be processed correctly when individual
Packit a4aae4
         elements are projected using short names.
Packit a4aae4
         9/1/98 jhrg */
Packit a4aae4
        /* var->set_send_p(true); */
Packit a4aae4
        //table.mark(name, true);
Packit a4aae4
        // We don't call mark() here for an array. Instead it is called from
Packit a4aae4
        // within the parser. jhrg 10/10/08
Packit a4aae4
        process_array_indices(var, indices); // throws on error
Packit a4aae4
        delete_array_indices(indices);
Packit a4aae4
    }
Packit a4aae4
    else if (is_grid_t(var)) {
Packit a4aae4
        process_grid_indices(var, indices);
Packit a4aae4
        table.mark(name, true);
Packit a4aae4
        delete_array_indices(indices);
Packit a4aae4
    }
Packit a4aae4
    else if (is_sequence_t(var)) {
Packit a4aae4
        table.mark(name, true);
Packit a4aae4
        process_sequence_indices(var, indices);
Packit a4aae4
        delete_array_indices(indices);
Packit a4aae4
    }
Packit a4aae4
    else if ((seq = parent_is_sequence(table, name))) {
Packit a4aae4
        process_sequence_indices(seq, indices);
Packit a4aae4
        table.mark(name, true);
Packit a4aae4
        delete_array_indices(indices);
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        return false;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Given three values (I1, I2, I3), all of which must be integers, build an
Packit a4aae4
// int_list which contains those values.
Packit a4aae4
// 
Packit a4aae4
// Note that we added support for * in the rightmost position of an index
Packit a4aae4
// (i.e., [*], [n:*], [n:m:*]) and indicate that star using -1 as an index value.
Packit a4aae4
// Bescause of this change, the test for the type of the rightmost value in
Packit a4aae4
// the index subexpr was changed to include signed int.
Packit a4aae4
// jhrg 12/20/12
Packit a4aae4
//
Packit a4aae4
// Returns: A pointer to an int_list of three integers or NULL if any of the
Packit a4aae4
// values are not integers.
Packit a4aae4
Packit a4aae4
int_list *
Packit a4aae4
make_array_index(value &i1, value &i2, value &i3)
Packit a4aae4
{
Packit a4aae4
    if (i1.type != dods_uint32_c || i2.type != dods_uint32_c || (i3.type != dods_uint32_c && i3.type != dods_int32_c))
Packit a4aae4
        return (int_list *) 0;
Packit a4aae4
Packit a4aae4
    int_list *index = new int_list;
Packit a4aae4
Packit a4aae4
    index->push_back((int) i1.v.i);
Packit a4aae4
    index->push_back((int) i2.v.i);
Packit a4aae4
    index->push_back((int) i3.v.i);
Packit a4aae4
Packit a4aae4
    DBG(cout << "index: ");
Packit a4aae4
    DBG(copy(index->begin(), index->end(), ostream_iterator<int>(cerr, " ")));
Packit a4aae4
    DBG(cerr << endl);
Packit a4aae4
Packit a4aae4
    return index;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int_list *
Packit a4aae4
make_array_index(value &i1, value &i2)
Packit a4aae4
{
Packit a4aae4
    if (i1.type != dods_uint32_c || (i2.type != dods_uint32_c && i2.type != dods_int32_c))
Packit a4aae4
	return (int_list *) 0;
Packit a4aae4
Packit a4aae4
    int_list *index = new int_list;
Packit a4aae4
Packit a4aae4
    index->push_back((int) i1.v.i);
Packit a4aae4
    index->push_back(1);
Packit a4aae4
    index->push_back((int) i2.v.i);
Packit a4aae4
Packit a4aae4
    DBG(cout << "index: ");
Packit a4aae4
    DBG(copy(index->begin(), index->end(), ostream_iterator<int>(cerr, " ")));
Packit a4aae4
    DBG(cerr << endl);
Packit a4aae4
Packit a4aae4
    return index;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int_list *
Packit a4aae4
make_array_index(value &i1)
Packit a4aae4
{
Packit a4aae4
    if (i1.type != dods_uint32_c && i1.type != dods_int32_c)
Packit a4aae4
	return (int_list *) 0;
Packit a4aae4
Packit a4aae4
    int_list *index = new int_list;
Packit a4aae4
Packit a4aae4
    // When the CE is Array[*] that means all of the elements, but the value
Packit a4aae4
    // of i1 will be -1. Make the projection triple be 0:1:-1 which is a 
Packit a4aae4
    // pattern that libdap::Array will recognize.
Packit a4aae4
    if (i1.v.i == -1)
Packit a4aae4
        index->push_back(0);
Packit a4aae4
    else
Packit a4aae4
        index->push_back((int) i1.v.i);
Packit a4aae4
    index->push_back(1);
Packit a4aae4
    index->push_back((int) i1.v.i);
Packit a4aae4
Packit a4aae4
    DBG(cout << "index: ");
Packit a4aae4
    DBG(copy(index->begin(), index->end(), ostream_iterator<int>(cerr, " ")));
Packit a4aae4
    DBG(cerr << endl);
Packit a4aae4
Packit a4aae4
    return index;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int_list_list *
Packit a4aae4
make_array_indices(int_list *index)
Packit a4aae4
{
Packit a4aae4
    int_list_list *indices = new int_list_list;
Packit a4aae4
Packit a4aae4
    DBG(cout << "index: ");
Packit a4aae4
    DBG(copy(index->begin(), index->end(), ostream_iterator<int>(cerr, " ")));
Packit a4aae4
    DBG(cerr << endl);
Packit a4aae4
Packit a4aae4
    assert(index);
Packit a4aae4
    indices->push_back(index);
Packit a4aae4
Packit a4aae4
    return indices;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int_list_list *
Packit a4aae4
append_array_index(int_list_list *indices, int_list *index)
Packit a4aae4
{
Packit a4aae4
    assert(indices);
Packit a4aae4
    assert(index);
Packit a4aae4
Packit a4aae4
    indices->push_back(index);
Packit a4aae4
Packit a4aae4
    return indices;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Delete an array indices list. 
Packit a4aae4
Packit a4aae4
void delete_array_indices(int_list_list *indices)
Packit a4aae4
{
Packit a4aae4
    assert(indices);
Packit a4aae4
Packit a4aae4
    for (int_list_citer i = indices->begin(); i != indices->end(); i++) {
Packit a4aae4
	int_list *il = *i;
Packit a4aae4
	assert(il);
Packit a4aae4
	delete il;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    delete indices;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool is_array_t(BaseType *variable)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
Packit a4aae4
    if (variable->type() != dods_array_c)
Packit a4aae4
	return false;
Packit a4aae4
    else
Packit a4aae4
	return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool is_grid_t(BaseType *variable)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
Packit a4aae4
    if (variable->type() != dods_grid_c)
Packit a4aae4
	return false;
Packit a4aae4
    else
Packit a4aae4
	return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool is_sequence_t(BaseType *variable)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
Packit a4aae4
    if (variable->type() != dods_sequence_c)
Packit a4aae4
	return false;
Packit a4aae4
    else
Packit a4aae4
	return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void process_array_indices(BaseType *variable, int_list_list *indices)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
Packit a4aae4
    Array *a = dynamic_cast<Array *>(variable); // replace with dynamic cast
Packit a4aae4
    if (!a)
Packit a4aae4
        throw Error(malformed_expr,
Packit a4aae4
		    string("The constraint expression evaluator expected an array; ") + variable->name() + " is not an array.");
Packit a4aae4
Packit a4aae4
    if (a->dimensions(true) != (unsigned) indices->size())
Packit a4aae4
        throw Error(malformed_expr,
Packit a4aae4
		    string("Error: The number of dimensions in the constraint for ") + variable->name()
Packit a4aae4
                    + " must match the number in the array.");
Packit a4aae4
Packit a4aae4
    DBG(cerr << "Before applying projection to array:" << endl);
Packit a4aae4
    DBG(a->print_decl(cerr, "", true, false, true));
Packit a4aae4
Packit a4aae4
    assert(indices);
Packit a4aae4
    
Packit a4aae4
    int_list_citer p = indices->begin();
Packit a4aae4
    Array::Dim_iter r = a->dim_begin();
Packit a4aae4
    for (; p != indices->end() && r != a->dim_end(); p++, r++) {
Packit a4aae4
        int_list *index = *p;
Packit a4aae4
        assert(index);
Packit a4aae4
Packit a4aae4
        int_citer q = index->begin();
Packit a4aae4
        assert(q != index->end());
Packit a4aae4
        int start = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stride = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stop = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        if (q != index->end())
Packit a4aae4
            throw Error(malformed_expr, string("Too many values in index list for ") + a->name() + ".");
Packit a4aae4
Packit a4aae4
        DBG(cerr << "process_array_indices: Setting constraint on " 
Packit a4aae4
            << a->name() << "[" << start << ":" << stop << "]"
Packit a4aae4
            << endl);
Packit a4aae4
Packit a4aae4
        // It's possible that an array will appear more than once in a CE
Packit a4aae4
        // (for example, if an array of structures is constrained so that
Packit a4aae4
        // only two fields are projected and there's an associated hyperslab).
Packit a4aae4
        // However, in this case the two hyperslabs must be equal; test for
Packit a4aae4
        // that here.
Packit a4aae4
        //
Packit a4aae4
        // We added '*' to mean 'the last element' in the array and use an index of -1
Packit a4aae4
        // to indicate that. If 'stop' is -1, don't test it here because dimension_stop()
Packit a4aae4
        // won't be -1 but the actual ending index of the array. jhrg 12/20/12
Packit a4aae4
Packit a4aae4
        if (a->send_p() && (a->dimension_start(r, true) != start || (a->dimension_stop(r, true) != stop && stop != -1)
Packit a4aae4
                            || a->dimension_stride(r, true) != stride))
Packit a4aae4
            throw Error(malformed_expr,
Packit a4aae4
                    string("The Array was already projected differently in the constraint expression: ") + a->name() + ".");
Packit a4aae4
Packit a4aae4
        a->add_constraint(r, start, stride, stop);
Packit a4aae4
Packit a4aae4
        DBG(cerr << "Set Constraint: " << a->dimension_size(r, true) << endl);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    DBG(cerr << "After applying projection to array:" << endl);
Packit a4aae4
    DBG(a->print_decl(cerr, "", true, false, true));
Packit a4aae4
Packit a4aae4
Packit a4aae4
    if (p != indices->end() && r == a->dim_end())
Packit a4aae4
        throw Error(malformed_expr, string("Too many indices in constraint for ") + a->name() + ".");
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void process_grid_indices(BaseType *variable, int_list_list *indices)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
    assert(variable->type() == dods_grid_c);
Packit a4aae4
    Grid *g = dynamic_cast<Grid *>(variable);
Packit a4aae4
    if (!g)
Packit a4aae4
        throw Error(unknown_error, "Expected a Grid variable");
Packit a4aae4
Packit a4aae4
    Array *a = g->get_array();
Packit a4aae4
Packit a4aae4
    if (a->dimensions(true) != (unsigned) indices->size())
Packit a4aae4
        throw Error(malformed_expr,
Packit a4aae4
		    string("Error: The number of dimensions in the constraint for ") + variable->name()
Packit a4aae4
		    + " must match the number in the grid.");
Packit a4aae4
Packit a4aae4
    // First do the constraints on the ARRAY in the grid.
Packit a4aae4
    process_array_indices(g->array_var(), indices);
Packit a4aae4
Packit a4aae4
    // Now process the maps.
Packit a4aae4
    Grid::Map_iter r = g->map_begin();
Packit a4aae4
Packit a4aae4
    // Suppress all maps by default.
Packit a4aae4
    for (; r != g->map_end(); r++) {
Packit a4aae4
        (*r)->set_send_p(false);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    // Add specified maps to the current projection.
Packit a4aae4
    assert(indices);
Packit a4aae4
    int_list_citer p = indices->begin();
Packit a4aae4
    r = g->map_begin();
Packit a4aae4
    for (; p != indices->end() && r != g->map_end(); p++, r++) {
Packit a4aae4
        int_list *index = *p;
Packit a4aae4
        assert(index);
Packit a4aae4
Packit a4aae4
        int_citer q = index->begin();
Packit a4aae4
        assert(q != index->end());
Packit a4aae4
        int start = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stride = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stop = *q;
Packit a4aae4
Packit a4aae4
        BaseType *btp = *r;
Packit a4aae4
        assert(btp);
Packit a4aae4
        assert(btp->type() == dods_array_c);
Packit a4aae4
        Array *a = (Array *) btp;
Packit a4aae4
        a->set_send_p(true);
Packit a4aae4
        a->reset_constraint();
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        if (q != index->end()) {
Packit a4aae4
            throw Error(malformed_expr, string("Too many values in index list for ") + a->name() + ".");
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        DBG(cerr << "process_grid_indices: Setting constraint on "
Packit a4aae4
            << a->name() << "[" << start << ":"
Packit a4aae4
            << stop << "]" << endl);
Packit a4aae4
    
Packit a4aae4
        Array::Dim_iter si = a->dim_begin();
Packit a4aae4
        a->add_constraint(si, start, stride, stop);
Packit a4aae4
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    DBG(cout << "Grid Constraint: ";
Packit a4aae4
	for (Array::Dim_iter dp = ((Array *) g->array_var())->dim_begin();
Packit a4aae4
	     dp != ((Array *) g->array_var())->dim_end(); dp++)
Packit a4aae4
	    cout << ((Array *) g->array_var())->dimension_size(dp, true) << " ";
Packit a4aae4
	    cout << endl
Packit a4aae4
	);
Packit a4aae4
Packit a4aae4
    if (p != indices->end() && r == g->map_end()) {
Packit a4aae4
        throw Error(malformed_expr,
Packit a4aae4
		    string("Too many indices in constraint for ") + (*r)->name() + ".");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void process_sequence_indices(BaseType *variable, int_list_list *indices)
Packit a4aae4
{
Packit a4aae4
    assert(variable);
Packit a4aae4
    assert(variable->type() == dods_sequence_c);
Packit a4aae4
    Sequence *s = dynamic_cast<Sequence *> (variable);
Packit a4aae4
    if (!s)
Packit a4aae4
        throw Error(malformed_expr, "Expected a Sequence variable");
Packit a4aae4
Packit a4aae4
    // Add specified maps to the current projection.
Packit a4aae4
    assert(indices);
Packit a4aae4
    for (int_list_citer p = indices->begin(); p != indices->end(); p++) {
Packit a4aae4
        int_list *index = *p;
Packit a4aae4
        assert(index);
Packit a4aae4
Packit a4aae4
        int_citer q = index->begin();
Packit a4aae4
        assert(q != index->end());
Packit a4aae4
        int start = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stride = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        int stop = *q;
Packit a4aae4
Packit a4aae4
        q++;
Packit a4aae4
        if (q != index->end()) {
Packit a4aae4
            throw Error(malformed_expr, string("Too many values in index list for ") + s->name() + ".");
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        s->set_row_number_constraint(start, stop, stride);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Given a value, wrap it up in a BaseType and return a pointer to the same.
Packit a4aae4
Packit a4aae4
BaseType *
Packit a4aae4
make_variable(ConstraintEvaluator &eval, const value &val)
Packit a4aae4
{
Packit a4aae4
    BaseType *var;
Packit a4aae4
    switch (val.type) {
Packit a4aae4
    case dods_int32_c: {
Packit a4aae4
        var = new Int32("dummy");
Packit a4aae4
        var->val2buf((void *) &val.v.i);
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    case dods_uint32_c: {
Packit a4aae4
        var = new UInt32("dummy");
Packit a4aae4
        var->val2buf((void *) &val.v.i);
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    case dods_float64_c: {
Packit a4aae4
        var = new Float64("dummy");
Packit a4aae4
        var->val2buf((void *) &val.v.f);
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    case dods_str_c: {
Packit a4aae4
        var = new Str("dummy");
Packit a4aae4
        var->val2buf((void *) val.v.s);
Packit a4aae4
        break;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    default:
Packit a4aae4
        var = (BaseType *) 0;
Packit a4aae4
        return var;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    var->set_read_p(true); // ...so the evaluator will know it has data
Packit a4aae4
    eval.append_constant(var);
Packit a4aae4
Packit a4aae4
    return var;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Given a string (passed in VAL), consult the DDS CE function lookup table
Packit a4aae4
// to see if a function by that name exists. 
Packit a4aae4
// NB: function arguments are type-checked at run-time.
Packit a4aae4
//
Packit a4aae4
// Returns: A pointer to the function or NULL if not such function exists.
Packit a4aae4
Packit a4aae4
bool_func get_function(const ConstraintEvaluator &eval, const char *name)
Packit a4aae4
{
Packit a4aae4
    bool_func f;
Packit a4aae4
Packit a4aae4
    if (eval.find_function(name, &f))
Packit a4aae4
        return f;
Packit a4aae4
    else
Packit a4aae4
        return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
btp_func get_btp_function(const ConstraintEvaluator &eval, const char *name)
Packit a4aae4
{
Packit a4aae4
    btp_func f;
Packit a4aae4
Packit a4aae4
    if (eval.find_function(name, &f))
Packit a4aae4
        return f;
Packit a4aae4
    else
Packit a4aae4
        return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
proj_func get_proj_function(const ConstraintEvaluator &eval, const char *name)
Packit a4aae4
{
Packit a4aae4
    proj_func f;
Packit a4aae4
Packit a4aae4
    if (eval.find_function(name, &f))
Packit a4aae4
        return f;
Packit a4aae4
    else
Packit a4aae4
        return 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
template<class arg_type_list, class arg_type>
Packit a4aae4
arg_type_list
Packit a4aae4
make_fast_arg_list(unsigned long vector_size_hint, arg_type value)
Packit a4aae4
{
Packit a4aae4
    arg_type_list args = new std::vector<arg_type>;
Packit a4aae4
    
Packit a4aae4
    if (vector_size_hint > 0) args->reserve(vector_size_hint);
Packit a4aae4
    
Packit a4aae4
    args->push_back(value);
Packit a4aae4
    return args;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
template<class arg_type_list, class arg_type>
Packit a4aae4
arg_type_list
Packit a4aae4
make_fast_arg_list(arg_type_list values, arg_type value)
Packit a4aae4
{
Packit a4aae4
    values->push_back(value);
Packit a4aae4
    return values;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
template<class t, class T>
Packit a4aae4
rvalue *build_constant_array(vector<t> *values, DDS *dds)
Packit a4aae4
{
Packit a4aae4
    //vector<t> *values = $5;
Packit a4aae4
            
Packit a4aae4
    T i("");
Packit a4aae4
    Array *array = new Array("", &i);
Packit a4aae4
    array->append_dim(values->size());
Packit a4aae4
    
Packit a4aae4
    // TODO Make set_value_nocopy() methods so that values' pointers can be copied
Packit a4aae4
    // instead of allocating memory twice. jhrg 7/5/13
Packit a4aae4
            
Packit a4aae4
    array->set_value(*values, values->size());
Packit a4aae4
    delete values;
Packit a4aae4
    array->set_read_p(true);
Packit a4aae4
            
Packit a4aae4
    static unsigned long counter = 1;
Packit a4aae4
    string name;
Packit a4aae4
    do {
Packit a4aae4
        name = "g" + long_to_string(counter++);
Packit a4aae4
    } while (dds->var(name));
Packit a4aae4
    array->set_name(name);
Packit a4aae4
            
Packit a4aae4
    return new rvalue(array);
Packit a4aae4
}
Packit a4aae4