Mercurial > flash_v2
diff host/libcdl/func.cxx @ 159:511f4dc167f6
Merge from eCos master repository on 2001-05-18-01:30:05-BST
| author | jlarmour |
|---|---|
| date | Fri, 18 May 2001 06:32:28 +0000 |
| parents | |
| children | 0d2b193a635f |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/host/libcdl/func.cxx @@ -0,0 +1,392 @@ +//{{{ Banner + +//============================================================================ +// +// func.cxx +// +// Implementation of CDL functions +// +//============================================================================ +//####COPYRIGHTBEGIN#### +// +// ---------------------------------------------------------------------------- +// Copyright (C) 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: 2001/04/20 +// Version: 0.01 +// +//####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> + +//}}} + +//{{{ Core + +// ---------------------------------------------------------------------------- +int CdlFunction::next_id = 1; +std::vector<CdlFunction*> CdlFunction::all_functions; + +// Dummy initializers, for e.g. when a particular function implementation does not +// support a certain type of inference. +void (*CdlFunction::null_check)(CdlExpression, const CdlSubexpression&) = + (void (*)(CdlExpression, const CdlSubexpression&)) 0; +bool (*CdlFunction::null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int) = + (bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int)) 0; +bool (*CdlFunction::null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int) = + (bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)) 0; + + +CdlFunction::CdlFunction(const char* name_arg, int number_args_arg, + void (*check_arg)(CdlExpression, const CdlSubexpression&), + void (*eval_arg)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&), + bool (*infer_bool_arg)(CdlTransaction, CdlExpression, unsigned int, bool, int), + bool (*infer_value_arg)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)) + : name(name_arg), + number_args(number_args_arg), + check_fn(check_arg), + eval_fn(eval_arg), + infer_bool_fn(infer_bool_arg), + infer_value_fn(infer_value_arg) +{ + id = next_id++; + all_functions.push_back(this); +} + +CdlFunction::~CdlFunction() +{ +} + +bool +CdlFunction::is_function(std::string name, int& id) +{ + CYG_REPORT_FUNCNAMETYPE("CdlFunction::is_function", "result %d"); + + bool result = false; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); !result && (i != all_functions.end()); i++) { + if (name == (*i)->name) { + result = true; + id = (*i)->id; + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +std::string +CdlFunction::get_name(int id) +{ + CYG_REPORT_FUNCNAME("CdlFunction::get_name"); + CYG_REPORT_FUNCARG1XV(id); + + std::string result = ""; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + result = (*i)->name; + break; + } + } + + CYG_REPORT_RETURN(); + return result; +} + +int +CdlFunction::get_args_count(int id) +{ + CYG_REPORT_FUNCNAMETYPE("CdlFunction::get_args_count", "result %d"); + CYG_REPORT_FUNCARG1XV(id); + + int result = 0; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + result = (*i)->number_args;; + break; + } + } + CYG_REPORT_RETVAL(result); + return result; +} + +void +CdlFunction::check(CdlExpression expr, const CdlSubexpression& subexpr) +{ + CYG_REPORT_FUNCNAME("CdlFunction::check"); + CYG_REPORT_FUNCARG2XV(expr, &subexpr); + + int id = subexpr.func; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + if (CdlFunction::null_check != (*i)->check_fn) { + (*((*i)->check_fn))(expr, subexpr); + } + break; + } + } + + CYG_REPORT_RETURN(); +} + +void +CdlFunction::eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result) +{ + CYG_REPORT_FUNCNAME("CdlFunction::eval"); + CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result); + + int id = subexpr.func; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + (*((*i)->eval_fn))(context, expr, subexpr, result); + break; + } + } + + CYG_REPORT_RETURN(); +} + +bool +CdlFunction::infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level) +{ + CYG_REPORT_FUNCNAMETYPE("CdlFunction::infer_bool", "result %d"); + CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level); + + bool result = false; + CdlSubexpression& subexpr = expr->sub_expressions[index]; + int id = subexpr.func; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + if (CdlFunction::null_infer_bool != (*i)->infer_bool_fn) { + result = (*((*i)->infer_bool_fn))(transaction, expr, index, goal, level); + } + break; + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +bool +CdlFunction::infer_value(CdlTransaction transaction, CdlExpression expr, unsigned int index, CdlSimpleValue& goal, int level) +{ + CYG_REPORT_FUNCNAMETYPE("CdlFunction::infer_value", "result %d"); + CYG_REPORT_FUNCARG5XV(transaction, expr, index, &goal, level); + + bool result = false; + CdlSubexpression& subexpr = expr->sub_expressions[index]; + int id = subexpr.func; + std::vector<CdlFunction*>::const_iterator i; + + for (i = all_functions.begin(); i != all_functions.end(); i++) { + if (id == (*i)->id) { + if (CdlFunction::null_infer_value != (*i)->infer_value_fn) { + result = (*((*i)->infer_value_fn))(transaction, expr, index, goal, level); + } + break; + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +//}}} +//{{{ is_substr() + +// ---------------------------------------------------------------------------- +// is_substr(A, B) +// +// For example, is_substr(CYGBLD_GLOBAL_CFLAGS, " -fno-exceptions ") +// +// There is one subtlety about substring matching: what to do about the +// start and end of a string. If the specified substring begins with a +// space then this will match either a space or the start of the string, +// similarly for the final character. + +static std::string::size_type +is_substr_find(std::string haystack, std::string needle, std::string::size_type& len_arg) +{ + CYG_REPORT_FUNCNAMETYPE("is_substr_find", "result %d"); + std::string::size_type result = std::string::npos; + + std::string::size_type haystack_len = haystack.length(); + std::string::size_type needle_len = needle.length(); + + bool leading_space = false; + bool trailing_space = false; + + if (' ' == needle[0]) { + leading_space = true; + needle_len--; + needle = std::string(needle, 1, needle_len); + } + if (' ' == needle[needle_len - 1]) { + trailing_space = true; + needle_len--; + needle = std::string(needle, 0, needle_len); + } + + std::string::size_type posn = haystack.find(needle); + while ((std::string::npos == result) && (std::string::npos != posn)) { + + std::string::size_type match_point = posn; + bool match = true; + + // A possible match has been found. If there was a leading + // space, check we are either at the start of the main string + // or that a space is present. + if (leading_space && (0 != posn) && (' ' != haystack[posn - 1])) { + match = false; + } + if (trailing_space && (haystack_len != (posn + needle_len)) && (' ' != haystack[posn + needle_len])) { + match = false; + } + + // The result and len_arg returns exclude the spaces. This is deliberate. + // Consider !is_substr("-g -O2 -fno-rtti -fno-exceptions", " -fnortti "). + // If during inference the spaces were removed as well, this would give + // "-g -O2-fno-exceptions", which is not desirable. + if (match) { + result = match_point; + len_arg = needle_len; + } else { + posn = haystack.find(needle, posn + 1); + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +static void +is_substr_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result) +{ + CYG_REPORT_FUNCNAME("is_substr_eval"); + CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result); + CYG_PRECONDITION_CLASSOC(context); + CYG_PRECONDITION_CLASSC(expr); + + CdlSimpleValue arg0; + CdlSimpleValue arg1; + expr->eval_subexpression(context, subexpr.args[0], arg0); + expr->eval_subexpression(context, subexpr.args[1], arg1); + + std::string::size_type len; + result = (std::string::npos != is_substr_find(arg0.get_value(), arg1.get_value(), len)); + CYG_REPORT_RETURN(); +} + +// Inference is only supported if the haystack argument is a reference that can be +// updated. The needle can be an arbitrary expression. +static bool +is_substr_infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level) +{ + CYG_REPORT_FUNCNAMETYPE("is_substr_infer_bool", "result %d"); + + bool result = false; + + CdlSubexpression& subexpr = expr->sub_expressions[index]; + CdlSubexpression& arg0 = expr->sub_expressions[subexpr.args[0]]; + try { + if (CdlExprOp_Reference == arg0.op) { + + CdlSimpleValue needle_value; + CdlEvalContext context(transaction); + expr->eval_subexpression(context, subexpr.args[1], needle_value); + std::string needle = needle_value.get_value(); + + CdlNode node = expr->references[arg0.reference_index].get_destination(); + CdlValuable valuable = 0; + if (0 != node) { + valuable = dynamic_cast<CdlValuable>(node); + } + if ((0 != valuable) && ((CdlValueFlavor_BoolData == valuable->get_flavor()) || (CdlValueFlavor_Data == valuable->get_flavor()))) { + // OK, we have a valuable which can be given a suitable value. + // What is the current string? + const CdlValue& current_value = transaction->get_whole_value(valuable); + std::string haystack = current_value.get_simple_value().get_value(); + + // What is the goal? If the needle should be in the + // haystack, append it if necessary. If the needle + // should not be in the haystack, remove all current occurrences. + if (goal) { + std::string::size_type len; + if (std::string::npos == is_substr_find(haystack, needle, len)) { + haystack = haystack + needle; + } + } else { + std::string::size_type posn, len; + for (posn = is_substr_find(haystack, needle, len); std::string::npos != posn; posn = is_substr_find(haystack, needle, len)) { + haystack.erase(posn, len); + } + } + + // OK, we have a new value for the haystack which should match the desired goal. + // Try and set this value. + CdlSimpleValue new_value(haystack); + result = CdlInfer::set_valuable_value(transaction, valuable, new_value, level); + } + } + } catch (...) { + result = false; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +static CdlFunction is_substr("is_substr", 2, CdlFunction::null_check, &is_substr_eval, &is_substr_infer_bool, CdlFunction::null_infer_value); + +//}}}
