Blame d4_function/d4_function_parser.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) 2014 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
%skeleton "lalr1.cc" /* -*- C++ -*- */
Packit a4aae4
%require "2.5"
Packit a4aae4
%defines
Packit a4aae4
Packit a4aae4
// The d4_function_parser.tab.cc and .hh files define and declare this class
Packit a4aae4
%define parser_class_name {D4FunctionParser}
Packit a4aae4
Packit a4aae4
// D4FunctionParser is in this namespace
Packit a4aae4
%define api.namespace {libdap}
Packit a4aae4
Packit a4aae4
%define parse.trace
Packit a4aae4
%define parse.error verbose
Packit a4aae4
%define parse.assert
Packit a4aae4
Packit a4aae4
// Could not get this to work with a C++ scanner built by flex. 8/10/13 jhrg
Packit a4aae4
// %define api.token.constructor
Packit a4aae4
%define api.value.type variant
Packit a4aae4
Packit a4aae4
// Because the code uses the C++ mode of flex, we don't use this. 8/8/13 jhrg
Packit a4aae4
// %define api.prefix { d4_function_ }
Packit a4aae4
Packit a4aae4
%code requires {
Packit a4aae4
Packit a4aae4
#include "D4FunctionEvaluator.h"
Packit a4aae4
#include "D4RValue.h"
Packit a4aae4
#include "dods-datatypes.h"
Packit a4aae4
Packit a4aae4
namespace libdap {
Packit a4aae4
    class D4FunctionScanner;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Pass both the scanner and parser objects to both the automatically generated
Packit a4aae4
// parser and scanner.
Packit a4aae4
%lex-param   { D4FunctionScanner  &scanner  }
Packit a4aae4
%parse-param { D4FunctionScanner  &scanner  }
Packit a4aae4
Packit a4aae4
%lex-param   { D4FunctionEvaluator  &evaluator  }
Packit a4aae4
%parse-param { D4FunctionEvaluator  &evaluator  }
Packit a4aae4
Packit a4aae4
%locations
Packit a4aae4
%initial-action
Packit a4aae4
{
Packit a4aae4
    // Initialize the initial location. This is printed when the parser builds
Packit a4aae4
    // its own error messages - when the parse fails as opposed to when the 
Packit a4aae4
    // function(s) name(s) a missing variable, ...
Packit a4aae4
Packit a4aae4
    @$.initialize (evaluator.expression());
Packit a4aae4
};
Packit a4aae4
Packit a4aae4
%code {
Packit a4aae4
    #include "BaseType.h"
Packit a4aae4
    #include "DMR.h"
Packit a4aae4
    #include "D4RValue.h"
Packit a4aae4
    #include "ServerFunctionsList.h"
Packit a4aae4
   
Packit a4aae4
    #include "parser-util.h"
Packit a4aae4
Packit a4aae4
    /* include for all driver functions */
Packit a4aae4
    #include "D4FunctionEvaluator.h"
Packit a4aae4
Packit a4aae4
    using namespace libdap ;
Packit a4aae4
    
Packit a4aae4
    /* this is silly, but I can't figure out a way around it */
Packit a4aae4
    static int yylex(libdap::D4FunctionParser::semantic_type *yylval,
Packit a4aae4
                     libdap::location *loc,
Packit a4aae4
                     libdap::D4FunctionScanner  &scanner,
Packit a4aae4
                     libdap::D4FunctionEvaluator   &evaluator);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
%type <D4RValueList*> functions "functions"
Packit a4aae4
%type <D4RValueList*> args "arguments"
Packit a4aae4
Packit a4aae4
%type <D4RValue*> arg "argument"
Packit a4aae4
%type <D4RValue*> function "function"
Packit a4aae4
Packit a4aae4
%type <D4Function> fname "function name"
Packit a4aae4
%type <D4RValue*> variable_or_constant "variable or constant"
Packit a4aae4
%type <D4RValue*> array_constant "array constant"
Packit a4aae4
Packit a4aae4
%type <std::vector<dods_byte>*> fast_byte_arg_list "fast byte arg list"
Packit a4aae4
%type <std::vector<dods_int8>*> fast_int8_arg_list "fast int8 arg list"
Packit a4aae4
%type <std::vector<dods_uint16>*> fast_uint16_arg_list "fast uint16 arg list"
Packit a4aae4
%type <std::vector<dods_int16>*> fast_int16_arg_list "fast int16 arg list"
Packit a4aae4
%type <std::vector<dods_uint32>*> fast_uint32_arg_list "fast uint32 arg list"
Packit a4aae4
%type <std::vector<dods_int32>*> fast_int32_arg_list "fast int32 arg list"
Packit a4aae4
%type <std::vector<dods_uint64>*> fast_uint64_arg_list "fast uint64 arg list"
Packit a4aae4
%type <std::vector<dods_int64>*> fast_int64_arg_list "fast int64 arg list"
Packit a4aae4
%type <std::vector<dods_float32>*> fast_float32_arg_list "fast float32 arg list"
Packit a4aae4
%type <std::vector<dods_float64>*> fast_float64_arg_list "fast float64 arg list"
Packit a4aae4
Packit a4aae4
%type <std::string> id path group name
Packit a4aae4
Packit a4aae4
// The strings used in the token definitions are used for error messages
Packit a4aae4
%token <std::string> WORD "word"
Packit a4aae4
%token <std::string> STRING "string"
Packit a4aae4
Packit a4aae4
%token 
Packit a4aae4
    END  0  "end of file"
Packit a4aae4
    
Packit a4aae4
    SEMICOLON ";"
Packit a4aae4
    COLON ":"
Packit a4aae4
Packit a4aae4
    LPAREN "("
Packit a4aae4
    RPAREN ")"
Packit a4aae4
    
Packit a4aae4
    COMMA ","
Packit a4aae4
Packit a4aae4
    GROUP_SEP "/"
Packit a4aae4
    PATH_SEP "."
Packit a4aae4
    
Packit a4aae4
    DOLLAR_BYTE "$Byte"
Packit a4aae4
    DOLLAR_UINT8 "$UInt8"
Packit a4aae4
    DOLLAR_INT8 "$Int8"
Packit a4aae4
    DOLLAR_UINT16 "$UInt16"
Packit a4aae4
    DOLLAR_INT16 "$Int16"
Packit a4aae4
    DOLLAR_UINT32 "$UInt32"
Packit a4aae4
    DOLLAR_INT32 "$Int32"
Packit a4aae4
    DOLLAR_UINT64 "$UInt64"
Packit a4aae4
    DOLLAR_INT64 "$Int64"
Packit a4aae4
    DOLLAR_FLOAT32 "$Float32"
Packit a4aae4
    DOLLAR_FLOAT64 "$Float64"
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
%start program;
Packit a4aae4
Packit a4aae4
program : functions 
Packit a4aae4
{ 
Packit a4aae4
    evaluator.set_result($1); 
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
functions : function 
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValueList($1); 
Packit a4aae4
}
Packit a4aae4
| functions ";" function 
Packit a4aae4
{ 
Packit a4aae4
    $1->add_rvalue($3);
Packit a4aae4
    $$ = $1; 
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
                    
Packit a4aae4
function : fname "(" args ")" 
Packit a4aae4
{ 
Packit a4aae4
    $$ = new D4RValue($1, $3); // Build a D4RValue from a D4Function pointer and a D4RValueList 
Packit a4aae4
} 
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fname: WORD 
Packit a4aae4
{ 
Packit a4aae4
    D4Function f;
Packit a4aae4
    if (!evaluator.sf_list()->find_function($1, &f)) {
Packit a4aae4
        // ...cloud use @1.{first,last}_column in these error messages.
Packit a4aae4
        throw Error(malformed_expr, "'" + $1 + "' is not a registered DAP4 server function.");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    $$ = f;
Packit a4aae4
}        
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
args: arg
Packit a4aae4
{ 
Packit a4aae4
    $$ = new D4RValueList($1); // build a D4RValueList from the D4RValue
Packit a4aae4
} 
Packit a4aae4
| args "," arg 
Packit a4aae4
{ 
Packit a4aae4
    $1->add_rvalue($3);
Packit a4aae4
    $$ = $1; // Append the D4RValue ($3) to the D4RValueList ($1), then return
Packit a4aae4
} 
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
arg: function
Packit a4aae4
{
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
| variable_or_constant
Packit a4aae4
{
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
| array_constant 
Packit a4aae4
{
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
variable_or_constant : id
Packit a4aae4
{
Packit a4aae4
    D4RValue *rvalue = evaluator.build_rvalue($1);
Packit a4aae4
    if (!rvalue) {
Packit a4aae4
        throw Error(malformed_expr, "'" + $1 + "' is not a variable, number or string.");
Packit a4aae4
    }
Packit a4aae4
    
Packit a4aae4
    $$ = rvalue;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
  
Packit a4aae4
array_constant : 
Packit a4aae4
DOLLAR_BYTE "(" arg_length_hint ":" fast_byte_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_UINT8 "(" arg_length_hint ":" fast_byte_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_INT8 "(" arg_length_hint ":" fast_int8_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_UINT16 "(" arg_length_hint ":" fast_uint16_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_INT16 "(" arg_length_hint ":" fast_int16_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_UINT32 "(" arg_length_hint ":" fast_uint32_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_INT32 "(" arg_length_hint ":" fast_int32_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_UINT64 "(" arg_length_hint ":" fast_uint64_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_INT64 "(" arg_length_hint ":" fast_int64_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_FLOAT32 "(" arg_length_hint ":" fast_float32_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
|
Packit a4aae4
DOLLAR_FLOAT64 "(" arg_length_hint ":" fast_float64_arg_list ")"
Packit a4aae4
{
Packit a4aae4
    $$ = new D4RValue(*($5));
Packit a4aae4
    delete $5;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
/* Here the arg length hint is stored in the eval class so it can be used by the 
Packit a4aae4
   method that allocates the vector. The value is passed to vector::reserve().
Packit a4aae4
   This rule is run for it's side-effect only. This is also used to track the 
Packit a4aae4
   current arg number so that the hint can be used. */
Packit a4aae4
   
Packit a4aae4
arg_length_hint : WORD
Packit a4aae4
{
Packit a4aae4
    evaluator.set_arg_length_hint(get_uint64($1.c_str()));
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_byte_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_byte(strtol($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_byte_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtol($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_int8_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_int8(strtol($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_int8_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtol($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_uint16_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_uint16(strtol($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_uint16_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtol($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_int16_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_int16(strtol($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_int16_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtol($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_uint32_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_uint32(strtoul($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_uint32_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtoul($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
fast_int32_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_int32(strtol($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_int32_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtol($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_uint64_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_uint64(strtoull($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_uint64_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtoull($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_int64_arg_list: WORD
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_int64(strtoll($1.c_str(), 0, 0)));
Packit a4aae4
}
Packit a4aae4
| fast_int64_arg_list "," WORD
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtoll($3.c_str(), 0, 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
// I'm using path for the $Float constants so that tokens with dots will 
Packit a4aae4
// parse. I could add a FLOAT token, and I might have to do that later on
Packit a4aae4
// when filters are added to the CE, but this will work for now.
Packit a4aae4
fast_float32_arg_list: path
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_float32(strtof($1.c_str(), 0)));
Packit a4aae4
}
Packit a4aae4
| fast_float32_arg_list "," path
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtof($3.c_str(), 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
fast_float64_arg_list: path
Packit a4aae4
{
Packit a4aae4
    $$ = evaluator.init_arg_list(dods_float64(strtod($1.c_str(), 0)));
Packit a4aae4
}
Packit a4aae4
| fast_float64_arg_list "," path
Packit a4aae4
{
Packit a4aae4
    $1->push_back(strtod($3.c_str(), 0));
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
id : path
Packit a4aae4
{
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
| "/" path
Packit a4aae4
{
Packit a4aae4
    $$.append("/");
Packit a4aae4
    $$.append($2);
Packit a4aae4
}
Packit a4aae4
| group "/" path
Packit a4aae4
{
Packit a4aae4
    $1.append("/");
Packit a4aae4
    $1.append($3);
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
group : "/" name
Packit a4aae4
{
Packit a4aae4
    $$.append("/");
Packit a4aae4
    $$.append($2);
Packit a4aae4
}
Packit a4aae4
| group "/" name
Packit a4aae4
{
Packit a4aae4
    $1.append(".");
Packit a4aae4
    $1.append($3);
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
path : name 
Packit a4aae4
{
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
| path "." name
Packit a4aae4
{
Packit a4aae4
    $1.append(".");
Packit a4aae4
    $1.append($3);
Packit a4aae4
    $$ = $1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
// Because some formats/datasets allow 'any' name for a variable, it's possible
Packit a4aae4
// that a variable name will be a number, etc. The grammar also allows STRING
Packit a4aae4
// to support "name"."name with spaces and dots (.)".x
Packit a4aae4
name : WORD 
Packit a4aae4
{
Packit a4aae4
    $$=$1;
Packit a4aae4
}
Packit a4aae4
| STRING 
Packit a4aae4
{
Packit a4aae4
    $$=$1;
Packit a4aae4
}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
// Forward the error to the driver for handling. The location parameter
Packit a4aae4
// provides the line number and character position of the error.
Packit a4aae4
void
Packit a4aae4
libdap::D4FunctionParser::error(const location_type &l, const std::string &m)
Packit a4aae4
{
Packit a4aae4
    evaluator.error(l, m);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/* include for access to scanner.yylex */
Packit a4aae4
#include "D4FunctionScanner.h"
Packit a4aae4
Packit a4aae4
static int yylex(libdap::D4FunctionParser::semantic_type *yylval,
Packit a4aae4
                 libdap::location *loc,
Packit a4aae4
                 libdap::D4FunctionScanner &scanner,
Packit a4aae4
                 libdap::D4FunctionEvaluator &evaluator)
Packit a4aae4
{
Packit a4aae4
    if (evaluator.trace_scanning())
Packit a4aae4
        scanner.set_debug(true);
Packit a4aae4
    
Packit a4aae4
    return( scanner.yylex(yylval, loc) );
Packit a4aae4
}