⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse.cxx

📁 移植到WLIT项目的redboot源代码
💻 CXX
📖 第 1 页 / 共 3 页
字号:
// 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::stringCdlParse::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 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 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.voidCdlParse::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();}voidCdlParse::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.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.// A variant of report_parse_error() which also adds the property prefix.voidCdlParse::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();}voidCdlParse::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 warningsvoidCdlParse::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();}voidCdlParse::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.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] + "'.");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -