| 1 |
26 |
unneback |
//{{{ Banner
|
| 2 |
|
|
|
| 3 |
|
|
//============================================================================
|
| 4 |
|
|
//
|
| 5 |
|
|
// expr.cxx
|
| 6 |
|
|
//
|
| 7 |
|
|
// Implementation of the various CDL expression classes.
|
| 8 |
|
|
//
|
| 9 |
|
|
//============================================================================
|
| 10 |
|
|
//####COPYRIGHTBEGIN####
|
| 11 |
|
|
//
|
| 12 |
|
|
// ----------------------------------------------------------------------------
|
| 13 |
|
|
// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
|
| 14 |
|
|
//
|
| 15 |
|
|
// This file is part of the eCos host tools.
|
| 16 |
|
|
//
|
| 17 |
|
|
// This program is free software; you can redistribute it and/or modify it
|
| 18 |
|
|
// under the terms of the GNU General Public License as published by the Free
|
| 19 |
|
|
// Software Foundation; either version 2 of the License, or (at your option)
|
| 20 |
|
|
// any later version.
|
| 21 |
|
|
//
|
| 22 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
| 23 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| 24 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
| 25 |
|
|
// more details.
|
| 26 |
|
|
//
|
| 27 |
|
|
// You should have received a copy of the GNU General Public License along with
|
| 28 |
|
|
// this program; if not, write to the Free Software Foundation, Inc.,
|
| 29 |
|
|
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
| 30 |
|
|
//
|
| 31 |
|
|
// ----------------------------------------------------------------------------
|
| 32 |
|
|
//
|
| 33 |
|
|
//####COPYRIGHTEND####
|
| 34 |
|
|
//============================================================================
|
| 35 |
|
|
//#####DESCRIPTIONBEGIN####
|
| 36 |
|
|
//
|
| 37 |
|
|
// Author(s): bartv
|
| 38 |
|
|
// Contact(s): bartv
|
| 39 |
|
|
// Date: 1999/02/02
|
| 40 |
|
|
// Version: 0.02
|
| 41 |
|
|
//
|
| 42 |
|
|
//####DESCRIPTIONEND####
|
| 43 |
|
|
//============================================================================
|
| 44 |
|
|
|
| 45 |
|
|
//}}}
|
| 46 |
|
|
//{{{ #include's
|
| 47 |
|
|
|
| 48 |
|
|
// ----------------------------------------------------------------------------
|
| 49 |
|
|
#include "cdlconfig.h"
|
| 50 |
|
|
|
| 51 |
|
|
// Get the infrastructure types, assertions, tracing and similar
|
| 52 |
|
|
// facilities.
|
| 53 |
|
|
#include <cyg/infra/cyg_ass.h>
|
| 54 |
|
|
#include <cyg/infra/cyg_trac.h>
|
| 55 |
|
|
|
| 56 |
|
|
// <cdlcore.hxx> defines everything implemented in this module.
|
| 57 |
|
|
// It implicitly supplies <string>, <vector> and <map> because
|
| 58 |
|
|
// the class definitions rely on these headers.
|
| 59 |
|
|
#include <cdlcore.hxx>
|
| 60 |
|
|
|
| 61 |
|
|
//}}}
|
| 62 |
|
|
|
| 63 |
|
|
//{{{ Statics
|
| 64 |
|
|
|
| 65 |
|
|
// ----------------------------------------------------------------------------
|
| 66 |
|
|
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlEvalContext);
|
| 67 |
|
|
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlExpressionBody);
|
| 68 |
|
|
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListExpressionBody);
|
| 69 |
|
|
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlGoalExpressionBody);
|
| 70 |
|
|
|
| 71 |
|
|
//}}}
|
| 72 |
|
|
//{{{ CdlEvalContext
|
| 73 |
|
|
|
| 74 |
|
|
// ----------------------------------------------------------------------------
|
| 75 |
|
|
// A utility class to keep track of the context in which expression
|
| 76 |
|
|
// evaluation is happening.
|
| 77 |
|
|
|
| 78 |
|
|
CdlEvalContext::CdlEvalContext(CdlTransaction transaction_arg, CdlNode node_arg, CdlProperty property_arg,
|
| 79 |
|
|
CdlToplevel toplevel_arg)
|
| 80 |
|
|
{
|
| 81 |
|
|
CYG_REPORT_FUNCNAME("CdlEvalContext::constructor");
|
| 82 |
|
|
CYG_REPORT_FUNCARG4XV(this, transaction_arg, node_arg, property_arg);
|
| 83 |
|
|
|
| 84 |
|
|
transaction = transaction_arg;
|
| 85 |
|
|
|
| 86 |
|
|
if ((0 == property_arg) && (0 != transaction)) {
|
| 87 |
|
|
CdlConflict conflict = transaction->get_conflict();
|
| 88 |
|
|
if (0 != conflict) {
|
| 89 |
|
|
property_arg = conflict->get_property();
|
| 90 |
|
|
}
|
| 91 |
|
|
}
|
| 92 |
|
|
property = property_arg;
|
| 93 |
|
|
|
| 94 |
|
|
if ((0 == node_arg) && (0 != transaction)) {
|
| 95 |
|
|
CdlConflict conflict = transaction->get_conflict();
|
| 96 |
|
|
if (0 != conflict) {
|
| 97 |
|
|
node_arg = conflict->get_node();
|
| 98 |
|
|
}
|
| 99 |
|
|
}
|
| 100 |
|
|
node = node_arg;
|
| 101 |
|
|
|
| 102 |
|
|
if (0 == toplevel_arg) {
|
| 103 |
|
|
if (0 != transaction) {
|
| 104 |
|
|
toplevel_arg = transaction->get_toplevel();
|
| 105 |
|
|
} else if (0 != node) {
|
| 106 |
|
|
toplevel_arg = node->get_toplevel();
|
| 107 |
|
|
}
|
| 108 |
|
|
}
|
| 109 |
|
|
toplevel = toplevel_arg;
|
| 110 |
|
|
|
| 111 |
|
|
cdlevalcontext_cookie = CdlEvalContext_Magic;
|
| 112 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 113 |
|
|
|
| 114 |
|
|
CYG_POSTCONDITION_THISC();
|
| 115 |
|
|
CYG_REPORT_RETURN();
|
| 116 |
|
|
}
|
| 117 |
|
|
|
| 118 |
|
|
CdlEvalContext::~CdlEvalContext()
|
| 119 |
|
|
{
|
| 120 |
|
|
CYG_REPORT_FUNCNAME("CdlEvalContext::destructor");
|
| 121 |
|
|
CYG_PRECONDITION_THISC();
|
| 122 |
|
|
|
| 123 |
|
|
cdlevalcontext_cookie = CdlEvalContext_Invalid;
|
| 124 |
|
|
transaction = 0;
|
| 125 |
|
|
node = 0;
|
| 126 |
|
|
property = 0;
|
| 127 |
|
|
toplevel = 0;
|
| 128 |
|
|
CYGDBG_MEMLEAK_DESTRUCTOR();
|
| 129 |
|
|
|
| 130 |
|
|
CYG_REPORT_RETURN();
|
| 131 |
|
|
}
|
| 132 |
|
|
|
| 133 |
|
|
// Given a context and a reference inside an expression, obtain the node
|
| 134 |
|
|
// being referenced - if it is loaded.
|
| 135 |
|
|
CdlNode
|
| 136 |
|
|
CdlEvalContext::resolve_reference(CdlExpression expr, int index)
|
| 137 |
|
|
{
|
| 138 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlEvalContext::resolve_reference", "result %");
|
| 139 |
|
|
CYG_REPORT_FUNCARG2XV(expr, index);
|
| 140 |
|
|
CYG_PRECONDITION_THISC();
|
| 141 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 142 |
|
|
CYG_PRECONDITIONC((0 <= index) && (index <= (int)expr->references.size()));
|
| 143 |
|
|
|
| 144 |
|
|
// This expression may be happening in the context of a particular
|
| 145 |
|
|
// property. If so then the destination may or may not be
|
| 146 |
|
|
// resolved, which will have been handled when the containing package
|
| 147 |
|
|
// was loaded. Alternatively this expression may be evaluated inside
|
| 148 |
|
|
// some arbitrary Tcl code, in which case references remain unbound
|
| 149 |
|
|
// and need to be resolved the hard way.
|
| 150 |
|
|
CdlNode result = 0;
|
| 151 |
|
|
if (0 != this->property) {
|
| 152 |
|
|
// There is a property, use the bound/unbound reference.
|
| 153 |
|
|
result = expr->references[index].get_destination();
|
| 154 |
|
|
} else {
|
| 155 |
|
|
// The destination name can be retrieved, but we still need some
|
| 156 |
|
|
// way of resolving it.
|
| 157 |
|
|
if (0 != this->toplevel) {
|
| 158 |
|
|
std::string destination_name = expr->references[index].get_destination_name();
|
| 159 |
|
|
result = this->toplevel->lookup(destination_name);
|
| 160 |
|
|
}
|
| 161 |
|
|
}
|
| 162 |
|
|
|
| 163 |
|
|
CYG_REPORT_RETVAL(result);
|
| 164 |
|
|
return result;
|
| 165 |
|
|
}
|
| 166 |
|
|
|
| 167 |
|
|
// Ditto, but also check that the result is a valuable.
|
| 168 |
|
|
CdlValuable
|
| 169 |
|
|
CdlEvalContext::resolve_valuable_reference(CdlExpression expr, int index)
|
| 170 |
|
|
{
|
| 171 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlEvalContext::resolve_reference", "result %");
|
| 172 |
|
|
CYG_REPORT_FUNCARG2XV(expr, index);
|
| 173 |
|
|
|
| 174 |
|
|
CdlValuable result = 0;
|
| 175 |
|
|
CdlNode node = this->resolve_reference(expr, index);
|
| 176 |
|
|
if (0 != node) {
|
| 177 |
|
|
result = dynamic_cast<CdlValuable>(node);
|
| 178 |
|
|
}
|
| 179 |
|
|
CYG_REPORT_RETVAL(result);
|
| 180 |
|
|
return result;
|
| 181 |
|
|
}
|
| 182 |
|
|
|
| 183 |
|
|
bool
|
| 184 |
|
|
CdlEvalContext::check_this(cyg_assert_class_zeal zeal) const
|
| 185 |
|
|
{
|
| 186 |
|
|
if (CdlEvalContext_Magic != cdlevalcontext_cookie) {
|
| 187 |
|
|
return false;
|
| 188 |
|
|
}
|
| 189 |
|
|
CYGDBG_MEMLEAK_CHECKTHIS();
|
| 190 |
|
|
|
| 191 |
|
|
if ((0 != transaction) && !transaction->check_this(zeal)) {
|
| 192 |
|
|
return false;
|
| 193 |
|
|
}
|
| 194 |
|
|
if ((0 != toplevel) && !toplevel->check_this(zeal)) {
|
| 195 |
|
|
return false;
|
| 196 |
|
|
}
|
| 197 |
|
|
if ((0 != node) && !node->check_this(zeal)) {
|
| 198 |
|
|
return false;
|
| 199 |
|
|
}
|
| 200 |
|
|
if ((0 != property) && !property->check_this(zeal)) {
|
| 201 |
|
|
return false;
|
| 202 |
|
|
}
|
| 203 |
|
|
return true;
|
| 204 |
|
|
}
|
| 205 |
|
|
|
| 206 |
|
|
//}}}
|
| 207 |
|
|
//{{{ Expression parsing
|
| 208 |
|
|
|
| 209 |
|
|
//{{{ Description
|
| 210 |
|
|
|
| 211 |
|
|
// ----------------------------------------------------------------------------
|
| 212 |
|
|
// There are a number of different entry points related to expression parsing,
|
| 213 |
|
|
// largely to support list and goal expressions. All of these eventually
|
| 214 |
|
|
// end up calling the function
|
| 215 |
|
|
// continue_parse(expr, data, index, token, token_end)
|
| 216 |
|
|
//
|
| 217 |
|
|
// The expr argument holds an existing expression object that needs to be
|
| 218 |
|
|
// updated. If token is Invalid then we are at the start of an expression
|
| 219 |
|
|
// (but not necessarily at the start of the string).
|
| 220 |
|
|
//
|
| 221 |
|
|
// The data string holds all of the expression that should be parsed.
|
| 222 |
|
|
// It is formed by concatenating all non-option arguments to the
|
| 223 |
|
|
// appropriate property command, with spaces between them.
|
| 224 |
|
|
//
|
| 225 |
|
|
// index is an input/output variable. On input it indicates where in
|
| 226 |
|
|
// the string parsing should continue. On output it indicates the
|
| 227 |
|
|
// location within the string where the terminating token began.
|
| 228 |
|
|
//
|
| 229 |
|
|
// token is an input/output variable. On input it can have the values
|
| 230 |
|
|
// Invalid or And. The former means that we are parsing a completely
|
| 231 |
|
|
// new expression. The latter is used for goal expressions: it is
|
| 232 |
|
|
// necessary to parse a new expression and then combine it with the
|
| 233 |
|
|
// existing one.
|
| 234 |
|
|
//
|
| 235 |
|
|
// token_end is an output variable. It indicates the location within
|
| 236 |
|
|
// the string where the terminating token ended. This is useful for
|
| 237 |
|
|
// e.g. ranges in a list expression.
|
| 238 |
|
|
//
|
| 239 |
|
|
// A conventional recursive descent parser is used.
|
| 240 |
|
|
|
| 241 |
|
|
//}}}
|
| 242 |
|
|
//{{{ Tokenization
|
| 243 |
|
|
|
| 244 |
|
|
// ----------------------------------------------------------------------------
|
| 245 |
|
|
// Tokenization.
|
| 246 |
|
|
|
| 247 |
|
|
//{{{ token enum
|
| 248 |
|
|
|
| 249 |
|
|
// A separate token enum is necessary, rather than re-using the CdlExprOp
|
| 250 |
|
|
// enum. Some tokens may correspond to several operators, and some tokens
|
| 251 |
|
|
// such as close-bracket do not correspond directly to an operator at all.
|
| 252 |
|
|
enum token {
|
| 253 |
|
|
T_Invalid = -2,
|
| 254 |
|
|
|
| 255 |
|
|
T_EOD = -1,
|
| 256 |
|
|
T_Reference = 1, // CYGPKG_HAL
|
| 257 |
|
|
T_String = 2, // "hello"
|
| 258 |
|
|
T_Integer = 3, // 123
|
| 259 |
|
|
T_Double = 4, // 3.1415
|
| 260 |
|
|
T_Range = 5, // to
|
| 261 |
|
|
T_OpenBracket = 6, // (
|
| 262 |
|
|
T_CloseBracket = 7, // )
|
| 263 |
|
|
T_Minus = 8, // -
|
| 264 |
|
|
T_Plus = 9, // +
|
| 265 |
|
|
T_Times = 10, // *
|
| 266 |
|
|
T_Divide = 11, // /
|
| 267 |
|
|
T_Exclamation = 12, // !
|
| 268 |
|
|
T_Tilde = 13, // ~
|
| 269 |
|
|
T_Questionmark = 14, // ?
|
| 270 |
|
|
T_Remainder = 15, // %
|
| 271 |
|
|
T_LeftShift = 16, // <<
|
| 272 |
|
|
T_RightShift = 17, // >>
|
| 273 |
|
|
T_LessThan = 18, // <
|
| 274 |
|
|
T_LessEqual = 19, // <=
|
| 275 |
|
|
T_GreaterThan = 20, // >
|
| 276 |
|
|
T_GreaterEqual = 21, // >=
|
| 277 |
|
|
T_Equal = 22, // ==
|
| 278 |
|
|
T_NotEqual = 23, // !=
|
| 279 |
|
|
T_BitAnd = 24, // &
|
| 280 |
|
|
T_BitXor = 25, // ^
|
| 281 |
|
|
T_BitOr = 26, // |
|
| 282 |
|
|
T_And = 27, // &&
|
| 283 |
|
|
T_Or = 28, // ||
|
| 284 |
|
|
T_Colon = 29, // : (in a conditional)
|
| 285 |
|
|
T_StringConcat = 30, // .
|
| 286 |
|
|
T_Function = 31, // is_substr etc.
|
| 287 |
|
|
T_Comma = 32, // , (inside a function)
|
| 288 |
|
|
T_Implies = 33, // implies
|
| 289 |
|
|
T_Xor = 34, // xor
|
| 290 |
|
|
T_Eqv = 35 // eqv
|
| 291 |
|
|
|
| 292 |
|
|
};
|
| 293 |
|
|
|
| 294 |
|
|
//}}}
|
| 295 |
|
|
//{{{ Statics
|
| 296 |
|
|
|
| 297 |
|
|
// Statics to keep track of the current state.
|
| 298 |
|
|
static std::string current_data = "";
|
| 299 |
|
|
static unsigned int current_index = 0;
|
| 300 |
|
|
static unsigned int token_start = 0;
|
| 301 |
|
|
static int current_char = EOF;
|
| 302 |
|
|
static token current_token = T_Invalid;
|
| 303 |
|
|
static std::string current_string = "";
|
| 304 |
|
|
static std::string current_reference = "";
|
| 305 |
|
|
static std::string current_special = "";
|
| 306 |
|
|
static cdl_int current_int = 0;
|
| 307 |
|
|
static double current_double = 0.0;
|
| 308 |
|
|
static CdlValueFormat current_format = CdlValueFormat_Default;
|
| 309 |
|
|
static int current_function_id = 0;
|
| 310 |
|
|
|
| 311 |
|
|
//}}}
|
| 312 |
|
|
//{{{ Character access
|
| 313 |
|
|
|
| 314 |
|
|
// ----------------------------------------------------------------------------
|
| 315 |
|
|
// Individual character access.
|
| 316 |
|
|
// Note that current_index is one character past current_char.
|
| 317 |
|
|
|
| 318 |
|
|
// Return the next character in the string, or EOF
|
| 319 |
|
|
static void
|
| 320 |
|
|
next_char()
|
| 321 |
|
|
{
|
| 322 |
|
|
if (current_index >= current_data.size()) {
|
| 323 |
|
|
current_char = EOF;
|
| 324 |
|
|
} else {
|
| 325 |
|
|
current_char = current_data[current_index++];
|
| 326 |
|
|
}
|
| 327 |
|
|
}
|
| 328 |
|
|
|
| 329 |
|
|
// Go back a character. This is useful when parsing
|
| 330 |
|
|
// strings. It is the responsibility of the calling code
|
| 331 |
|
|
// to make sure that we are not at the start of the buffer.
|
| 332 |
|
|
static void
|
| 333 |
|
|
backup_char()
|
| 334 |
|
|
{
|
| 335 |
|
|
CYG_ASSERTC(((EOF == current_char) && (0 < current_index)) || (1 < current_index));
|
| 336 |
|
|
if (EOF != current_char) {
|
| 337 |
|
|
current_index--;
|
| 338 |
|
|
}
|
| 339 |
|
|
current_char = current_data[current_index - 1];
|
| 340 |
|
|
}
|
| 341 |
|
|
|
| 342 |
|
|
//}}}
|
| 343 |
|
|
//{{{ get_error_location()
|
| 344 |
|
|
|
| 345 |
|
|
// ----------------------------------------------------------------------------
|
| 346 |
|
|
// Construct part of a diagnostic message, indicating the
|
| 347 |
|
|
// area in the data where the error occurred. This string
|
| 348 |
|
|
// is of the form {...data} ^char^ {data...}. Ideally
|
| 349 |
|
|
// the ^ markers would be on a subsequent line, eliminating
|
| 350 |
|
|
// the need for braces, but there is insufficient control
|
| 351 |
|
|
// of how the message gets presented to the user.
|
| 352 |
|
|
//
|
| 353 |
|
|
// Care has to be taken with EOD.
|
| 354 |
|
|
static std::string
|
| 355 |
|
|
get_error_location()
|
| 356 |
|
|
{
|
| 357 |
|
|
CYG_REPORT_FUNCNAME("get_error_location");
|
| 358 |
|
|
std::string result = "";
|
| 359 |
|
|
|
| 360 |
|
|
// token_start is probably the best place for centering the error.
|
| 361 |
|
|
// current_index is past the point where the error has occurred.
|
| 362 |
|
|
if (token_start > 1) {
|
| 363 |
|
|
if (token_start > 16) {
|
| 364 |
|
|
result = "{..." + current_data.substr(token_start - 13, 13) + "} ";
|
| 365 |
|
|
} else {
|
| 366 |
|
|
result = "{" + current_data.substr(0, token_start) + "}";
|
| 367 |
|
|
}
|
| 368 |
|
|
}
|
| 369 |
|
|
|
| 370 |
|
|
if (current_char == EOF) {
|
| 371 |
|
|
result += " <end of data>";
|
| 372 |
|
|
} else {
|
| 373 |
|
|
result += " ^" + std::string(1, current_data[token_start]) + "^ ";
|
| 374 |
|
|
}
|
| 375 |
|
|
|
| 376 |
|
|
if (token_start < current_data.size()) {
|
| 377 |
|
|
if ((token_start + 16) < current_data.size()) {
|
| 378 |
|
|
result += "{" + current_data.substr(token_start + 1, current_data.size() - (token_start+1)) + "}";
|
| 379 |
|
|
} else {
|
| 380 |
|
|
result += "{" + current_data.substr(token_start, 13) + "...}";
|
| 381 |
|
|
}
|
| 382 |
|
|
}
|
| 383 |
|
|
|
| 384 |
|
|
CYG_REPORT_RETURN();
|
| 385 |
|
|
return result;
|
| 386 |
|
|
}
|
| 387 |
|
|
|
| 388 |
|
|
// Export this functionality available to other modules, especially func.cxx and its
|
| 389 |
|
|
// argument checking routines.
|
| 390 |
|
|
std::string
|
| 391 |
|
|
CdlParse::get_expression_error_location(void)
|
| 392 |
|
|
{
|
| 393 |
|
|
return get_error_location();
|
| 394 |
|
|
}
|
| 395 |
|
|
|
| 396 |
|
|
//}}}
|
| 397 |
|
|
//{{{ Token translation
|
| 398 |
|
|
|
| 399 |
|
|
// ----------------------------------------------------------------------------
|
| 400 |
|
|
|
| 401 |
|
|
// Convert a token into a binary expression operator
|
| 402 |
|
|
static CdlExprOp
|
| 403 |
|
|
token_to_binary_expr_op()
|
| 404 |
|
|
{
|
| 405 |
|
|
CYG_REPORT_FUNCNAMETYPE("token_to_expr_op", "op %d");
|
| 406 |
|
|
CdlExprOp result = CdlExprOp_Invalid;
|
| 407 |
|
|
|
| 408 |
|
|
switch(current_token) {
|
| 409 |
|
|
case T_Minus: result = CdlExprOp_Subtract; break;
|
| 410 |
|
|
case T_Plus: result = CdlExprOp_Add; break;
|
| 411 |
|
|
case T_Times: result = CdlExprOp_Multiply; break;
|
| 412 |
|
|
case T_Divide: result = CdlExprOp_Divide; break;
|
| 413 |
|
|
case T_Remainder: result = CdlExprOp_Remainder; break;
|
| 414 |
|
|
case T_LeftShift: result = CdlExprOp_LeftShift; break;
|
| 415 |
|
|
case T_RightShift: result = CdlExprOp_RightShift; break;
|
| 416 |
|
|
case T_LessThan: result = CdlExprOp_LessThan; break;
|
| 417 |
|
|
case T_LessEqual: result = CdlExprOp_LessEqual; break;
|
| 418 |
|
|
case T_GreaterThan: result = CdlExprOp_GreaterThan; break;
|
| 419 |
|
|
case T_GreaterEqual: result = CdlExprOp_GreaterEqual; break;
|
| 420 |
|
|
case T_Equal: result = CdlExprOp_Equal; break;
|
| 421 |
|
|
case T_NotEqual: result = CdlExprOp_NotEqual; break;
|
| 422 |
|
|
case T_BitAnd: result = CdlExprOp_BitAnd; break;
|
| 423 |
|
|
case T_BitXor: result = CdlExprOp_BitXor; break;
|
| 424 |
|
|
case T_BitOr: result = CdlExprOp_BitOr; break;
|
| 425 |
|
|
case T_And: result = CdlExprOp_And; break;
|
| 426 |
|
|
case T_Or: result = CdlExprOp_Or; break;
|
| 427 |
|
|
case T_StringConcat: result = CdlExprOp_StringConcat; break;
|
| 428 |
|
|
case T_Implies: result = CdlExprOp_Implies; break;
|
| 429 |
|
|
case T_Xor: result = CdlExprOp_Xor; break;
|
| 430 |
|
|
case T_Eqv: result = CdlExprOp_Eqv; break;
|
| 431 |
|
|
default: result = CdlExprOp_Invalid; break;
|
| 432 |
|
|
}
|
| 433 |
|
|
|
| 434 |
|
|
CYG_REPORT_RETVAL(result);
|
| 435 |
|
|
return result;
|
| 436 |
|
|
}
|
| 437 |
|
|
|
| 438 |
|
|
// Convert a token into an ExprOp. This way the internal token enum does
|
| 439 |
|
|
// not need to be exported in order to define the interface.
|
| 440 |
|
|
//
|
| 441 |
|
|
// In practice the higher level code will only look for a handful of
|
| 442 |
|
|
// cases, mainly EOD and the range operator, but we might as well
|
| 443 |
|
|
// do the job property.
|
| 444 |
|
|
static CdlExprOp
|
| 445 |
|
|
token_to_expr_op()
|
| 446 |
|
|
{
|
| 447 |
|
|
CYG_REPORT_FUNCNAMETYPE("token_to_expr_op", "expr op %d");
|
| 448 |
|
|
CdlExprOp result;
|
| 449 |
|
|
|
| 450 |
|
|
// Many of the tokens are already handled for binary operators.
|
| 451 |
|
|
result = token_to_binary_expr_op();
|
| 452 |
|
|
if (CdlExprOp_Invalid == result) {
|
| 453 |
|
|
switch(current_token) {
|
| 454 |
|
|
case T_EOD: result = CdlExprOp_EOD; break;
|
| 455 |
|
|
case T_Reference: result = CdlExprOp_Reference; break;
|
| 456 |
|
|
case T_String: result = CdlExprOp_StringConstant; break;
|
| 457 |
|
|
case T_Integer: result = CdlExprOp_IntegerConstant; break;
|
| 458 |
|
|
case T_Double: result = CdlExprOp_DoubleConstant; break;
|
| 459 |
|
|
case T_Range: result = CdlExprOp_Range; break;
|
| 460 |
|
|
case T_Exclamation: result = CdlExprOp_LogicalNot; break;
|
| 461 |
|
|
case T_Tilde: result = CdlExprOp_BitNot; break;
|
| 462 |
|
|
case T_Questionmark:
|
| 463 |
|
|
case T_Colon: result = CdlExprOp_Cond; break; // best guess
|
| 464 |
|
|
case T_Function: result = CdlExprOp_Function; break;
|
| 465 |
|
|
case T_OpenBracket:
|
| 466 |
|
|
case T_CloseBracket:
|
| 467 |
|
|
case T_Invalid:
|
| 468 |
|
|
default: result = CdlExprOp_Invalid; break;
|
| 469 |
|
|
}
|
| 470 |
|
|
}
|
| 471 |
|
|
CYG_REPORT_RETVAL(result);
|
| 472 |
|
|
return result;
|
| 473 |
|
|
}
|
| 474 |
|
|
|
| 475 |
|
|
// A utility routine to turn the current token back into a string
|
| 476 |
|
|
// This is used for diagnostics.
|
| 477 |
|
|
static std::string
|
| 478 |
|
|
token_to_string()
|
| 479 |
|
|
{
|
| 480 |
|
|
CYG_REPORT_FUNCNAME("token_to_string");
|
| 481 |
|
|
std::string result = "";
|
| 482 |
|
|
|
| 483 |
|
|
switch(current_token) {
|
| 484 |
|
|
case T_EOD: result = "<end of data>"; break;
|
| 485 |
|
|
case T_Reference: result = "reference to " + current_reference; break;
|
| 486 |
|
|
case T_String: result = "string \"" + current_string + "\""; break;
|
| 487 |
|
|
case T_Integer:
|
| 488 |
|
|
{
|
| 489 |
|
|
std::string tmp;
|
| 490 |
|
|
Cdl::integer_to_string(current_int, tmp, current_format);
|
| 491 |
|
|
result = "integer constant " + tmp;
|
| 492 |
|
|
break;
|
| 493 |
|
|
}
|
| 494 |
|
|
case T_Double:
|
| 495 |
|
|
{
|
| 496 |
|
|
std::string tmp;
|
| 497 |
|
|
Cdl::double_to_string(current_double, tmp, current_format);
|
| 498 |
|
|
result = "double constant " + tmp;
|
| 499 |
|
|
break;
|
| 500 |
|
|
}
|
| 501 |
|
|
case T_Range: result = "range operator \"to\""; break;
|
| 502 |
|
|
case T_OpenBracket: result = "open bracket ("; break;
|
| 503 |
|
|
case T_CloseBracket: result = "close bracket )"; break;
|
| 504 |
|
|
case T_Minus: result = "minus sign -"; break;
|
| 505 |
|
|
case T_Plus: result = "plus sign +"; break;
|
| 506 |
|
|
case T_Times: result = "multiply operator *"; break;
|
| 507 |
|
|
case T_Divide: result = "divide operator /"; break;
|
| 508 |
|
|
case T_Exclamation: result = "not operator !"; break;
|
| 509 |
|
|
case T_Tilde: result = "bitwise not operator ~"; break;
|
| 510 |
|
|
case T_Questionmark: result = "question mark ?"; break;
|
| 511 |
|
|
case T_Remainder: result = "remainder operator %"; break;
|
| 512 |
|
|
case T_LeftShift: result = "left shift operator <<"; break;
|
| 513 |
|
|
case T_RightShift: result = "right shift operator >>"; break;
|
| 514 |
|
|
case T_LessThan: result = "less-than operator <"; break;
|
| 515 |
|
|
case T_LessEqual: result = "less-or-equal operator <="; break;
|
| 516 |
|
|
case T_GreaterThan: result = "greater-than operator >"; break;
|
| 517 |
|
|
case T_GreaterEqual: result = "greater-or-equal operator >="; break;
|
| 518 |
|
|
case T_Equal: result = "equality operator =="; break;
|
| 519 |
|
|
case T_NotEqual: result = "not-equal operator !="; break;
|
| 520 |
|
|
case T_BitAnd: result = "bitwise and operator &"; break;
|
| 521 |
|
|
case T_BitXor: result = "bitwise xor operator ^"; break;
|
| 522 |
|
|
case T_BitOr: result = "bitwise or operator |"; break;
|
| 523 |
|
|
case T_And: result = "and operator &&"; break;
|
| 524 |
|
|
case T_Or: result = "or operator ||"; break;
|
| 525 |
|
|
case T_Colon: result = "colon"; break;
|
| 526 |
|
|
case T_StringConcat: result = "string concatenation operator ."; break;
|
| 527 |
|
|
case T_Implies: result = "implies operator"; break;
|
| 528 |
|
|
case T_Xor: result = "logical xor operator"; break;
|
| 529 |
|
|
case T_Eqv: result = "logical equivalence operator eqv"; break;
|
| 530 |
|
|
case T_Function: result = std::string("function call ") + CdlFunction::get_name(current_function_id); break;
|
| 531 |
|
|
case T_Invalid:
|
| 532 |
|
|
default: result = "<invalid token>"; break;
|
| 533 |
|
|
}
|
| 534 |
|
|
|
| 535 |
|
|
CYG_REPORT_RETURN();
|
| 536 |
|
|
return result;
|
| 537 |
|
|
}
|
| 538 |
|
|
|
| 539 |
|
|
//}}}
|
| 540 |
|
|
//{{{ Literals
|
| 541 |
|
|
|
| 542 |
|
|
// ----------------------------------------------------------------------------
|
| 543 |
|
|
//{{{ process_string()
|
| 544 |
|
|
|
| 545 |
|
|
// The start of a string has been detected. Work out the entire string,
|
| 546 |
|
|
// allowing for backslash escapes.
|
| 547 |
|
|
static void
|
| 548 |
|
|
process_string()
|
| 549 |
|
|
{
|
| 550 |
|
|
CYG_REPORT_FUNCNAME("process_string");
|
| 551 |
|
|
CYG_ASSERTC('"' == current_char);
|
| 552 |
|
|
CYG_ASSERTC("" == current_string);
|
| 553 |
|
|
|
| 554 |
|
|
std::string result = "";
|
| 555 |
|
|
|
| 556 |
|
|
// Move past the leading quote mark.
|
| 557 |
|
|
next_char();
|
| 558 |
|
|
while ('"' != current_char) {
|
| 559 |
|
|
if (EOF == current_char) {
|
| 560 |
|
|
throw CdlParseException("Premature end of data in string constant.\n" + get_error_location());
|
| 561 |
|
|
} else if ('\\' == current_char) {
|
| 562 |
|
|
// Allow \a, \b, \f, \n, \r, \t, \v, \ddd and \xhh.
|
| 563 |
|
|
// Also copy with \newline space.
|
| 564 |
|
|
// Any other character gets passed through unchanged.
|
| 565 |
|
|
next_char();
|
| 566 |
|
|
switch(current_char) {
|
| 567 |
|
|
case EOF:
|
| 568 |
|
|
throw CdlParseException("Premature end of data after backslash in string constant.\n" + get_error_location());
|
| 569 |
|
|
case 'a':
|
| 570 |
|
|
result += '\a';
|
| 571 |
|
|
break;
|
| 572 |
|
|
case 'b':
|
| 573 |
|
|
result += '\b';
|
| 574 |
|
|
break;
|
| 575 |
|
|
case 'f':
|
| 576 |
|
|
result += '\f';
|
| 577 |
|
|
break;
|
| 578 |
|
|
case 'n':
|
| 579 |
|
|
result += '\n';
|
| 580 |
|
|
break;
|
| 581 |
|
|
case 'r':
|
| 582 |
|
|
result += '\r';
|
| 583 |
|
|
break;
|
| 584 |
|
|
case 't':
|
| 585 |
|
|
result += '\t';
|
| 586 |
|
|
break;
|
| 587 |
|
|
case 'v':
|
| 588 |
|
|
result += '\v';
|
| 589 |
|
|
break;
|
| 590 |
|
|
case 'x':
|
| 591 |
|
|
{
|
| 592 |
|
|
cdl_int tmp = 0;
|
| 593 |
|
|
next_char();
|
| 594 |
|
|
if (!isxdigit(current_char)) {
|
| 595 |
|
|
throw CdlParseException("Non-hexadecimal digit detected in string \\x escape sequence.\n" +
|
| 596 |
|
|
get_error_location());
|
| 597 |
|
|
}
|
| 598 |
|
|
// NOTE: there is no overflow detection here.
|
| 599 |
|
|
do {
|
| 600 |
|
|
tmp *= 16;
|
| 601 |
|
|
if (('0' <= current_char) && (current_char <= '9')) {
|
| 602 |
|
|
tmp += (current_char - '0');
|
| 603 |
|
|
} else if (('a' <= current_char) && (current_char <= 'f')) {
|
| 604 |
|
|
tmp += 10 + (current_char - 'a');
|
| 605 |
|
|
} else if (('A' <= current_char) && (current_char <= 'F')) {
|
| 606 |
|
|
tmp += 10 + (current_char - 'A');
|
| 607 |
|
|
} else {
|
| 608 |
|
|
CYG_FAIL("C library error, isxdigit() succeeded on non-hexadecimal character");
|
| 609 |
|
|
}
|
| 610 |
|
|
next_char();
|
| 611 |
|
|
} while(isxdigit(current_char));
|
| 612 |
|
|
backup_char();
|
| 613 |
|
|
result += (char) tmp;
|
| 614 |
|
|
}
|
| 615 |
|
|
|
| 616 |
|
|
case '\n':
|
| 617 |
|
|
next_char();
|
| 618 |
|
|
while ((EOF != current_char) && isspace(current_char)) {
|
| 619 |
|
|
next_char();
|
| 620 |
|
|
}
|
| 621 |
|
|
// We have gone one too far, back up.
|
| 622 |
|
|
backup_char();
|
| 623 |
|
|
result += " ";
|
| 624 |
|
|
break;
|
| 625 |
|
|
|
| 626 |
|
|
default:
|
| 627 |
|
|
if (('0' <= current_char) && (current_char <= '7')) {
|
| 628 |
|
|
// A sequence of octal digits.
|
| 629 |
|
|
cdl_int tmp = 0;
|
| 630 |
|
|
do {
|
| 631 |
|
|
tmp = (8 * tmp) + (current_char - '0');
|
| 632 |
|
|
next_char();
|
| 633 |
|
|
} while (('0' <= current_char) && (current_char <= '7'));
|
| 634 |
|
|
backup_char();
|
| 635 |
|
|
result += (char) tmp;
|
| 636 |
|
|
} else {
|
| 637 |
|
|
// For all other backslash sequences, just add the second character
|
| 638 |
|
|
result += (char) current_char;
|
| 639 |
|
|
}
|
| 640 |
|
|
}
|
| 641 |
|
|
} else {
|
| 642 |
|
|
result += (char) current_char;
|
| 643 |
|
|
}
|
| 644 |
|
|
next_char();
|
| 645 |
|
|
}
|
| 646 |
|
|
// The closing quote has been reached, move past it.
|
| 647 |
|
|
next_char();
|
| 648 |
|
|
|
| 649 |
|
|
// And all done.
|
| 650 |
|
|
current_token = T_String;
|
| 651 |
|
|
current_string = result;
|
| 652 |
|
|
|
| 653 |
|
|
CYG_REPORT_RETURN();
|
| 654 |
|
|
}
|
| 655 |
|
|
|
| 656 |
|
|
//}}}
|
| 657 |
|
|
//{{{ process_number()
|
| 658 |
|
|
|
| 659 |
|
|
// The start of a number has been detected. This number may be an
|
| 660 |
|
|
// integer or a double. It is necessary to figure out where the number
|
| 661 |
|
|
// ends and invoke the appropriate Cdl:: conversion utility.
|
| 662 |
|
|
//
|
| 663 |
|
|
// Care has to be taken with termination. Consider a token such as
|
| 664 |
|
|
// 134_5. This is not a string because there are no quote marks, nor
|
| 665 |
|
|
// is it a valid reference, and because it begins with a digit it
|
| 666 |
|
|
// should be interpreted as a number. The 134 bit works fine, then
|
| 667 |
|
|
// number processing stops leaving current_char as '_'. If we are
|
| 668 |
|
|
// parsing a list expression then the following _5 will actually
|
| 669 |
|
|
// be interpreted as a reference. To avoid this, here is a utility
|
| 670 |
|
|
// which checks number completion and throws an exception if
|
| 671 |
|
|
// necessary.
|
| 672 |
|
|
static void check_number_termination()
|
| 673 |
|
|
{
|
| 674 |
|
|
CYG_REPORT_FUNCNAME("check_number_termination");
|
| 675 |
|
|
|
| 676 |
|
|
// End-of-data or any whitespace is ok.
|
| 677 |
|
|
if ((EOF != current_char) && !isspace(current_char)) {
|
| 678 |
|
|
// Any valid operator is ok as well, or brackets for that matter.
|
| 679 |
|
|
if (('-' != current_char) && ('+' != current_char) && ('*' != current_char) &&
|
| 680 |
|
|
('/' != current_char) && ('!' != current_char) && ('~' != current_char) &&
|
| 681 |
|
|
('?' != current_char) && ('%' != current_char) && ('<' != current_char) &&
|
| 682 |
|
|
('>' != current_char) && ('=' != current_char) && ('&' != current_char) &&
|
| 683 |
|
|
('^' != current_char) && ('|' != current_char) && (':' != current_char) &&
|
| 684 |
|
|
('(' != current_char) && (')' != current_char)) {
|
| 685 |
|
|
|
| 686 |
|
|
std::string tmp;
|
| 687 |
|
|
Cdl::integer_to_string(current_int, tmp);
|
| 688 |
|
|
throw CdlParseException("Invalid character detected after number " + tmp + "\n" + get_error_location());
|
| 689 |
|
|
}
|
| 690 |
|
|
}
|
| 691 |
|
|
|
| 692 |
|
|
CYG_REPORT_RETURN();
|
| 693 |
|
|
}
|
| 694 |
|
|
|
| 695 |
|
|
static void
|
| 696 |
|
|
process_number()
|
| 697 |
|
|
{
|
| 698 |
|
|
CYG_REPORT_FUNCNAME("process_number");
|
| 699 |
|
|
|
| 700 |
|
|
std::string tmp = "";
|
| 701 |
|
|
bool is_float = false;
|
| 702 |
|
|
|
| 703 |
|
|
// Detect the special cases of 0x and octal numbers.
|
| 704 |
|
|
if ('0' == current_char) {
|
| 705 |
|
|
next_char();
|
| 706 |
|
|
if (('x' == current_char) || ('X' == current_char)) {
|
| 707 |
|
|
|
| 708 |
|
|
next_char();
|
| 709 |
|
|
if (!isxdigit(current_char)) {
|
| 710 |
|
|
throw CdlParseException("Invalid hexadecimal number, expected at least one hexadecimal digit after 0x.\n"
|
| 711 |
|
|
+ get_error_location());
|
| 712 |
|
|
}
|
| 713 |
|
|
current_int = 0;
|
| 714 |
|
|
do {
|
| 715 |
|
|
current_int *= 16;
|
| 716 |
|
|
if (('0' <= current_char) && (current_char <= '9')) {
|
| 717 |
|
|
current_int += (current_char - '0');
|
| 718 |
|
|
} else if (('a' <= current_char) && (current_char <= 'f')) {
|
| 719 |
|
|
current_int += 10 + (current_char - 'a');
|
| 720 |
|
|
} else {
|
| 721 |
|
|
current_int += 10 + (current_char - 'A');
|
| 722 |
|
|
}
|
| 723 |
|
|
next_char();
|
| 724 |
|
|
} while(isxdigit(current_char));
|
| 725 |
|
|
current_token = T_Integer;
|
| 726 |
|
|
current_format = CdlValueFormat_Hex;
|
| 727 |
|
|
check_number_termination();
|
| 728 |
|
|
CYG_REPORT_RETURN();
|
| 729 |
|
|
return;
|
| 730 |
|
|
|
| 731 |
|
|
} else if (('0' <= current_char) && (current_char <= '7')) {
|
| 732 |
|
|
|
| 733 |
|
|
current_int = 0;
|
| 734 |
|
|
do {
|
| 735 |
|
|
current_int *= 8;
|
| 736 |
|
|
current_int += (current_char - '0');
|
| 737 |
|
|
next_char();
|
| 738 |
|
|
} while (('0' <= current_char) && (current_char <= '7'));
|
| 739 |
|
|
current_token = T_Integer;
|
| 740 |
|
|
current_format = CdlValueFormat_Octal;
|
| 741 |
|
|
check_number_termination();
|
| 742 |
|
|
CYG_REPORT_RETURN();
|
| 743 |
|
|
return;
|
| 744 |
|
|
|
| 745 |
|
|
} else if (('8' == current_char) || ('9' == current_char)) {
|
| 746 |
|
|
throw CdlParseException("08... and 09... are not valid octal numbers.\n" + get_error_location());
|
| 747 |
|
|
} else {
|
| 748 |
|
|
// This could be plain 0, or 0.123
|
| 749 |
|
|
// Backup, and let the rest of the code take care of things
|
| 750 |
|
|
backup_char();
|
| 751 |
|
|
}
|
| 752 |
|
|
}
|
| 753 |
|
|
|
| 754 |
|
|
do {
|
| 755 |
|
|
tmp += (char) current_char;
|
| 756 |
|
|
next_char();
|
| 757 |
|
|
} while(isdigit(current_char));
|
| 758 |
|
|
|
| 759 |
|
|
// If we have found a . then we have a floating point number with a fraction.
|
| 760 |
|
|
if ('.' == current_char) {
|
| 761 |
|
|
tmp += '.';
|
| 762 |
|
|
next_char();
|
| 763 |
|
|
if (!isdigit(current_char)) {
|
| 764 |
|
|
throw CdlParseException("Invalid floating point constant, expected a digit for the fractional part.\n" +
|
| 765 |
|
|
get_error_location());
|
| 766 |
|
|
}
|
| 767 |
|
|
is_float = true;
|
| 768 |
|
|
do {
|
| 769 |
|
|
tmp += (char) current_char;
|
| 770 |
|
|
next_char();
|
| 771 |
|
|
} while(isdigit(current_char));
|
| 772 |
|
|
}
|
| 773 |
|
|
|
| 774 |
|
|
// If we have found e or E then we have a floating point number with an exponent
|
| 775 |
|
|
if (('e' == current_char) || ('E' == current_char)) {
|
| 776 |
|
|
tmp += 'E';
|
| 777 |
|
|
next_char();
|
| 778 |
|
|
if (('+' == current_char) || ('-' == current_char)) {
|
| 779 |
|
|
tmp += current_char;
|
| 780 |
|
|
next_char();
|
| 781 |
|
|
}
|
| 782 |
|
|
if (!isdigit(current_char)) {
|
| 783 |
|
|
throw CdlParseException("Invalid floating point constant, expected a digit for the exponent.\n" +
|
| 784 |
|
|
get_error_location());
|
| 785 |
|
|
}
|
| 786 |
|
|
is_float = true;
|
| 787 |
|
|
do {
|
| 788 |
|
|
tmp += (char) current_char;
|
| 789 |
|
|
next_char();
|
| 790 |
|
|
} while(isdigit(current_char));
|
| 791 |
|
|
}
|
| 792 |
|
|
|
| 793 |
|
|
if (is_float) {
|
| 794 |
|
|
if (!Cdl::string_to_double(tmp, current_double)) {
|
| 795 |
|
|
throw CdlParseException("Invalid floating point constant `" + tmp + "'.\n" + get_error_location());
|
| 796 |
|
|
} else {
|
| 797 |
|
|
current_token = T_Double;
|
| 798 |
|
|
}
|
| 799 |
|
|
} else {
|
| 800 |
|
|
if (!Cdl::string_to_integer(tmp, current_int)) {
|
| 801 |
|
|
throw CdlParseException("Invalid integer constant `" + tmp + "'.\n" + get_error_location());
|
| 802 |
|
|
} else {
|
| 803 |
|
|
current_token = T_Integer;
|
| 804 |
|
|
}
|
| 805 |
|
|
}
|
| 806 |
|
|
|
| 807 |
|
|
check_number_termination();
|
| 808 |
|
|
CYG_REPORT_RETURN();
|
| 809 |
|
|
}
|
| 810 |
|
|
|
| 811 |
|
|
//}}}
|
| 812 |
|
|
//{{{ process_alphanumeric()
|
| 813 |
|
|
|
| 814 |
|
|
// The start of an alphanumeric sequence has been detected. This may
|
| 815 |
|
|
// be a reference, a function call, or an operator like eq or to. All
|
| 816 |
|
|
// such sequences must be a valid C preprocessor name, so the only
|
| 817 |
|
|
// characters allowed are underscore, upper and lower case characters,
|
| 818 |
|
|
// and digits. The first character cannot be a digit, but that has
|
| 819 |
|
|
// been checked already.
|
| 820 |
|
|
//
|
| 821 |
|
|
// Some care has to be taken with locale's, the C library may decide
|
| 822 |
|
|
// that a character is a letter even though the same character is not
|
| 823 |
|
|
// valid as far as the preprocessor is concerned.
|
| 824 |
|
|
static void
|
| 825 |
|
|
process_alphanumeric()
|
| 826 |
|
|
{
|
| 827 |
|
|
CYG_REPORT_FUNCNAME("process_alphanumeric");
|
| 828 |
|
|
|
| 829 |
|
|
do {
|
| 830 |
|
|
current_reference += (char) current_char;
|
| 831 |
|
|
next_char();
|
| 832 |
|
|
} while (('_' == current_char) || isdigit(current_char) ||
|
| 833 |
|
|
(('a' <= current_char) && (current_char <= 'z')) ||
|
| 834 |
|
|
(('A' <= current_char) && (current_char <= 'Z')));
|
| 835 |
|
|
|
| 836 |
|
|
CYG_REPORT_RETURN();
|
| 837 |
|
|
}
|
| 838 |
|
|
|
| 839 |
|
|
//}}}
|
| 840 |
|
|
//{{{ process_special()
|
| 841 |
|
|
|
| 842 |
|
|
// Usually an alphanumeric sequence of characters is a reference, e.g.
|
| 843 |
|
|
// CYGPKG_KERNEL. However there are only so many special characters
|
| 844 |
|
|
// available so some operators are implemented as a sequence, e.g.
|
| 845 |
|
|
// "to". CDL also supports functions like is_substr().
|
| 846 |
|
|
//
|
| 847 |
|
|
// The data will have been collected into the current_reference string
|
| 848 |
|
|
// by a call to process_alphanumeric().
|
| 849 |
|
|
|
| 850 |
|
|
static bool
|
| 851 |
|
|
process_special()
|
| 852 |
|
|
{
|
| 853 |
|
|
CYG_REPORT_FUNCNAMETYPE("process_special", "special %d");
|
| 854 |
|
|
bool result = false;
|
| 855 |
|
|
|
| 856 |
|
|
if ("to" == current_reference) {
|
| 857 |
|
|
current_token = T_Range;
|
| 858 |
|
|
result = true;
|
| 859 |
|
|
} else if ("implies" == current_reference) {
|
| 860 |
|
|
current_token = T_Implies;
|
| 861 |
|
|
result = true;
|
| 862 |
|
|
} else if ("xor" == current_reference) {
|
| 863 |
|
|
current_token = T_Xor;
|
| 864 |
|
|
result = true;
|
| 865 |
|
|
} else if ("eqv" == current_reference) {
|
| 866 |
|
|
current_token = T_Eqv;
|
| 867 |
|
|
result = true;
|
| 868 |
|
|
} else if (CdlFunction::is_function(current_reference.c_str(), current_function_id)) {
|
| 869 |
|
|
current_token = T_Function;
|
| 870 |
|
|
result = true;
|
| 871 |
|
|
}
|
| 872 |
|
|
|
| 873 |
|
|
if (result) {
|
| 874 |
|
|
current_special = current_reference;
|
| 875 |
|
|
current_reference = "";
|
| 876 |
|
|
}
|
| 877 |
|
|
CYG_REPORT_RETVAL(result);
|
| 878 |
|
|
return result;
|
| 879 |
|
|
}
|
| 880 |
|
|
|
| 881 |
|
|
//}}}
|
| 882 |
|
|
|
| 883 |
|
|
//}}}
|
| 884 |
|
|
//{{{ next_token()
|
| 885 |
|
|
|
| 886 |
|
|
// ----------------------------------------------------------------------------
|
| 887 |
|
|
// Work out what the next token is. This includes the handling of
|
| 888 |
|
|
// strings, integers, doubles, and references.
|
| 889 |
|
|
static void
|
| 890 |
|
|
next_token()
|
| 891 |
|
|
{
|
| 892 |
|
|
CYG_REPORT_FUNCNAMETYPE("next_token", "token %d");
|
| 893 |
|
|
|
| 894 |
|
|
// Make sure there is no dross left lying around from the previous call.
|
| 895 |
|
|
current_token = T_Invalid;
|
| 896 |
|
|
current_string = "";
|
| 897 |
|
|
current_reference = "";
|
| 898 |
|
|
current_special = "";
|
| 899 |
|
|
current_int = 0;
|
| 900 |
|
|
current_double = 0.0;
|
| 901 |
|
|
current_format = CdlValueFormat_Default;
|
| 902 |
|
|
current_function_id = 0;
|
| 903 |
|
|
|
| 904 |
|
|
// Skip leading white space. This includes newlines, tabs, etc,
|
| 905 |
|
|
// consider the case of:
|
| 906 |
|
|
// ...
|
| 907 |
|
|
// legal_values {
|
| 908 |
|
|
// 1
|
| 909 |
|
|
// 2
|
| 910 |
|
|
// 4
|
| 911 |
|
|
// ..
|
| 912 |
|
|
// }
|
| 913 |
|
|
// ...
|
| 914 |
|
|
// which is perfectly legitimate. White space inside strings
|
| 915 |
|
|
// is handled by the string literal code, and does not get filtered
|
| 916 |
|
|
// out here.
|
| 917 |
|
|
//
|
| 918 |
|
|
// Exactly which characters are white-space is implementation-defined,
|
| 919 |
|
|
// so a special check for EOF is in order.
|
| 920 |
|
|
while ((EOF != current_char) && isspace(current_char)) {
|
| 921 |
|
|
next_char();
|
| 922 |
|
|
}
|
| 923 |
|
|
|
| 924 |
|
|
// Remember the token starting point. next_char() has actually moved
|
| 925 |
|
|
// the index on by one.
|
| 926 |
|
|
token_start = current_index - 1;
|
| 927 |
|
|
|
| 928 |
|
|
// The simple cases can be handled inline, the more complicated cases
|
| 929 |
|
|
// involve other functions
|
| 930 |
|
|
switch(current_char) {
|
| 931 |
|
|
|
| 932 |
|
|
case EOF:
|
| 933 |
|
|
current_token = T_EOD;
|
| 934 |
|
|
break;
|
| 935 |
|
|
|
| 936 |
|
|
case '"':
|
| 937 |
|
|
process_string();
|
| 938 |
|
|
break;
|
| 939 |
|
|
|
| 940 |
|
|
case '(':
|
| 941 |
|
|
current_token = T_OpenBracket;
|
| 942 |
|
|
next_char();
|
| 943 |
|
|
break;
|
| 944 |
|
|
|
| 945 |
|
|
case ')':
|
| 946 |
|
|
current_token = T_CloseBracket;
|
| 947 |
|
|
next_char();
|
| 948 |
|
|
break;
|
| 949 |
|
|
|
| 950 |
|
|
// At this level it is not possible to distinguish between
|
| 951 |
|
|
// unary and binary operators, so no attempt is made to
|
| 952 |
|
|
// turn - and + into part of a number.
|
| 953 |
|
|
case '-':
|
| 954 |
|
|
current_token = T_Minus;
|
| 955 |
|
|
next_char();
|
| 956 |
|
|
break;
|
| 957 |
|
|
|
| 958 |
|
|
case '+':
|
| 959 |
|
|
current_token = T_Plus;
|
| 960 |
|
|
next_char();
|
| 961 |
|
|
break;
|
| 962 |
|
|
|
| 963 |
|
|
case '*':
|
| 964 |
|
|
current_token = T_Times;
|
| 965 |
|
|
next_char();
|
| 966 |
|
|
break;
|
| 967 |
|
|
|
| 968 |
|
|
case '/':
|
| 969 |
|
|
current_token = T_Divide;
|
| 970 |
|
|
next_char();
|
| 971 |
|
|
break;
|
| 972 |
|
|
|
| 973 |
|
|
case '!':
|
| 974 |
|
|
next_char();
|
| 975 |
|
|
if ('=' == current_char) {
|
| 976 |
|
|
current_token = T_NotEqual;
|
| 977 |
|
|
next_char();
|
| 978 |
|
|
} else {
|
| 979 |
|
|
current_token = T_Exclamation;
|
| 980 |
|
|
}
|
| 981 |
|
|
break;
|
| 982 |
|
|
|
| 983 |
|
|
case '~':
|
| 984 |
|
|
current_token = T_Tilde;
|
| 985 |
|
|
next_char();
|
| 986 |
|
|
break;
|
| 987 |
|
|
|
| 988 |
|
|
case '?':
|
| 989 |
|
|
current_token = T_Questionmark;
|
| 990 |
|
|
next_char();
|
| 991 |
|
|
break;
|
| 992 |
|
|
|
| 993 |
|
|
case '%':
|
| 994 |
|
|
current_token = T_Remainder;
|
| 995 |
|
|
next_char();
|
| 996 |
|
|
break;
|
| 997 |
|
|
|
| 998 |
|
|
case '<':
|
| 999 |
|
|
next_char();
|
| 1000 |
|
|
if ('<' == current_char) {
|
| 1001 |
|
|
current_token = T_LeftShift;
|
| 1002 |
|
|
next_char();
|
| 1003 |
|
|
} else if ('=' == current_char) {
|
| 1004 |
|
|
current_token = T_LessEqual;
|
| 1005 |
|
|
next_char();
|
| 1006 |
|
|
} else {
|
| 1007 |
|
|
current_token = T_LessThan;
|
| 1008 |
|
|
}
|
| 1009 |
|
|
break;
|
| 1010 |
|
|
|
| 1011 |
|
|
case '>':
|
| 1012 |
|
|
next_char();
|
| 1013 |
|
|
if ('>' == current_char) {
|
| 1014 |
|
|
current_token = T_RightShift;
|
| 1015 |
|
|
next_char();
|
| 1016 |
|
|
} else if ('=' == current_char) {
|
| 1017 |
|
|
current_token = T_GreaterEqual;
|
| 1018 |
|
|
next_char();
|
| 1019 |
|
|
} else {
|
| 1020 |
|
|
current_token = T_GreaterThan;
|
| 1021 |
|
|
}
|
| 1022 |
|
|
break;
|
| 1023 |
|
|
|
| 1024 |
|
|
case '=':
|
| 1025 |
|
|
next_char();
|
| 1026 |
|
|
if ('=' != current_char) {
|
| 1027 |
|
|
throw CdlParseException(std::string("Incomplete == operator in expression.\n") + get_error_location());
|
| 1028 |
|
|
} else {
|
| 1029 |
|
|
current_token = T_Equal;
|
| 1030 |
|
|
next_char();
|
| 1031 |
|
|
}
|
| 1032 |
|
|
break;
|
| 1033 |
|
|
|
| 1034 |
|
|
case '&':
|
| 1035 |
|
|
next_char();
|
| 1036 |
|
|
if ('&' == current_char) {
|
| 1037 |
|
|
current_token = T_And;
|
| 1038 |
|
|
next_char();
|
| 1039 |
|
|
} else {
|
| 1040 |
|
|
current_token = T_BitAnd;
|
| 1041 |
|
|
}
|
| 1042 |
|
|
break;
|
| 1043 |
|
|
|
| 1044 |
|
|
case '^':
|
| 1045 |
|
|
current_token = T_BitXor;
|
| 1046 |
|
|
next_char();
|
| 1047 |
|
|
break;
|
| 1048 |
|
|
|
| 1049 |
|
|
case '|':
|
| 1050 |
|
|
next_char();
|
| 1051 |
|
|
if ('|' == current_char) {
|
| 1052 |
|
|
current_token = T_Or;
|
| 1053 |
|
|
next_char();
|
| 1054 |
|
|
} else {
|
| 1055 |
|
|
current_token = T_BitOr;
|
| 1056 |
|
|
}
|
| 1057 |
|
|
break;
|
| 1058 |
|
|
|
| 1059 |
|
|
case ':':
|
| 1060 |
|
|
current_token = T_Colon;
|
| 1061 |
|
|
next_char();
|
| 1062 |
|
|
break;
|
| 1063 |
|
|
|
| 1064 |
|
|
case '.':
|
| 1065 |
|
|
current_token = T_StringConcat;
|
| 1066 |
|
|
next_char();
|
| 1067 |
|
|
break;
|
| 1068 |
|
|
|
| 1069 |
|
|
case ',':
|
| 1070 |
|
|
current_token = T_Comma;
|
| 1071 |
|
|
next_char();
|
| 1072 |
|
|
break;
|
| 1073 |
|
|
|
| 1074 |
|
|
default:
|
| 1075 |
|
|
// String constants have been handled already. The only
|
| 1076 |
|
|
// valid tokens that are left are numbers, references,
|
| 1077 |
|
|
// "specials" such as the range and string equality
|
| 1078 |
|
|
// operators, and functions.
|
| 1079 |
|
|
//
|
| 1080 |
|
|
// Numbers should begin with a digit (plus and minus are
|
| 1081 |
|
|
// tokenized separately).
|
| 1082 |
|
|
//
|
| 1083 |
|
|
// References must be valid C preprocessor symbols, i.e.
|
| 1084 |
|
|
// they must begin with either a letter or an underscore.
|
| 1085 |
|
|
// The range operator is handled most conveniently as
|
| 1086 |
|
|
// a special case of a reference.
|
| 1087 |
|
|
if (isdigit(current_char)) {
|
| 1088 |
|
|
process_number();
|
| 1089 |
|
|
} else if (('_' == current_char) ||
|
| 1090 |
|
|
(('a' <= current_char) && (current_char <= 'z')) ||
|
| 1091 |
|
|
(('A' <= current_char) && (current_char <= 'Z'))) {
|
| 1092 |
|
|
process_alphanumeric();
|
| 1093 |
|
|
if (!process_special()) {
|
| 1094 |
|
|
current_token = T_Reference;
|
| 1095 |
|
|
}
|
| 1096 |
|
|
} else {
|
| 1097 |
|
|
std::string msg = "Unexpected character '";
|
| 1098 |
|
|
msg += (char) current_char;
|
| 1099 |
|
|
msg += "' in expression.\n";
|
| 1100 |
|
|
msg += get_error_location();
|
| 1101 |
|
|
throw CdlParseException(msg);
|
| 1102 |
|
|
}
|
| 1103 |
|
|
break;
|
| 1104 |
|
|
}
|
| 1105 |
|
|
|
| 1106 |
|
|
CYG_REPORT_RETVAL(current_token);
|
| 1107 |
|
|
}
|
| 1108 |
|
|
|
| 1109 |
|
|
//}}}
|
| 1110 |
|
|
//{{{ initialise_tokenisation()
|
| 1111 |
|
|
|
| 1112 |
|
|
// ----------------------------------------------------------------------------
|
| 1113 |
|
|
// This is called at the start of expression parsing. It
|
| 1114 |
|
|
// sets up the appropriate statics, and provides initial
|
| 1115 |
|
|
// values for current_char and current_token.
|
| 1116 |
|
|
static void
|
| 1117 |
|
|
initialise_tokenisation(std::string data, int index)
|
| 1118 |
|
|
{
|
| 1119 |
|
|
CYG_REPORT_FUNCNAME("initialise_tokenization");
|
| 1120 |
|
|
|
| 1121 |
|
|
current_data = data;
|
| 1122 |
|
|
current_index = static_cast<unsigned int>(index);
|
| 1123 |
|
|
token_start = current_index;
|
| 1124 |
|
|
next_char();
|
| 1125 |
|
|
next_token();
|
| 1126 |
|
|
|
| 1127 |
|
|
CYG_REPORT_RETURN();
|
| 1128 |
|
|
}
|
| 1129 |
|
|
|
| 1130 |
|
|
//}}}
|
| 1131 |
|
|
|
| 1132 |
|
|
//}}}
|
| 1133 |
|
|
//{{{ Syntactic analysis
|
| 1134 |
|
|
|
| 1135 |
|
|
// ----------------------------------------------------------------------------
|
| 1136 |
|
|
// Syntactic analysis.
|
| 1137 |
|
|
//
|
| 1138 |
|
|
// The BNF of CDL expressions is something like this:
|
| 1139 |
|
|
//
|
| 1140 |
|
|
// <expression> ::= <conditional>
|
| 1141 |
|
|
// <conditional> ::= <implies> ? <conditional> : <conditional> | <implies>
|
| 1142 |
|
|
// <implies> ::= <eqv> [<implies op> <implies>] implies
|
| 1143 |
|
|
// <eqv> ::= <or> [<eqv op> <eqv>] xor, eqv
|
| 1144 |
|
|
// <or> ::= <and> [<or op> <or>] ||
|
| 1145 |
|
|
// <and> ::= <bitor> [<and op> <and>] &&
|
| 1146 |
|
|
// <bitor> ::= <bitxor> [<bitor op> <bitor>] |
|
| 1147 |
|
|
// <bitxor> ::= <bitand> [<bitxor op> <bitxor>] ^
|
| 1148 |
|
|
// <bitand> ::= <eq> [<bitand op> <and>] &
|
| 1149 |
|
|
// <eq> ::= <comp> [<eq op> <eq>] == !=
|
| 1150 |
|
|
// <comp> ::= <shift> [<comp op> <comp>] < <= > >=
|
| 1151 |
|
|
// <shift> ::= <add> [<shift op> <shift>] << >>
|
| 1152 |
|
|
// <add> ::= <mult> [<add op> <add>] + - .
|
| 1153 |
|
|
// <mult> ::= <unary> [<mult op> <mult>] * / %
|
| 1154 |
|
|
// <unary> ::= -<unary> | +<unary> | !<unary> | *<unary> | ?<unary> |
|
| 1155 |
|
|
// ~<unary> |
|
| 1156 |
|
|
// <string constant> | <integer constant> |
|
| 1157 |
|
|
// <double constant> | <reference> |
|
| 1158 |
|
|
// ( <expression> ) | <function>
|
| 1159 |
|
|
//
|
| 1160 |
|
|
// There are separate functions for each of these terms.
|
| 1161 |
|
|
|
| 1162 |
|
|
// A forward declaration, needed for bracketed subexpressions.
|
| 1163 |
|
|
static void parse_expression(CdlExpression);
|
| 1164 |
|
|
|
| 1165 |
|
|
// A utility to add a reference to the current expression, returning
|
| 1166 |
|
|
// the index.
|
| 1167 |
|
|
static int
|
| 1168 |
|
|
push_reference(CdlExpression expr, const std::string& reference)
|
| 1169 |
|
|
{
|
| 1170 |
|
|
CYG_REPORT_FUNCNAMETYPE("push_reference", "new index %d");
|
| 1171 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 1172 |
|
|
|
| 1173 |
|
|
CdlReference ref(reference);
|
| 1174 |
|
|
expr->references.push_back(ref);
|
| 1175 |
|
|
int result = (int) expr->references.size() - 1;
|
| 1176 |
|
|
|
| 1177 |
|
|
CYG_REPORT_RETVAL(result);
|
| 1178 |
|
|
return result;
|
| 1179 |
|
|
}
|
| 1180 |
|
|
|
| 1181 |
|
|
// A utility to add a subexpression, returning its index.
|
| 1182 |
|
|
static void
|
| 1183 |
|
|
push_subexpression(CdlExpression expr, const CdlSubexpression& subexpr)
|
| 1184 |
|
|
{
|
| 1185 |
|
|
CYG_REPORT_FUNCNAME("push_subexpression");
|
| 1186 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 1187 |
|
|
|
| 1188 |
|
|
expr->sub_expressions.push_back(subexpr);
|
| 1189 |
|
|
expr->first_subexpression = ((int) expr->sub_expressions.size()) - 1;
|
| 1190 |
|
|
|
| 1191 |
|
|
CYG_REPORT_RETURN();
|
| 1192 |
|
|
}
|
| 1193 |
|
|
|
| 1194 |
|
|
// Another utility to hold of the most recent subexpression
|
| 1195 |
|
|
static CdlSubexpression&
|
| 1196 |
|
|
current_subexpression(CdlExpression expr)
|
| 1197 |
|
|
{
|
| 1198 |
|
|
CYG_REPORT_FUNCNAME("current_subexpression");
|
| 1199 |
|
|
|
| 1200 |
|
|
CdlSubexpression& result = expr->sub_expressions[expr->first_subexpression];
|
| 1201 |
|
|
|
| 1202 |
|
|
CYG_REPORT_RETURN();
|
| 1203 |
|
|
return result;
|
| 1204 |
|
|
}
|
| 1205 |
|
|
|
| 1206 |
|
|
static void
|
| 1207 |
|
|
parse_function(CdlExpression expr)
|
| 1208 |
|
|
{
|
| 1209 |
|
|
CYG_REPORT_FUNCNAME("parse_function");
|
| 1210 |
|
|
CYG_REPORT_FUNCARG1XV(expr);
|
| 1211 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 1212 |
|
|
|
| 1213 |
|
|
CdlSubexpression subexpr;
|
| 1214 |
|
|
subexpr.op = CdlExprOp_Function;
|
| 1215 |
|
|
subexpr.func = current_function_id;
|
| 1216 |
|
|
|
| 1217 |
|
|
int number_of_args = CdlFunction::get_args_count(current_function_id);
|
| 1218 |
|
|
CYG_ASSERTC((0 < number_of_args) && (number_of_args <= CdlFunction_MaxArgs));
|
| 1219 |
|
|
std::string name = current_special;
|
| 1220 |
|
|
|
| 1221 |
|
|
// check for the opening bracket: xyzzy(arg1, arg2)
|
| 1222 |
|
|
next_token();
|
| 1223 |
|
|
if (T_OpenBracket != current_token) {
|
| 1224 |
|
|
throw CdlParseException(std::string("Expected opening bracket after function ") + name + "\n" + get_error_location());
|
| 1225 |
|
|
}
|
| 1226 |
|
|
next_token();
|
| 1227 |
|
|
|
| 1228 |
|
|
int i;
|
| 1229 |
|
|
for (i = 0; i < number_of_args; i++) {
|
| 1230 |
|
|
parse_expression(expr);
|
| 1231 |
|
|
subexpr.args[i] = expr->first_subexpression;
|
| 1232 |
|
|
if (i < (number_of_args - 1)) {
|
| 1233 |
|
|
if (T_Comma != current_token) {
|
| 1234 |
|
|
throw CdlParseException(std::string("Expected comma between arguments in function ") +
|
| 1235 |
|
|
name + "\n" + get_error_location());
|
| 1236 |
|
|
}
|
| 1237 |
|
|
next_token();
|
| 1238 |
|
|
}
|
| 1239 |
|
|
}
|
| 1240 |
|
|
if (T_Comma == current_token) {
|
| 1241 |
|
|
throw CdlParseException(std::string("Too many arguments passed to function ") + name + "\n" + get_error_location());
|
| 1242 |
|
|
}
|
| 1243 |
|
|
if (T_CloseBracket != current_token) {
|
| 1244 |
|
|
throw CdlParseException(std::string("Expected closing bracket after function ") + name + "\n" + get_error_location());
|
| 1245 |
|
|
}
|
| 1246 |
|
|
next_token();
|
| 1247 |
|
|
|
| 1248 |
|
|
// Allow the function implementation to check its arguments if it is so inclined.
|
| 1249 |
|
|
CdlFunction::check(expr, subexpr);
|
| 1250 |
|
|
|
| 1251 |
|
|
push_subexpression(expr, subexpr);
|
| 1252 |
|
|
CYG_REPORT_RETURN();
|
| 1253 |
|
|
}
|
| 1254 |
|
|
|
| 1255 |
|
|
static void
|
| 1256 |
|
|
parse_unary(CdlExpression expr)
|
| 1257 |
|
|
{
|
| 1258 |
|
|
CYG_REPORT_FUNCNAME("parse_operand");
|
| 1259 |
|
|
CYG_REPORT_FUNCARG1XV(expr);
|
| 1260 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 1261 |
|
|
|
| 1262 |
|
|
CdlSubexpression subexpr;
|
| 1263 |
|
|
|
| 1264 |
|
|
switch(current_token) {
|
| 1265 |
|
|
case T_EOD :
|
| 1266 |
|
|
{
|
| 1267 |
|
|
// This warrants a special case
|
| 1268 |
|
|
throw CdlParseException("End of expression reached when expecting an operand.\n" + get_error_location());
|
| 1269 |
|
|
}
|
| 1270 |
|
|
|
| 1271 |
|
|
case T_Function :
|
| 1272 |
|
|
{
|
| 1273 |
|
|
parse_function(expr);
|
| 1274 |
|
|
break;
|
| 1275 |
|
|
}
|
| 1276 |
|
|
|
| 1277 |
|
|
case T_Reference :
|
| 1278 |
|
|
{
|
| 1279 |
|
|
subexpr.op = CdlExprOp_Reference;
|
| 1280 |
|
|
subexpr.reference_index = push_reference(expr, current_reference);
|
| 1281 |
|
|
push_subexpression(expr, subexpr);
|
| 1282 |
|
|
next_token();
|
| 1283 |
|
|
break;
|
| 1284 |
|
|
}
|
| 1285 |
|
|
|
| 1286 |
|
|
case T_String :
|
| 1287 |
|
|
{
|
| 1288 |
|
|
subexpr.op = CdlExprOp_StringConstant;
|
| 1289 |
|
|
subexpr.constants = current_string;
|
| 1290 |
|
|
push_subexpression(expr, subexpr);
|
| 1291 |
|
|
next_token();
|
| 1292 |
|
|
break;
|
| 1293 |
|
|
}
|
| 1294 |
|
|
|
| 1295 |
|
|
case T_Integer :
|
| 1296 |
|
|
{
|
| 1297 |
|
|
subexpr.op = CdlExprOp_IntegerConstant;
|
| 1298 |
|
|
subexpr.constants.set_integer_value(current_int, current_format);
|
| 1299 |
|
|
push_subexpression(expr, subexpr);
|
| 1300 |
|
|
next_token();
|
| 1301 |
|
|
break;
|
| 1302 |
|
|
}
|
| 1303 |
|
|
|
| 1304 |
|
|
case T_Double :
|
| 1305 |
|
|
{
|
| 1306 |
|
|
subexpr.op = CdlExprOp_DoubleConstant;
|
| 1307 |
|
|
subexpr.constants.set_double_value(current_double, current_format);
|
| 1308 |
|
|
push_subexpression(expr, subexpr);
|
| 1309 |
|
|
next_token();
|
| 1310 |
|
|
break;
|
| 1311 |
|
|
}
|
| 1312 |
|
|
|
| 1313 |
|
|
case T_OpenBracket :
|
| 1314 |
|
|
{
|
| 1315 |
|
|
next_token();
|
| 1316 |
|
|
parse_expression(expr);
|
| 1317 |
|
|
if (T_CloseBracket != current_token) {
|
| 1318 |
|
|
throw CdlParseException("Missing close bracket after subexpression.\n" + get_error_location());
|
| 1319 |
|
|
}
|
| 1320 |
|
|
next_token();
|
| 1321 |
|
|
break;
|
| 1322 |
|
|
}
|
| 1323 |
|
|
|
| 1324 |
|
|
case T_Minus :
|
| 1325 |
|
|
{
|
| 1326 |
|
|
next_token();
|
| 1327 |
|
|
parse_unary(expr);
|
| 1328 |
|
|
CdlSubexpression& last_sub = current_subexpression(expr);
|
| 1329 |
|
|
if (CdlExprOp_IntegerConstant == last_sub.op) {
|
| 1330 |
|
|
// Do the negating inline, no need for another subexpression.
|
| 1331 |
|
|
last_sub.constants = last_sub.constants.get_integer_value() * -1;
|
| 1332 |
|
|
} else if (CdlExprOp_DoubleConstant == last_sub.op) {
|
| 1333 |
|
|
last_sub.constants = last_sub.constants.get_double_value() * -1;
|
| 1334 |
|
|
} else {
|
| 1335 |
|
|
// We could detect certain cases such as string constants etc.
|
| 1336 |
|
|
// For now don't bother.
|
| 1337 |
|
|
subexpr.op = CdlExprOp_Negate;
|
| 1338 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1339 |
|
|
push_subexpression(expr, subexpr);
|
| 1340 |
|
|
}
|
| 1341 |
|
|
break;
|
| 1342 |
|
|
}
|
| 1343 |
|
|
|
| 1344 |
|
|
case T_Plus :
|
| 1345 |
|
|
{
|
| 1346 |
|
|
next_token();
|
| 1347 |
|
|
parse_unary(expr);
|
| 1348 |
|
|
CdlSubexpression& last_sub = current_subexpression(expr);
|
| 1349 |
|
|
if ((CdlExprOp_IntegerConstant == last_sub.op) || (CdlExprOp_DoubleConstant == last_sub.op)) {
|
| 1350 |
|
|
// No need to do anything here.
|
| 1351 |
|
|
} else {
|
| 1352 |
|
|
subexpr.op = CdlExprOp_Plus;
|
| 1353 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1354 |
|
|
push_subexpression(expr, subexpr);
|
| 1355 |
|
|
}
|
| 1356 |
|
|
break;
|
| 1357 |
|
|
}
|
| 1358 |
|
|
|
| 1359 |
|
|
case T_Times :
|
| 1360 |
|
|
{
|
| 1361 |
|
|
next_token();
|
| 1362 |
|
|
parse_unary(expr);
|
| 1363 |
|
|
subexpr.op = CdlExprOp_Indirect;
|
| 1364 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1365 |
|
|
push_subexpression(expr, subexpr);
|
| 1366 |
|
|
break;
|
| 1367 |
|
|
}
|
| 1368 |
|
|
|
| 1369 |
|
|
case T_Exclamation :
|
| 1370 |
|
|
{
|
| 1371 |
|
|
next_token();
|
| 1372 |
|
|
parse_unary(expr);
|
| 1373 |
|
|
subexpr.op = CdlExprOp_LogicalNot;
|
| 1374 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1375 |
|
|
push_subexpression(expr, subexpr);
|
| 1376 |
|
|
break;
|
| 1377 |
|
|
}
|
| 1378 |
|
|
|
| 1379 |
|
|
case T_Tilde :
|
| 1380 |
|
|
{
|
| 1381 |
|
|
next_token();
|
| 1382 |
|
|
parse_unary(expr);
|
| 1383 |
|
|
subexpr.op = CdlExprOp_BitNot;
|
| 1384 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1385 |
|
|
push_subexpression(expr, subexpr);
|
| 1386 |
|
|
break;
|
| 1387 |
|
|
}
|
| 1388 |
|
|
|
| 1389 |
|
|
case T_Questionmark:
|
| 1390 |
|
|
{
|
| 1391 |
|
|
// This is the `active' operator, it can only be applied directly to a reference.
|
| 1392 |
|
|
next_token();
|
| 1393 |
|
|
parse_unary(expr);
|
| 1394 |
|
|
CdlSubexpression& last_sub = current_subexpression(expr);
|
| 1395 |
|
|
if (CdlExprOp_Reference != last_sub.op) {
|
| 1396 |
|
|
throw CdlParseException("The active operator ? can only be applied directly to a reference.\n" +
|
| 1397 |
|
|
get_error_location());
|
| 1398 |
|
|
}
|
| 1399 |
|
|
// There is no point in creating a new subexpression object, just modify
|
| 1400 |
|
|
// the existing one. This has the useful side effect of avoiding
|
| 1401 |
|
|
// reference substitution in the eval code.
|
| 1402 |
|
|
last_sub.op = CdlExprOp_Active;
|
| 1403 |
|
|
break;
|
| 1404 |
|
|
}
|
| 1405 |
|
|
default:
|
| 1406 |
|
|
{
|
| 1407 |
|
|
throw CdlParseException("Unexpected token `" + token_to_string() + "', expecting an operand.\n" +
|
| 1408 |
|
|
get_error_location());
|
| 1409 |
|
|
}
|
| 1410 |
|
|
}
|
| 1411 |
|
|
|
| 1412 |
|
|
CYG_REPORT_RETURN();
|
| 1413 |
|
|
}
|
| 1414 |
|
|
|
| 1415 |
|
|
static void
|
| 1416 |
|
|
parse_multiply(CdlExpression expr)
|
| 1417 |
|
|
{
|
| 1418 |
|
|
CYG_REPORT_FUNCNAME("parse_multiply");
|
| 1419 |
|
|
|
| 1420 |
|
|
parse_unary(expr);
|
| 1421 |
|
|
while ((T_Times == current_token) || (T_Divide == current_token) || (T_Remainder == current_token)) {
|
| 1422 |
|
|
|
| 1423 |
|
|
CdlSubexpression subexpr;
|
| 1424 |
|
|
subexpr.op =
|
| 1425 |
|
|
(T_Times == current_token) ? CdlExprOp_Multiply :
|
| 1426 |
|
|
(T_Divide == current_token) ? CdlExprOp_Divide : CdlExprOp_Remainder;
|
| 1427 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1428 |
|
|
|
| 1429 |
|
|
next_token();
|
| 1430 |
|
|
parse_unary(expr);
|
| 1431 |
|
|
|
| 1432 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1433 |
|
|
push_subexpression(expr, subexpr);
|
| 1434 |
|
|
}
|
| 1435 |
|
|
|
| 1436 |
|
|
CYG_REPORT_RETURN();
|
| 1437 |
|
|
}
|
| 1438 |
|
|
|
| 1439 |
|
|
static void
|
| 1440 |
|
|
parse_add(CdlExpression expr)
|
| 1441 |
|
|
{
|
| 1442 |
|
|
CYG_REPORT_FUNCNAME("parse_add");
|
| 1443 |
|
|
|
| 1444 |
|
|
parse_multiply(expr);
|
| 1445 |
|
|
while ((T_Plus == current_token) ||
|
| 1446 |
|
|
(T_Minus == current_token) ||
|
| 1447 |
|
|
(T_StringConcat == current_token)) {
|
| 1448 |
|
|
|
| 1449 |
|
|
CdlSubexpression subexpr;
|
| 1450 |
|
|
subexpr.op = (T_Plus == current_token) ? CdlExprOp_Add :
|
| 1451 |
|
|
(T_Minus == current_token) ? CdlExprOp_Subtract :
|
| 1452 |
|
|
CdlExprOp_StringConcat;
|
| 1453 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1454 |
|
|
|
| 1455 |
|
|
next_token();
|
| 1456 |
|
|
parse_multiply(expr);
|
| 1457 |
|
|
|
| 1458 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1459 |
|
|
push_subexpression(expr, subexpr);
|
| 1460 |
|
|
}
|
| 1461 |
|
|
|
| 1462 |
|
|
CYG_REPORT_RETURN();
|
| 1463 |
|
|
}
|
| 1464 |
|
|
|
| 1465 |
|
|
static void
|
| 1466 |
|
|
parse_shift(CdlExpression expr)
|
| 1467 |
|
|
{
|
| 1468 |
|
|
CYG_REPORT_FUNCNAME("parse_shift");
|
| 1469 |
|
|
|
| 1470 |
|
|
parse_add(expr);
|
| 1471 |
|
|
while ((T_LeftShift == current_token) || (T_RightShift == current_token)) {
|
| 1472 |
|
|
|
| 1473 |
|
|
CdlSubexpression subexpr;
|
| 1474 |
|
|
subexpr.op = (T_LeftShift == current_token) ? CdlExprOp_LeftShift : CdlExprOp_RightShift;
|
| 1475 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1476 |
|
|
|
| 1477 |
|
|
next_token();
|
| 1478 |
|
|
parse_add(expr);
|
| 1479 |
|
|
|
| 1480 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1481 |
|
|
push_subexpression(expr, subexpr);
|
| 1482 |
|
|
}
|
| 1483 |
|
|
|
| 1484 |
|
|
CYG_REPORT_RETURN();
|
| 1485 |
|
|
}
|
| 1486 |
|
|
|
| 1487 |
|
|
static void
|
| 1488 |
|
|
parse_comparison(CdlExpression expr)
|
| 1489 |
|
|
{
|
| 1490 |
|
|
CYG_REPORT_FUNCNAME("parse_comparison");
|
| 1491 |
|
|
|
| 1492 |
|
|
parse_shift(expr);
|
| 1493 |
|
|
while ((T_LessThan == current_token) || (T_LessEqual == current_token) ||
|
| 1494 |
|
|
(T_GreaterThan == current_token) || (T_GreaterEqual == current_token)) {
|
| 1495 |
|
|
|
| 1496 |
|
|
CdlSubexpression subexpr;
|
| 1497 |
|
|
subexpr.op =
|
| 1498 |
|
|
(T_LessThan == current_token) ? CdlExprOp_LessThan :
|
| 1499 |
|
|
(T_LessEqual == current_token) ? CdlExprOp_LessEqual :
|
| 1500 |
|
|
(T_GreaterThan == current_token) ? CdlExprOp_GreaterThan : CdlExprOp_GreaterEqual;
|
| 1501 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1502 |
|
|
|
| 1503 |
|
|
next_token();
|
| 1504 |
|
|
parse_shift(expr);
|
| 1505 |
|
|
|
| 1506 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1507 |
|
|
push_subexpression(expr, subexpr);
|
| 1508 |
|
|
}
|
| 1509 |
|
|
|
| 1510 |
|
|
CYG_REPORT_RETURN();
|
| 1511 |
|
|
}
|
| 1512 |
|
|
|
| 1513 |
|
|
static void
|
| 1514 |
|
|
parse_equals(CdlExpression expr)
|
| 1515 |
|
|
{
|
| 1516 |
|
|
CYG_REPORT_FUNCNAME("parse_equals");
|
| 1517 |
|
|
|
| 1518 |
|
|
parse_comparison(expr);
|
| 1519 |
|
|
while ((T_Equal == current_token) ||
|
| 1520 |
|
|
(T_NotEqual == current_token)) {
|
| 1521 |
|
|
|
| 1522 |
|
|
CdlSubexpression subexpr;
|
| 1523 |
|
|
subexpr.op = (T_Equal == current_token) ? CdlExprOp_Equal : CdlExprOp_NotEqual;
|
| 1524 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1525 |
|
|
|
| 1526 |
|
|
next_token();
|
| 1527 |
|
|
parse_comparison(expr);
|
| 1528 |
|
|
|
| 1529 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1530 |
|
|
push_subexpression(expr, subexpr);
|
| 1531 |
|
|
}
|
| 1532 |
|
|
|
| 1533 |
|
|
CYG_REPORT_RETURN();
|
| 1534 |
|
|
}
|
| 1535 |
|
|
|
| 1536 |
|
|
static void
|
| 1537 |
|
|
parse_bitand(CdlExpression expr)
|
| 1538 |
|
|
{
|
| 1539 |
|
|
CYG_REPORT_FUNCNAME("parse_bitand");
|
| 1540 |
|
|
|
| 1541 |
|
|
parse_equals(expr);
|
| 1542 |
|
|
while (T_BitAnd == current_token) {
|
| 1543 |
|
|
|
| 1544 |
|
|
CdlSubexpression subexpr;
|
| 1545 |
|
|
subexpr.op = CdlExprOp_BitAnd;
|
| 1546 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1547 |
|
|
|
| 1548 |
|
|
next_token();
|
| 1549 |
|
|
parse_equals(expr);
|
| 1550 |
|
|
|
| 1551 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1552 |
|
|
push_subexpression(expr, subexpr);
|
| 1553 |
|
|
}
|
| 1554 |
|
|
|
| 1555 |
|
|
CYG_REPORT_RETURN();
|
| 1556 |
|
|
}
|
| 1557 |
|
|
|
| 1558 |
|
|
static void
|
| 1559 |
|
|
parse_bitxor(CdlExpression expr)
|
| 1560 |
|
|
{
|
| 1561 |
|
|
CYG_REPORT_FUNCNAME("parse_bitxor");
|
| 1562 |
|
|
|
| 1563 |
|
|
parse_bitand(expr);
|
| 1564 |
|
|
while (T_BitXor == current_token) {
|
| 1565 |
|
|
|
| 1566 |
|
|
CdlSubexpression subexpr;
|
| 1567 |
|
|
subexpr.op = CdlExprOp_BitXor;
|
| 1568 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1569 |
|
|
|
| 1570 |
|
|
next_token();
|
| 1571 |
|
|
parse_bitand(expr);
|
| 1572 |
|
|
|
| 1573 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1574 |
|
|
push_subexpression(expr, subexpr);
|
| 1575 |
|
|
}
|
| 1576 |
|
|
|
| 1577 |
|
|
CYG_REPORT_RETURN();
|
| 1578 |
|
|
}
|
| 1579 |
|
|
|
| 1580 |
|
|
static void
|
| 1581 |
|
|
parse_bitor(CdlExpression expr)
|
| 1582 |
|
|
{
|
| 1583 |
|
|
CYG_REPORT_FUNCNAME("parse_bitor");
|
| 1584 |
|
|
|
| 1585 |
|
|
parse_bitxor(expr);
|
| 1586 |
|
|
while (T_BitOr == current_token) {
|
| 1587 |
|
|
|
| 1588 |
|
|
CdlSubexpression subexpr;
|
| 1589 |
|
|
subexpr.op = CdlExprOp_BitOr;
|
| 1590 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1591 |
|
|
|
| 1592 |
|
|
next_token();
|
| 1593 |
|
|
parse_bitxor(expr);
|
| 1594 |
|
|
|
| 1595 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1596 |
|
|
push_subexpression(expr, subexpr);
|
| 1597 |
|
|
}
|
| 1598 |
|
|
|
| 1599 |
|
|
CYG_REPORT_RETURN();
|
| 1600 |
|
|
}
|
| 1601 |
|
|
|
| 1602 |
|
|
static void
|
| 1603 |
|
|
parse_and(CdlExpression expr)
|
| 1604 |
|
|
{
|
| 1605 |
|
|
CYG_REPORT_FUNCNAME("parse_and");
|
| 1606 |
|
|
parse_bitor(expr);
|
| 1607 |
|
|
while (T_And == current_token) {
|
| 1608 |
|
|
|
| 1609 |
|
|
CdlSubexpression subexpr;
|
| 1610 |
|
|
subexpr.op = CdlExprOp_And;
|
| 1611 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1612 |
|
|
|
| 1613 |
|
|
next_token();
|
| 1614 |
|
|
parse_bitor(expr);
|
| 1615 |
|
|
|
| 1616 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1617 |
|
|
push_subexpression(expr, subexpr);
|
| 1618 |
|
|
}
|
| 1619 |
|
|
|
| 1620 |
|
|
CYG_REPORT_RETURN();
|
| 1621 |
|
|
}
|
| 1622 |
|
|
|
| 1623 |
|
|
static void
|
| 1624 |
|
|
parse_or(CdlExpression expr)
|
| 1625 |
|
|
{
|
| 1626 |
|
|
CYG_REPORT_FUNCNAME("parse_or");
|
| 1627 |
|
|
|
| 1628 |
|
|
parse_and(expr);
|
| 1629 |
|
|
while (T_Or == current_token) {
|
| 1630 |
|
|
|
| 1631 |
|
|
CdlSubexpression subexpr;
|
| 1632 |
|
|
subexpr.op = CdlExprOp_Or;
|
| 1633 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1634 |
|
|
|
| 1635 |
|
|
next_token();
|
| 1636 |
|
|
parse_and(expr);
|
| 1637 |
|
|
|
| 1638 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1639 |
|
|
push_subexpression(expr, subexpr);
|
| 1640 |
|
|
}
|
| 1641 |
|
|
|
| 1642 |
|
|
CYG_REPORT_RETURN();
|
| 1643 |
|
|
}
|
| 1644 |
|
|
|
| 1645 |
|
|
static void
|
| 1646 |
|
|
parse_eqv(CdlExpression expr)
|
| 1647 |
|
|
{
|
| 1648 |
|
|
CYG_REPORT_FUNCNAME("parse_eqv");
|
| 1649 |
|
|
|
| 1650 |
|
|
parse_or(expr);
|
| 1651 |
|
|
while ((T_Xor == current_token) || (T_Eqv == current_token)) {
|
| 1652 |
|
|
|
| 1653 |
|
|
CdlSubexpression subexpr;
|
| 1654 |
|
|
subexpr.op = (T_Xor == current_token) ? CdlExprOp_Xor : CdlExprOp_Eqv;
|
| 1655 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1656 |
|
|
|
| 1657 |
|
|
next_token();
|
| 1658 |
|
|
parse_or(expr);
|
| 1659 |
|
|
|
| 1660 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1661 |
|
|
push_subexpression(expr, subexpr);
|
| 1662 |
|
|
}
|
| 1663 |
|
|
|
| 1664 |
|
|
CYG_REPORT_RETURN();
|
| 1665 |
|
|
}
|
| 1666 |
|
|
|
| 1667 |
|
|
static void
|
| 1668 |
|
|
parse_implies(CdlExpression expr)
|
| 1669 |
|
|
{
|
| 1670 |
|
|
CYG_REPORT_FUNCNAME("parse_implies");
|
| 1671 |
|
|
|
| 1672 |
|
|
parse_eqv(expr);
|
| 1673 |
|
|
while (T_Implies == current_token) {
|
| 1674 |
|
|
|
| 1675 |
|
|
CdlSubexpression subexpr;
|
| 1676 |
|
|
subexpr.op = CdlExprOp_Implies;
|
| 1677 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1678 |
|
|
|
| 1679 |
|
|
next_token();
|
| 1680 |
|
|
parse_eqv(expr);
|
| 1681 |
|
|
|
| 1682 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1683 |
|
|
push_subexpression(expr, subexpr);
|
| 1684 |
|
|
}
|
| 1685 |
|
|
|
| 1686 |
|
|
CYG_REPORT_RETURN();
|
| 1687 |
|
|
}
|
| 1688 |
|
|
|
| 1689 |
|
|
static void
|
| 1690 |
|
|
parse_conditional(CdlExpression expr)
|
| 1691 |
|
|
{
|
| 1692 |
|
|
CYG_REPORT_FUNCNAME("parse_conditional");
|
| 1693 |
|
|
|
| 1694 |
|
|
parse_implies(expr);
|
| 1695 |
|
|
if (T_Questionmark == current_token) {
|
| 1696 |
|
|
CdlSubexpression subexpr;
|
| 1697 |
|
|
subexpr.op = CdlExprOp_Cond;
|
| 1698 |
|
|
subexpr.lhs_index = expr->first_subexpression;
|
| 1699 |
|
|
|
| 1700 |
|
|
next_token();
|
| 1701 |
|
|
parse_conditional(expr);
|
| 1702 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1703 |
|
|
|
| 1704 |
|
|
if (T_Colon != current_token) {
|
| 1705 |
|
|
throw CdlParseException("Expected colon in conditional expression.\n" + get_error_location());
|
| 1706 |
|
|
}
|
| 1707 |
|
|
|
| 1708 |
|
|
next_token();
|
| 1709 |
|
|
parse_conditional(expr);
|
| 1710 |
|
|
subexpr.rrhs_index = expr->first_subexpression;
|
| 1711 |
|
|
|
| 1712 |
|
|
push_subexpression(expr, subexpr);
|
| 1713 |
|
|
}
|
| 1714 |
|
|
|
| 1715 |
|
|
CYG_REPORT_RETURN();
|
| 1716 |
|
|
}
|
| 1717 |
|
|
|
| 1718 |
|
|
static void
|
| 1719 |
|
|
parse_expression(CdlExpression expr)
|
| 1720 |
|
|
{
|
| 1721 |
|
|
CYG_REPORT_FUNCNAME("parse_expression");
|
| 1722 |
|
|
|
| 1723 |
|
|
parse_conditional(expr);
|
| 1724 |
|
|
|
| 1725 |
|
|
CYG_REPORT_RETURN();
|
| 1726 |
|
|
}
|
| 1727 |
|
|
|
| 1728 |
|
|
// ----------------------------------------------------------------------------
|
| 1729 |
|
|
// The entry point.
|
| 1730 |
|
|
void
|
| 1731 |
|
|
CdlExpressionBody::continue_parse(CdlExpression expr, std::string data, int& index, CdlExprOp& token, int& token_end)
|
| 1732 |
|
|
{
|
| 1733 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::continue_parse");
|
| 1734 |
|
|
CYG_REPORT_FUNCARG1XV(expr);
|
| 1735 |
|
|
CYG_PRECONDITION_CLASSC(expr);
|
| 1736 |
|
|
CYG_PRECONDITIONC((CdlExprOp_Invalid == token) || (CdlExprOp_And == token));
|
| 1737 |
|
|
|
| 1738 |
|
|
int current_subexpr = expr->first_subexpression;
|
| 1739 |
|
|
initialise_tokenisation(data, index);
|
| 1740 |
|
|
parse_expression(expr);
|
| 1741 |
|
|
if (CdlExprOp_And == token) {
|
| 1742 |
|
|
CdlSubexpression subexpr;
|
| 1743 |
|
|
subexpr.op = CdlExprOp_And;
|
| 1744 |
|
|
subexpr.lhs_index = current_subexpr;
|
| 1745 |
|
|
subexpr.rhs_index = expr->first_subexpression;
|
| 1746 |
|
|
push_subexpression(expr, subexpr);
|
| 1747 |
|
|
}
|
| 1748 |
|
|
token = token_to_expr_op();
|
| 1749 |
|
|
index = token_start;
|
| 1750 |
|
|
token_end = current_index;
|
| 1751 |
|
|
|
| 1752 |
|
|
CYG_REPORT_RETURN();
|
| 1753 |
|
|
}
|
| 1754 |
|
|
|
| 1755 |
|
|
//}}}
|
| 1756 |
|
|
|
| 1757 |
|
|
//}}}
|
| 1758 |
|
|
//{{{ Expression Evaluation
|
| 1759 |
|
|
|
| 1760 |
|
|
// ----------------------------------------------------------------------------
|
| 1761 |
|
|
// Expression evaluation. This always happens in the context of a
|
| 1762 |
|
|
// particular toplevel. The parsed expression is held in what amounts
|
| 1763 |
|
|
// to a simple tree, so evaluation involves some recursion and a big
|
| 1764 |
|
|
// switch statement.
|
| 1765 |
|
|
|
| 1766 |
|
|
static void
|
| 1767 |
|
|
evaluate_subexpr(CdlEvalContext& context, CdlExpression expr, int subexpr_index, CdlSimpleValue& result)
|
| 1768 |
|
|
{
|
| 1769 |
|
|
CYG_REPORT_FUNCNAME("evaluate_subexpr");
|
| 1770 |
|
|
CYG_REPORT_FUNCARG2XV(expr, subexpr_index);
|
| 1771 |
|
|
CYG_ASSERTC((subexpr_index >= 0) && ((unsigned int)subexpr_index < expr->sub_expressions.size()));
|
| 1772 |
|
|
|
| 1773 |
|
|
const CdlSubexpression& subexpr = expr->sub_expressions[subexpr_index];
|
| 1774 |
|
|
switch(subexpr.op) {
|
| 1775 |
|
|
case CdlExprOp_StringConstant :
|
| 1776 |
|
|
case CdlExprOp_IntegerConstant :
|
| 1777 |
|
|
case CdlExprOp_DoubleConstant :
|
| 1778 |
|
|
{
|
| 1779 |
|
|
result = subexpr.constants;
|
| 1780 |
|
|
break;
|
| 1781 |
|
|
}
|
| 1782 |
|
|
case CdlExprOp_Function :
|
| 1783 |
|
|
{
|
| 1784 |
|
|
CdlFunction::eval(context, expr, subexpr, result);
|
| 1785 |
|
|
break;
|
| 1786 |
|
|
}
|
| 1787 |
|
|
case CdlExprOp_Reference :
|
| 1788 |
|
|
{
|
| 1789 |
|
|
// This expression may be happening in the context of a particular
|
| 1790 |
|
|
// property. If so then the destination may or may not be resolved,
|
| 1791 |
|
|
// and this is significant in the context of loading and unloading.
|
| 1792 |
|
|
// Alternatively this expression may be being evaluated inside
|
| 1793 |
|
|
// some Tcl code, with no particular context.
|
| 1794 |
|
|
CdlNode destination = 0;
|
| 1795 |
|
|
if (0 != context.property) {
|
| 1796 |
|
|
// There is a property, use the bound/unbound reference.
|
| 1797 |
|
|
destination = expr->references[subexpr.reference_index].get_destination();
|
| 1798 |
|
|
} else {
|
| 1799 |
|
|
// The destination name can be retrieved, but we still need some
|
| 1800 |
|
|
// way of resolving it.
|
| 1801 |
|
|
if (0 != context.toplevel) {
|
| 1802 |
|
|
std::string destination_name = expr->references[subexpr.reference_index].get_destination_name();
|
| 1803 |
|
|
destination = context.toplevel->lookup(destination_name);
|
| 1804 |
|
|
}
|
| 1805 |
|
|
}
|
| 1806 |
|
|
if (0 == destination) {
|
| 1807 |
|
|
// There are two ways of handling this.
|
| 1808 |
|
|
// 1) throw an eval exception, which will usually result
|
| 1809 |
|
|
// in a new conflict object
|
| 1810 |
|
|
// 2) substitute a value of 0.
|
| 1811 |
|
|
// There should already be a conflict object for an
|
| 1812 |
|
|
// unresolved reference, and having two conflicts for
|
| 1813 |
|
|
// essentially the same error is not useful. Using a value
|
| 1814 |
|
|
// of 0 allows things to continue for a bit longer. It is
|
| 1815 |
|
|
// consistent with active vs. inactive values, gives
|
| 1816 |
|
|
// basically the right result for "requires" properties,
|
| 1817 |
|
|
// and so on.
|
| 1818 |
|
|
//
|
| 1819 |
|
|
// For now option (2) has it, but this decision may be
|
| 1820 |
|
|
// reversed in future.
|
| 1821 |
|
|
result = false;
|
| 1822 |
|
|
} else {
|
| 1823 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(destination);
|
| 1824 |
|
|
if (0 == valuable) {
|
| 1825 |
|
|
// This is a serious problem, an exception is warranted.
|
| 1826 |
|
|
throw CdlEvalException("The expression references `" + destination->get_class_name() + " " +
|
| 1827 |
|
|
destination->get_name() + "' which does not have a value.");
|
| 1828 |
|
|
} else {
|
| 1829 |
|
|
CdlSimpleValue::eval_valuable(context, valuable, result);
|
| 1830 |
|
|
}
|
| 1831 |
|
|
}
|
| 1832 |
|
|
break;
|
| 1833 |
|
|
}
|
| 1834 |
|
|
case CdlExprOp_Negate :
|
| 1835 |
|
|
{
|
| 1836 |
|
|
// Unary -. Evaluate the target. If it is numeric, fine. Otherwise
|
| 1837 |
|
|
// an error is warranted.
|
| 1838 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 1839 |
|
|
if (result.has_integer_value()) {
|
| 1840 |
|
|
result.set_integer_value(-1 * result.get_integer_value());
|
| 1841 |
|
|
} else if (result.has_double_value()) {
|
| 1842 |
|
|
result.set_double_value(-1.0 * result.get_double_value());
|
| 1843 |
|
|
} else {
|
| 1844 |
|
|
throw CdlEvalException("Attempt to negate non-numeric value `" + result.get_value() + "'.");
|
| 1845 |
|
|
}
|
| 1846 |
|
|
break;
|
| 1847 |
|
|
}
|
| 1848 |
|
|
case CdlExprOp_Plus :
|
| 1849 |
|
|
{
|
| 1850 |
|
|
// Unary +. Essentially this just checks that the current value is numeric.
|
| 1851 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 1852 |
|
|
if ((!result.has_integer_value()) && (!result.has_double_value())) {
|
| 1853 |
|
|
throw CdlEvalException("Attempt to apply unary + operator to non-numeric value `" + result.get_value() + "'.");
|
| 1854 |
|
|
}
|
| 1855 |
|
|
break;
|
| 1856 |
|
|
}
|
| 1857 |
|
|
case CdlExprOp_LogicalNot :
|
| 1858 |
|
|
{
|
| 1859 |
|
|
// !x
|
| 1860 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 1861 |
|
|
if (result.get_bool_value()) {
|
| 1862 |
|
|
result = false;;
|
| 1863 |
|
|
} else {
|
| 1864 |
|
|
result = true;
|
| 1865 |
|
|
}
|
| 1866 |
|
|
result.set_value_format(CdlValueFormat_Default);
|
| 1867 |
|
|
break;
|
| 1868 |
|
|
}
|
| 1869 |
|
|
case CdlExprOp_BitNot :
|
| 1870 |
|
|
{
|
| 1871 |
|
|
// ~x. The operand must be an integer value.
|
| 1872 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 1873 |
|
|
if (result.has_integer_value()) {
|
| 1874 |
|
|
cdl_int tmp = result.get_integer_value();
|
| 1875 |
|
|
result = ~tmp;
|
| 1876 |
|
|
} else {
|
| 1877 |
|
|
throw CdlEvalException("Attempt to apply unary ~ operator to non-integer value `" + result.get_value() + "'.");
|
| 1878 |
|
|
}
|
| 1879 |
|
|
break;
|
| 1880 |
|
|
}
|
| 1881 |
|
|
case CdlExprOp_Indirect :
|
| 1882 |
|
|
{
|
| 1883 |
|
|
// *x. The operand must evaluate to a string, and that string should be
|
| 1884 |
|
|
// the name of a CdlValuable object.
|
| 1885 |
|
|
CdlNode destination = 0;
|
| 1886 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 1887 |
|
|
std::string name = result.get_value();
|
| 1888 |
|
|
|
| 1889 |
|
|
if (0 != context.toplevel) {
|
| 1890 |
|
|
destination = context.toplevel->lookup(name);
|
| 1891 |
|
|
} else {
|
| 1892 |
|
|
CYG_FAIL("This situation should probably never happen.");
|
| 1893 |
|
|
}
|
| 1894 |
|
|
|
| 1895 |
|
|
if (0 == destination) {
|
| 1896 |
|
|
throw CdlEvalException("Attempt to apply unary indirection operator * to `" + name +
|
| 1897 |
|
|
"', which is not the name of a known CDL entity.");
|
| 1898 |
|
|
} else {
|
| 1899 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(destination);
|
| 1900 |
|
|
if (0 == valuable) {
|
| 1901 |
|
|
throw CdlEvalException("Attempt to apply unary indirection operator * to `" + name +
|
| 1902 |
|
|
"', which does not have a value.");
|
| 1903 |
|
|
} else {
|
| 1904 |
|
|
CdlSimpleValue::eval_valuable(context, valuable, result);
|
| 1905 |
|
|
}
|
| 1906 |
|
|
}
|
| 1907 |
|
|
break;
|
| 1908 |
|
|
}
|
| 1909 |
|
|
case CdlExprOp_Active :
|
| 1910 |
|
|
{
|
| 1911 |
|
|
// ?x. If x is currently unresolved then default to 0.
|
| 1912 |
|
|
// See the CdlExprOp_Reference code above for a similar case.
|
| 1913 |
|
|
CdlNode destination = 0;
|
| 1914 |
|
|
if (0 != context.property) {
|
| 1915 |
|
|
destination = expr->references[subexpr.reference_index].get_destination();
|
| 1916 |
|
|
} else {
|
| 1917 |
|
|
if (0 != context.toplevel) {
|
| 1918 |
|
|
std::string destination_name = expr->references[subexpr.reference_index].get_destination_name();
|
| 1919 |
|
|
destination = context.toplevel->lookup(destination_name);
|
| 1920 |
|
|
}
|
| 1921 |
|
|
}
|
| 1922 |
|
|
|
| 1923 |
|
|
bool active = false;
|
| 1924 |
|
|
if ((0 != destination) && context.transaction->is_active(destination)) {
|
| 1925 |
|
|
active = true;
|
| 1926 |
|
|
}
|
| 1927 |
|
|
if (active) {
|
| 1928 |
|
|
result = true;
|
| 1929 |
|
|
} else {
|
| 1930 |
|
|
result = false;
|
| 1931 |
|
|
}
|
| 1932 |
|
|
break;
|
| 1933 |
|
|
}
|
| 1934 |
|
|
case CdlExprOp_Multiply :
|
| 1935 |
|
|
{
|
| 1936 |
|
|
// x * y. For now this only makes sense for numerical data,
|
| 1937 |
|
|
// but it is possible to mix and match integer and double
|
| 1938 |
|
|
// precision data.
|
| 1939 |
|
|
//
|
| 1940 |
|
|
// Strictly speaking the rhs need only be evaluated if it
|
| 1941 |
|
|
// is known that the lhs is numeric.
|
| 1942 |
|
|
CdlSimpleValue lhs;
|
| 1943 |
|
|
CdlSimpleValue rhs;
|
| 1944 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 1945 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 1946 |
|
|
if ((!(lhs.has_integer_value() || lhs.has_double_value())) ||
|
| 1947 |
|
|
(!(rhs.has_integer_value() || rhs.has_double_value()))) {
|
| 1948 |
|
|
throw CdlEvalException("Attempt to multiply non-numerical values: `" + lhs.get_value() + "' * `" +
|
| 1949 |
|
|
rhs.get_value() + "'.");
|
| 1950 |
|
|
}
|
| 1951 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 1952 |
|
|
result = lhs.get_integer_value() * rhs.get_integer_value();
|
| 1953 |
|
|
} else {
|
| 1954 |
|
|
result = lhs.get_double_value() * rhs.get_double_value();
|
| 1955 |
|
|
}
|
| 1956 |
|
|
result.set_value_format(lhs, rhs);
|
| 1957 |
|
|
break;
|
| 1958 |
|
|
}
|
| 1959 |
|
|
case CdlExprOp_Divide :
|
| 1960 |
|
|
{
|
| 1961 |
|
|
// x / y. Basically the same as multiplication, apart from a check for
|
| 1962 |
|
|
// division by zero.
|
| 1963 |
|
|
CdlSimpleValue lhs;
|
| 1964 |
|
|
CdlSimpleValue rhs;
|
| 1965 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 1966 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 1967 |
|
|
if ((!(lhs.has_integer_value() || lhs.has_double_value())) ||
|
| 1968 |
|
|
(!(rhs.has_integer_value() || rhs.has_double_value()))) {
|
| 1969 |
|
|
throw CdlEvalException("Attempt to divide non-numerical values: `" + lhs.get_value() + "' / `" +
|
| 1970 |
|
|
rhs.get_value() + "'.");
|
| 1971 |
|
|
}
|
| 1972 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 1973 |
|
|
cdl_int rhs_val = rhs.get_integer_value();
|
| 1974 |
|
|
if (0 == rhs_val) {
|
| 1975 |
|
|
throw CdlEvalException("Division by zero error: `" + lhs.get_value() + "' / `" + rhs.get_value() + "'.");
|
| 1976 |
|
|
} else {
|
| 1977 |
|
|
result = lhs.get_integer_value() / rhs_val;
|
| 1978 |
|
|
}
|
| 1979 |
|
|
} else {
|
| 1980 |
|
|
double rhs_val = rhs.get_double_value();
|
| 1981 |
|
|
if (0.0 == rhs_val) {
|
| 1982 |
|
|
throw CdlEvalException("Division by zero error: `" + lhs.get_value() + "' / `" + rhs.get_value() + "'.");
|
| 1983 |
|
|
}
|
| 1984 |
|
|
result = lhs.get_double_value() / rhs_val;
|
| 1985 |
|
|
}
|
| 1986 |
|
|
result.set_value_format(lhs, rhs);
|
| 1987 |
|
|
break;
|
| 1988 |
|
|
}
|
| 1989 |
|
|
case CdlExprOp_Remainder :
|
| 1990 |
|
|
{
|
| 1991 |
|
|
// x % y. Both operands must be integral.
|
| 1992 |
|
|
CdlSimpleValue lhs;
|
| 1993 |
|
|
CdlSimpleValue rhs;
|
| 1994 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 1995 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 1996 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 1997 |
|
|
throw CdlEvalException("Attempt to use the remainder operator on non integral data: `" +
|
| 1998 |
|
|
lhs.get_value() + "' % `" + rhs.get_value() + "'.");
|
| 1999 |
|
|
}
|
| 2000 |
|
|
cdl_int rhs_val = rhs.get_integer_value();
|
| 2001 |
|
|
if (0 == rhs_val) {
|
| 2002 |
|
|
throw CdlEvalException("Division by zero error: `" + lhs.get_value() + "' % `" + rhs.get_value() + "'.");
|
| 2003 |
|
|
}
|
| 2004 |
|
|
result = lhs.get_integer_value() % rhs_val;
|
| 2005 |
|
|
result.set_value_format(lhs, rhs);
|
| 2006 |
|
|
break;
|
| 2007 |
|
|
}
|
| 2008 |
|
|
case CdlExprOp_Add :
|
| 2009 |
|
|
{
|
| 2010 |
|
|
// x + y. For now this only makes sense for numerical data,
|
| 2011 |
|
|
// but it is possible to mix and match integer and double
|
| 2012 |
|
|
// precision data. Arguably for string data this operator
|
| 2013 |
|
|
// should mean concatenation, but it would probably be
|
| 2014 |
|
|
// safer to have a separate operator for that.
|
| 2015 |
|
|
//
|
| 2016 |
|
|
// Strictly speaking the rhs need only be evaluated if it
|
| 2017 |
|
|
// is known that the lhs is numeric.
|
| 2018 |
|
|
CdlSimpleValue lhs;
|
| 2019 |
|
|
CdlSimpleValue rhs;
|
| 2020 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2021 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2022 |
|
|
if ((!(lhs.has_integer_value() || lhs.has_double_value())) ||
|
| 2023 |
|
|
(!(rhs.has_integer_value() || rhs.has_double_value()))) {
|
| 2024 |
|
|
throw CdlEvalException("Attempt to add non-numerical values: `" + lhs.get_value() + "' + `" +
|
| 2025 |
|
|
rhs.get_value() + "'.");
|
| 2026 |
|
|
}
|
| 2027 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 2028 |
|
|
result = lhs.get_integer_value() + rhs.get_integer_value();
|
| 2029 |
|
|
} else {
|
| 2030 |
|
|
result = lhs.get_double_value() + rhs.get_double_value();
|
| 2031 |
|
|
}
|
| 2032 |
|
|
result.set_value_format(lhs, rhs);
|
| 2033 |
|
|
break;
|
| 2034 |
|
|
}
|
| 2035 |
|
|
case CdlExprOp_Subtract :
|
| 2036 |
|
|
{
|
| 2037 |
|
|
// x - y. Again only numerical data is supported for now.
|
| 2038 |
|
|
CdlSimpleValue lhs;
|
| 2039 |
|
|
CdlSimpleValue rhs;
|
| 2040 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2041 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2042 |
|
|
if ((!(lhs.has_integer_value() || lhs.has_double_value())) ||
|
| 2043 |
|
|
(!(rhs.has_integer_value() || rhs.has_double_value()))) {
|
| 2044 |
|
|
throw CdlEvalException("Attempt to subtract non-numerical values: `" + lhs.get_value() + "' - `" +
|
| 2045 |
|
|
rhs.get_value() + "'.");
|
| 2046 |
|
|
}
|
| 2047 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 2048 |
|
|
result = lhs.get_integer_value() - rhs.get_integer_value();
|
| 2049 |
|
|
} else {
|
| 2050 |
|
|
result = lhs.get_double_value() - rhs.get_double_value();
|
| 2051 |
|
|
}
|
| 2052 |
|
|
result.set_value_format(lhs, rhs);
|
| 2053 |
|
|
break;
|
| 2054 |
|
|
}
|
| 2055 |
|
|
case CdlExprOp_LeftShift :
|
| 2056 |
|
|
{
|
| 2057 |
|
|
// x << y. Both operands must be integral. For now there is no
|
| 2058 |
|
|
// check on the value of y.
|
| 2059 |
|
|
CdlSimpleValue lhs;
|
| 2060 |
|
|
CdlSimpleValue rhs;
|
| 2061 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2062 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2063 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 2064 |
|
|
throw CdlEvalException("Attempt to use the left-shift operator on non integral data: `" +
|
| 2065 |
|
|
lhs.get_value() + "' << `" + rhs.get_value() + "'.");
|
| 2066 |
|
|
}
|
| 2067 |
|
|
result = lhs.get_integer_value() << rhs.get_integer_value();
|
| 2068 |
|
|
result.set_value_format(lhs, rhs);
|
| 2069 |
|
|
break;
|
| 2070 |
|
|
}
|
| 2071 |
|
|
case CdlExprOp_RightShift :
|
| 2072 |
|
|
{
|
| 2073 |
|
|
// x >> y. Both operands must be integral. For now there is no
|
| 2074 |
|
|
// check on the value of y.
|
| 2075 |
|
|
CdlSimpleValue lhs;
|
| 2076 |
|
|
CdlSimpleValue rhs;
|
| 2077 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2078 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2079 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 2080 |
|
|
throw CdlEvalException("Attempt to use the right-shift operator on non integral data: `" +
|
| 2081 |
|
|
lhs.get_value() + "' >> `" + rhs.get_value() + "'.");
|
| 2082 |
|
|
}
|
| 2083 |
|
|
result = lhs.get_integer_value() >> rhs.get_integer_value();
|
| 2084 |
|
|
result.set_value_format(lhs, rhs);
|
| 2085 |
|
|
break;
|
| 2086 |
|
|
}
|
| 2087 |
|
|
case CdlExprOp_LessThan :
|
| 2088 |
|
|
case CdlExprOp_LessEqual :
|
| 2089 |
|
|
case CdlExprOp_GreaterThan :
|
| 2090 |
|
|
case CdlExprOp_GreaterEqual :
|
| 2091 |
|
|
{
|
| 2092 |
|
|
// x < y, and similar comparison operators. These share
|
| 2093 |
|
|
// sufficient code to warrant a common implementation. Only
|
| 2094 |
|
|
// numerical data is supported for now. These operator could
|
| 2095 |
|
|
// be interpreted as e.g. substring operations, but arguably
|
| 2096 |
|
|
// separate operators would be better for that.
|
| 2097 |
|
|
CdlSimpleValue lhs;
|
| 2098 |
|
|
CdlSimpleValue rhs;
|
| 2099 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2100 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2101 |
|
|
if ((!(lhs.has_integer_value() || lhs.has_double_value())) ||
|
| 2102 |
|
|
(!(rhs.has_integer_value() || rhs.has_double_value()))) {
|
| 2103 |
|
|
|
| 2104 |
|
|
std::string op_str =
|
| 2105 |
|
|
(CdlExprOp_LessThan == subexpr.op) ? "<" :
|
| 2106 |
|
|
(CdlExprOp_LessEqual == subexpr.op) ? "<=" :
|
| 2107 |
|
|
(CdlExprOp_GreaterThan == subexpr.op) ? ">" : ">=";
|
| 2108 |
|
|
|
| 2109 |
|
|
throw CdlEvalException("Attempt to compare non-numerical values: `" + lhs.get_value() +
|
| 2110 |
|
|
"' " + op_str + " `" + rhs.get_value() + "'.");
|
| 2111 |
|
|
}
|
| 2112 |
|
|
bool val = false;
|
| 2113 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 2114 |
|
|
cdl_int lhs_val = lhs.get_integer_value();
|
| 2115 |
|
|
cdl_int rhs_val = rhs.get_integer_value();
|
| 2116 |
|
|
val =
|
| 2117 |
|
|
(CdlExprOp_LessThan == subexpr.op) ? (lhs_val < rhs_val) :
|
| 2118 |
|
|
(CdlExprOp_LessEqual == subexpr.op) ? (lhs_val <= rhs_val) :
|
| 2119 |
|
|
(CdlExprOp_GreaterThan == subexpr.op) ? (lhs_val > rhs_val) : (lhs_val >= rhs_val);
|
| 2120 |
|
|
} else {
|
| 2121 |
|
|
double lhs_val = lhs.get_double_value();
|
| 2122 |
|
|
double rhs_val = rhs.get_double_value();
|
| 2123 |
|
|
val =
|
| 2124 |
|
|
(CdlExprOp_LessThan == subexpr.op) ? (lhs_val < rhs_val) :
|
| 2125 |
|
|
(CdlExprOp_LessEqual == subexpr.op) ? (lhs_val <= rhs_val) :
|
| 2126 |
|
|
(CdlExprOp_GreaterThan == subexpr.op) ? (lhs_val > rhs_val) : (lhs_val >= rhs_val);
|
| 2127 |
|
|
}
|
| 2128 |
|
|
result = val;
|
| 2129 |
|
|
break;
|
| 2130 |
|
|
}
|
| 2131 |
|
|
case CdlExprOp_Equal :
|
| 2132 |
|
|
{
|
| 2133 |
|
|
// x == y. For numerical data this should be a numerical comparison.
|
| 2134 |
|
|
// Otherwise a string comparison has to be used.
|
| 2135 |
|
|
bool val = false;
|
| 2136 |
|
|
CdlSimpleValue lhs;
|
| 2137 |
|
|
CdlSimpleValue rhs;
|
| 2138 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2139 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2140 |
|
|
if ((lhs.has_integer_value() || lhs.has_double_value()) &&
|
| 2141 |
|
|
(rhs.has_integer_value() || rhs.has_double_value())) {
|
| 2142 |
|
|
|
| 2143 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 2144 |
|
|
if (lhs.get_integer_value() == rhs.get_integer_value()) {
|
| 2145 |
|
|
val = true;
|
| 2146 |
|
|
} else {
|
| 2147 |
|
|
val = false;
|
| 2148 |
|
|
}
|
| 2149 |
|
|
} else {
|
| 2150 |
|
|
if (lhs.get_double_value() == rhs.get_double_value()) {
|
| 2151 |
|
|
val = true;
|
| 2152 |
|
|
} else {
|
| 2153 |
|
|
val = false;
|
| 2154 |
|
|
}
|
| 2155 |
|
|
|
| 2156 |
|
|
}
|
| 2157 |
|
|
} else {
|
| 2158 |
|
|
// At least one of the two sides is non-numerical. Do a string comparison.
|
| 2159 |
|
|
if (lhs.get_value() == rhs.get_value()) {
|
| 2160 |
|
|
val = true;
|
| 2161 |
|
|
} else {
|
| 2162 |
|
|
val = false;
|
| 2163 |
|
|
}
|
| 2164 |
|
|
}
|
| 2165 |
|
|
result = val;
|
| 2166 |
|
|
break;
|
| 2167 |
|
|
}
|
| 2168 |
|
|
case CdlExprOp_NotEqual :
|
| 2169 |
|
|
{
|
| 2170 |
|
|
// x != y. For numerical data this should be a numerical comparison.
|
| 2171 |
|
|
// Otherwise a string comparison has to be used.
|
| 2172 |
|
|
bool val = false;
|
| 2173 |
|
|
CdlSimpleValue lhs;
|
| 2174 |
|
|
CdlSimpleValue rhs;
|
| 2175 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2176 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2177 |
|
|
if ((lhs.has_integer_value() || lhs.has_double_value()) &&
|
| 2178 |
|
|
(rhs.has_integer_value() || rhs.has_double_value())) {
|
| 2179 |
|
|
|
| 2180 |
|
|
if (lhs.has_integer_value() && rhs.has_integer_value()) {
|
| 2181 |
|
|
if (lhs.get_integer_value() != rhs.get_integer_value()) {
|
| 2182 |
|
|
val = true;
|
| 2183 |
|
|
} else {
|
| 2184 |
|
|
val = false;
|
| 2185 |
|
|
}
|
| 2186 |
|
|
} else {
|
| 2187 |
|
|
if (lhs.get_double_value() != rhs.get_double_value()) {
|
| 2188 |
|
|
val = true;
|
| 2189 |
|
|
} else {
|
| 2190 |
|
|
val = false;
|
| 2191 |
|
|
}
|
| 2192 |
|
|
|
| 2193 |
|
|
}
|
| 2194 |
|
|
} else {
|
| 2195 |
|
|
// At least one of the two sides is non-numerical. Do a string comparison.
|
| 2196 |
|
|
if (lhs.get_value() != rhs.get_value()) {
|
| 2197 |
|
|
val = true;
|
| 2198 |
|
|
} else {
|
| 2199 |
|
|
val = false;
|
| 2200 |
|
|
}
|
| 2201 |
|
|
}
|
| 2202 |
|
|
result = val;
|
| 2203 |
|
|
break;
|
| 2204 |
|
|
}
|
| 2205 |
|
|
case CdlExprOp_BitAnd :
|
| 2206 |
|
|
{
|
| 2207 |
|
|
// x & y. Only integer data is supported.
|
| 2208 |
|
|
CdlSimpleValue lhs;
|
| 2209 |
|
|
CdlSimpleValue rhs;
|
| 2210 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2211 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2212 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 2213 |
|
|
throw CdlEvalException("Attempt to use the bitwise and operator on non integral data: `" +
|
| 2214 |
|
|
lhs.get_value() + "' & `" + rhs.get_value() + "'.");
|
| 2215 |
|
|
}
|
| 2216 |
|
|
result = lhs.get_integer_value() & rhs.get_integer_value();
|
| 2217 |
|
|
result.set_value_format(lhs, rhs);
|
| 2218 |
|
|
break;
|
| 2219 |
|
|
}
|
| 2220 |
|
|
case CdlExprOp_BitXor :
|
| 2221 |
|
|
{
|
| 2222 |
|
|
// x ^ y. Only integer data is supported.
|
| 2223 |
|
|
CdlSimpleValue lhs;
|
| 2224 |
|
|
CdlSimpleValue rhs;
|
| 2225 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2226 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2227 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 2228 |
|
|
throw CdlEvalException("Attempt to use the bitwise xor operator on non integral data: `" +
|
| 2229 |
|
|
lhs.get_value() + "' ^ `" + rhs.get_value() + "'.");
|
| 2230 |
|
|
}
|
| 2231 |
|
|
result = lhs.get_integer_value() ^ rhs.get_integer_value();
|
| 2232 |
|
|
result.set_value_format(lhs, rhs);
|
| 2233 |
|
|
break;
|
| 2234 |
|
|
}
|
| 2235 |
|
|
case CdlExprOp_BitOr :
|
| 2236 |
|
|
{
|
| 2237 |
|
|
// x | y. Only integer data is supported.
|
| 2238 |
|
|
CdlSimpleValue lhs;
|
| 2239 |
|
|
CdlSimpleValue rhs;
|
| 2240 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2241 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2242 |
|
|
if (!(lhs.has_integer_value() && rhs.has_integer_value())) {
|
| 2243 |
|
|
throw CdlEvalException("Attempt to use the bitwise or operator on non integral data: `" +
|
| 2244 |
|
|
lhs.get_value() + "' | `" + rhs.get_value() + "'.");
|
| 2245 |
|
|
}
|
| 2246 |
|
|
result = lhs.get_integer_value() | rhs.get_integer_value();
|
| 2247 |
|
|
result.set_value_format(lhs, rhs);
|
| 2248 |
|
|
break;
|
| 2249 |
|
|
}
|
| 2250 |
|
|
case CdlExprOp_And :
|
| 2251 |
|
|
{
|
| 2252 |
|
|
// x && y. Both sides should be interpreted as boolean values,
|
| 2253 |
|
|
// and "y" should only be evaluated if necessary.
|
| 2254 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 2255 |
|
|
if (!result.get_bool_value()) {
|
| 2256 |
|
|
result = false;
|
| 2257 |
|
|
} else {
|
| 2258 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, result);
|
| 2259 |
|
|
if (result.get_bool_value()) {
|
| 2260 |
|
|
result = true;
|
| 2261 |
|
|
} else {
|
| 2262 |
|
|
result = false;
|
| 2263 |
|
|
}
|
| 2264 |
|
|
}
|
| 2265 |
|
|
break;
|
| 2266 |
|
|
}
|
| 2267 |
|
|
case CdlExprOp_Or :
|
| 2268 |
|
|
{
|
| 2269 |
|
|
// x || y. Both sides should be interpreted as boolean values,
|
| 2270 |
|
|
// and "y" should only be evaluated if necessary.
|
| 2271 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 2272 |
|
|
if (result.get_bool_value()) {
|
| 2273 |
|
|
result = true;
|
| 2274 |
|
|
} else {
|
| 2275 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, result);
|
| 2276 |
|
|
if (result.get_bool_value()) {
|
| 2277 |
|
|
result = true;
|
| 2278 |
|
|
} else {
|
| 2279 |
|
|
result = false;
|
| 2280 |
|
|
}
|
| 2281 |
|
|
}
|
| 2282 |
|
|
break;
|
| 2283 |
|
|
}
|
| 2284 |
|
|
case CdlExprOp_Xor :
|
| 2285 |
|
|
{
|
| 2286 |
|
|
// x xor y. Both sides should be interpreted as boolean values.
|
| 2287 |
|
|
CdlSimpleValue lhs;
|
| 2288 |
|
|
CdlSimpleValue rhs;
|
| 2289 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2290 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2291 |
|
|
|
| 2292 |
|
|
bool lhs_bool = lhs.get_bool_value();
|
| 2293 |
|
|
bool rhs_bool = rhs.get_bool_value();
|
| 2294 |
|
|
if ((lhs_bool && !rhs_bool) || (!lhs_bool && rhs_bool)) {
|
| 2295 |
|
|
result = true;
|
| 2296 |
|
|
} else {
|
| 2297 |
|
|
result = false;
|
| 2298 |
|
|
}
|
| 2299 |
|
|
|
| 2300 |
|
|
break;
|
| 2301 |
|
|
}
|
| 2302 |
|
|
case CdlExprOp_Eqv :
|
| 2303 |
|
|
{
|
| 2304 |
|
|
// x eqv y. Both sides should be interpreted as boolean values.
|
| 2305 |
|
|
CdlSimpleValue lhs;
|
| 2306 |
|
|
CdlSimpleValue rhs;
|
| 2307 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2308 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2309 |
|
|
|
| 2310 |
|
|
bool lhs_bool = lhs.get_bool_value();
|
| 2311 |
|
|
bool rhs_bool = rhs.get_bool_value();
|
| 2312 |
|
|
if ((!lhs_bool && !rhs_bool) || (lhs_bool && rhs_bool)) {
|
| 2313 |
|
|
result = true;
|
| 2314 |
|
|
} else {
|
| 2315 |
|
|
result = false;
|
| 2316 |
|
|
}
|
| 2317 |
|
|
|
| 2318 |
|
|
break;
|
| 2319 |
|
|
}
|
| 2320 |
|
|
case CdlExprOp_Implies :
|
| 2321 |
|
|
{
|
| 2322 |
|
|
// x implies y. Both sides should be interpreted as boolean values.
|
| 2323 |
|
|
CdlSimpleValue lhs;
|
| 2324 |
|
|
CdlSimpleValue rhs;
|
| 2325 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2326 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2327 |
|
|
|
| 2328 |
|
|
bool lhs_bool = lhs.get_bool_value();
|
| 2329 |
|
|
bool rhs_bool = rhs.get_bool_value();
|
| 2330 |
|
|
if (!lhs_bool || rhs_bool) {
|
| 2331 |
|
|
result = true;
|
| 2332 |
|
|
} else {
|
| 2333 |
|
|
result = false;
|
| 2334 |
|
|
}
|
| 2335 |
|
|
|
| 2336 |
|
|
break;
|
| 2337 |
|
|
}
|
| 2338 |
|
|
case CdlExprOp_Cond :
|
| 2339 |
|
|
{
|
| 2340 |
|
|
// x ? a : b.
|
| 2341 |
|
|
// First evaluate the condition. Then evaluate either the second
|
| 2342 |
|
|
// or third argument, as appropriate.
|
| 2343 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, result);
|
| 2344 |
|
|
if (result.get_bool_value()) {
|
| 2345 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, result);
|
| 2346 |
|
|
} else {
|
| 2347 |
|
|
evaluate_subexpr(context, expr, subexpr.rrhs_index, result);
|
| 2348 |
|
|
}
|
| 2349 |
|
|
break;
|
| 2350 |
|
|
}
|
| 2351 |
|
|
case CdlExprOp_StringConcat :
|
| 2352 |
|
|
{
|
| 2353 |
|
|
// a . b
|
| 2354 |
|
|
CdlSimpleValue lhs;
|
| 2355 |
|
|
CdlSimpleValue rhs;
|
| 2356 |
|
|
evaluate_subexpr(context, expr, subexpr.lhs_index, lhs);
|
| 2357 |
|
|
evaluate_subexpr(context, expr, subexpr.rhs_index, rhs);
|
| 2358 |
|
|
result = lhs.get_value() + rhs.get_value();
|
| 2359 |
|
|
break;
|
| 2360 |
|
|
}
|
| 2361 |
|
|
|
| 2362 |
|
|
default:
|
| 2363 |
|
|
break;
|
| 2364 |
|
|
}
|
| 2365 |
|
|
|
| 2366 |
|
|
CYG_REPORT_RETURN();
|
| 2367 |
|
|
}
|
| 2368 |
|
|
|
| 2369 |
|
|
// ----------------------------------------------------------------------------
|
| 2370 |
|
|
void
|
| 2371 |
|
|
CdlExpressionBody::eval_internal(CdlEvalContext& context, CdlSimpleValue& result)
|
| 2372 |
|
|
{
|
| 2373 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::eval_internal)");
|
| 2374 |
|
|
CYG_REPORT_FUNCARG3XV(this, &context, &result);
|
| 2375 |
|
|
CYG_INVARIANT_THISC(CdlExpressionBody);
|
| 2376 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 2377 |
|
|
|
| 2378 |
|
|
evaluate_subexpr(context, this, first_subexpression, result);
|
| 2379 |
|
|
|
| 2380 |
|
|
CYG_REPORT_RETURN();
|
| 2381 |
|
|
}
|
| 2382 |
|
|
|
| 2383 |
|
|
void
|
| 2384 |
|
|
CdlExpressionBody::eval_subexpression(CdlEvalContext& context, int index, CdlSimpleValue& result)
|
| 2385 |
|
|
{
|
| 2386 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::eval_subexpression)");
|
| 2387 |
|
|
CYG_REPORT_FUNCARG4XV(this, &context, index, &result);
|
| 2388 |
|
|
CYG_INVARIANT_THISC(CdlExpressionBody);
|
| 2389 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 2390 |
|
|
|
| 2391 |
|
|
evaluate_subexpr(context, this, index, result);
|
| 2392 |
|
|
|
| 2393 |
|
|
CYG_REPORT_RETURN();
|
| 2394 |
|
|
}
|
| 2395 |
|
|
|
| 2396 |
|
|
//}}}
|
| 2397 |
|
|
|
| 2398 |
|
|
//{{{ CdlExpression
|
| 2399 |
|
|
|
| 2400 |
|
|
//{{{ Construction
|
| 2401 |
|
|
|
| 2402 |
|
|
// ----------------------------------------------------------------------------
|
| 2403 |
|
|
// Ordinary expressions.
|
| 2404 |
|
|
//
|
| 2405 |
|
|
// The default constructor is private and does very little. Expressions
|
| 2406 |
|
|
// are created primarily by means of the parse() member function. There
|
| 2407 |
|
|
// is an argument for having constructors that take the same arguments
|
| 2408 |
|
|
// as the parse() member functions and relying on exception handling,
|
| 2409 |
|
|
// but that gets tricky for goal expressions and continue_parse().
|
| 2410 |
|
|
//
|
| 2411 |
|
|
// The copy constructor is protected and is used when creating e.g.
|
| 2412 |
|
|
// a default_value property object, which inherits from the ordinary
|
| 2413 |
|
|
// expression class. Again it might be better to do the parsing in
|
| 2414 |
|
|
// the constructor itself.
|
| 2415 |
|
|
//
|
| 2416 |
|
|
// The assignment operator is private and illegal.
|
| 2417 |
|
|
|
| 2418 |
|
|
CdlExpressionBody::CdlExpressionBody()
|
| 2419 |
|
|
{
|
| 2420 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression:: default constructor");
|
| 2421 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 2422 |
|
|
|
| 2423 |
|
|
expression_string = "";
|
| 2424 |
|
|
first_subexpression = -1;
|
| 2425 |
|
|
|
| 2426 |
|
|
cdlexpressionbody_cookie = CdlExpressionBody_Magic;
|
| 2427 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 2428 |
|
|
|
| 2429 |
|
|
CYG_POSTCONDITION_THISC();
|
| 2430 |
|
|
CYG_REPORT_RETURN();
|
| 2431 |
|
|
}
|
| 2432 |
|
|
|
| 2433 |
|
|
CdlExpressionBody::CdlExpressionBody(const CdlExpressionBody& original)
|
| 2434 |
|
|
{
|
| 2435 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression:: copy constructor");
|
| 2436 |
|
|
CYG_REPORT_FUNCARG2XV(this, &original);
|
| 2437 |
|
|
CYG_INVARIANT_CLASSOC(CdlExpressionBody, original);
|
| 2438 |
|
|
|
| 2439 |
|
|
// Sub-expressions are simple structs, so this should result in a bit-wise
|
| 2440 |
|
|
// copy of each vector element
|
| 2441 |
|
|
sub_expressions = original.sub_expressions;
|
| 2442 |
|
|
|
| 2443 |
|
|
// Simple scalar
|
| 2444 |
|
|
first_subexpression = original.first_subexpression;
|
| 2445 |
|
|
|
| 2446 |
|
|
// The CdlReference class has a valid copy constructor and assignment
|
| 2447 |
|
|
// operator, provided that the reference is not yet bound. This should
|
| 2448 |
|
|
// be true when this copy constructor gets invoked, after parsing
|
| 2449 |
|
|
// and during the construction of a derived property object.
|
| 2450 |
|
|
references = original.references;
|
| 2451 |
|
|
expression_string = original.expression_string;
|
| 2452 |
|
|
|
| 2453 |
|
|
cdlexpressionbody_cookie = CdlExpressionBody_Magic;
|
| 2454 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 2455 |
|
|
|
| 2456 |
|
|
CYG_POSTCONDITION_THISC();
|
| 2457 |
|
|
CYG_REPORT_RETURN();
|
| 2458 |
|
|
}
|
| 2459 |
|
|
|
| 2460 |
|
|
//}}}
|
| 2461 |
|
|
//{{{ check_this()
|
| 2462 |
|
|
|
| 2463 |
|
|
// ----------------------------------------------------------------------------
|
| 2464 |
|
|
// check_this(). Expression objects can exist before any parsing has
|
| 2465 |
|
|
// happened, not to mention in the middle of parsing. The
|
| 2466 |
|
|
// first_subexpression field can be used to detect this.
|
| 2467 |
|
|
|
| 2468 |
|
|
bool
|
| 2469 |
|
|
CdlExpressionBody::check_this(cyg_assert_class_zeal zeal) const
|
| 2470 |
|
|
{
|
| 2471 |
|
|
if (CdlExpressionBody_Magic != cdlexpressionbody_cookie) {
|
| 2472 |
|
|
return false;
|
| 2473 |
|
|
}
|
| 2474 |
|
|
CYGDBG_MEMLEAK_CHECKTHIS();
|
| 2475 |
|
|
|
| 2476 |
|
|
if (-1 == first_subexpression) {
|
| 2477 |
|
|
return true;
|
| 2478 |
|
|
}
|
| 2479 |
|
|
|
| 2480 |
|
|
switch(zeal) {
|
| 2481 |
|
|
case cyg_system_test :
|
| 2482 |
|
|
case cyg_extreme :
|
| 2483 |
|
|
case cyg_thorough :
|
| 2484 |
|
|
{
|
| 2485 |
|
|
for (std::vector<CdlReference>::const_iterator i = references.begin(); i != references.end(); i++) {
|
| 2486 |
|
|
if (!i->check_this(cyg_quick)) {
|
| 2487 |
|
|
return false;
|
| 2488 |
|
|
}
|
| 2489 |
|
|
}
|
| 2490 |
|
|
}
|
| 2491 |
|
|
case cyg_quick :
|
| 2492 |
|
|
if ((unsigned)first_subexpression >= sub_expressions.size()) {
|
| 2493 |
|
|
return false;
|
| 2494 |
|
|
}
|
| 2495 |
|
|
case cyg_trivial :
|
| 2496 |
|
|
case cyg_none :
|
| 2497 |
|
|
break;
|
| 2498 |
|
|
}
|
| 2499 |
|
|
|
| 2500 |
|
|
return true;
|
| 2501 |
|
|
}
|
| 2502 |
|
|
|
| 2503 |
|
|
//}}}
|
| 2504 |
|
|
//{{{ Destruction
|
| 2505 |
|
|
|
| 2506 |
|
|
CdlExpressionBody::~CdlExpressionBody()
|
| 2507 |
|
|
{
|
| 2508 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::destructor");
|
| 2509 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 2510 |
|
|
CYG_PRECONDITION_THISC();
|
| 2511 |
|
|
|
| 2512 |
|
|
cdlexpressionbody_cookie = CdlExpressionBody_Invalid;
|
| 2513 |
|
|
first_subexpression = -1;
|
| 2514 |
|
|
sub_expressions.clear();
|
| 2515 |
|
|
expression_string = "";
|
| 2516 |
|
|
|
| 2517 |
|
|
// This assumes that all references have been unbound already by
|
| 2518 |
|
|
// higher-level destructors.
|
| 2519 |
|
|
references.clear();
|
| 2520 |
|
|
|
| 2521 |
|
|
CYGDBG_MEMLEAK_DESTRUCTOR();
|
| 2522 |
|
|
|
| 2523 |
|
|
CYG_REPORT_RETURN();
|
| 2524 |
|
|
}
|
| 2525 |
|
|
|
| 2526 |
|
|
//}}}
|
| 2527 |
|
|
//{{{ Parsing - exported interface
|
| 2528 |
|
|
|
| 2529 |
|
|
// ----------------------------------------------------------------------------
|
| 2530 |
|
|
// parse(string) invokes parse(string, ...) and checks that the expression
|
| 2531 |
|
|
// has terminated with EOD. Parsing of list expressions etc. can terminate
|
| 2532 |
|
|
// with some other token.
|
| 2533 |
|
|
//
|
| 2534 |
|
|
// parse(string, ...) allocates the expression object and invokes
|
| 2535 |
|
|
// continue_parse().
|
| 2536 |
|
|
//
|
| 2537 |
|
|
// continue_parse() is supposed to do all the hard work.
|
| 2538 |
|
|
|
| 2539 |
|
|
CdlExpression
|
| 2540 |
|
|
CdlExpressionBody::parse(std::string data)
|
| 2541 |
|
|
{
|
| 2542 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlExpression::parse", "result %p");
|
| 2543 |
|
|
|
| 2544 |
|
|
CdlExpression result = 0;
|
| 2545 |
|
|
int index = 0;
|
| 2546 |
|
|
CdlExprOp next_op = CdlExprOp_Invalid;
|
| 2547 |
|
|
int end_index;
|
| 2548 |
|
|
|
| 2549 |
|
|
result = parse(data, index, next_op, end_index);
|
| 2550 |
|
|
|
| 2551 |
|
|
// Either there has already been a parsing or out-of-memory
|
| 2552 |
|
|
// exception, or we should be at the end of the expression string.
|
| 2553 |
|
|
if (CdlExprOp_EOD != next_op) {
|
| 2554 |
|
|
delete result;
|
| 2555 |
|
|
throw CdlParseException("Unexpected data at end of expression.\n" + get_error_location());
|
| 2556 |
|
|
}
|
| 2557 |
|
|
|
| 2558 |
|
|
// Keep a copy of the original string for diagnostics purposes.
|
| 2559 |
|
|
result->expression_string = data;
|
| 2560 |
|
|
|
| 2561 |
|
|
CYG_REPORT_RETVAL(result);
|
| 2562 |
|
|
return result;
|
| 2563 |
|
|
}
|
| 2564 |
|
|
|
| 2565 |
|
|
CdlExpression
|
| 2566 |
|
|
CdlExpressionBody::parse(std::string data, int& index, CdlExprOp& next_token, int& token_end)
|
| 2567 |
|
|
{
|
| 2568 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlExpression::parse", "result %d");
|
| 2569 |
|
|
|
| 2570 |
|
|
CdlExpression result = new CdlExpressionBody;
|
| 2571 |
|
|
|
| 2572 |
|
|
try {
|
| 2573 |
|
|
continue_parse(result, data, index, next_token, token_end);
|
| 2574 |
|
|
}
|
| 2575 |
|
|
catch (...) {
|
| 2576 |
|
|
delete result;
|
| 2577 |
|
|
throw;
|
| 2578 |
|
|
}
|
| 2579 |
|
|
|
| 2580 |
|
|
CYG_REPORT_RETVAL(result);
|
| 2581 |
|
|
return result;
|
| 2582 |
|
|
}
|
| 2583 |
|
|
|
| 2584 |
|
|
//}}}
|
| 2585 |
|
|
//{{{ update()
|
| 2586 |
|
|
|
| 2587 |
|
|
// ----------------------------------------------------------------------------
|
| 2588 |
|
|
// There has been a change in the toplevel which involves entities being
|
| 2589 |
|
|
// created or destroyed, and reference resolution is required.
|
| 2590 |
|
|
|
| 2591 |
|
|
bool
|
| 2592 |
|
|
CdlExpressionBody::update(CdlTransaction transaction, CdlNode source, CdlProperty source_prop, CdlNode dest, CdlUpdate change)
|
| 2593 |
|
|
{
|
| 2594 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlExpression::update", "result %d");
|
| 2595 |
|
|
CYG_REPORT_FUNCARG6XV(this, transaction, source, source_prop, dest, change);
|
| 2596 |
|
|
CYG_PRECONDITION_THISC();
|
| 2597 |
|
|
CYG_PRECONDITION_CLASSC(source);
|
| 2598 |
|
|
CYG_PRECONDITION_CLASSC(source_prop);
|
| 2599 |
|
|
|
| 2600 |
|
|
CdlToplevel toplevel = source->get_toplevel();
|
| 2601 |
|
|
bool result = false;
|
| 2602 |
|
|
std::vector<CdlReference>::iterator ref_i;
|
| 2603 |
|
|
|
| 2604 |
|
|
switch(change) {
|
| 2605 |
|
|
case CdlUpdate_Loaded:
|
| 2606 |
|
|
{
|
| 2607 |
|
|
// The source package has just been loaded. Try to resolve every
|
| 2608 |
|
|
// reference, creating CdlConflict objects where necessary.
|
| 2609 |
|
|
CYG_ASSERTC(0 == dest);
|
| 2610 |
|
|
for (ref_i = references.begin(); ref_i != references.end(); ref_i++) {
|
| 2611 |
|
|
dest = toplevel->lookup(ref_i->get_destination_name());
|
| 2612 |
|
|
if (0 == dest) {
|
| 2613 |
|
|
CdlConflict_UnresolvedBody::make(transaction, source, source_prop, ref_i->get_destination_name());
|
| 2614 |
|
|
} else {
|
| 2615 |
|
|
ref_i->bind(source, source_prop, dest);
|
| 2616 |
|
|
}
|
| 2617 |
|
|
}
|
| 2618 |
|
|
result = true;
|
| 2619 |
|
|
break;
|
| 2620 |
|
|
}
|
| 2621 |
|
|
|
| 2622 |
|
|
case CdlUpdate_Unloading:
|
| 2623 |
|
|
{
|
| 2624 |
|
|
// The source package is being unloaded. Unbind all currently bound references.
|
| 2625 |
|
|
// Also destroy any unresolved conflicts.
|
| 2626 |
|
|
CYG_ASSERTC(0 == dest);
|
| 2627 |
|
|
for (ref_i = references.begin(); ref_i != references.end(); ref_i++) {
|
| 2628 |
|
|
dest = ref_i->get_destination();
|
| 2629 |
|
|
if (0 != dest) {
|
| 2630 |
|
|
ref_i->unbind(source, source_prop);
|
| 2631 |
|
|
}
|
| 2632 |
|
|
}
|
| 2633 |
|
|
result = true;
|
| 2634 |
|
|
break;
|
| 2635 |
|
|
}
|
| 2636 |
|
|
|
| 2637 |
|
|
case CdlUpdate_Created :
|
| 2638 |
|
|
{
|
| 2639 |
|
|
|
| 2640 |
|
|
// A previously unresolved reference can now be resolved.
|
| 2641 |
|
|
// It is necessary to search the vector for an unresolved
|
| 2642 |
|
|
// reference with the desired name, and do the binding.
|
| 2643 |
|
|
// This search may fail in the case of list expressions.
|
| 2644 |
|
|
CYG_ASSERT_CLASSC(dest);
|
| 2645 |
|
|
std::string dest_name = dest->get_name();
|
| 2646 |
|
|
for (ref_i = references.begin(); !result && (ref_i != references.end()); ref_i++) {
|
| 2647 |
|
|
if ((dest_name == ref_i->get_destination_name()) && (0 == ref_i->get_destination())) {
|
| 2648 |
|
|
ref_i->bind(source, source_prop, dest);
|
| 2649 |
|
|
result = true;
|
| 2650 |
|
|
|
| 2651 |
|
|
std::vector<CdlConflict> conflicts;
|
| 2652 |
|
|
std::vector<CdlConflict>::iterator conf_i;
|
| 2653 |
|
|
transaction->get_structural_conflicts(source, source_prop, &CdlConflict_UnresolvedBody::test, conflicts);
|
| 2654 |
|
|
for (conf_i = conflicts.begin(); conf_i != conflicts.end(); conf_i++) {
|
| 2655 |
|
|
CdlConflict_Unresolved real_conf = dynamic_cast<CdlConflict_Unresolved>(*conf_i);
|
| 2656 |
|
|
CYG_ASSERTC(0 != real_conf);
|
| 2657 |
|
|
if (dest_name == real_conf->get_target_name()) {
|
| 2658 |
|
|
transaction->clear_conflict(real_conf);
|
| 2659 |
|
|
break;
|
| 2660 |
|
|
}
|
| 2661 |
|
|
}
|
| 2662 |
|
|
CYG_ASSERTC(conf_i != conflicts.end());
|
| 2663 |
|
|
}
|
| 2664 |
|
|
}
|
| 2665 |
|
|
break;
|
| 2666 |
|
|
}
|
| 2667 |
|
|
|
| 2668 |
|
|
case CdlUpdate_Destroyed :
|
| 2669 |
|
|
{
|
| 2670 |
|
|
// A previously resolved reference is about to become illegal.
|
| 2671 |
|
|
// Search the vector for a resolved reference object matching
|
| 2672 |
|
|
// the destination, and unbind it. Also create a conflict
|
| 2673 |
|
|
// object. The search can fail in the case of list expressions
|
| 2674 |
|
|
CYG_ASSERT_CLASSC(dest);
|
| 2675 |
|
|
for (ref_i = references.begin(); !result && (ref_i != references.end()); ref_i++) {
|
| 2676 |
|
|
if (dest == ref_i->get_destination()) {
|
| 2677 |
|
|
ref_i->unbind(source, source_prop);
|
| 2678 |
|
|
CdlConflict_UnresolvedBody::make(transaction, source, source_prop, ref_i->get_destination_name());
|
| 2679 |
|
|
result = true;
|
| 2680 |
|
|
}
|
| 2681 |
|
|
}
|
| 2682 |
|
|
break;
|
| 2683 |
|
|
}
|
| 2684 |
|
|
|
| 2685 |
|
|
default :
|
| 2686 |
|
|
CYG_FAIL("Illegal change type passed to CdlExpression::update");
|
| 2687 |
|
|
break;
|
| 2688 |
|
|
}
|
| 2689 |
|
|
|
| 2690 |
|
|
CYG_REPORT_RETVAL(result);
|
| 2691 |
|
|
return result;
|
| 2692 |
|
|
}
|
| 2693 |
|
|
|
| 2694 |
|
|
//}}}
|
| 2695 |
|
|
//{{{ Evaluation
|
| 2696 |
|
|
|
| 2697 |
|
|
// ----------------------------------------------------------------------------
|
| 2698 |
|
|
// Expression evaluation. At the end of the day everything filters through
|
| 2699 |
|
|
// to eval_internal() which should all the hard work.
|
| 2700 |
|
|
//
|
| 2701 |
|
|
// The eval() member function handles EvalException conflicts. The
|
| 2702 |
|
|
// eval_internal() member function does not, and is used for list
|
| 2703 |
|
|
// and goal expressions as well.
|
| 2704 |
|
|
|
| 2705 |
|
|
void
|
| 2706 |
|
|
CdlExpressionBody::eval(CdlEvalContext& context, CdlSimpleValue& result)
|
| 2707 |
|
|
{
|
| 2708 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::eval");
|
| 2709 |
|
|
|
| 2710 |
|
|
try {
|
| 2711 |
|
|
|
| 2712 |
|
|
eval_internal(context, result);
|
| 2713 |
|
|
|
| 2714 |
|
|
// Evaluation has succeeded, so if there was an EvalException
|
| 2715 |
|
|
// conflict get rid of it. This can only happen in the context
|
| 2716 |
|
|
// of a transaction.
|
| 2717 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 2718 |
|
|
context.transaction->clear_conflicts(context.node, context.property, &CdlConflict_EvalExceptionBody::test);
|
| 2719 |
|
|
}
|
| 2720 |
|
|
|
| 2721 |
|
|
} catch(CdlEvalException e) {
|
| 2722 |
|
|
|
| 2723 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 2724 |
|
|
|
| 2725 |
|
|
CdlConflict conflict = context.transaction->get_conflict(context.node, context.property,
|
| 2726 |
|
|
&CdlConflict_EvalExceptionBody::test);
|
| 2727 |
|
|
if (0 == conflict) {
|
| 2728 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 2729 |
|
|
} else {
|
| 2730 |
|
|
|
| 2731 |
|
|
CdlConflict_EvalException eval_conf = dynamic_cast<CdlConflict_EvalException>(conflict);
|
| 2732 |
|
|
CYG_ASSERTC(0 != eval_conf);
|
| 2733 |
|
|
if (eval_conf->get_explanation() != e.get_message()) {
|
| 2734 |
|
|
|
| 2735 |
|
|
// Replace the conflict object. That way higher level code gets informed
|
| 2736 |
|
|
// there has been a change.
|
| 2737 |
|
|
context.transaction->clear_conflict(conflict);
|
| 2738 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 2739 |
|
|
}
|
| 2740 |
|
|
}
|
| 2741 |
|
|
}
|
| 2742 |
|
|
|
| 2743 |
|
|
throw;
|
| 2744 |
|
|
}
|
| 2745 |
|
|
}
|
| 2746 |
|
|
|
| 2747 |
|
|
//}}}
|
| 2748 |
|
|
//{{{ Misc
|
| 2749 |
|
|
|
| 2750 |
|
|
// ----------------------------------------------------------------------------
|
| 2751 |
|
|
|
| 2752 |
|
|
std::string
|
| 2753 |
|
|
CdlExpressionBody::get_original_string() const
|
| 2754 |
|
|
{
|
| 2755 |
|
|
CYG_REPORT_FUNCNAME("CdlExpression::get_original_string");
|
| 2756 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 2757 |
|
|
CYG_PRECONDITION_THISC();
|
| 2758 |
|
|
|
| 2759 |
|
|
CYG_REPORT_RETURN();
|
| 2760 |
|
|
return expression_string;
|
| 2761 |
|
|
}
|
| 2762 |
|
|
|
| 2763 |
|
|
//}}}
|
| 2764 |
|
|
|
| 2765 |
|
|
//}}}
|
| 2766 |
|
|
//{{{ CdlListExpression
|
| 2767 |
|
|
|
| 2768 |
|
|
//{{{ Construction
|
| 2769 |
|
|
|
| 2770 |
|
|
// ----------------------------------------------------------------------------
|
| 2771 |
|
|
// The normal sequence of events is:
|
| 2772 |
|
|
//
|
| 2773 |
|
|
// 1) higher level code calls CdlListExpressionbody::parse()
|
| 2774 |
|
|
// 2) this static member creates a new and empty list expression object.
|
| 2775 |
|
|
// The constructor need not do very much.
|
| 2776 |
|
|
// 3) the parse() member then fills in the newly created object
|
| 2777 |
|
|
// 4) the object is returned to higher-level code
|
| 2778 |
|
|
// 5) usually the list expression will now become part of
|
| 2779 |
|
|
// a property object by means of a copy constructor.
|
| 2780 |
|
|
//
|
| 2781 |
|
|
// The only complication is that a list expression contains a vector
|
| 2782 |
|
|
// of CdlExpression pointers which must be freed during the destructor.
|
| 2783 |
|
|
// The copy constructor does not make duplicates of the individual
|
| 2784 |
|
|
// expression objects, instead ownership is transferred.
|
| 2785 |
|
|
|
| 2786 |
|
|
CdlListExpressionBody::CdlListExpressionBody()
|
| 2787 |
|
|
{
|
| 2788 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression:: default constructor");
|
| 2789 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 2790 |
|
|
|
| 2791 |
|
|
expression_string = "";
|
| 2792 |
|
|
|
| 2793 |
|
|
cdllistexpressionbody_cookie = CdlListExpressionBody_Magic;
|
| 2794 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 2795 |
|
|
|
| 2796 |
|
|
CYG_POSTCONDITION_THISC();
|
| 2797 |
|
|
CYG_REPORT_RETURN();
|
| 2798 |
|
|
}
|
| 2799 |
|
|
|
| 2800 |
|
|
CdlListExpressionBody::CdlListExpressionBody(const CdlListExpressionBody& original)
|
| 2801 |
|
|
{
|
| 2802 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression:: copy constructor");
|
| 2803 |
|
|
CYG_REPORT_FUNCARG2XV(this, &original);
|
| 2804 |
|
|
CYG_INVARIANT_CLASSOC(CdlListExpressionBody, original);
|
| 2805 |
|
|
|
| 2806 |
|
|
expression_string = original.expression_string;
|
| 2807 |
|
|
|
| 2808 |
|
|
// These copy across the pointers
|
| 2809 |
|
|
data = original.data;
|
| 2810 |
|
|
ranges = original.ranges;
|
| 2811 |
|
|
|
| 2812 |
|
|
// And this clears out the pointers, but leaves the expression objects lying around
|
| 2813 |
|
|
CdlListExpression tmp = const_cast<CdlListExpression>(&original);
|
| 2814 |
|
|
tmp->data.clear();
|
| 2815 |
|
|
tmp->ranges.clear();
|
| 2816 |
|
|
|
| 2817 |
|
|
cdllistexpressionbody_cookie = CdlListExpressionBody_Magic;
|
| 2818 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 2819 |
|
|
|
| 2820 |
|
|
CYG_POSTCONDITION_THISC();
|
| 2821 |
|
|
CYG_REPORT_RETURN();
|
| 2822 |
|
|
}
|
| 2823 |
|
|
|
| 2824 |
|
|
//}}}
|
| 2825 |
|
|
//{{{ Destruction
|
| 2826 |
|
|
|
| 2827 |
|
|
CdlListExpressionBody::~CdlListExpressionBody()
|
| 2828 |
|
|
{
|
| 2829 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression:: destructor");
|
| 2830 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 2831 |
|
|
CYG_PRECONDITION_THISC();
|
| 2832 |
|
|
|
| 2833 |
|
|
cdllistexpressionbody_cookie = CdlListExpressionBody_Invalid;
|
| 2834 |
|
|
expression_string = "";
|
| 2835 |
|
|
|
| 2836 |
|
|
for (std::vector<CdlExpression>::iterator i = data.begin(); i != data.end(); i++) {
|
| 2837 |
|
|
delete *i;
|
| 2838 |
|
|
*i = 0;
|
| 2839 |
|
|
}
|
| 2840 |
|
|
for (std::vector<std::pair<CdlExpression, CdlExpression> >::iterator j = ranges.begin(); j != ranges.end(); j++) {
|
| 2841 |
|
|
delete j->first;
|
| 2842 |
|
|
delete j->second;
|
| 2843 |
|
|
j->first = 0;
|
| 2844 |
|
|
j->second = 0;
|
| 2845 |
|
|
}
|
| 2846 |
|
|
data.clear();
|
| 2847 |
|
|
ranges.clear();
|
| 2848 |
|
|
CYGDBG_MEMLEAK_DESTRUCTOR();
|
| 2849 |
|
|
|
| 2850 |
|
|
CYG_REPORT_RETURN();
|
| 2851 |
|
|
}
|
| 2852 |
|
|
|
| 2853 |
|
|
//}}}
|
| 2854 |
|
|
//{{{ check_this()
|
| 2855 |
|
|
|
| 2856 |
|
|
// ----------------------------------------------------------------------------
|
| 2857 |
|
|
bool
|
| 2858 |
|
|
CdlListExpressionBody::check_this(cyg_assert_class_zeal zeal) const
|
| 2859 |
|
|
{
|
| 2860 |
|
|
if (CdlListExpressionBody_Magic != cdllistexpressionbody_cookie) {
|
| 2861 |
|
|
return false;
|
| 2862 |
|
|
}
|
| 2863 |
|
|
CYGDBG_MEMLEAK_CHECKTHIS();
|
| 2864 |
|
|
switch(zeal) {
|
| 2865 |
|
|
case cyg_system_test :
|
| 2866 |
|
|
case cyg_extreme :
|
| 2867 |
|
|
case cyg_thorough :
|
| 2868 |
|
|
{
|
| 2869 |
|
|
for (std::vector<CdlExpression>::const_iterator i = data.begin(); i != data.end(); i++) {
|
| 2870 |
|
|
if (!(*i)->check_this(cyg_quick)) {
|
| 2871 |
|
|
return false;
|
| 2872 |
|
|
}
|
| 2873 |
|
|
}
|
| 2874 |
|
|
for (std::vector<std::pair<CdlExpression,CdlExpression> >::const_iterator j = ranges.begin();
|
| 2875 |
|
|
j != ranges.end();
|
| 2876 |
|
|
j++) {
|
| 2877 |
|
|
if (!(j->first->check_this(cyg_quick)) || !(j->second->check_this(cyg_quick))) {
|
| 2878 |
|
|
return false;
|
| 2879 |
|
|
}
|
| 2880 |
|
|
}
|
| 2881 |
|
|
}
|
| 2882 |
|
|
case cyg_quick :
|
| 2883 |
|
|
case cyg_trivial :
|
| 2884 |
|
|
case cyg_none :
|
| 2885 |
|
|
default :
|
| 2886 |
|
|
break;
|
| 2887 |
|
|
}
|
| 2888 |
|
|
|
| 2889 |
|
|
return true;
|
| 2890 |
|
|
}
|
| 2891 |
|
|
|
| 2892 |
|
|
//}}}
|
| 2893 |
|
|
//{{{ Parsing
|
| 2894 |
|
|
|
| 2895 |
|
|
// ----------------------------------------------------------------------------
|
| 2896 |
|
|
// Parsing a list expression involves repeated parsing of ordinary
|
| 2897 |
|
|
// expressions until an EOD token is reached.
|
| 2898 |
|
|
|
| 2899 |
|
|
CdlListExpression
|
| 2900 |
|
|
CdlListExpressionBody::parse(std::string data)
|
| 2901 |
|
|
{
|
| 2902 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::parse", "result %p");
|
| 2903 |
|
|
|
| 2904 |
|
|
// Allocate an expression object that can then be filled in.
|
| 2905 |
|
|
CdlListExpression result = new CdlListExpressionBody;
|
| 2906 |
|
|
|
| 2907 |
|
|
// Do the parsing in a try/catch statement to make sure the
|
| 2908 |
|
|
// allocated expression gets freed on a parse error.
|
| 2909 |
|
|
try {
|
| 2910 |
|
|
int index = 0;
|
| 2911 |
|
|
int end_index = 0;
|
| 2912 |
|
|
CdlExprOp op = CdlExprOp_Invalid;
|
| 2913 |
|
|
CdlExpression expr1 = 0;
|
| 2914 |
|
|
|
| 2915 |
|
|
do {
|
| 2916 |
|
|
// Try to parse the next expression in the list
|
| 2917 |
|
|
op = CdlExprOp_Invalid;
|
| 2918 |
|
|
expr1 = CdlExpressionBody::parse(data, index, op, end_index);
|
| 2919 |
|
|
|
| 2920 |
|
|
// There should now be a valid expression, failure would have
|
| 2921 |
|
|
// resulted in an exception.
|
| 2922 |
|
|
CYG_ASSERT_CLASSC(expr1);
|
| 2923 |
|
|
|
| 2924 |
|
|
// Allow for ranges.
|
| 2925 |
|
|
if (CdlExprOp_Range != op) {
|
| 2926 |
|
|
// A simple expression, just add it to the current data vector
|
| 2927 |
|
|
// "index" will contain the appropriate value.
|
| 2928 |
|
|
result->data.push_back(expr1);
|
| 2929 |
|
|
} else {
|
| 2930 |
|
|
// A range expression. Get the other end of the range.
|
| 2931 |
|
|
// This requires manipulating index a bit.
|
| 2932 |
|
|
CdlExpression expr2 = 0;
|
| 2933 |
|
|
index = end_index;
|
| 2934 |
|
|
op = CdlExprOp_Invalid;
|
| 2935 |
|
|
try {
|
| 2936 |
|
|
expr2 = CdlExpressionBody::parse(data, index, op, end_index);
|
| 2937 |
|
|
}
|
| 2938 |
|
|
catch (...) {
|
| 2939 |
|
|
delete expr1;
|
| 2940 |
|
|
throw;
|
| 2941 |
|
|
}
|
| 2942 |
|
|
result->ranges.push_back(std::make_pair(expr1, expr2));
|
| 2943 |
|
|
}
|
| 2944 |
|
|
} while (CdlExprOp_EOD != op);
|
| 2945 |
|
|
}
|
| 2946 |
|
|
catch (...) {
|
| 2947 |
|
|
delete result;
|
| 2948 |
|
|
throw;
|
| 2949 |
|
|
}
|
| 2950 |
|
|
|
| 2951 |
|
|
// Keep track of the original string for diagnostics purposes
|
| 2952 |
|
|
result->expression_string = data;
|
| 2953 |
|
|
|
| 2954 |
|
|
CYG_REPORT_RETVAL(result);
|
| 2955 |
|
|
return result;
|
| 2956 |
|
|
}
|
| 2957 |
|
|
|
| 2958 |
|
|
//}}}
|
| 2959 |
|
|
//{{{ update()
|
| 2960 |
|
|
|
| 2961 |
|
|
// ----------------------------------------------------------------------------
|
| 2962 |
|
|
// This code is invoked when it is necessary to update the references
|
| 2963 |
|
|
// for the list expression. There are four situations in which this
|
| 2964 |
|
|
// can happen: the package has just been loaded; the package is being
|
| 2965 |
|
|
// unloaded; a referenced target is being created; a referenced target is
|
| 2966 |
|
|
// being destroyed.
|
| 2967 |
|
|
//
|
| 2968 |
|
|
// The first two cases simply involve processing every expression that
|
| 2969 |
|
|
// makes up the overall list expression. The last two cases involve
|
| 2970 |
|
|
// searching through the expressions until an applicable one is found.
|
| 2971 |
|
|
// Note that an expression may contain multiple references to another
|
| 2972 |
|
|
// object, resulting in multiple calls to this function.
|
| 2973 |
|
|
|
| 2974 |
|
|
bool
|
| 2975 |
|
|
CdlListExpressionBody::update(CdlTransaction transact, CdlNode source, CdlProperty source_prop, CdlNode dest, CdlUpdate change)
|
| 2976 |
|
|
{
|
| 2977 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::update", "result %d");
|
| 2978 |
|
|
CYG_REPORT_FUNCARG6XV(this, transact, source, source_prop, dest, change);
|
| 2979 |
|
|
CYG_PRECONDITION_THISC();
|
| 2980 |
|
|
CYG_PRECONDITION_CLASSC(source);
|
| 2981 |
|
|
CYG_PRECONDITION_CLASSC(source_prop);
|
| 2982 |
|
|
|
| 2983 |
|
|
bool result = false;
|
| 2984 |
|
|
|
| 2985 |
|
|
if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
|
| 2986 |
|
|
|
| 2987 |
|
|
std::vector<CdlExpression>::const_iterator expr_i;
|
| 2988 |
|
|
std::vector<std::pair<CdlExpression, CdlExpression> >::const_iterator pair_i;
|
| 2989 |
|
|
|
| 2990 |
|
|
for (expr_i = data.begin(); expr_i != data.end(); expr_i++) {
|
| 2991 |
|
|
bool handled = (*expr_i)->update(transact, source, source_prop, dest, change);
|
| 2992 |
|
|
CYG_ASSERTC(handled);
|
| 2993 |
|
|
CYG_UNUSED_PARAM(bool, handled);
|
| 2994 |
|
|
}
|
| 2995 |
|
|
for (pair_i = ranges.begin(); pair_i != ranges.end(); pair_i++) {
|
| 2996 |
|
|
bool handled = pair_i->first->update(transact, source, source_prop, dest, change);
|
| 2997 |
|
|
CYG_ASSERTC(handled);
|
| 2998 |
|
|
handled = pair_i->second->update(transact, source, source_prop, dest, change);
|
| 2999 |
|
|
CYG_ASSERTC(handled);
|
| 3000 |
|
|
}
|
| 3001 |
|
|
|
| 3002 |
|
|
result = true;
|
| 3003 |
|
|
|
| 3004 |
|
|
} else {
|
| 3005 |
|
|
CYG_ASSERTC((CdlUpdate_Created == change) || (CdlUpdate_Destroyed == change));
|
| 3006 |
|
|
|
| 3007 |
|
|
std::vector<CdlExpression>::const_iterator expr_i;
|
| 3008 |
|
|
std::vector<std::pair<CdlExpression, CdlExpression> >::const_iterator pair_i;
|
| 3009 |
|
|
|
| 3010 |
|
|
for (expr_i = data.begin(); !result && (expr_i != data.end()); expr_i++) {
|
| 3011 |
|
|
result = (*expr_i)->update(transact, source, source_prop, dest, change);
|
| 3012 |
|
|
}
|
| 3013 |
|
|
for (pair_i = ranges.begin(); !result && (pair_i != ranges.end()); pair_i++) {
|
| 3014 |
|
|
result = pair_i->first->update(transact, source, source_prop, dest, change);
|
| 3015 |
|
|
if (!result) {
|
| 3016 |
|
|
result = pair_i->second->update(transact, source, source_prop, dest, change);
|
| 3017 |
|
|
}
|
| 3018 |
|
|
}
|
| 3019 |
|
|
}
|
| 3020 |
|
|
|
| 3021 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3022 |
|
|
return result;
|
| 3023 |
|
|
}
|
| 3024 |
|
|
|
| 3025 |
|
|
//}}}
|
| 3026 |
|
|
//{{{ Evaluation
|
| 3027 |
|
|
|
| 3028 |
|
|
// ----------------------------------------------------------------------------
|
| 3029 |
|
|
// Evaluation. The hard work is actually done in eval_internal()
|
| 3030 |
|
|
|
| 3031 |
|
|
void
|
| 3032 |
|
|
CdlListExpressionBody::eval(CdlEvalContext& context, CdlListValue& result)
|
| 3033 |
|
|
{
|
| 3034 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression::eval");
|
| 3035 |
|
|
CYG_REPORT_FUNCARG3XV(this, &context, &result);
|
| 3036 |
|
|
CYG_PRECONDITION_THISC();
|
| 3037 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3038 |
|
|
|
| 3039 |
|
|
this->eval_internal(context, result);
|
| 3040 |
|
|
|
| 3041 |
|
|
CYG_REPORT_RETURN();
|
| 3042 |
|
|
}
|
| 3043 |
|
|
|
| 3044 |
|
|
// ----------------------------------------------------------------------------
|
| 3045 |
|
|
// This requires evaluating each expression in the data and ranges
|
| 3046 |
|
|
// vectors and adding the result to the appropriate vector in result.
|
| 3047 |
|
|
// Various error conditions are possible.
|
| 3048 |
|
|
|
| 3049 |
|
|
void
|
| 3050 |
|
|
CdlListExpressionBody::eval_internal(CdlEvalContext& context, CdlListValue& result)
|
| 3051 |
|
|
{
|
| 3052 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression::eval_internal");
|
| 3053 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3054 |
|
|
|
| 3055 |
|
|
result.table.clear();
|
| 3056 |
|
|
result.integer_ranges.clear();
|
| 3057 |
|
|
result.double_ranges.clear();
|
| 3058 |
|
|
|
| 3059 |
|
|
CdlSimpleValue val1;
|
| 3060 |
|
|
CdlSimpleValue val2;
|
| 3061 |
|
|
|
| 3062 |
|
|
try {
|
| 3063 |
|
|
for (std::vector<CdlExpression>::const_iterator i = data.begin(); i != data.end(); i++) {
|
| 3064 |
|
|
(*i)->eval_internal(context, val1);
|
| 3065 |
|
|
if ("" != val1.get_value()) {
|
| 3066 |
|
|
result.table.push_back(val1);
|
| 3067 |
|
|
}
|
| 3068 |
|
|
}
|
| 3069 |
|
|
for (std::vector<std::pair<CdlExpression,CdlExpression> >::const_iterator j = ranges.begin(); j != ranges.end(); j++) {
|
| 3070 |
|
|
j->first->eval_internal(context, val1);
|
| 3071 |
|
|
j->second->eval_internal(context, val2);
|
| 3072 |
|
|
|
| 3073 |
|
|
if (val1.has_integer_value() && val2.has_integer_value()) {
|
| 3074 |
|
|
cdl_int x1 = val1.get_integer_value();
|
| 3075 |
|
|
cdl_int x2 = val2.get_integer_value();
|
| 3076 |
|
|
if (x1 > x2) {
|
| 3077 |
|
|
cdl_int tmp = x1;
|
| 3078 |
|
|
x1 = x2;
|
| 3079 |
|
|
x2 = tmp;
|
| 3080 |
|
|
}
|
| 3081 |
|
|
result.integer_ranges.push_back(std::make_pair(x1, x2));
|
| 3082 |
|
|
} else if (val1.has_double_value() && val2.has_double_value()) {
|
| 3083 |
|
|
double x1 = val1.get_double_value();
|
| 3084 |
|
|
double x2 = val2.get_double_value();
|
| 3085 |
|
|
if (x1 > x2) {
|
| 3086 |
|
|
double tmp = x1;
|
| 3087 |
|
|
x1 = x2;
|
| 3088 |
|
|
x2 = tmp;
|
| 3089 |
|
|
}
|
| 3090 |
|
|
result.double_ranges.push_back(std::make_pair(x1, x2));
|
| 3091 |
|
|
} else {
|
| 3092 |
|
|
throw CdlEvalException("Range expression involves non-numerical limits");
|
| 3093 |
|
|
}
|
| 3094 |
|
|
}
|
| 3095 |
|
|
|
| 3096 |
|
|
// Any problems would have resulted in an exception. If there
|
| 3097 |
|
|
// was a previous EvalExeption for this property, it is no
|
| 3098 |
|
|
// longer applicable
|
| 3099 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 3100 |
|
|
context.transaction->clear_conflicts(context.node, context.property, &CdlConflict_EvalExceptionBody::test);
|
| 3101 |
|
|
}
|
| 3102 |
|
|
|
| 3103 |
|
|
} catch(CdlEvalException e) {
|
| 3104 |
|
|
|
| 3105 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 3106 |
|
|
|
| 3107 |
|
|
CdlConflict conflict = context.transaction->get_conflict(context.node, context.property,
|
| 3108 |
|
|
&CdlConflict_EvalExceptionBody::test);
|
| 3109 |
|
|
if (0 == conflict) {
|
| 3110 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 3111 |
|
|
} else {
|
| 3112 |
|
|
CdlConflict_EvalException eval_conf = dynamic_cast<CdlConflict_EvalException>(conflict);
|
| 3113 |
|
|
CYG_ASSERTC(0 != eval_conf);
|
| 3114 |
|
|
if (eval_conf->get_explanation() != e.get_message()) {
|
| 3115 |
|
|
|
| 3116 |
|
|
// Replace the conflict object. Higher level will be informed about this.
|
| 3117 |
|
|
context.transaction->clear_conflict(conflict);
|
| 3118 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 3119 |
|
|
}
|
| 3120 |
|
|
}
|
| 3121 |
|
|
}
|
| 3122 |
|
|
|
| 3123 |
|
|
throw;
|
| 3124 |
|
|
}
|
| 3125 |
|
|
|
| 3126 |
|
|
CYG_REPORT_RETURN();
|
| 3127 |
|
|
}
|
| 3128 |
|
|
|
| 3129 |
|
|
//}}}
|
| 3130 |
|
|
//{{{ is_member()
|
| 3131 |
|
|
|
| 3132 |
|
|
// ----------------------------------------------------------------------------
|
| 3133 |
|
|
|
| 3134 |
|
|
bool
|
| 3135 |
|
|
CdlListExpressionBody::is_member(CdlEvalContext& context, CdlSimpleValue& val)
|
| 3136 |
|
|
{
|
| 3137 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::is_member (value)", "result %d");
|
| 3138 |
|
|
CYG_REPORT_FUNCARG3XV(this, &context, &val);
|
| 3139 |
|
|
CYG_PRECONDITION_THISC();
|
| 3140 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3141 |
|
|
|
| 3142 |
|
|
bool result = false;
|
| 3143 |
|
|
CdlListValue list_val;
|
| 3144 |
|
|
eval_internal(context, list_val);
|
| 3145 |
|
|
result = list_val.is_member(val);
|
| 3146 |
|
|
|
| 3147 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3148 |
|
|
return result;
|
| 3149 |
|
|
}
|
| 3150 |
|
|
|
| 3151 |
|
|
bool
|
| 3152 |
|
|
CdlListExpressionBody::is_member(CdlEvalContext& context, std::string val)
|
| 3153 |
|
|
{
|
| 3154 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::is_member (string)", "result %d");
|
| 3155 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3156 |
|
|
CYG_PRECONDITION_THISC();
|
| 3157 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3158 |
|
|
|
| 3159 |
|
|
bool result = false;
|
| 3160 |
|
|
CdlListValue list_val;
|
| 3161 |
|
|
eval_internal(context, list_val);
|
| 3162 |
|
|
result = list_val.is_member(val);
|
| 3163 |
|
|
|
| 3164 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3165 |
|
|
return result;
|
| 3166 |
|
|
}
|
| 3167 |
|
|
|
| 3168 |
|
|
bool
|
| 3169 |
|
|
CdlListExpressionBody::is_member(CdlEvalContext& context, cdl_int val)
|
| 3170 |
|
|
{
|
| 3171 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::is_member (int)", "result %d");
|
| 3172 |
|
|
CYG_REPORT_FUNCARG3XV(this, &context, (int) val);
|
| 3173 |
|
|
CYG_PRECONDITION_THISC();
|
| 3174 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3175 |
|
|
|
| 3176 |
|
|
bool result = false;
|
| 3177 |
|
|
CdlListValue list_val;
|
| 3178 |
|
|
eval_internal(context, list_val);
|
| 3179 |
|
|
result = list_val.is_member(val);
|
| 3180 |
|
|
|
| 3181 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3182 |
|
|
return result;
|
| 3183 |
|
|
}
|
| 3184 |
|
|
|
| 3185 |
|
|
bool
|
| 3186 |
|
|
CdlListExpressionBody::is_member(CdlEvalContext& context, double val)
|
| 3187 |
|
|
{
|
| 3188 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlListExpression::is_member (double)", "result %d");
|
| 3189 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3190 |
|
|
CYG_PRECONDITION_THISC();
|
| 3191 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3192 |
|
|
|
| 3193 |
|
|
bool result = false;
|
| 3194 |
|
|
CdlListValue list_val;
|
| 3195 |
|
|
eval_internal(context, list_val);
|
| 3196 |
|
|
result = list_val.is_member(val);
|
| 3197 |
|
|
|
| 3198 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3199 |
|
|
return result;
|
| 3200 |
|
|
}
|
| 3201 |
|
|
|
| 3202 |
|
|
//}}}
|
| 3203 |
|
|
//{{{ Misc
|
| 3204 |
|
|
|
| 3205 |
|
|
// ----------------------------------------------------------------------------
|
| 3206 |
|
|
|
| 3207 |
|
|
std::string
|
| 3208 |
|
|
CdlListExpressionBody::get_original_string() const
|
| 3209 |
|
|
{
|
| 3210 |
|
|
CYG_REPORT_FUNCNAME("CdlListExpression::get_original_string");
|
| 3211 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 3212 |
|
|
CYG_PRECONDITION_THISC();
|
| 3213 |
|
|
|
| 3214 |
|
|
CYG_REPORT_RETURN();
|
| 3215 |
|
|
return expression_string;
|
| 3216 |
|
|
}
|
| 3217 |
|
|
|
| 3218 |
|
|
//}}}
|
| 3219 |
|
|
|
| 3220 |
|
|
//}}}
|
| 3221 |
|
|
//{{{ CdlGoalExpression
|
| 3222 |
|
|
|
| 3223 |
|
|
// ----------------------------------------------------------------------------
|
| 3224 |
|
|
// Constructors etc. are pretty much as per ordinary and list
|
| 3225 |
|
|
// expressions. Most of the work is done in the private base class.
|
| 3226 |
|
|
|
| 3227 |
|
|
CdlGoalExpressionBody::CdlGoalExpressionBody()
|
| 3228 |
|
|
: CdlExpressionBody()
|
| 3229 |
|
|
{
|
| 3230 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression::default_constructor");
|
| 3231 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 3232 |
|
|
|
| 3233 |
|
|
expression_string = "";
|
| 3234 |
|
|
cdlgoalexpressionbody_cookie = CdlGoalExpressionBody_Magic;
|
| 3235 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 3236 |
|
|
|
| 3237 |
|
|
CYG_POSTCONDITION_THISC();
|
| 3238 |
|
|
CYG_REPORT_RETURN();
|
| 3239 |
|
|
}
|
| 3240 |
|
|
|
| 3241 |
|
|
CdlGoalExpressionBody::CdlGoalExpressionBody(const CdlGoalExpressionBody& original)
|
| 3242 |
|
|
: CdlExpressionBody(original)
|
| 3243 |
|
|
{
|
| 3244 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression:: copy constructor");
|
| 3245 |
|
|
CYG_REPORT_FUNCARG2XV(this, &original);
|
| 3246 |
|
|
CYG_INVARIANT_CLASSOC(CdlGoalExpressionBody, original);
|
| 3247 |
|
|
|
| 3248 |
|
|
expression_string = original.expression_string;
|
| 3249 |
|
|
cdlgoalexpressionbody_cookie = CdlGoalExpressionBody_Magic;
|
| 3250 |
|
|
CYGDBG_MEMLEAK_CONSTRUCTOR();
|
| 3251 |
|
|
|
| 3252 |
|
|
CYG_POSTCONDITION_THISC();
|
| 3253 |
|
|
CYG_REPORT_RETURN();
|
| 3254 |
|
|
}
|
| 3255 |
|
|
|
| 3256 |
|
|
CdlGoalExpressionBody::~CdlGoalExpressionBody()
|
| 3257 |
|
|
{
|
| 3258 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression:: destructor");
|
| 3259 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 3260 |
|
|
CYG_PRECONDITION_THISC();
|
| 3261 |
|
|
|
| 3262 |
|
|
cdlgoalexpressionbody_cookie = CdlGoalExpressionBody_Invalid;
|
| 3263 |
|
|
expression_string = "";
|
| 3264 |
|
|
CYGDBG_MEMLEAK_DESTRUCTOR();
|
| 3265 |
|
|
|
| 3266 |
|
|
CYG_REPORT_RETURN();
|
| 3267 |
|
|
}
|
| 3268 |
|
|
|
| 3269 |
|
|
// ----------------------------------------------------------------------------
|
| 3270 |
|
|
// Parsing. A goal expression acts a bit like a list expression with
|
| 3271 |
|
|
// implicit && operators between the various expressions. It could be
|
| 3272 |
|
|
// implemented as a vector of expressions (which might make diagnostics
|
| 3273 |
|
|
// easier) but it is almost as easy to derive a goal expression from
|
| 3274 |
|
|
// an ordinary one.
|
| 3275 |
|
|
|
| 3276 |
|
|
CdlGoalExpression
|
| 3277 |
|
|
CdlGoalExpressionBody::parse(std::string data)
|
| 3278 |
|
|
{
|
| 3279 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlGoalExpression::parse", "result %p");
|
| 3280 |
|
|
|
| 3281 |
|
|
CdlGoalExpression result = new CdlGoalExpressionBody;
|
| 3282 |
|
|
|
| 3283 |
|
|
try {
|
| 3284 |
|
|
int index = 0;
|
| 3285 |
|
|
CdlExprOp op = CdlExprOp_Invalid;
|
| 3286 |
|
|
int end_index = 0;
|
| 3287 |
|
|
|
| 3288 |
|
|
// Parse the first expression in the data.
|
| 3289 |
|
|
CdlExpressionBody::continue_parse(result, data, index, op, end_index);
|
| 3290 |
|
|
|
| 3291 |
|
|
// At this stage we have reached end-of-data or we should be
|
| 3292 |
|
|
// at the start of another expression - any binary or ternary
|
| 3293 |
|
|
// operands would have been subsumed in the previous expression.
|
| 3294 |
|
|
// We need to keep adding && operators and new expressions until
|
| 3295 |
|
|
// end-of-data.
|
| 3296 |
|
|
while (CdlExprOp_EOD != op) {
|
| 3297 |
|
|
op = CdlExprOp_And;
|
| 3298 |
|
|
CdlExpressionBody::continue_parse(result, data, index, op, end_index);
|
| 3299 |
|
|
}
|
| 3300 |
|
|
}
|
| 3301 |
|
|
catch(...) {
|
| 3302 |
|
|
delete result;
|
| 3303 |
|
|
throw;
|
| 3304 |
|
|
}
|
| 3305 |
|
|
|
| 3306 |
|
|
// Keep track of the original expression string for diagnostics purposes
|
| 3307 |
|
|
result->expression_string = data;
|
| 3308 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3309 |
|
|
return result;
|
| 3310 |
|
|
}
|
| 3311 |
|
|
|
| 3312 |
|
|
// ----------------------------------------------------------------------------
|
| 3313 |
|
|
void
|
| 3314 |
|
|
CdlGoalExpressionBody::eval(CdlEvalContext& context, bool& result)
|
| 3315 |
|
|
{
|
| 3316 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression::eval");
|
| 3317 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3318 |
|
|
CYG_PRECONDITION_THISC();
|
| 3319 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3320 |
|
|
|
| 3321 |
|
|
eval_internal(context, result);
|
| 3322 |
|
|
|
| 3323 |
|
|
CYG_REPORT_RETURN();
|
| 3324 |
|
|
}
|
| 3325 |
|
|
|
| 3326 |
|
|
bool
|
| 3327 |
|
|
CdlGoalExpressionBody::eval(CdlEvalContext& context)
|
| 3328 |
|
|
{
|
| 3329 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlGoalExpression::eval", "result %d");
|
| 3330 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3331 |
|
|
CYG_PRECONDITION_THISC();
|
| 3332 |
|
|
CYG_PRECONDITION_CLASSOC(context);
|
| 3333 |
|
|
|
| 3334 |
|
|
bool result;
|
| 3335 |
|
|
eval_internal(context, result);
|
| 3336 |
|
|
|
| 3337 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3338 |
|
|
return result;
|
| 3339 |
|
|
}
|
| 3340 |
|
|
|
| 3341 |
|
|
// ----------------------------------------------------------------------------
|
| 3342 |
|
|
// Provide access to the underlying CdlExpression object. This allows the
|
| 3343 |
|
|
// inference engine etc. to work out why a goal expression is failing
|
| 3344 |
|
|
|
| 3345 |
|
|
CdlExpression
|
| 3346 |
|
|
CdlGoalExpressionBody::get_expression()
|
| 3347 |
|
|
{
|
| 3348 |
|
|
CYG_REPORT_FUNCNAMETYPE("CdlGoalExpression::get_expression", "result %p");
|
| 3349 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 3350 |
|
|
CYG_PRECONDITION_THISC();
|
| 3351 |
|
|
|
| 3352 |
|
|
CdlExpression result = this;
|
| 3353 |
|
|
CYG_REPORT_RETVAL(result);
|
| 3354 |
|
|
return result;
|
| 3355 |
|
|
}
|
| 3356 |
|
|
|
| 3357 |
|
|
// ----------------------------------------------------------------------------
|
| 3358 |
|
|
|
| 3359 |
|
|
bool
|
| 3360 |
|
|
CdlGoalExpressionBody::check_this(cyg_assert_class_zeal zeal) const
|
| 3361 |
|
|
{
|
| 3362 |
|
|
if (CdlGoalExpressionBody_Magic != cdlgoalexpressionbody_cookie) {
|
| 3363 |
|
|
return false;
|
| 3364 |
|
|
}
|
| 3365 |
|
|
CYGDBG_MEMLEAK_CHECKTHIS();
|
| 3366 |
|
|
|
| 3367 |
|
|
// There is no data specific to a goal expression, just let the
|
| 3368 |
|
|
// underlying check_this() member do its stuff.
|
| 3369 |
|
|
|
| 3370 |
|
|
return inherited::check_this(zeal);
|
| 3371 |
|
|
}
|
| 3372 |
|
|
|
| 3373 |
|
|
// ----------------------------------------------------------------------------
|
| 3374 |
|
|
|
| 3375 |
|
|
std::string
|
| 3376 |
|
|
CdlGoalExpressionBody::get_original_string() const
|
| 3377 |
|
|
{
|
| 3378 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression::get_original_string");
|
| 3379 |
|
|
CYG_REPORT_FUNCARG1XV(this);
|
| 3380 |
|
|
CYG_PRECONDITION_THISC();
|
| 3381 |
|
|
|
| 3382 |
|
|
CYG_REPORT_RETURN();
|
| 3383 |
|
|
return expression_string;
|
| 3384 |
|
|
}
|
| 3385 |
|
|
|
| 3386 |
|
|
// ----------------------------------------------------------------------------
|
| 3387 |
|
|
|
| 3388 |
|
|
void
|
| 3389 |
|
|
CdlGoalExpressionBody::eval_internal(CdlEvalContext& context, bool& result)
|
| 3390 |
|
|
{
|
| 3391 |
|
|
CYG_REPORT_FUNCNAME("CdlGoalExpression::eval_internal");
|
| 3392 |
|
|
CYG_REPORT_FUNCARG2XV(this, &context);
|
| 3393 |
|
|
// The assertions are all done in the calling code
|
| 3394 |
|
|
|
| 3395 |
|
|
// Start by evaluating the underlying expression
|
| 3396 |
|
|
CdlSimpleValue val;
|
| 3397 |
|
|
try {
|
| 3398 |
|
|
inherited::eval_internal(context, val);
|
| 3399 |
|
|
|
| 3400 |
|
|
// The evaluation succeeded. Do we have an integer, a string, ...?
|
| 3401 |
|
|
if (val.has_integer_value()) {
|
| 3402 |
|
|
result = (0 != val.get_integer_value());
|
| 3403 |
|
|
} else if (val.has_double_value()) {
|
| 3404 |
|
|
result = (0.0 != val.get_double_value());
|
| 3405 |
|
|
} else {
|
| 3406 |
|
|
result = ("" != val.get_value());
|
| 3407 |
|
|
}
|
| 3408 |
|
|
|
| 3409 |
|
|
// If there is an EvalException conflict for this property, it is no longer applicable
|
| 3410 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 3411 |
|
|
context.transaction->clear_conflicts(context.node, context.property,
|
| 3412 |
|
|
&CdlConflict_EvalExceptionBody::test);
|
| 3413 |
|
|
}
|
| 3414 |
|
|
|
| 3415 |
|
|
} catch(CdlEvalException e) {
|
| 3416 |
|
|
if ((0 != context.transaction) && (0 != context.node) && (0 != context.property)) {
|
| 3417 |
|
|
CdlConflict conflict = context.transaction->get_conflict(context.node, context.property,
|
| 3418 |
|
|
&CdlConflict_EvalExceptionBody::test);
|
| 3419 |
|
|
if (0 == conflict) {
|
| 3420 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 3421 |
|
|
} else {
|
| 3422 |
|
|
CdlConflict_EvalException eval_conf = dynamic_cast<CdlConflict_EvalException>(conflict);
|
| 3423 |
|
|
CYG_ASSERTC(0 != eval_conf);
|
| 3424 |
|
|
if (eval_conf->get_explanation() != e.get_message()) {
|
| 3425 |
|
|
// Replace the conflict object. Higher level can detect this.
|
| 3426 |
|
|
context.transaction->clear_conflict(conflict);
|
| 3427 |
|
|
CdlConflict_EvalExceptionBody::make(context.transaction, context.node, context.property, e.get_message());
|
| 3428 |
|
|
}
|
| 3429 |
|
|
}
|
| 3430 |
|
|
throw;
|
| 3431 |
|
|
}
|
| 3432 |
|
|
}
|
| 3433 |
|
|
|
| 3434 |
|
|
CYG_REPORT_RETURN();
|
| 3435 |
|
|
}
|
| 3436 |
|
|
|
| 3437 |
|
|
//}}}
|