📄 parse.cpp
字号:
case ']': if (in_ident) { start++; goto extract; } square_brackets++; break; default: start++; goto extract; } } }extract: /* ident is the leftmost token, stack[*] the ones to the right * Example: str.left(2,5).toUpper() * ^^^ ^^^^ ^^^^^^^ * ident stack[1] stack[0] */ ident = scanForIdent(&start); if (!ident) return false; /* we need this little kludge with old_type to avoid mem leaks */ QString type, old_type; /* for static access, parsing is done, just return the identifier */ if (exp->access != AccessStatic) { QString saved_start = start; // start can change, so we save it getScopeAndLocals(scope, expr, ident); /* if we have the start of a function/method, don't return the type * of this function, but className, which it is member of */ type = getTypeOfToken(ident, NULL, scope, scanForFuncdef(saved_start)); /* members can't be local variables */ scope->localdef[0] = '\0'; while (type!="" && num_stack > 0) { ident = scanForIdent(&stack[--num_stack]); old_type = type; //<brc code>: namespace workaround: if the "type" of an identifier is namespace ignore it if (type == "namespace") old_type = ""; //<\end brc code> type = getTypeOfToken(ident, old_type.toAscii(), scope, scanForFuncdef(stack[num_stack])); } } else /* static member */ type = ident; /* copy result into passed Expression argument */ if (type!="" && !(exp->access == AccessInFunction)) { exp->className = type; exp->function[0] = '\0'; return true; } else if (exp->access == AccessInFunction) { exp->className = old_type; exp->function = ident; return true; } return false;}Expression Parse::parseExpression(QString expression, Scope * scope, bool showAllResults){ Expression exp; exp.access = ParseError; int len = expression.length(); if (len < 1) return exp; // we found that the user has beginning to write if(!showAllResults) { QByteArray array(expression.toLocal8Bit() ); if( !array.count() ) return exp; const char *start = array.data(), *p = start; //const char *start = expression.toLocal8Bit(), *p = start; while (*p) p++; p--; while (p != start && *p != '.' && *p != '\n' && *p != '\r' && *p != ' ' && *p != '\t' && *p != ';' && *p != '{' && *p != '}' && *p != '(' && *p != ',' && (p-1) != start && (*p != '>' || *(p - 1) != '-') && (*p != ':' || *(p - 1) != ':')) p--; exp.writing = p+1; } /* A global function should be completed, if nothing else is found */ exp.access = AccessGlobal; bool allow_AccessInFunction = true; // false, when other characters than whitespace were typed /* search for the type of the correct completion */ while (--len >= 0) { char last = ((const char*)expression.toAscii())[len]; switch (last) { case ' ': case '\t': /* skip initial spaces */ if (exp.access == AccessGlobal) { /* exp.access = ParseError;*/ continue; } else { exp.access = AccessGlobal; goto extract; } case '>': if (len && expression[len - 1] == '-') { exp.access = AccessPointer; expression[len + 1] = '\0'; /* truncate the string */ goto extract; } else { exp.access = AccessGlobal; /* XXX: AccessError ? */ goto extract; } case '.': exp.access = AccessMembers; expression[len + 1] = '\0'; /* truncate the string */ goto extract; case ':': if (len && expression[len - 1] == ':') { exp.access = AccessStatic; expression[len + 1] = '\0'; /* truncate the string */ goto extract; } else { exp.access = AccessGlobal; goto extract; } case '(': if (allow_AccessInFunction) { exp.access = AccessInFunction; expression[len + 1] = '\0'; /* truncate the string */ } goto extract; default: if (isalpha(last) || last == '_') { /* we only list function definitions if after the opening * ( bracket of the function is no identifier */ allow_AccessInFunction = false; break; } else goto extract; } }extract: /* now extract the type out of the string */ if (exp.access == AccessMembers || exp.access == AccessPointer || exp.access == AccessStatic || exp.access == AccessInFunction) { if (!getTypeOfExpression(expression.toAscii(), &exp, scope)) exp.access = ParseError; } else if (exp.access == AccessGlobal) getScopeAndLocals(scope, expression.toAscii(), NULL); return exp;}Tag Parse::prettifyTag(const tagEntry * entry){ Tag tag; tag.name = entry->name; tag.kind = tagsField(entry, "kind"); tag.access = tagsField(entry, "access"); tag.signature = tagsField(entry, "signature"); tag.isFunction = (tag.signature.length()); char *p = (char *) entry->address.pattern; /* for a macro the pattern is already parsed */ if (tag.kind == "macro") { /* NOTE: exuberant-ctags 5.5.4 does not provide a valid pattern for found macros * work around it, by getting the line myself */ char pat_macro[512]; unsigned long line = entry->address.lineNumber; if (line == 0) /* sometimes ctags can't find the correct line */ return tag; FILE *fileMacro = fopen(entry->file, "r"); if (fileMacro) { while ((p = fgets(pat_macro, 512, fileMacro)) != NULL) { line--; if (line <= 0) { /* remove leading spaces */ p++; /* skip over # - it is added later again */ while (*p == ' ' || *p == '\t') p++; tag.longName = '#' + p; /* remove new line at the end */ tag.longName.remove(tag.longName.length() - 1, 1); break; } } tag.longName += " [macro]"; fclose(fileMacro); return tag; } } /* special handling for enumerator */ if (tag.kind == "enumerator") { /* skip whitespace from variable/function patterns */ size_t skip = strspn(p, "/^ \t"); p += skip; /* remove trailing $/ characters */ char *pos = NULL; if ((pos = strstr(p, "$/")) != NULL) *pos = '\0'; /* replace \/\/ and \/ * *\/ to correctly show comments */ while ((pos = strstr(p, "\\/\\/")) != NULL) memcpy(pos, " //", 4); while ((pos = strstr(p, "\\/*")) != NULL) memcpy(pos, " /*", 3); while ((pos = strstr(p, "*\\/")) != NULL) memcpy(pos, " */", 3); tag.longName += QString(p) + " [enumerator]"; return tag; } size_t skip = strspn(p, "/^ \t"); p += skip; /* remove trailing $/ characters */ char *pos = NULL; if ((pos = strstr(p, "$/")) != NULL) *pos = '\0'; tag.longName += p; /* if it is a function, add signature as well */ if (tag.signature.length()) tag.parameters += tag.signature; if (tag.access.length() && tag.access == "private" || tag.access == "protected") tag.longName += '[' + tag.access + ']'; return tag;}bool Parse::getScopeAndLocals(Scope * sc, const QString &expr, const QString &ident){ // initialize scope if nothing better is found sc->scope = ""; sc->localdef = ""; /* create a tags file for `expr' with function names only. * The function with the highest line number is our valid scope * --sort=no, because tags generation probably faster, and * so I just have to look for the last entry to find 'my' tag */ QString command = ctagsCmdPath + " --language-force=c++ --sort=no --fields=fKmnsz --c++-kinds=fn -o \"" + smallTagsFilePath + "\" \"" + parsedFilePath + '\"'; // I don't process any user input, so system() should be safe enough QProcess ctags; ctags.execute(command); QFile::remove (parsedFilePath); if (ctags.exitStatus() == QProcess::CrashExit) return false; /* find the last entry, this is our current scope */ tagFileInfo info; tagFile *tfile = tagsOpen(smallTagsFilePath.toAscii(), &info); tagEntry entry; const char *scope = NULL; if (tfile && info.status.opened) { if (tagsFirst(tfile, &entry) == TagSuccess) { do scope = tagsField(&entry, "class"); while (tagsNext(tfile, &entry) == TagSuccess); } tagsClose(tfile); } /* must be before the 'type = extract_type_qualifier()' code, which modifies scope */ if (scope) sc->scope = scope; /* get local definition (if any) */ if (ident!="") { QString type = extractTypeQualifier(expr, ident); if (type.length()) { sc->localdef = type; } else sc->localdef = ""; } QFile::remove (smallTagsFilePath); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -