Mercurial > ecos
view host/libcdl/parse.cxx @ 3252:2dba5f2af421
* src/core/snmp/msg_out.c: Applied lwip bugfix #29256.
ip_addr_set_hton(...) does not exist in this revision, so an
equivalent solution was provided. The application was retested.
Any application that worked around the problem by using
htonl(...) will need to be changed by removing it. [ Bugzilla 1001789 ]
| author | jld |
|---|---|
| date | Sat, 22 Jun 2013 14:58:09 +0000 |
| parents | 74dbf4c3f2e1 |
| children |
line wrap: on
line source
//{{{ Banner //============================================================================ // // parse.cxx // // Miscellaneous parsing routines // //============================================================================ // ####ECOSHOSTGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of the eCos host tools. // Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. // // 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 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., 51 Franklin Street, // Fifth Floor, Boston, MA 02110-1301, USA. // ------------------------------------------- // ####ECOSHOSTGPLCOPYRIGHTEND#### //============================================================================ //#####DESCRIPTIONBEGIN#### // // Author(s): bartv // Contact(s): bartv // Date: 1999/02/23 // Version: 0.02 // //####DESCRIPTIONEND#### //============================================================================ //}}} //{{{ #include's // ---------------------------------------------------------------------------- #include "cdlconfig.h" #include <cstring> // 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. std::string CdlParse::get_tcl_cmd_name(std::string name) { std::string result; if ((name[0] == ':') && (name[1] == ':')) { result = std::string(name, 2, name.size() - 2); } else { result = name; } return result; } // 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::string CdlParse::concatenate_argv(int argc, const 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::string get_option_string(const char* name) { std::string result = ""; while ((*name != ':') && (*name != '\0')) { result += *name++; } return result; } int CdlParse::parse_options(CdlInterpreter interp, std::string diag_prefix, const char** options, int argc, const 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; } const 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, std::string("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, std::string("Ambiguous option name `") + name + "'.\n" + "It can match `" + get_option_string(options[opt_index]) + "'\n" + "or `" + get_option_string(options[i]) + "'."); index++; break; } else { opt_index = i; } } } } if (-1 == opt_index) { CdlParse::report_warning(interp, diag_prefix, std::string("Invalid option `") + name + "'."); index++; break; } // The option has been identified successfully. Extract the flags. bool flag_flag = false; bool multiple_flag = false; const 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, std::string("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, std::string("Missing data for option `") + name + "'."); } else { value = argv[index]; } index++; } // At this stage index points at the next argument to be processed, and should not // be updated again. // Unless the option can occur multiple times, make sure that it is not already // present in the options vector. if (!multiple_flag) { for (i = 0; i < result.size(); i++) { if (name == result[i].first) { CdlParse::report_warning(interp, diag_prefix, std::string("Option `") + name + "' can only be used once."); break; } } } // The name/value pair is valid, so add it to the result vector. result.push_back(std::make_pair(name, value)); } CYG_REPORT_RETVAL(index); return index; } //}}} //{{{ Diagnostic construction // Construct a suitable diagnostic for a parsing error. This may occur // when reading in a CDL script, a savefile, a database, or anything // similar. // // A diagnostic should take the following form: // // <context> <linenumber> [, <node identifier>] [, <extra identifier>] : [<classification>, ] <message> // // The context should be set in the Tcl interpreter. Typically it // will be a filename. // // In practice generating the line number is not really feasible at // present, the Tcl interpreter does not keep track of sufficient // information. At least, not in the public data structures, there is // a termOffset field in the internal data structures which might // be used to do the right thing. I do not want to start relying // on Tcl internals just yet, or add support to the Tcl core for // keeping track of line numbers. // // For many data files there will the concept of a current node, // e.g. an option whose properties or savefile information are // being processed. The CdlInterpreter class keeps track of the // current node, so if it is defined then the node's class and // name can be part of the message. This happens automatically, // no effort is required on the part of calling code. // // There may also be additional information, for example // identifying the specific property where the error was detected. // This is handled by an extra argument. // // The classification is likely to be something like "warning", // "error", or "internal error". It is controlled by the calling // code, but typically it is provided by calling via report_warning() // etc. // // The message should identify the actual error. It should be // a proper sentence, i.e. begin with a capital error and end with // a full stop, unless the last word is an identifier or filename // or something similarly special in which case the trailing // dot will be discarded. The message should not end with a // newline character, and the result string will not end with one // either. That is left to higher level code. std::string CdlParse::construct_diagnostic(CdlInterpreter interp, std::string classification, std::string sub_id, std::string message) { CYG_REPORT_FUNCNAME("CdlParse::construct_diagnostic"); CYG_PRECONDITION_CLASSC(interp); std::string context = interp->get_context(); CdlNode current_node = interp->get_node(); std::string result; if ("" == context) { result = "<unknown context>"; } else { result = context; } if (0 != current_node) { result += ", " + current_node->get_class_name() + " " + current_node->get_name(); } if ("" != sub_id) { result += ", " + sub_id; } result += ": " + classification; // Now it is time to start worrying about layout, indenting // subsequent lines, and so on. int index = result.length(); int message_len = message.length(); int message_index; bool indent_needed = false; // Find out how many characters there are in the message up to the first newline for (message_index = 0; (message_index < message_len) && ('\n' != message[message_index]); message_index++) { ; } // Should the message start on the next line, suitably indented? // This depends in part on whether or not there was a classification. if ("" == classification) { // The current result ends with a colon and a space. if ((index + message_index) <= 72) { // The first line of the message can still fit. No need to do anything. } else { // Start indenting immediately, do not add anything else to the current line. indent_needed = true; } } else { // We may want a comma and a space after the classification if ((index + 2 + message_index) <= 72) { result += ", "; } else { indent_needed = true; } } // Now we can process the message one character at a time, adding // newlines and indentation just in time. for (message_index = 0; message_index < message_len; message_index++) { if (indent_needed) { result += "\n "; indent_needed = false; } if ('\n' == message[message_index]) { indent_needed = true; } else { result += message[message_index]; } } CYG_REPORT_RETURN(); return result; } //}}} //{{{ Error count tracking // Keep track of the number of errors that have occurred while doing some // parsing. This functionality is not provided directly by the CdlInterpreter // class, instead it is implemented using assoc data. static const char error_count_key[] = "CdlErrorCount"; static void error_count_delproc(ClientData data, Tcl_Interp* interp) { CYG_REPORT_FUNCNAME("CdlParse::error_count_delproc"); int* newed_ptr = static_cast<int*>(data); delete newed_ptr; CYG_REPORT_RETURN(); } void CdlParse::clear_error_count(CdlInterpreter interp) { CYG_REPORT_FUNCNAME("CdlParse::clear_error_count"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key)); if (0 != newed_ptr) { *newed_ptr = 0; } CYG_REPORT_RETURN(); } void CdlParse::incr_error_count(CdlInterpreter interp, int how_much) { CYG_REPORT_FUNCNAME("CdlParse::incr_error_counter"); CYG_REPORT_FUNCARG2("interp %p, how_much %d", interp, how_much); CYG_PRECONDITION_CLASSC(interp); CYG_PRECONDITION(how_much > 0, "previous errors cannot be undone"); int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key)); if (0 == newed_ptr) { newed_ptr = new int(how_much); interp->set_assoc_data(error_count_key, static_cast<void*>(newed_ptr), &error_count_delproc); } else { CYG_ASSERT((*newed_ptr + how_much) > *newed_ptr, "number of parsing errors should not overflow"); *newed_ptr += how_much; } CYG_REPORT_RETURN(); } int CdlParse::get_error_count(CdlInterpreter interp) { CYG_REPORT_FUNCNAMETYPE("CdlParse::get_error_count", "count %d"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); int result = 0; int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key)); if (0 != newed_ptr) { result = *newed_ptr; } CYG_REPORT_RETVAL(result); return result; } //}}} //{{{ Error and warning reporting // Report errors and warnings. These will be called during parsing // operations, both of CDL and similar data scripts and for savefiles. // The parsing involves running a Tcl interpreter extended with the // appropriate set of commands. Typically the call graph will look // something like this: // // libcdl C++ code such as load_package() // libcdl CdlInterpreter::eval() // Tcl interpreter // libcdl parsing code // report_error() // // If the Tcl script is invalid then parsing errors may get reported // at the higher level code as well. // // There are two classes of diagnostic: errors and warnings. // Additional levels may be added in future, but there does not seem // to be an urgent need for them. Client code should provide callback // functions so that the messages can be displayed to the user, and // these callbacks will be registered with the current CdlInterpreter. // // If no error callback is defined then a ParseException will be // raised instead, and the rest of the current script will not be // processed. Alternatively the error callback itself can raise a // ParseException. Care is taken to ensure that the exception does not // go straight through the Tcl interpreter, since that would prevent // the Tcl code from cleaning up appropriately. If no exception is // raised then the library keeps track of the number of errors, and // this information is accessible once the script has been fully // processed. This allows multiple errors to be reported in a single // run. // // If no warning callback is provided then warnings are ignored. void CdlParse::report_error(CdlInterpreter interp, std::string sub_id, std::string message) { CYG_REPORT_FUNCNAME("CdlParse::report_error"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); incr_error_count(interp); std::string full_message = construct_diagnostic(interp, "error", sub_id, message); // Now, either invoke the callback if it is provided, or throw the exception. CdlDiagnosticFnPtr fn = interp->get_error_fn_ptr(); if (0 == fn) { throw CdlParseException(full_message); } else { (*fn)(full_message); } CYG_REPORT_RETURN(); } void CdlParse::report_warning(CdlInterpreter interp, std::string sub_id, std::string message) { CYG_REPORT_FUNCNAME("CdlParse::report_warning"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); // If there is no warning callback, do nothing. This is really a // bug in the calling application. CdlDiagnosticFnPtr fn = interp->get_warning_fn_ptr(); if (0 != fn) { std::string full_message = construct_diagnostic(interp, "warning", sub_id, message); (*fn)(full_message); } CYG_REPORT_RETURN(); } //}}} //{{{ The "unknown" command // ---------------------------------------------------------------------------- // This routine should be installed in interpreters that get used for // parsing CDL scripts. It gets invoked when the CDL script contains // an unrecognised command, e.g. because of a typo, and makes sure that // the usual diagnostics process is observed. // // This routine should be uninstalled after the parsing is complete, // to avoid e.g. a ParseException when it is not expected. int CdlParse::unknown_command(CdlInterpreter interp, int argc, const char* argv[]) { CYG_REPORT_FUNCNAME("CdlParse::unknown_command"); CYG_REPORT_FUNCARG3XV(interp, argc, argv); CYG_PRECONDITIONC(2 <= argc); CYG_PRECONDITION_CLASSC(interp); report_error(interp, "", std::string("Unknown command `") + argv[1] + "'."); CYG_UNUSED_PARAM(int, argc); return TCL_OK; } //}}} //}}} //{{{ Property-related parser utilities // ---------------------------------------------------------------------------- // Utilities related to parsing properties, rather than more general parsing. // A variant of report_parse_error() which also adds the property prefix. void CdlParse::report_property_parse_error(CdlInterpreter interp, std::string argv0, std::string msg) { CYG_REPORT_FUNCNAME("CdlPase::report_property_parse_error"); incr_error_count(interp); std::string diag = construct_diagnostic(interp, "error", std::string("property ") + CdlParse::get_tcl_cmd_name(argv0), msg); // Now, either invoke the callback if it is provided, or throw the exception. CdlDiagnosticFnPtr fn = interp->get_error_fn_ptr(); if (0 == fn) { throw CdlParseException(diag); } else { (*fn)(diag); } CYG_REPORT_RETURN(); } void CdlParse::report_property_parse_error(CdlInterpreter interp, CdlProperty prop, std::string msg) { CYG_REPORT_FUNCNAME("CdlParse::report_property_parse_error"); report_property_parse_error(interp, (prop->get_argv())[0], msg); CYG_REPORT_RETURN(); } // Repeat for warnings void CdlParse::report_property_parse_warning(CdlInterpreter interp, std::string argv0, std::string msg) { CYG_REPORT_FUNCNAME("CdlPase::report_property_parse_warning"); CdlDiagnosticFnPtr fn = interp->get_error_fn_ptr(); if (0 != fn) { std::string diag = construct_diagnostic(interp, "error", std::string("property ") + CdlParse::get_tcl_cmd_name(argv0), msg); (*fn)(diag); } CYG_REPORT_RETURN(); } void CdlParse::report_property_parse_warning(CdlInterpreter interp, CdlProperty prop, std::string msg) { CYG_REPORT_FUNCNAME("CdlParse::report_property_parse_warning"); report_property_parse_warning(interp, (prop->get_argv())[0], msg); CYG_REPORT_RETURN(); } //}}} //{{{ Generic property parsers // ---------------------------------------------------------------------------- // Generic parsers // // These routines provide some more generic property parsing routines. argv[0] // generally provides sufficient information to allow for sensible error messages. // The command-specific parsers have to provide a property name. In addition it is // possible to provide a function to handle per-command options, and another // function that performs a final sanity check before the property gets added // to the current entity. //{{{ parse_minimal_property() // ---------------------------------------------------------------------------- // A minimal property takes no arguments. int CdlParse::parse_minimal_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Minimal)) { CYG_REPORT_FUNCNAME("parse_minimal_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_Minimal new_property = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); if (data_index < argc) { CdlParse::report_property_parse_error(interp, argv[0], std::string("Unexpected data `") + argv[data_index] + "'."); } else { // The command is valid, turn it into a property. // The property has been parsed successfully. Add it to the current node CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_MinimalBody::make(current_node, name, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } catch(...) { if (0 != new_property) { delete new_property; } throw; } return TCL_OK; } //}}} //{{{ parse_string_property() // ---------------------------------------------------------------------------- int CdlParse::parse_string_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_String)) { CYG_REPORT_FUNCNAME("parse_string_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_String new_property = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); if (data_index == argc) { CdlParse::report_property_parse_error(interp, argv[0], "Missing argument."); } else if ((data_index + 1) < argc) { CdlParse::report_property_parse_error(interp, argv[0], std::string("Too many arguments, expecting just one.")); } else { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_StringBody::make(current_node, name, argv[data_index], argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } catch(...) { if (0 != new_property) { delete new_property; } throw; } CYG_REPORT_RETURN(); return TCL_OK; } //}}} //{{{ parse_tclcode_property() // ---------------------------------------------------------------------------- int CdlParse::parse_tclcode_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_TclCode)) { CYG_REPORT_FUNCNAME("parse_tclcode_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_TclCode new_property = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); if (data_index == argc) { CdlParse::report_property_parse_error(interp, argv[0], "Missing Tcl code."); } else if ((data_index + 1) < argc) { CdlParse::report_property_parse_error(interp, argv[0], std::string("Invalid number of arguments.\n") + "Expecting one argument, a Tcl code fragment."); } else if (!Tcl_CommandComplete(CDL_TCL_CONST_CAST(char*, argv[data_index]))) { CdlParse::report_property_parse_error(interp, argv[0], "Incomplete Tcl code fragment."); } else { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_TclCodeBody::make(current_node, name, argv[data_index], argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } catch(...) { if (0 != new_property) { delete new_property; } throw; } return TCL_OK; } //}}} //{{{ parse_stringvector_property() // ---------------------------------------------------------------------------- int CdlParse::parse_stringvector_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_StringVector), bool allow_empty) { CYG_REPORT_FUNCNAME("parse_tclcode_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_StringVector new_property = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); if (!allow_empty && (data_index == argc)) { CdlParse::report_property_parse_error(interp, argv[0], "Missing arguments."); } else { // Creating the property requires a vector of strings. std::vector<std::string> strings; for ( ; data_index < argc; data_index++) { strings.push_back(argv[data_index]); } CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_StringVectorBody::make(current_node, name, strings, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } catch(...) { if (0 != new_property) { delete new_property; } throw; } return TCL_OK; } //}}} //{{{ parse_reference_property() // ---------------------------------------------------------------------------- int CdlParse::parse_reference_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Reference), bool allow_empty, CdlUpdateHandler update_handler) { CYG_REPORT_FUNCNAME("parse_reference_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_Reference new_property = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); if (data_index == argc) { CdlParse::report_property_parse_error(interp, argv[0], "Missing argument."); } else if ((data_index + 1) < argc) { CdlParse::report_property_parse_error(interp, argv[0], "Too many arguments, expecting just one."); } else { std::string refname = argv[data_index]; if (!(Cdl::is_valid_cdl_name(refname) || (allow_empty && ("" == refname)))) { CdlParse::report_property_parse_error(interp, argv[0], "`" + refname + "' is not a valid CDL name"); } else { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_ReferenceBody::make(current_node, name, refname, update_handler, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } } catch(...) { if (0 != new_property) { delete new_property; } throw; } return TCL_OK; } //}}} //{{{ parse_expression_property() // ---------------------------------------------------------------------------- int CdlParse::parse_expression_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Expression), CdlUpdateHandler update_handler) { CYG_REPORT_FUNCNAME("parse_expression_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_Expression new_property = 0; CdlExpression expr = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index); if ("" == all_args) { CdlParse::report_property_parse_error(interp, argv[0], "Missing expression data."); } else { // The CdlExpression class has its own parsing routine. This // will raise an exception if there are any problems. It is // desirable to catch the exception and report the error via // the normal reporting mechanisms, which may allow parsing to // continue. try { expr = CdlExpressionBody::parse(all_args); } catch(CdlParseException e) { CdlParse::report_property_parse_error(interp, argv[0], e.get_message()); } if (0 != expr) { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_ExpressionBody::make(current_node, name, expr, update_handler, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } } catch(...) { if (0 != expr) { delete expr; } if (0 != new_property) { delete new_property; } throw; } if (0 != expr) { delete expr; } return TCL_OK; } //}}} //{{{ parse_list_expression_property() // ---------------------------------------------------------------------------- int CdlParse::parse_listexpression_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_ListExpression), CdlUpdateHandler update_handler) { CYG_REPORT_FUNCNAME("parse_list_expression_property"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_ListExpression new_property = 0; CdlListExpression expr = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index); if ("" == all_args) { CdlParse::report_property_parse_error(interp, argv[0], "Missing list expression data."); } else { try { expr = CdlListExpressionBody::parse(all_args); } catch(CdlParseException e) { CdlParse::report_property_parse_error(interp, argv[0], e.get_message()); } if (0 != expr) { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_ListExpressionBody::make(current_node, name, expr, update_handler, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } } catch(...) { if (0 != expr) { delete expr; } if (0 != new_property) { delete new_property; } throw; } if (0 != expr) { delete expr; } return TCL_OK; } //}}} //{{{ parse_goalexpression_property() // ---------------------------------------------------------------------------- int CdlParse::parse_goalexpression_property(CdlInterpreter interp, int argc, const char* argv[], std::string name, const char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_GoalExpression), CdlUpdateHandler update_handler) { CYG_REPORT_FUNCNAMETYPE("parse_goal_expression_property", "result %d"); CYG_PRECONDITION_CLASSC(interp); CdlProperty_GoalExpression new_property = 0; CdlGoalExpression expr = 0; try { std::vector<std::pair<std::string,std::string> > options; int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options); std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index); if ("" == all_args) { CdlParse::report_property_parse_error(interp, argv[0], "Missing goal expression data."); } else { try { expr = CdlGoalExpressionBody::parse(all_args); } catch(CdlParseException e) { CdlParse::report_property_parse_error(interp, argv[0], e.get_message()); } if (0 != expr) { CdlNode current_node = interp->get_node(); CYG_ASSERTC(0 != current_node); new_property = CdlProperty_GoalExpressionBody::make(current_node, name, expr, update_handler, argc, argv, options); if (0 != final_parser) { (*final_parser)(interp, new_property); } } } } catch(...) { if (0 != expr) { delete expr; } if (0 != new_property) { delete new_property; } throw; } if (0 != expr) { delete expr; } return TCL_OK; } //}}} //}}}
