📄 expr.cxx
字号:
//{{{ Banner //============================================================================//// expr.cxx//// Implementation of the various CDL expression classes.////============================================================================//####COPYRIGHTBEGIN####// // ----------------------------------------------------------------------------// Copyright (C) 1999, 2000 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; node = node_arg; property = property_arg; if (0 == toplevel_arg) { if (0 != transaction) { toplevel = transaction->get_toplevel(); } else if (0 != node) { toplevel = node->get_toplevel(); } else { toplevel = toplevel_arg; } } else { 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();}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)};//}}}//{{{ 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 cdl_int current_int = 0;static double current_double = 0.0;static CdlValueFormat current_format = CdlValueFormat_Default;//}}}//{{{ 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;}//}}}//{{{ Token translation // ----------------------------------------------------------------------------// Convert a token into a binary expression operatorstatic CdlExprOptoken_to_binary_expr_op(){ CYG_REPORT_FUNCNAMETYPE("token_to_expr_op", "op %d"); CdlExprOp result = CdlExprOp_Invalid; switch(current_token) { case T_Minus: result = CdlExprOp_Subtract; break; case T_Plus: result = CdlExprOp_Add; break; case T_Times: result = CdlExprOp_Multiply; break; case T_Divide: result = CdlExprOp_Divide; break; case T_Remainder: result = CdlExprOp_Remainder; break; case T_LeftShift: result = CdlExprOp_LeftShift; break; case T_RightShift: result = CdlExprOp_RightShift; break; case T_LessThan: result = CdlExprOp_LessThan; break; case T_LessEqual: result = CdlExprOp_LessEqual; break; case T_GreaterThan: result = CdlExprOp_GreaterThan; break; case T_GreaterEqual: result = CdlExprOp_GreaterEqual; break; case T_Equal: result = CdlExprOp_Equal; break; case T_NotEqual: result = CdlExprOp_NotEqual; break; case T_BitAnd: result = CdlExprOp_BitAnd; break; case T_BitXor: result = CdlExprOp_BitXor; break; case T_BitOr: result = CdlExprOp_BitOr; break; case T_And: result = CdlExprOp_And; break; case T_Or: result = CdlExprOp_Or; break; default: result = CdlExprOp_Invalid; break; } CYG_REPORT_RETVAL(result); return result;}// Convert a token into an ExprOp. This way the internal token enum does// not need to be exported in order to define the interface.//// In practice the higher level code will only look for a handful of// cases, mainly EOD and the range operator, but we might as well// do the job property.static CdlExprOptoken_to_expr_op(){ CYG_REPORT_FUNCNAMETYPE("token_to_expr_op", "expr op %d"); CdlExprOp result; // Many of the tokens are already handled for binary operators. result = token_to_binary_expr_op(); if (CdlExprOp_Invalid == result) { switch(current_token) { case T_EOD: result = CdlExprOp_EOD; break; case T_Reference: result = CdlExprOp_Reference; break; case T_String: result = CdlExprOp_StringConstant; break; case T_Integer: result = CdlExprOp_IntegerConstant; break; case T_Double: result = CdlExprOp_DoubleConstant; break; case T_Range: result = CdlExprOp_Range; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -