libdap
Updated for version 3.17.0
|
00001 // -*- mode: c++; c-basic-offset:4 -*- 00002 00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00004 // Access Protocol. 00005 00006 // Copyright (c) 2014 OPeNDAP, Inc. 00007 // Author: James Gallagher <jgallagher@opendap.org> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 // 00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00024 00025 #include <cstdlib> 00026 #include <cerrno> 00027 00028 #include <string> 00029 #include <sstream> 00030 #include <iterator> 00031 00032 //#define DODS_DEBUG 00033 00034 #include "D4FunctionScanner.h" 00035 #include "D4FunctionEvaluator.h" 00036 #include "d4_function_parser.tab.hh" 00037 00038 #include "DMR.h" 00039 #include "D4Group.h" 00040 #include "D4RValue.h" 00041 00042 #include "BaseType.h" 00043 #include "Array.h" 00044 #include "D4Enum.h" 00045 00046 #include "escaping.h" 00047 #include "util.h" 00048 #include "debug.h" 00049 00050 namespace libdap { 00051 00064 bool D4FunctionEvaluator::parse(const std::string &expr) 00065 { 00066 d_expr = expr; // set for error messages. See the %initial-action section of .yy 00067 00068 std::istringstream iss(expr); 00069 D4FunctionScanner scanner(iss); 00070 D4FunctionParser parser(scanner, *this /* driver */); 00071 00072 if (trace_parsing()) { 00073 parser.set_debug_level(1); 00074 parser.set_debug_stream(std::cerr); 00075 } 00076 00077 return parser.parse() == 0; 00078 } 00079 00107 void D4FunctionEvaluator::eval(DMR *function_result) 00108 { 00109 #if 0 00110 ServerFunctionsList *sf_list = ServerFunctionsList::TheList(); 00111 ServerFunction *scale = new D4TestFunction; 00112 sf_list->add_function(scale); 00113 00114 D4FunctionEvaluator parser(dataset, sf_list); 00115 if (ce_parser_debug) parser.set_trace_parsing(true); 00116 bool parse_ok = parser.parse(function); 00117 if (!parse_ok) 00118 Error(malformed_expr, "Function Expression failed to parse."); 00119 else { 00120 if (ce_parser_debug) cerr << "Function Parse OK" << endl; 00121 D4RValueList *result = parser.result(); 00122 00123 function_result = new DMR(&d4_factory, "function_results"); 00124 #endif 00125 00126 if (!d_result) throw InternalErr(__FILE__, __LINE__, "Must parse() the function expression before calling eval()"); 00127 00128 D4Group *root = function_result->root(); // Load everything in the root group 00129 00130 for (D4RValueList::iter i = d_result->begin(), e = d_result->end(); i != e; ++i) { 00131 // Copy the BaseTypes; this means all of the function results can 00132 // be deleted, which addresses the memory leak issue with function 00133 // results. This should also copy the D4Dimensions. jhrg 3/17/14 00134 root->add_var((*i)->value(*d_dmr)); 00135 } 00136 00137 delete d_result; // The parser/function allocates the BaseType*s that hold the results. 00138 d_result = 0; 00139 00140 // Variables can use Dimensions and Enumerations, so those need to be copied 00141 // from the source dataset to the result. NB: The variables that refer to these 00142 // use weak pointers. 00143 00144 // Make a set of D4Dimensions. For each variable in 'function_result', look 00145 // for its dimensions in 'dataset' (by name) and add a pointer to those to the 00146 // set. Then copy all the stuff in the set into the root group of 'function_ 00147 // result.' 00148 set<D4Dimension*> dim_set; 00149 00150 for (Constructor::Vars_iter i = root->var_begin(), ie = root->var_end(); i != ie; ++i) { 00151 if ((*i)->is_vector_type()) { 00152 Array *a = static_cast<Array*>(*i); 00153 for (Array::Dim_iter d = a->dim_begin(), de = a->dim_end(); d != de; ++d) { 00154 if (a->dimension_D4dim(d)) { 00155 dim_set.insert(a->dimension_D4dim(d)); 00156 } 00157 } 00158 } 00159 } 00160 00161 // Copy the D4Dimensions and EnumDefs because this all goes in a new DMR - we don't 00162 // want to share those across DMRs because the DMRs delete those (so sharing htem 00163 // across DMRs would lead to dangling pointers. 00164 for (set<D4Dimension*>::iterator i = dim_set.begin(), e = dim_set.end(); i != e; ++i) { 00165 root->dims()->add_dim(*i); 00166 } 00167 00168 // Now lets do the enumerations.... 00169 set<D4EnumDef*> enum_def_set; 00170 for (Constructor::Vars_iter i = root->var_begin(), ie = root->var_end(); i != ie; ++i) { 00171 if ((*i)->type() == dods_enum_c) { 00172 enum_def_set.insert(static_cast<D4Enum*>(*i)->enumeration()); 00173 } 00174 } 00175 00176 for (set<D4EnumDef*>::iterator i = enum_def_set.begin(), e = enum_def_set.end(); i != e; ++i) { 00177 root->enum_defs()->add_enum(*i); 00178 } 00179 } 00180 00181 // libdap contains functions (in parser-util.cc) that test if a string 00182 // can be converted to an int32, e.g., but I used a more streamlined 00183 // approach here. 3/13/14 jhrg 00196 D4RValue * 00197 D4FunctionEvaluator::build_rvalue(const std::string &id) 00198 { 00199 BaseType *btp = 0; 00200 00201 // Look for the id in the dataset first 00202 if (top_basetype()) { 00203 btp = top_basetype()->var(id); 00204 } 00205 else { 00206 btp = dmr()->root()->find_var(id); 00207 } 00208 00209 if (btp) return new D4RValue(btp); 00210 00211 // If the id is not a variable, try to turn it into a constant, 00212 // otherwise, its an error. 00213 char *end_ptr = 0; 00214 00215 errno = 0; 00216 long long ll_val = strtoll(id.c_str(), &end_ptr, 0); 00217 if (*end_ptr == '\0' && errno == 0) return new D4RValue(ll_val); 00218 00219 // Test for unsigned after signed since strtoull() accepts a minus sign 00220 // (and will return a huge number if that's the case). jhrg 3/13/14 00221 errno = 0; 00222 unsigned long long ull_val = strtoull(id.c_str(), &end_ptr, 0); 00223 if (*end_ptr == '\0' && errno == 0) return new D4RValue(ull_val); 00224 00225 errno = 0; 00226 double d_val = strtod(id.c_str(), &end_ptr); 00227 if (*end_ptr == '\0' && errno == 0) return new D4RValue(d_val); 00228 00229 // To be a valid string, the id must be quoted (using double quotes) 00230 if (is_quoted(id)) return new D4RValue(www2id(id)); 00231 00232 // if it's none of these, return null 00233 return 0; 00234 } 00235 00236 template<typename T> 00237 std::vector<T> * 00238 D4FunctionEvaluator::init_arg_list(T val) 00239 { 00240 std::vector<T> *arg_list = new std::vector<T>(); 00241 if (get_arg_length_hint() > 0) arg_list->reserve(get_arg_length_hint()); 00242 00243 arg_list->push_back(val); 00244 00245 return arg_list; 00246 } 00247 00248 // Force an instantiation so this can be called from within the d4_function.yy 00249 // parser. 00250 template std::vector<dods_byte> *D4FunctionEvaluator::init_arg_list(dods_byte val); 00251 template std::vector<dods_int8> *D4FunctionEvaluator::init_arg_list(dods_int8 val); 00252 template std::vector<dods_uint16> *D4FunctionEvaluator::init_arg_list(dods_uint16 val); 00253 template std::vector<dods_int16> *D4FunctionEvaluator::init_arg_list(dods_int16 val); 00254 template std::vector<dods_uint32> *D4FunctionEvaluator::init_arg_list(dods_uint32 val); 00255 template std::vector<dods_int32> *D4FunctionEvaluator::init_arg_list(dods_int32 val); 00256 template std::vector<dods_uint64> *D4FunctionEvaluator::init_arg_list(dods_uint64 val); 00257 template std::vector<dods_int64> *D4FunctionEvaluator::init_arg_list(dods_int64 val); 00258 template std::vector<dods_float32> *D4FunctionEvaluator::init_arg_list(dods_float32 val); 00259 template std::vector<dods_float64> *D4FunctionEvaluator::init_arg_list(dods_float64 val); 00260 00261 // This method is called from the parser (see d4_function_parser.yy, down in the code 00262 // section). This will be called during the call to D4FunctionParser::parse(), that 00263 // is inside D4FunctionEvaluator::parse(...) 00264 void D4FunctionEvaluator::error(const libdap::location &l, const std::string &m) 00265 { 00266 ostringstream oss; 00267 oss << l << ": " << m << ends; 00268 throw Error(malformed_expr, oss.str()); 00269 } 00270 00271 } /* namespace libdap */