/* Algorithm adapted from from GNU etags. * Scheme tag functions * look for (def... xyzzy * look for (def... (xyzzy * look for (def ... ((... (xyzzy .... * look for (set! xyzzy */ static void readIdentifier (vString *const name, const unsigned char *cp) { const unsigned char *p; vStringClear (name); /* Go till you get to white space or a syntactic break */ for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++) vStringPut (name, (int) *p); }
static void readIdentifier (lexingState * st) { const unsigned char *p; vStringClear (st->name); /* first char is a simple letter */ if (isAlpha (*st->cp) || *st->cp == '_') vStringPut (st->name, (int) *st->cp); /* Go till you get identifier chars */ for (p = st->cp + 1; isIdent (*p); p++) vStringPut (st->name, (int) *p); st->cp = p; vStringTerminate (st->name); }
static void parseLet (const unsigned char *line, int infunction) { vString *name = vStringNew (); const unsigned char *cp = line; const unsigned char *np = line; /* get the name */ if (isspace ((int) *cp)) { while (*cp && isspace ((int) *cp)) ++cp; /* * Ignore lets which set: * & - local buffer vim settings * @ - registers * [ - Lists or Dictionaries */ if (!*cp || *cp == '&' || *cp == '@' || *cp == '[' ) goto cleanUp; /* * Ignore vim variables which are read only * v: - Vim variables. */ np = cp; ++np; if ((int) *cp == 'v' && (int) *np == ':' ) goto cleanUp; /* Skip non-global vars in functions */ if (infunction && (int) *cp != 'g') goto cleanUp; /* deal with spaces, $, @ and & */ while (*cp && *cp != '$' && !isalnum ((int) *cp)) ++cp; if (!*cp) goto cleanUp; /* cp = skipPrefix (cp, &scope); */ do { if (!*cp) break; vStringPut (name, (int) *cp); ++cp; } while (isalnum ((int) *cp) || *cp == '_' || *cp == '#' || *cp == ':' || *cp == '$'); vStringTerminate (name); makeSimpleTag (name, VimKinds, K_VARIABLE); vStringClear (name); } cleanUp: vStringDelete (name); }
static void makeJsTag (tokenInfo *const token, const jsKind kind, vString *const signature) { if (JsKinds [kind].enabled && ! token->ignoreTag ) { const char *name = vStringValue (token->string); vString *fullscope = vStringNewCopy (token->scope); const char *p; tagEntryInfo e; if ((p = strrchr (name, '.')) != NULL) { if (vStringLength (fullscope) > 0) vStringPut (fullscope, '.'); vStringNCatS (fullscope, name, p - name); name = p + 1; } initTagEntry (&e, name); e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; e.kindName = JsKinds [kind].name; e.kind = JsKinds [kind].letter; if ( vStringLength(fullscope) > 0 ) { jsKind parent_kind = JSTAG_CLASS; /* if we're creating a function (and not a method), * guess we're inside another function */ if (kind == JSTAG_FUNCTION) parent_kind = JSTAG_FUNCTION; e.extensionFields.scope[0] = JsKinds [parent_kind].name; e.extensionFields.scope[1] = vStringValue (fullscope); } if (signature && vStringLength(signature)) { size_t i; /* sanitize signature by replacing all control characters with a * space (because it's simple). * there should never be any junk in a valid signature, but who * knows what the user wrote and CTags doesn't cope well with weird * characters. */ for (i = 0; i < signature->length; i++) { unsigned char c = (unsigned char) signature->buffer[i]; if (c < 0x20 /* below space */ || c == 0x7F /* DEL */) signature->buffer[i] = ' '; } e.extensionFields.arglist = vStringValue(signature); } makeTagEntry (&e); vStringDelete (fullscope); } }
/* Match the name of a tag (function, variable, type, ...) starting at pos. */ static char const *extract_name (char const *pos, vString * name) { while (isspace (*pos)) pos++; vStringClear (name); for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++) vStringPut (name, *pos); return pos; }
static void scanIdentifier (lexerState *lexer) { vStringClear(lexer->token_str); do { vStringPut(lexer->token_str, (char) lexer->cur_c); advanceChar(lexer); } while(lexer->cur_c != EOF && isIdentifierContinue(lexer->cur_c)); }
/* parses a class or an interface: * class Foo {} * class Foo extends Bar {} * class Foo extends Bar implements iFoo, iBar {} * interface iFoo {} * interface iBar extends iFoo {} * * if @name is not NULL, parses an anonymous class with name @name * new class {} * new class(1, 2) {} * new class(1, 2) extends Foo implements iFoo, iBar {} */ static boolean parseClassOrIface (tokenInfo *const token, const phpKind kind, const tokenInfo *name) { boolean readNext = TRUE; implType impl = CurrentStatement.impl; tokenInfo *nameFree = NULL; vString *inheritance = NULL; readToken (token); if (name) /* anonymous class */ { /* skip possible construction arguments */ skipOverParens (token); } else /* normal, named class */ { if (token->type != TOKEN_IDENTIFIER) return FALSE; name = nameFree = newToken (); copyToken (nameFree, token, TRUE); readToken (token); } inheritance = vStringNew (); /* read every identifiers, keywords and commas, and assume each * identifier (not keyword) is an inheritance * (like in "class Foo extends Bar implements iA, iB") */ while (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_KEYWORD || token->type == TOKEN_COMMA) { if (token->type == TOKEN_IDENTIFIER) { if (vStringLength (inheritance) > 0) vStringPut (inheritance, ','); vStringCat (inheritance, token->string); } readToken (token); } makeClassOrIfaceTag (kind, name, inheritance, impl); if (token->type == TOKEN_OPEN_CURLY) enterScope (token, name->string, kind); else readNext = FALSE; if (nameFree) deleteToken (nameFree); vStringDelete (inheritance); return readNext; }
static void parseSelector (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, (char) c); c = getcFromInputFile (); } while (isSelectorChar (c)); ungetcToInputFile (c); }
static void parseString (vString * const string, const int delimiter) { bool end = false; while (!end) { int c = getcFromInputFile (); if (c == EOF) end = true; else if (c == '\\') { c = getcFromInputFile (); /* This maybe a ' or ". */ vStringPut (string, c); } else if (c == delimiter) end = true; else vStringPut (string, c); } }
static void parseTemplateString (vString *const string) { int c; do { c = fileGetc (); if (c == '`') break; vStringPut (string, c); if (c == '\\') { c = fileGetc(); vStringPut(string, c); } else if (c == '$') { c = fileGetc (); if (c != '{') fileUngetc (c); else { int depth = 1; /* we need to use the real token machinery to handle strings, * comments, regexes and whatnot */ tokenInfo *token = newToken (); LastTokenType = TOKEN_UNDEFINED; vStringPut(string, c); do { readTokenFull (token, FALSE, string); if (isType (token, TOKEN_OPEN_CURLY)) depth++; else if (isType (token, TOKEN_CLOSE_CURLY)) depth--; } while (! isType (token, TOKEN_EOF) && depth > 0); deleteToken (token); } } } while (c != EOF); vStringTerminate (string); }
static void add_tag(const char *token, haskellKind kind, vString *name) { int i; for (i = 0; token[i] != '\0'; ++i) vStringPut(name, token[i]); vStringTerminate(name); makeSimpleTag(name, HaskellKinds, kind); vStringClear(name); }
/* Reads an identifier, whose first character is given by "c", into "tag", * together with the file location and corresponding line number. */ static void readIdentifier (int c, vString *const name) { vStringClear (name); do { vStringPut (name, c); c = getcAndCollect (); } while (c != EOF && cppIsident (c)); ungetcAndCollect (c); }
static void pushScope (tokenInfo *const token, const tokenInfo *const parent, const jsonKind parentKind) { if (vStringLength (token->scope) > 0) vStringPut (token->scope, '.'); vStringCat (token->scope, parent->string); vStringTerminate (token->scope); token->scopeKind = parentKind; }
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind) { if (isspace (**cp)) { vString *name = vStringNew (); vString *chunk = vStringNew (); rubyKind actual_kind; unsigned int i = 0; /* parse the identifier, allowing scoping like "class Foo::Bar::Baz" */ while (1) { actual_kind = parseIdentifier (cp, chunk, expected_kind); if (i++ > 0) vStringPut (name, '.'); vStringCat (name, chunk); vStringClear (chunk); if (actual_kind != K_UNDEFINED && (*cp)[0] == ':' && (*cp)[1] == ':') *cp += 2; else break; } vStringDelete (chunk); vStringTerminate (name); if (actual_kind == K_UNDEFINED || vStringLength (name) == 0) { /* * What kind of tags should we create for code like this? * * %w(self.clfloor clfloor).each do |name| * module_eval <<-"end;" * def #{name}(x, y=1) * q, r = x.divmod(y) * q = q.to_i * return q, r * end * end; * end * * Or this? * * class << HTTP * * For now, we don't create any. */ } else { emitRubyTag (name, actual_kind); } vStringDelete (name); } }
/* * Emits a tag for the given 'name' of kind 'kind' at the current nesting. */ static void emitRubyTag (vString* name, rubyKind kind) { tagEntryInfo tag; vString* scope; tagEntryInfo *parent; rubyKind parent_kind = K_UNDEFINED; NestingLevel *lvl; const char *unqualified_name; const char *qualified_name; int r; if (!RubyKinds[kind].enabled) { return; } vStringTerminate (name); scope = nestingLevelsToScope (nesting); lvl = nestingLevelsGetCurrent (nesting); parent = getEntryOfNestingLevel (lvl); if (parent) parent_kind = parent->kind - RubyKinds; qualified_name = vStringValue (name); unqualified_name = strrchr (qualified_name, SCOPE_SEPARATOR); if (unqualified_name && unqualified_name[1]) { if (unqualified_name > qualified_name) { if (vStringLength (scope) > 0) vStringPut (scope, SCOPE_SEPARATOR); vStringNCatS (scope, qualified_name, unqualified_name - qualified_name); /* assume module parent type for a lack of a better option */ parent_kind = K_MODULE; } unqualified_name++; } else unqualified_name = qualified_name; initTagEntry (&tag, unqualified_name, &(RubyKinds [kind])); if (vStringLength (scope) > 0) { Assert (0 <= parent_kind && (size_t) parent_kind < (ARRAY_SIZE (RubyKinds))); tag.extensionFields.scopeKind = &(RubyKinds [parent_kind]); tag.extensionFields.scopeName = vStringValue (scope); } r = makeTagEntry (&tag); nestingLevelsPush (nesting, r); vStringClear (name); vStringDelete (scope); }
/** * Reads from 'start' to 'end' and eliminates all spaces * inbetween. */ static char *readBetweenDelimitersWhileTrimmingSpaces(char start, char end) { static vString *wordBuffer = 0; int z; if (!wordBuffer) wordBuffer = vStringNew(); else vStringClear(wordBuffer); z = skipToNonWhite(); if (z != start) return NULL; while ((z = cppGetc()) != EOF && z != end) { if (isspace(z)) continue; vStringPut(wordBuffer, z); } if (z == EOF) return NULL; vStringPut(wordBuffer, z); vStringPut(wordBuffer, 0); return vStringValue(wordBuffer); }
static void parseFunction (const unsigned char *line) { vString *name = vStringNew (); /* boolean inFunction = FALSE; */ int scope; const unsigned char *cp = line + 1; if ((int) *++cp == 'n' && (int) *++cp == 'c' && (int) *++cp == 't' && (int) *++cp == 'i' && (int) *++cp == 'o' && (int) *++cp == 'n') ++cp; if ((int) *cp == '!') ++cp; if (isspace ((int) *cp)) { while (*cp && isspace ((int) *cp)) ++cp; if (*cp) { cp = skipPrefix (cp, &scope); if (isupper ((int) *cp) || scope == 's' || /* script scope */ scope == '<' || /* script scope */ scope == 'd' || /* dictionary */ scope == 'a') /* autoload */ { do { vStringPut (name, (int) *cp); ++cp; } while (isalnum ((int) *cp) || *cp == '_' || *cp == '.' || *cp == '#'); vStringTerminate (name); makeSimpleTag (name, VimKinds, K_FUNCTION); vStringClear (name); } } } /* TODO - update struct to indicate inside function */ while ((line = readVimLine ()) != NULL) { /* * Vim7 added the for/endfo[r] construct, so we must first * check for an "endfo", before a "endf" */ if ( (!strncmp ((const char*) line, "endfo", (size_t) 5) == 0) && (strncmp ((const char*) line, "endf", (size_t) 4) == 0) ) break; /* TODO - call parseVimLine */ } vStringDelete (name); }
static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, (char) c); c = getcFromInputFile (); } while (isIdentChar (c)); ungetcToInputFile (c); vStringTerminate (string); }
/* * Copies the characters forming an identifier from *cp into * name, leaving *cp pointing to the character after the identifier. */ static rubyKind parseIdentifier ( const unsigned char** cp, vString* name, rubyKind kind) { /* Method names are slightly different to class and variable names. * A method name may optionally end with a question mark, exclamation * point or equals sign. These are all part of the name. * A method name may also contain a period if it's a singleton method. */ const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_"; skipWhitespace (cp); /* Check for an anonymous (singleton) class such as "class << HTTP". */ if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<') { return K_UNDEFINED; } /* Check for operators such as "def []=(key, val)". */ if (kind == K_METHOD || kind == K_SINGLETON) { if (parseRubyOperator (name, cp)) { return kind; } } /* Copy the identifier into 'name'. */ while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok))) { char last_char = **cp; vStringPut (name, last_char); ++*cp; if (kind == K_METHOD) { /* Recognize singleton methods. */ if (last_char == '.') { vStringTerminate (name); vStringClear (name); return parseIdentifier (cp, name, K_SINGLETON); } /* Recognize characters which mark the end of a method name. */ if (charIsIn (last_char, "?!=")) { break; } } } return kind; }
static const unsigned char *parseIdentifier ( const unsigned char *cp, vString *const identifier) { vStringClear (identifier); while (isIdentifierCharacter ((int) *cp)) { vStringPut (identifier, (int) *cp); ++cp; } return cp; }
static void parseString (vString * const string, const int delimiter) { boolean end = FALSE; while (!end) { int c = fileGetc (); if (c == EOF) end = TRUE; else if (c == '\\') { c = fileGetc (); /* This maybe a ' or ". */ vStringPut (string, c); } else if (c == delimiter) end = TRUE; else vStringPut (string, c); } vStringTerminate (string); }
static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, c); c = getcFromInputFile (); } while (isIdentChar (c)); vStringTerminate (string); ungetcToInputFile (c); /* always unget, LF might add a semicolon */ }
static void parseSelector (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, (char) c); c = fileGetc (); } while (isSelectorChar (c)); fileUngetc (c); vStringTerminate (string); }
static void parseString (vString *const string, const int delimiter) { boolean end = FALSE; while (! end) { int c = fileGetc (); if (c == EOF) end = TRUE; else if (c == '\\') { /* Eat the escape sequence (\", \', etc). We properly handle * <LineContinuation> by eating a whole \<CR><LF> not to see <LF> * as an unescaped character, which is invalid and handled below. * Also, handle the fact that <LineContinuation> produces an empty * sequence. * See ECMA-262 7.8.4 */ c = fileGetc(); if (c != '\r' && c != '\n') vStringPut(string, c); else if (c == '\r') { c = fileGetc(); if (c != '\n') fileUngetc (c); } } else if (c == delimiter) end = TRUE; else if (c == '\r' || c == '\n') { /* those are invalid when not escaped */ end = TRUE; /* we don't want to eat the newline itself to let the automatic * semicolon insertion code kick in */ fileUngetc (c); } else vStringPut (string, c); } vStringTerminate (string); }
/* While ANSI only permits lines of the form: * # line n "filename" * Earlier compilers generated lines of the form * # n filename * GNU C will output lines of the form: * # n "filename" * So we need to be fairly flexible in what we accept. */ static vString *readFileName (char *s) { vString *const fileName = vStringNew (); bool quoteDelimited = false; skipWhite (&s); if (*s == '"') { s++; /* skip double-quote */ quoteDelimited = true; } while (*s != '\0' && *s != '\n' && (quoteDelimited ? (*s != '"') : (*s != ' ' && *s != '\t'))) { vStringPut (fileName, *s); s++; } vStringPut (fileName, '\0'); return fileName; }
/* Read a VHDL identifier beginning with "firstChar" and place it into "name". */ static void parseIdentifier (vString * const string, const int firstChar) { int c = firstChar; Assert (isIdentChar1 (c)); do { vStringPut (string, c); c = getcFromInputFile (); } while (isIdentChar (c)); if (!isspace (c)) ungetcToInputFile (c); /* unget non-identifier character */ }
/* Read a C identifier beginning with "firstChar" and places it into * "name". */ static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; Assert (isIdentChar (c)); do { vStringPut (string, c); c = fileGetc (); } while (isIdentChar (c)); vStringTerminate (string); fileUngetc (c); /* unget non-identifier character */ }
static void readIdentifier (const int first, vString *const id) { int c = first; vStringClear (id); while (isIdentifier (c)) { vStringPut (id, c); c = nextChar (); } fileUngetc (c); vStringTerminate (id); }
CXXToken * cxxTokenChainExtractRange( CXXToken * from, CXXToken * to, unsigned int uFlags ) { if(!from) return NULL; CXXToken * pToken = from; CXXToken * pRet = cxxTokenCreate(); pRet->iLineNumber = pToken->iLineNumber; pRet->oFilePosition = pToken->oFilePosition; pRet->eType = pToken->eType; cxxTokenAppendToString(pRet->pszWord,pToken); if( (!(uFlags & CXXTokenChainExtractRangeNoTrailingSpaces)) && pToken->bFollowedBySpace ) vStringPut (pRet->pszWord, ' '); pRet->bFollowedBySpace = pToken->bFollowedBySpace; while(pToken != to) { pToken = pToken->pNext; if(!pToken) return pRet; cxxTokenAppendToString(pRet->pszWord,pToken); if( (!(uFlags & CXXTokenChainExtractRangeNoTrailingSpaces)) && pToken->bFollowedBySpace ) vStringPut (pRet->pszWord, ' '); pRet->bFollowedBySpace = pToken->bFollowedBySpace; } return pRet; }
void cxxTokenChainJoinInString( CXXTokenChain * tc, vString * s, const char * szSeparator, unsigned int uFlags ) { if(!tc) return; if(tc->iCount == 0) return; CXXToken * t = tc->pHead; cxxTokenAppendToString(s,t); if( (!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) && t->bFollowedBySpace ) vStringPut (s, ' '); t = t->pNext; while(t) { if(szSeparator) vStringCatS(s,szSeparator); cxxTokenAppendToString(s,t); if( (!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) && t->bFollowedBySpace ) vStringPut (s, ' '); t = t->pNext; } }