📄 parse.cxx
字号:
} 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 + ", 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 prefix // Construct a suitable prefix for any warning or error message. This// should include the filename and the entity name.//// Obviously a line number would be rather useful as well, but this is not// very easy because of the way Tcl interpreters work.std::stringCdlParse::get_diagnostic_prefix(CdlInterpreter interp){ std::string filename = interp->get_filename(); CdlNode current_node = interp->get_node(); std::string result = ("" != filename) ? filename : "<unknown data source>"; if (0 != current_node) { result += ", " + current_node->get_class_name() + " " + current_node->get_name(); } result += "\n "; 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 voiderror_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();}voidCdlParse::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();}voidCdlParse::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();}intCdlParse::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 an error or warning. This involves adding a suitable prefix// and invoking the reporting callback currently associated with the// interpreter. For errors it is also necessary to increment the error// counter so that later count can detect the number of errors that// have occurred.//// The error callback is allowed to raise a CdlParseException. This should// not be caught here. Instead this exception is caught in every parse// routine, before it can go back through the Tcl interpreter.//// FIXME: cope with prefixing multiline error messages.voidCdlParse::report_error(CdlInterpreter interp, std::string message){ CYG_REPORT_FUNCNAME("CdlParse::report_error"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); incr_error_count(interp); message = get_diagnostic_prefix(interp) + message; CdlDiagnosticFnPtr fn = interp->get_error_fn_ptr(); CYG_ASSERT(0 != fn, "during parsing an interpreter should have an associated error reporting function"); (*fn)(message); CYG_REPORT_RETURN();}voidCdlParse::report_warning(CdlInterpreter interp, std::string message){ CYG_REPORT_FUNCNAME("CdlParse::report_warning"); CYG_REPORT_FUNCARG1("interp %p", interp); CYG_PRECONDITION_CLASSC(interp); message = get_diagnostic_prefix(interp) + message; CdlDiagnosticFnPtr fn = interp->get_warning_fn_ptr(); if (0 != fn) { (*fn)(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.intCdlParse::unknown_command(CdlInterpreter interp, int argc, 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.// Provide a prefix that matches the current property.std::stringCdlParse::get_property_prefix(char* argv0){ CYG_REPORT_FUNCNAME("CdlParse::get_property_prefix"); std::string result = std::string("Property " ) + CdlParse::get_tcl_cmd_name(argv0) + ", "; CYG_REPORT_RETURN(); return result;}std::stringCdlParse::get_property_prefix(CdlProperty prop){ CYG_REPORT_FUNCNAME("CdlParse::get_property_prefix"); std::string result = std::string("Property "); const std::vector<std::string>& argv = prop->get_argv(); result = result + argv[0] + ", "; CYG_REPORT_RETURN(); return result;}// A variant of report_parse_error() which also adds the property prefix.voidCdlParse::report_property_parse_error(CdlInterpreter interp, char* argv0, std::string msg){ CYG_REPORT_FUNCNAME("CdlPase::report_property_parse_error"); report_error(interp, get_property_prefix(argv0) + msg); CYG_REPORT_RETURN();}voidCdlParse::report_property_parse_error(CdlInterpreter interp, CdlProperty prop, std::string msg){ CYG_REPORT_FUNCNAME("CdlParse::report_property_parse_error"); report_error(interp, get_property_prefix(prop) + 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.intCdlParse::parse_minimal_property(CdlInterpreter interp, int argc, char** argv, std::string name, 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() // ----------------------------------------------------------------------------intCdlParse::parse_string_property(CdlInterpreter interp, int argc, char** argv, std::string name, 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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -