📄 expr.cxx
字号:
//{{{ Banner //============================================================================//// expr.cxx//// Implementation of the various CDL expression classes.////============================================================================//####COPYRIGHTBEGIN####// // ----------------------------------------------------------------------------// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.//// This file is part of the eCos host tools.//// This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 of the License, or (at your option) // any later version.// // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details.// // You should have received a copy of the GNU General Public License along with// this program; if not, write to the Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// ----------------------------------------------------------------------------// //####COPYRIGHTEND####//============================================================================//#####DESCRIPTIONBEGIN####//// Author(s): bartv// Contact(s): bartv// Date: 1999/02/02// Version: 0.02////####DESCRIPTIONEND####//============================================================================//}}}//{{{ #include's // ----------------------------------------------------------------------------#include "cdlconfig.h"// Get the infrastructure types, assertions, tracing and similar// facilities.#include <cyg/infra/cyg_ass.h>#include <cyg/infra/cyg_trac.h>// <cdlcore.hxx> defines everything implemented in this module.// It implicitly supplies <string>, <vector> and <map> because// the class definitions rely on these headers.#include <cdlcore.hxx>//}}}//{{{ Statics // ----------------------------------------------------------------------------CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlEvalContext);CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlExpressionBody);CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListExpressionBody);CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlGoalExpressionBody);//}}}//{{{ CdlEvalContext // ----------------------------------------------------------------------------// A utility class to keep track of the context in which expression// evaluation is happening.CdlEvalContext::CdlEvalContext(CdlTransaction transaction_arg, CdlNode node_arg, CdlProperty property_arg, CdlToplevel toplevel_arg){ CYG_REPORT_FUNCNAME("CdlEvalContext::constructor"); CYG_REPORT_FUNCARG4XV(this, transaction_arg, node_arg, property_arg); transaction = transaction_arg; if ((0 == property_arg) && (0 != transaction)) { CdlConflict conflict = transaction->get_conflict(); if (0 != conflict) { property_arg = conflict->get_property(); } } property = property_arg; if ((0 == node_arg) && (0 != transaction)) { CdlConflict conflict = transaction->get_conflict(); if (0 != conflict) { node_arg = conflict->get_node(); } } node = node_arg; if (0 == toplevel_arg) { if (0 != transaction) { toplevel_arg = transaction->get_toplevel(); } else if (0 != node) { toplevel_arg = node->get_toplevel(); } } toplevel = toplevel_arg; cdlevalcontext_cookie = CdlEvalContext_Magic; CYGDBG_MEMLEAK_CONSTRUCTOR(); CYG_POSTCONDITION_THISC(); CYG_REPORT_RETURN();}CdlEvalContext::~CdlEvalContext(){ CYG_REPORT_FUNCNAME("CdlEvalContext::destructor"); CYG_PRECONDITION_THISC(); cdlevalcontext_cookie = CdlEvalContext_Invalid; transaction = 0; node = 0; property = 0; toplevel = 0; CYGDBG_MEMLEAK_DESTRUCTOR(); CYG_REPORT_RETURN();}// Given a context and a reference inside an expression, obtain the node// being referenced - if it is loaded.CdlNodeCdlEvalContext::resolve_reference(CdlExpression expr, int index){ CYG_REPORT_FUNCNAMETYPE("CdlEvalContext::resolve_reference", "result %"); CYG_REPORT_FUNCARG2XV(expr, index); CYG_PRECONDITION_THISC(); CYG_PRECONDITION_CLASSC(expr); CYG_PRECONDITIONC((0 <= index) && (index <= (int)expr->references.size())); // This expression may be happening in the context of a particular // property. If so then the destination may or may not be // resolved, which will have been handled when the containing package // was loaded. Alternatively this expression may be evaluated inside // some arbitrary Tcl code, in which case references remain unbound // and need to be resolved the hard way. CdlNode result = 0; if (0 != this->property) { // There is a property, use the bound/unbound reference. result = expr->references[index].get_destination(); } else { // The destination name can be retrieved, but we still need some // way of resolving it. if (0 != this->toplevel) { std::string destination_name = expr->references[index].get_destination_name(); result = this->toplevel->lookup(destination_name); } } CYG_REPORT_RETVAL(result); return result;}// Ditto, but also check that the result is a valuable.CdlValuableCdlEvalContext::resolve_valuable_reference(CdlExpression expr, int index){ CYG_REPORT_FUNCNAMETYPE("CdlEvalContext::resolve_reference", "result %"); CYG_REPORT_FUNCARG2XV(expr, index); CdlValuable result = 0; CdlNode node = this->resolve_reference(expr, index); if (0 != node) { result = dynamic_cast<CdlValuable>(node); } CYG_REPORT_RETVAL(result); return result;}boolCdlEvalContext::check_this(cyg_assert_class_zeal zeal) const{ if (CdlEvalContext_Magic != cdlevalcontext_cookie) { return false; } CYGDBG_MEMLEAK_CHECKTHIS(); if ((0 != transaction) && !transaction->check_this(zeal)) { return false; } if ((0 != toplevel) && !toplevel->check_this(zeal)) { return false; } if ((0 != node) && !node->check_this(zeal)) { return false; } if ((0 != property) && !property->check_this(zeal)) { return false; } return true;}//}}}//{{{ Expression parsing //{{{ Description // ----------------------------------------------------------------------------// There are a number of different entry points related to expression parsing,// largely to support list and goal expressions. All of these eventually// end up calling the function// continue_parse(expr, data, index, token, token_end)//// The expr argument holds an existing expression object that needs to be// updated. If token is Invalid then we are at the start of an expression// (but not necessarily at the start of the string).//// The data string holds all of the expression that should be parsed.// It is formed by concatenating all non-option arguments to the// appropriate property command, with spaces between them.//// index is an input/output variable. On input it indicates where in// the string parsing should continue. On output it indicates the// location within the string where the terminating token began.//// token is an input/output variable. On input it can have the values// Invalid or And. The former means that we are parsing a completely// new expression. The latter is used for goal expressions: it is// necessary to parse a new expression and then combine it with the// existing one.//// token_end is an output variable. It indicates the location within// the string where the terminating token ended. This is useful for// e.g. ranges in a list expression.//// A conventional recursive descent parser is used.//}}}//{{{ Tokenization // ----------------------------------------------------------------------------// Tokenization.//{{{ token enum // A separate token enum is necessary, rather than re-using the CdlExprOp// enum. Some tokens may correspond to several operators, and some tokens// such as close-bracket do not correspond directly to an operator at all.enum token { T_Invalid = -2, T_EOD = -1, T_Reference = 1, // CYGPKG_HAL T_String = 2, // "hello" T_Integer = 3, // 123 T_Double = 4, // 3.1415 T_Range = 5, // to T_OpenBracket = 6, // ( T_CloseBracket = 7, // ) T_Minus = 8, // - T_Plus = 9, // + T_Times = 10, // * T_Divide = 11, // / T_Exclamation = 12, // ! T_Tilde = 13, // ~ T_Questionmark = 14, // ? T_Remainder = 15, // % T_LeftShift = 16, // << T_RightShift = 17, // >> T_LessThan = 18, // < T_LessEqual = 19, // <= T_GreaterThan = 20, // > T_GreaterEqual = 21, // >= T_Equal = 22, // == T_NotEqual = 23, // != T_BitAnd = 24, // & T_BitXor = 25, // ^ T_BitOr = 26, // | T_And = 27, // && T_Or = 28, // || T_Colon = 29, // : (in a conditional) T_StringConcat = 30, // . T_Function = 31, // is_substr etc. T_Comma = 32, // , (inside a function) T_Implies = 33, // implies T_Xor = 34, // xor T_Eqv = 35 // eqv };//}}}//{{{ Statics // Statics to keep track of the current state.static std::string current_data = "";static unsigned int current_index = 0;static unsigned int token_start = 0;static int current_char = EOF;static token current_token = T_Invalid;static std::string current_string = "";static std::string current_reference = "";static std::string current_special = "";static cdl_int current_int = 0;static double current_double = 0.0;static CdlValueFormat current_format = CdlValueFormat_Default;static int current_function_id = 0;//}}}//{{{ Character access // ----------------------------------------------------------------------------// Individual character access.// Note that current_index is one character past current_char.// Return the next character in the string, or EOFstatic voidnext_char(){ if (current_index >= current_data.size()) { current_char = EOF; } else { current_char = current_data[current_index++]; }}// Go back a character. This is useful when parsing// strings. It is the responsibility of the calling code// to make sure that we are not at the start of the buffer.static voidbackup_char(){ CYG_ASSERTC(((EOF == current_char) && (0 < current_index)) || (1 < current_index)); if (EOF != current_char) { current_index--; } current_char = current_data[current_index - 1];}//}}}//{{{ get_error_location() // ----------------------------------------------------------------------------// Construct part of a diagnostic message, indicating the// area in the data where the error occurred. This string// is of the form {...data} ^char^ {data...}. Ideally// the ^ markers would be on a subsequent line, eliminating// the need for braces, but there is insufficient control// of how the message gets presented to the user.//// Care has to be taken with EOD.static std::stringget_error_location(){ CYG_REPORT_FUNCNAME("get_error_location"); std::string result = ""; // token_start is probably the best place for centering the error. // current_index is past the point where the error has occurred. if (token_start > 1) { if (token_start > 16) { result = "{..." + current_data.substr(token_start - 13, 13) + "} "; } else { result = "{" + current_data.substr(0, token_start) + "}"; } } if (current_char == EOF) { result += " <end of data>"; } else { result += " ^" + std::string(1, current_data[token_start]) + "^ "; } if (token_start < current_data.size()) { if ((token_start + 16) < current_data.size()) { result += "{" + current_data.substr(token_start + 1, current_data.size() - (token_start+1)) + "}"; } else { result += "{" + current_data.substr(token_start, 13) + "...}"; } } CYG_REPORT_RETURN(); return result;}// Export this functionality available to other modules, especially func.cxx and its// argument checking routines.std::string
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -