|
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 1994-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 |
Grammar for the DAS. This grammar can be used with the bison parser
|
|
Packit |
a4aae4 |
generator to build a parser for the DAS. It assumes that a scanner called
|
|
Packit |
a4aae4 |
`daslex()' exists and that the objects DAS and AttrTable also exist.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
jhrg 7/12/94
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%code requires {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define YYSTYPE char *
|
|
Packit |
a4aae4 |
#define ATTR_STRING_QUOTE_FIX
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <string>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <vector>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "DAS.h"
|
|
Packit |
a4aae4 |
#include "Error.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
#include "parser.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
// #include "das.tab.hh"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef TRACE_NEW
|
|
Packit |
a4aae4 |
#include "trace_new.h"
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define yylex daslex
|
|
Packit |
a4aae4 |
#define yyerror daserror
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
using namespace libdap ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// These macros are used to access the `arguments' passed to the parser. A
|
|
Packit |
a4aae4 |
// pointer to an error object and a pointer to an integer status variable are
|
|
Packit |
a4aae4 |
// passed in to the parser within a structure (which itself is passed as a
|
|
Packit |
a4aae4 |
// pointer). Note that the ERROR macro explicitly casts OBJ to an ERROR *.
|
|
Packit |
a4aae4 |
// The parser now throws an exception when it encounters an error. 5/23/2002
|
|
Packit |
a4aae4 |
// jhrg
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define DAS_OBJ(arg) ((DAS *)((parser_arg *)(arg))->_object)
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define YYPARSE_PARAM arg
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
extern int das_line_num; /* defined in das.lex */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // code requires
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%code {
|
|
Packit |
a4aae4 |
// No global static objects. We go through this every so often, I guess I
|
|
Packit |
a4aae4 |
// should learn... 1/24/2000 jhrg
|
|
Packit |
a4aae4 |
static string *name; /* holds name in attr_pair rule */
|
|
Packit |
a4aae4 |
static string *type; /* holds type in attr_pair rule */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static vector<AttrTable *> *attr_tab_stack;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// I use a vector of AttrTable pointers for a stack
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define TOP_OF_STACK (attr_tab_stack->back())
|
|
Packit |
a4aae4 |
#define PUSH(x) (attr_tab_stack->push_back((x)))
|
|
Packit |
a4aae4 |
#define POP (attr_tab_stack->pop_back())
|
|
Packit |
a4aae4 |
#define STACK_LENGTH (attr_tab_stack->size())
|
|
Packit |
a4aae4 |
#define OUTER_TABLE_ONLY (attr_tab_stack->size() == 1)
|
|
Packit |
a4aae4 |
#define STACK_EMPTY (attr_tab_stack->empty())
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define TYPE_NAME_VALUE(x) *type << " " << *name << " " << (x)
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static const char *ATTR_TUPLE_MSG =
|
|
Packit |
a4aae4 |
"Expected an attribute type (Byte, Int16, UInt16, Int32, UInt32, Float32,\n\
|
|
Packit |
a4aae4 |
Float64, String or Url) followed by a name and value.";
|
|
Packit |
a4aae4 |
static const char *NO_DAS_MSG =
|
|
Packit |
a4aae4 |
"The attribute object returned from the dataset was null\n\
|
|
Packit |
a4aae4 |
Check that the URL is correct.";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
typedef int checker(const char *);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int daslex(void);
|
|
Packit |
a4aae4 |
static void daserror(parser_arg *arg, const string &s /*char *s*/);
|
|
Packit |
a4aae4 |
static void add_attribute(const string &type, const string &name,
|
|
Packit |
a4aae4 |
const string &value, checker *chk) throw (Error);
|
|
Packit |
a4aae4 |
static void add_alias(AttrTable *das, AttrTable *current, const string &name,
|
|
Packit |
a4aae4 |
const string &src) throw (Error);
|
|
Packit |
a4aae4 |
static void add_bad_attribute(AttrTable *attr, const string &type,
|
|
Packit |
a4aae4 |
const string &name, const string &value,
|
|
Packit |
a4aae4 |
const string &msg;;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // code
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%require "2.4"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%parse-param {parser_arg *arg}
|
|
Packit |
a4aae4 |
%name-prefix "das"
|
|
Packit |
a4aae4 |
%defines
|
|
Packit |
a4aae4 |
%debug
|
|
Packit |
a4aae4 |
%verbose
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%expect 26
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%token SCAN_ATTR
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%token SCAN_WORD
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%token SCAN_ALIAS
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%token SCAN_BYTE
|
|
Packit |
a4aae4 |
%token SCAN_INT16
|
|
Packit |
a4aae4 |
%token SCAN_UINT16
|
|
Packit |
a4aae4 |
%token SCAN_INT32
|
|
Packit |
a4aae4 |
%token SCAN_UINT32
|
|
Packit |
a4aae4 |
%token SCAN_FLOAT32
|
|
Packit |
a4aae4 |
%token SCAN_FLOAT64
|
|
Packit |
a4aae4 |
%token SCAN_STRING
|
|
Packit |
a4aae4 |
%token SCAN_URL
|
|
Packit |
a4aae4 |
%token SCAN_XML
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%%
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/*
|
|
Packit |
a4aae4 |
Parser algorithm:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Look for a `variable' name (this can be any identifier, but by convention
|
|
Packit |
a4aae4 |
it is either the name of a variable in a dataset or the name of a grouping
|
|
Packit |
a4aae4 |
of global attributes). Create a new attribute table for this identifier and
|
|
Packit |
a4aae4 |
push the new attribute table onto a stack. If attribute tuples
|
|
Packit |
a4aae4 |
(type-name-value tuples) are found, intern them in the attribute table
|
|
Packit |
a4aae4 |
found on the top of the stack. If the start of a new attribute table if
|
|
Packit |
a4aae4 |
found (before the current table is closed), create the new table and push
|
|
Packit |
a4aae4 |
*it* on the stack. As attribute tables are closed, pop them off the stack.
|
|
Packit |
a4aae4 |
This algorithm ensures that we can nest attribute tables to an arbitrary
|
|
Packit |
a4aae4 |
depth.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Aliases are handled using mfuncs of both the DAS and AttrTable objects. This
|
|
Packit |
a4aae4 |
is necessary because the first level of a DAS object can contain only
|
|
Packit |
a4aae4 |
AttrTables, not attribute tuples. Whereas, the subsequent levels can
|
|
Packit |
a4aae4 |
contain both. Thus the compete definition is split into two objects. In
|
|
Packit |
a4aae4 |
part this is also a hold over from an older design which did not
|
|
Packit |
a4aae4 |
have the recursive properties of the current design.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Aliases can be made between attributes within a given lexical level, from
|
|
Packit |
a4aae4 |
one level to the next within a sub-hierarchy or across hierarchies.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Tokens:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BYTE, INT32, UINT32, FLOAT64, STRING and URL are tokens for the type
|
|
Packit |
a4aae4 |
keywords. The tokens INT, FLOAT, STR and ID are returned by the scanner to
|
|
Packit |
a4aae4 |
indicate the type of the value represented by the string contained in the
|
|
Packit |
a4aae4 |
global DASLVAL. These two types of tokens are used to implement type
|
|
Packit |
a4aae4 |
checking for the attributes. See the rules `bytes', etc. Additional tokens:
|
|
Packit |
a4aae4 |
ATTR (indicates the start of an attribute object) and ALIAS (indicates an
|
|
Packit |
a4aae4 |
alias). */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/* This rule makes sure the objects needed by this parser are built. Because
|
|
Packit |
a4aae4 |
the DODS DAP library is often used with linkers that are not C++-aware, we
|
|
Packit |
a4aae4 |
cannot use global objects (because their constructors might never be
|
|
Packit |
a4aae4 |
called). I had thought this was going to go away... 1/24/2000 jhrg */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attr_start:
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!name) name = new string();
|
|
Packit |
a4aae4 |
if (!type) type = new string();
|
|
Packit |
a4aae4 |
if (!attr_tab_stack) attr_tab_stack = new vector<AttrTable *>;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// push outermost AttrTable
|
|
Packit |
a4aae4 |
PUSH(DAS_OBJ(arg)->get_top_level_attributes());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
attributes
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
POP; // pop the DAS/AttrTable before stack's dtor
|
|
Packit |
a4aae4 |
delete name; name = 0;
|
|
Packit |
a4aae4 |
delete type; type = 0;
|
|
Packit |
a4aae4 |
delete attr_tab_stack; attr_tab_stack = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attributes: attribute
|
|
Packit |
a4aae4 |
| attributes attribute
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attribute: SCAN_ATTR '{' attr_list '}'
|
|
Packit |
a4aae4 |
| error
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
parse_error((parser_arg *)arg, NO_DAS_MSG, das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attr_list: /* empty */
|
|
Packit |
a4aae4 |
| attr_tuple
|
|
Packit |
a4aae4 |
| attr_list attr_tuple
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attr_tuple: alias
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_BYTE { save_str(*type, "Byte", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
bytes ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_INT16 { save_str(*type, "Int16", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
int16 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_UINT16 { save_str(*type, "UInt16", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
uint16 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_INT32 { save_str(*type, "Int32", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
int32 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_UINT32 { save_str(*type, "UInt32", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
uint32 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_FLOAT32 { save_str(*type, "Float32", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
float32 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_FLOAT64 { save_str(*type, "Float64", das_line_num); }
|
|
Packit |
a4aae4 |
name { save_str(*name, $3, das_line_num); }
|
|
Packit |
a4aae4 |
float64 ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_STRING { *type = "String"; }
|
|
Packit |
a4aae4 |
name { *name = $3; }
|
|
Packit |
a4aae4 |
strs ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_URL { *type = "Url"; }
|
|
Packit |
a4aae4 |
name { *name = $3; }
|
|
Packit |
a4aae4 |
urls ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_XML { *type = "OtherXML"; }
|
|
Packit |
a4aae4 |
name { *name = $3; }
|
|
Packit |
a4aae4 |
xml ';'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Processing ID: " << $1 << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
AttrTable *at = TOP_OF_STACK->get_attr_table($1);
|
|
Packit |
a4aae4 |
if (!at) {
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
at = TOP_OF_STACK->append_container($1);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
// re-throw with line number info
|
|
Packit |
a4aae4 |
parse_error(e.get_error_message().c_str(),
|
|
Packit |
a4aae4 |
das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
PUSH(at);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << " Pushed attr_tab: " << at << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
'{' attr_list
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
/* pop top of stack; store in attr_tab */
|
|
Packit |
a4aae4 |
DBG(cerr << " Popped attr_tab: " << TOP_OF_STACK << endl);
|
|
Packit |
a4aae4 |
POP;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
'}'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
| error
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
parse_error(ATTR_TUPLE_MSG, das_line_num, $1);
|
|
Packit |
a4aae4 |
} ';'
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bytes: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_byte);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| bytes ',' SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_byte);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int16: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_int16);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| int16 ',' SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_int16);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
uint16: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_uint16);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| uint16 ',' SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_uint16);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int32: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_int32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| int32 ',' SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_int32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
uint32: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_uint32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| uint32 ',' SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_uint32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
float32: float_or_int
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_float32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| float32 ',' float_or_int
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_float32);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
float64: float_or_int
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_float64);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| float64 ',' float_or_int
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_float64);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
strs: str_or_id
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string attr = remove_quotes($1);
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, attr, 0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| strs ',' str_or_id
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string attr = remove_quotes($3);
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, attr, 0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
urls: url
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $1, &check_url);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
| urls ',' url
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, $3, &check_url);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
xml: SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// XML must be quoted in the DAS but the quotes are an
|
|
Packit |
a4aae4 |
// artifact of the DAS syntax so they are not part of the
|
|
Packit |
a4aae4 |
// value.
|
|
Packit |
a4aae4 |
string xml = unescape_double_quotes($1);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (is_quoted(xml))
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, remove_quotes(xml), 0);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
add_attribute(*type, *name, xml, 0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
url: SCAN_WORD
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
str_or_id: SCAN_WORD
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
float_or_int: SCAN_WORD
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
name: SCAN_WORD | SCAN_ATTR | SCAN_ALIAS | SCAN_BYTE | SCAN_INT16
|
|
Packit |
a4aae4 |
| SCAN_UINT16 | SCAN_INT32 | SCAN_UINT32 | SCAN_FLOAT32
|
|
Packit |
a4aae4 |
| SCAN_FLOAT64 | SCAN_STRING | SCAN_URL | SCAN_XML
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
alias: SCAN_ALIAS SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
*name = $2;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
SCAN_WORD
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_alias( DAS_OBJ(arg)->get_top_level_attributes(),
|
|
Packit |
a4aae4 |
TOP_OF_STACK, *name, string($4) ) ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
';'
|
|
Packit |
a4aae4 |
;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
%%
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This function is required for linking, but DODS uses its own error
|
|
Packit |
a4aae4 |
// reporting mechanism.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
daserror(parser_arg *, const string &)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static string
|
|
Packit |
a4aae4 |
a_or_an(const string &subject)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string first_char(1, subject[0]);
|
|
Packit |
a4aae4 |
string::size_type pos = first_char.find_first_of("aeiouAEIOUyY");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (pos == string::npos)
|
|
Packit |
a4aae4 |
return "a";
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
return "an";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This code used to throw an exception when a bad attribute value came
|
|
Packit |
a4aae4 |
// along; now it dumps the errant value(s) into a sub container called *_DODS
|
|
Packit |
a4aae4 |
// and stores the parser's error message in a string attribute named
|
|
Packit |
a4aae4 |
// `explanation.'
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
add_attribute(const string &type, const string &name, const string &value,
|
|
Packit |
a4aae4 |
checker *chk) throw (Error)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Adding: " << type << " " << name << " " << value \
|
|
Packit |
a4aae4 |
<< " to Attrtable: " << TOP_OF_STACK << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (chk && !(*chk)(value.c_str())) {
|
|
Packit |
a4aae4 |
string msg = "`";
|
|
Packit |
a4aae4 |
msg += value + "' is not " + a_or_an(type) + " " + type + " value.";
|
|
Packit |
a4aae4 |
add_bad_attribute(TOP_OF_STACK, type, name, value, msg);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (STACK_EMPTY) {
|
|
Packit |
a4aae4 |
string msg = "Whoa! Attribute table stack empty when adding `" ;
|
|
Packit |
a4aae4 |
msg += name + ".' ";
|
|
Packit |
a4aae4 |
parse_error(msg, das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// Special treatment for XML: remove the double quotes that were
|
|
Packit |
a4aae4 |
// included in the value by this parser.
|
|
Packit |
a4aae4 |
if (type == OtherXML && is_quoted(value))
|
|
Packit |
a4aae4 |
TOP_OF_STACK->append_attr(name, type, value.substr(1, value.size()-2));
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
TOP_OF_STACK->append_attr(name, type, value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
// re-throw with line number
|
|
Packit |
a4aae4 |
parse_error(e.get_error_message().c_str(), das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
add_alias(AttrTable *das, AttrTable *current, const string &name,
|
|
Packit |
a4aae4 |
const string &src) throw (Error)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Adding an alias: " << name << ": " << src << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
AttrTable *table = das->get_attr_table(src);
|
|
Packit |
a4aae4 |
if (table) {
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
current->add_container_alias(name, table);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
parse_error(e.get_error_message().c_str(), das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
current->add_value_alias(das, name, src);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
parse_error(e.get_error_message().c_str(), das_line_num);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
add_bad_attribute(AttrTable *attr, const string &type, const string &name,
|
|
Packit |
a4aae4 |
const string &value, const string &msg)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// First, if this bad value is already in a *_dods_errors container,
|
|
Packit |
a4aae4 |
// then just add it. This can happen when the server side processes a DAS
|
|
Packit |
a4aae4 |
// and then hands it off to a client which does the same.
|
|
Packit |
a4aae4 |
// Make a new container. Call it <attr's name>_errors. If that container
|
|
Packit |
a4aae4 |
// already exists, use it.
|
|
Packit |
a4aae4 |
// Add the attribute.
|
|
Packit |
a4aae4 |
// Add the error string to an attribute in the container called
|
|
Packit |
a4aae4 |
// `
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (attr->get_name().find("_dods_errors") != string::npos) {
|
|
Packit |
a4aae4 |
attr->append_attr(name, type, value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
string error_cont_name = attr->get_name() + "_dods_errors";
|
|
Packit |
a4aae4 |
AttrTable *error_cont = attr->get_attr_table(error_cont_name);
|
|
Packit |
a4aae4 |
if (!error_cont)
|
|
Packit |
a4aae4 |
error_cont = attr->append_container(error_cont_name);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
error_cont->append_attr(name, type, value);
|
|
Packit |
a4aae4 |
#ifndef ATTR_STRING_QUOTE_FIX
|
|
Packit |
a4aae4 |
error_cont->append_attr(name + "_explanation", "String",
|
|
Packit |
a4aae4 |
"\"" + msg + "\"");
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
error_cont->append_attr(name + "_explanation", "String", msg);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|