📄 parse.cxx
字号:
//{{{ Banner //============================================================================//// parse.cxx//// Miscellaneous parsing routines////============================================================================//####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/23// 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>//}}}//{{{ Description // ----------------------------------------------------------------------------// All CDL data is read via a Tcl interpreter, so the parsing is done by// procedures that appear as Tcl commands. This has obvious advantages in// terms of expressive power, but does result in a little bit of confusion// when producing diagnostics.//// Errors should not bypass the Tcl interpreter, to ensure that that// stays in a consistent state. In particular it is not possible to let// arbitrary C++ exceptions to go straight through the Tcl interpreter,// this is likely to result in a corrupted interpreter.// // Also, it is not a good idea to abort parsing as soon as anything// goes wrong. Instead there should be an error handling callback associated// with the interpreter, which can be used to report errors. This// callback may choose to raise an exception.//// Consider the case of parsing a property (which accounts for most of// the code in this module). A property does not exist in isolation,// only within the context of a suitable CDL entity such as an option.// If parsing succeeds and a property object is created then it must// be added to the current CDL entity.//// Therefore a typical parse routine looks like this://// 1) get the current CDL node from the interpreter// 2) do basic parsing of the data. Any errors should be reported// via the callback.// 3) create a suitable CdlProperty object// 4) add the property to the current entity//// std::bad_alloc and CdlStringException exceptions can be thrown, they// will be intercepted by the CdlInterpreter class.//}}}//{{{ Statics // ----------------------------------------------------------------------------// The string "property " is needed in various places. Provide it as a static// to cut down the number of times the string constructor has to run.static std::string property_string = "property ";//}}}//{{{ Generic parsing-related utilities //{{{ argv manipulation // ----------------------------------------------------------------------------// Some of the properties have aliases in the CDL data, so argv[0] has to be// used to work out what is actually being parsed. However the Tcl interpreter// may prefix the command name with :: to indicate the global namespace.const char*CdlParse::get_tcl_cmd_name(const char* name){ if ((name[0] == ':') && (name[1] == ':')) { return &(name[2]); } else { return name; }}// Given a list of arguments, concatenate them together into a C++ string.// This makes expression parsing easier. The final argument should be an// index into the array, typically the result of a call to skip_argv_options().std::stringCdlParse::concatenate_argv(int argc, char** argv, int index){ CYG_REPORT_FUNCNAME("CdlParse::concatenate_argv"); std::string result = ""; for ( int i = index ; i < argc; i++) { if (i > index) { result += ' '; } result += std::string(argv[i]); } CYG_REPORT_RETURN(); return result;}// ----------------------------------------------------------------------------// Option parsing.//// Some properties accept modifiers in their argument list. For example,// by default a "compile" property is just a list of source files that// should be compiled and added to the current library. It is possible// to specify an alternative library via a modifier://// ...// compile -library=libextras.a dummy.cxx// ...//// The rules applied for such options are intended to follow common Tcl// practice://// 1) any initial arguments beginning with a - are assumed to be// options.//// 2) the first argument which does not begin with a - stops option// processing.//// 3) option processing can also be terminated with a -- argument.// This may occasionally be required, e.g. to have -ve constants// in an expression.//// 4) the parsing code does not distinguish between single and double// hyphens. If there happens to be a second - in an option then this// is just ignored.//// 5) it is not necessary to supply the whole option name, as long as// what is provided is unambiguous. For example -lib=libextras.a is// acceptable (for now anyway, conceivably it would break in future).// Option processing is case sensitive.//// 6) name/value pairs can take the form -name=value or the form// -name value, whichever is appropriate.//// The parse_options() function takes the current interpreter (so that// it can generate diagnostics), a prefix such as `property// "requires"' or `package CYGPKG_HAL', details of the options to be// parsed, an argc/argv list, an index, and a reference to a vector.// The parsed options get placed in the vector, and the index argument// gets updated to point at the first non-option argument. It will// report problems via report_warning().//// The options description consists of a pointer to an array of// C strings (allowing static initialization). Passing a zero// argument indicates that the property takes no options. Otherwise// the array should be zero terminated.//// Each entry in the array takes the form "name:flags". The optional// flags consist of zero or more characters indicating how the option// should be interpreted. Valid flags are://// f - this option takes no data, it is just a boolean flag. The// default behaviour assumes name/value pairs.//// m - this option can occur multiple times. The default behaviour// is that each option can only occur once.// Utility function to get hold of an option name without the colon// or terminating flags.static std::stringget_option_string(char* name){ std::string result = ""; while ((*name != ':') && (*name != '\0')) { result += *name++; } return result;}intCdlParse::parse_options(CdlInterpreter interp, std::string diag_prefix, char** options, int argc, char** argv, int index, std::vector<std::pair<std::string,std::string> >& result){ CYG_REPORT_FUNCNAMETYPE("CdlParse::parse_options", "final index %d"); CYG_REPORT_FUNCARG4XV(interp, options, argc, argv); CYG_PRECONDITION_CLASSC(interp); CYG_PRECONDITIONC(argc > 0); // The property name must be present. // It is possible for some of the arguments to have been processed already. CYG_PRECONDITIONC((index > 0) && (index <= argc)); while((index < argc) && ('-' == argv[index][0])) { std::string name = ""; std::string value = ""; // The sequence -- should always terminate option processing. if (0 == strcmp(argv[index], "--")) { index++; break; } char* arg_ptr = argv[index]; // Skip the initial -, and the second one as well if it is present. if ('-' == *++arg_ptr) { arg_ptr++; } // Construct the option name. This is the current argument up // to but not including the '=' character or EOD. while (('=' != *arg_ptr) && ('\0' != *arg_ptr)) { name += *arg_ptr++; } if ("" == name) { // One of "-", "-=xxx", or "--=x" CdlParse::report_warning(interp, diag_prefix + ", invalid option string " + argv[index]); } // Do not try to extract the value unless we are sure there // should be one. Instead try to match the option name. The // current value of name should be a unique substring of // one of the known option strings. // // Note that the supplied options descriptor can be NULL, // since most properties do not yet take any options. // In that case opt_index will remain at -1, and we should // get an "invalid option" diagnostic. unsigned int i; int opt_index = -1; if (0 != options) { for (i = 0; 0 != options[i]; i++) { if (0 == strncmp(name.c_str(), options[i], name.size())) { if (-1 != opt_index) { CdlParse::report_warning(interp, diag_prefix + ", ambiguous option name " + name + ", it can match " + get_option_string(options[opt_index]) + " or " + get_option_string(options[i])); index++; break; } else { opt_index = i; } } } } if (-1 == opt_index) { CdlParse::report_warning(interp, diag_prefix + ", invalid option " + name); index++; break; } // The option has been identified successfully. Extract the flags. bool flag_flag = false; bool multiple_flag = false; char* tmp = options[opt_index]; while (('\0' != *tmp) && (':' != *tmp)) { tmp++; } if (':' == *tmp) { do { tmp++; if ('f' == *tmp) { flag_flag = true; } else if ('m' == *tmp) { multiple_flag = true; } else if ('\0' != *tmp) { CYG_FAIL("Invalid property option"); } } while ('\0' != *tmp); } // We now know the full option name. Use it for future diagnostics. name = get_option_string(options[opt_index]); // Take care of the value. if (flag_flag) { // There should not be a value. If the current argument is of the // form x=y then this is an error. if ('=' == *arg_ptr) { CdlParse::report_warning(interp, diag_prefix + ", option " + name + " does not take any data"); } // Leave index pointing at the next argument to be processed. index++; } else { if ('=' == *arg_ptr) { value = std::string(++arg_ptr); } else if (++index == argc) { CdlParse::report_warning(interp, diag_prefix + ", missing data for option " + name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -