ParsingExprList.C 12.3 KB
Newer Older
hrchilds's avatar
hrchilds committed
1 2
/*****************************************************************************
*
bonnell's avatar
bonnell committed
3
* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC
hrchilds's avatar
hrchilds committed
4
* Produced at the Lawrence Livermore National Laboratory
5
* LLNL-CODE-442911
hrchilds's avatar
hrchilds committed
6 7
* All rights reserved.
*
8
* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The
hrchilds's avatar
hrchilds committed
9 10 11 12 13 14 15 16 17 18
* full copyright notice is contained in the file COPYRIGHT located at the root
* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
*
* Redistribution  and  use  in  source  and  binary  forms,  with  or  without
* modification, are permitted provided that the following conditions are met:
*
*  - Redistributions of  source code must  retain the above  copyright notice,
*    this list of conditions and the disclaimer below.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
19 20 21
*    documentation and/or other materials provided with the distribution.
*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may
*    be used to endorse or promote products derived from this software without
hrchilds's avatar
hrchilds committed
22 23 24 25 26
*    specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
27 28 29
* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,
* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY
* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL
hrchilds's avatar
hrchilds committed
30 31 32 33 34 35 36 37 38
* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*****************************************************************************/

hrchilds's avatar
hrchilds committed
39 40 41 42 43 44
#include <stdio.h>
#include <ParsingExprList.h>
#include <ExpressionList.h>
#include <Expression.h>
#include <ExprNode.h>
#include <ExprNodeFactory.h>
hrchilds's avatar
hrchilds committed
45
#include <ExprParser.h>
hrchilds's avatar
hrchilds committed
46 47
#include <string>
#include <set>
hrchilds's avatar
hrchilds committed
48
#include <vector>
hrchilds's avatar
hrchilds committed
49 50 51 52
#include <ImproperUseException.h>
#include <RecursiveExpressionException.h>
using std::set;
using std::string;
hrchilds's avatar
hrchilds committed
53
using std::vector;
hrchilds's avatar
hrchilds committed
54 55 56 57 58 59 60 61 62 63 64 65 66

ParsingExprList * ParsingExprList::instance = 0;

// ****************************************************************************
// Method: ParsingExprList::ParsingExprList
//
// Purpose: 
//   Default constructor for the ParsingExprList class.
//
// Programmer: Sean Ahern
// Creation:   Wed Feb  5 13:53:33 PST 2003
//
// Modifications:
hrchilds's avatar
hrchilds committed
67 68
//    Jeremy Meredith, Wed Nov 24 12:27:15 PST 2004
//    Refactored and changed parser base classes around.
hrchilds's avatar
hrchilds committed
69 70 71 72 73 74 75 76
//
// ****************************************************************************
ParsingExprList::ParsingExprList() : SimpleObserver()
{
    // Make this object observe the expression list.
    exprList.Attach(this);

    // Make a default parser.
hrchilds's avatar
hrchilds committed
77
    parser = new ExprParser(new ExprNodeFactory());
hrchilds's avatar
hrchilds committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

    // Set the instance variable.
    instance = this;
}

// ****************************************************************************
// Method: ParsingExprList::ParsingExprList
//
// Purpose: 
//   Constructor for the ParsingExprList class that includes a parser
//   interface.
//
// Programmer: Sean Ahern
// Creation:   Wed Feb  5 13:53:26 PST 2003
//
// Modifications:
hrchilds's avatar
hrchilds committed
94 95
//    Jeremy Meredith, Wed Nov 24 12:27:15 PST 2004
//    Refactored and changed parser base classes around.
hrchilds's avatar
hrchilds committed
96 97
//
// ****************************************************************************
hrchilds's avatar
hrchilds committed
98
ParsingExprList::ParsingExprList(Parser *p) : SimpleObserver(),
hrchilds's avatar
hrchilds committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    parser(p)
{
    // Make this object observe the expression list.
    exprList.Attach(this);

    // Set the instance variable.
    instance = this;
}

// ****************************************************************************
// Method: ParsingExprList::~ParsingExprList
//
// Purpose: 
//   Destructor for the ParsingExprList class.
//
// Programmer: Sean Ahern
// Creation:   Tue Sep 25 15:23:46 PDT 2001
//
// Modifications:
//
// ****************************************************************************
ParsingExprList::~ParsingExprList()
{
    delete parser;
}

// ****************************************************************************
// Method: ParsingExprList::Instance
//
// Purpose: 
//   Return a pointer to the sole instance of the ParsingExprList class.
//
// Programmer: Sean Ahern
// Creation:   Fri Jun 28 11:16:01 PDT 2002
//
// Modifications:
//   
// ****************************************************************************
ParsingExprList*
ParsingExprList::Instance()
{
    // If the sole instance hasn't been instantiated, then instantiate it.
    if (instance == 0)
        instance = new ParsingExprList;

    return instance;
}

// ****************************************************************************
// Method: ParsingExprList::Update
//
// Purpose: 
//   This method is called when the expression list is updated from
//   somewhere else.
//
// Programmer: Sean Ahern
// Creation:   Tue Sep 25 15:23:48 PDT 2001
//
// Modifications:
//   
// ****************************************************************************
void
ParsingExprList::Update(Subject *)
{
}

// ****************************************************************************
// Method: ParsingExprList::GetExpression
//
// Purpose: 
//   Returns the Expression for the given variable name.
//
// Arguments:
//   varname : The name of the variable.
//
// Returns: A pointer to the Expression corresponding to the varname, if it
//          exists.  NULL if not.
//
// Note:       
//
// Programmer: Sean Ahern
// Creation:   Wed Dec 11 17:05:14 PST 2002
//
// Modifications:
//   
// ****************************************************************************
Expression*
ParsingExprList::GetExpression(const char *varname)
{
    return Instance()->GetList()->operator[](varname);
}

// ****************************************************************************
// Method: ParsingExprList::GetExpressionTree
//
// Purpose: 
//   Returns the expression tree for the specified expression or NULL if
//   the expression does not exist.
//
// Arguments:
//   varname : The name of the expression for which to get the tree.
//
// Returns:    The expression tree for the specified expression or NULL if
//   the expression does not exist.
//
// Note:       Moved from ViewerEngineManager.C
//
// Programmer: Sean Ahern
// Creation:   Wed Feb  5 13:52:35 PST 2003
//
// Modifications:
hrchilds's avatar
hrchilds committed
210 211
//    Jeremy Meredith, Wed Nov 24 12:27:15 PST 2004
//    Refactored and changed parse tree classes and return types around.
hrchilds's avatar
hrchilds committed
212 213 214 215 216 217 218 219 220 221 222
//   
// ****************************************************************************
ExprNode *
ParsingExprList::GetExpressionTree(const char *varname)
{
    ExprNode *tree = 0;

    // Get the expression tree for the expression.
    //Expression *exp = const_cast<ExpressionList&>(exprList)[varname];
    Expression *exp = GetExpression(varname);
    if (exp != NULL)
hrchilds's avatar
hrchilds committed
223 224 225 226
    {
        ParseTreeNode *t=Instance()->GetParser()->Parse(exp->GetDefinition());
        tree = (ExprNode*)t;
    }
hrchilds's avatar
hrchilds committed
227 228 229 230 231
    else
        tree = NULL;

    return tree;
}
hrchilds's avatar
hrchilds committed
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

// ****************************************************************************
// Method: ParsingExprList::GetExpressionTree
//
// Purpose: 
//   Returns the expression tree for the specified expression or NULL if
//   the expression does not exist.
//
// Arguments:
//   expr : The expression for which to get the tree.
//
// Returns:    The expression tree for the specified expression or NULL if
//   the expression does not exist.
//
// Programmer: Jeremy Meredith
// Creation:   August 14, 2003
//
// Modifications:
hrchilds's avatar
hrchilds committed
250 251
//    Jeremy Meredith, Wed Nov 24 12:27:15 PST 2004
//    Refactored and changed parse tree classes and return types around.
hrchilds's avatar
hrchilds committed
252 253 254 255 256 257 258 259
//   
// ****************************************************************************
ExprNode *
ParsingExprList::GetExpressionTree(Expression *expr)
{
    if (!expr)
        return NULL;

hrchilds's avatar
hrchilds committed
260 261
    ParseTreeNode *t = Instance()->GetParser()->Parse(expr->GetDefinition());
    return (ExprNode*)t;
hrchilds's avatar
hrchilds committed
262
}
hrchilds's avatar
hrchilds committed
263 264 265


// ****************************************************************************
hrchilds's avatar
hrchilds committed
266
//  Function:  ParsingExprList::GetRealVariableHelper
hrchilds's avatar
hrchilds committed
267 268 269 270 271 272 273 274 275 276 277 278 279
//
//  Purpose:
//    Determine the first true database variable for any given
//    expression.  Throw an ImproperUseException if there were
//    no real variables in an expression, throw a
//    RecursiveExpressionException if the expression is recursive,
//    and return the empty string if an unknown error occurred
//    during parsing.
//
//  Arguments:
//    var        the original variable name
//
//  Programmer:  Jeremy Meredith
hrchilds's avatar
hrchilds committed
280
//  Creation:    January  9, 2005
hrchilds's avatar
hrchilds committed
281
//
hrchilds's avatar
hrchilds committed
282 283 284 285 286 287
//  Modifications:
//    Brad Whitlock, Thu Feb 24 16:07:13 PST 2005
//    I made it iterate over varLeaves as a set instead of first creating
//    a vector of strings because the vector constructor was not taking
//    the set container's iterators successfully on MSVC 6.0.
//
hrchilds's avatar
hrchilds committed
288 289 290
//    Jeremy Meredith, Mon Jun 13 15:51:50 PDT 2005
//    Delete the parse tree when we're done with it.  This fixes leaks.
//
291 292 293
//    Cyrus Harrison, Tue Jul  3 10:50:39 PDT 2007
//    Modified to work with returned vector from GetVarleaves()
//    
hrchilds's avatar
hrchilds committed
294
// ****************************************************************************
hrchilds's avatar
hrchilds committed
295

hrchilds's avatar
hrchilds committed
296 297
static string
GetRealVariableHelper(const string &var, set<string> expandedVars)
hrchilds's avatar
hrchilds committed
298
{
hrchilds's avatar
hrchilds committed
299 300 301 302 303 304
    // Check for recursion in expanded vars
    if (expandedVars.count(var))
    {
        EXCEPTION1(RecursiveExpressionException, var);
    }
    expandedVars.insert(var);
hrchilds's avatar
hrchilds committed
305

hrchilds's avatar
hrchilds committed
306 307 308 309 310 311 312
    // If this variable is not an expression, then it is real
    Expression *expr = ParsingExprList::GetExpression(var);
    if (!expr)
    {
        // Found the real variable
        return var;
    }
hrchilds's avatar
hrchilds committed
313

hrchilds's avatar
hrchilds committed
314 315 316
    // Otherwise, descend into it; get the expression tree
    ExprNode *tree = ParsingExprList::GetExpressionTree(expr);
    if (!tree)
hrchilds's avatar
hrchilds committed
317
    {
hrchilds's avatar
hrchilds committed
318 319 320 321 322 323
        // We won't normally get here because error
        // conditions will usually throw exceptions.
        // Otherwise, every expression should have
        // a tree.
        return "";
    }
hrchilds's avatar
hrchilds committed
324

hrchilds's avatar
hrchilds committed
325
    // Get the leaves for this expression
326
    const vector<string> &varLeaves = tree->GetVarLeaves();
hrchilds's avatar
hrchilds committed
327
    if (varLeaves.empty())
hrchilds's avatar
hrchilds committed
328 329
    {
        delete tree;
hrchilds's avatar
hrchilds committed
330
        return "";
hrchilds's avatar
hrchilds committed
331
    }
hrchilds's avatar
hrchilds committed
332

hrchilds's avatar
hrchilds committed
333
    // For each leaf, look for a real variable
334
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
hrchilds's avatar
hrchilds committed
335
    // Don't use const iterator on win32 MSVC 6.
336
    for (std::vector<std::string>::iterator it = varLeaves.begin();
hrchilds's avatar
hrchilds committed
337 338
         it != varLeaves.end(); ++it)
#else
339
    for (std::vector<std::string>::const_iterator it = varLeaves.begin();
hrchilds's avatar
hrchilds committed
340 341
         it != varLeaves.end(); ++it)
#endif
hrchilds's avatar
hrchilds committed
342
    {
hrchilds's avatar
hrchilds committed
343
        string realvar = GetRealVariableHelper(*it, expandedVars);
hrchilds's avatar
hrchilds committed
344

hrchilds's avatar
hrchilds committed
345 346
        // If we found a real variable, return it!
        if (!realvar.empty())
hrchilds's avatar
hrchilds committed
347 348
        {
            delete tree;
hrchilds's avatar
hrchilds committed
349
            return realvar;
hrchilds's avatar
hrchilds committed
350
        }
hrchilds's avatar
hrchilds committed
351 352
    }

hrchilds's avatar
hrchilds committed
353
    // Didn't find any real variables
hrchilds's avatar
hrchilds committed
354
    delete tree;
hrchilds's avatar
hrchilds committed
355
    return "";
hrchilds's avatar
hrchilds committed
356 357
}

hrchilds's avatar
hrchilds committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
// ****************************************************************************
//  Method:  ParsingExprList::GetRealVariable
//
//  Purpose:
//    Determine the first true database variable for any given
//    expression.  Throw an ImproperUseException if there were
//    no real variables in an expression, throw a
//    RecursiveExpressionException if the expression is recursive,
//    and return the empty string if an unknown error occurred
//    during parsing.
//
//    Most of the work is done inside the recursion helper function.
//    This merely makes sure we actually have a real variable before
//    returning to the original caller, as well as setting up an
//    empty expanded variables set for the helper function.
//
//  Arguments:
//    var        the original variable name
//
//  Programmer:  Jeremy Meredith
//  Creation:    January  9, 2005
//
// ****************************************************************************
string
ParsingExprList::GetRealVariable(const string &var)
{
    set<string> emptySet;
    string realvar = GetRealVariableHelper(var, emptySet);

    if (realvar.empty())
    {
        EXCEPTION1(ImproperUseException,
                   "After parsing, expression has no real variables.");
    }

    return realvar;
}