/* * Returns a string describing the scope in 'list'. * We record the current scope as a list of entered scopes. * Scopes corresponding to 'if' statements and the like are * represented by empty strings. Scopes corresponding to * modules and classes are represented by the name of the * module or class. */ static vString* stringListToScope (const stringList* list) { unsigned int i; unsigned int chunks_output = 0; vString* result = vStringNew (); const unsigned int max = stringListCount (list); for (i = 0; i < max; ++i) { vString* chunk = stringListItem (list, i); if (vStringLength (chunk) > 0) { vStringCatS (result, (chunks_output++ > 0) ? "." : ""); vStringCatS (result, vStringValue (chunk)); } } return result; }
static void makeVhdlTag (tokenInfo * const token, const vhdlKind kind) { if (VhdlKinds[kind].enabled) { /* * If a scope has been added to the token, change the token * string to include the scope when making the tag. */ if (vStringLength (token->scope) > 0) { vString *fulltag = vStringNew (); vStringCopy (fulltag, token->scope); vStringCatS (fulltag, "."); vStringCatS (fulltag, vStringValue (token->string)); vStringTerminate (fulltag); vStringCopy (token->string, fulltag); vStringDelete (fulltag); } makeConstTag (token, kind); } }
CXXToken * cxxTokenCreateKeyword(int iLineNumber,MIOPos oFilePosition,enum CXXKeyword eKeyword) { CXXToken * pToken = cxxTokenCreate(); pToken->iLineNumber = iLineNumber; pToken->oFilePosition = oFilePosition; pToken->eType = CXXTokenTypeKeyword; pToken->eKeyword = eKeyword; pToken->bFollowedBySpace = TRUE; vStringCatS(pToken->pszWord,cxxKeywordName(eKeyword)); return pToken; }
static boolean recurseIntoDirectory (const char *const dirName) { boolean resize = FALSE; if (isRecursiveLink (dirName)) verbose ("ignoring \"%s\" (recursive link)\n", dirName); else if (! Option.recurse) verbose ("ignoring \"%s\" (directory)\n", dirName); else { verbose ("RECURSING into directory \"%s\"\n", dirName); #if defined (HAVE_OPENDIR) resize = recurseUsingOpendir (dirName); #elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) { vString *const pattern = vStringNew (); vStringCopyS (pattern, dirName); vStringPut (pattern, OUTPUT_PATH_SEPARATOR); vStringCatS (pattern, "*.*"); resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern)); vStringDelete (pattern); } #elif defined (AMIGA) { vString *const pattern = vStringNew (); if (*dirName != '\0' && strcmp (dirName, ".") != 0) { vStringCopyS (pattern, dirName); if (dirName [strlen (dirName) - 1] != '/') vStringPut (pattern, '/'); } vStringCatS (pattern, "#?"); resize = createTagsForAmigaWildcard (vStringValue (pattern)); vStringDelete (pattern); } #endif } return resize; }
static void addToScope (tokenInfo *const token, const vString *const extra, int kindOfUpperScope) { if (vStringLength (token->scope) > 0) { const char* sep; sep = phpScopeSeparatorFor(token->parentKind, kindOfUpperScope); vStringCatS (token->scope, sep); } vStringCat (token->scope, extra); vStringTerminate(token->scope); }
static void findAbcTags (void) { vString *name = vStringNew(); const unsigned char *line; while ((line = readLineFromInputFile()) != NULL) { /*int name_len = vStringLength(name);*/ /* underlines must be the same length or more */ /*if (name_len > 0 && (line[0] == '=' || line[0] == '-') && issame((const char*) line)) { makeAbcTag(name, TRUE); }*/ /* if (line[1] == '%') { vStringClear(name); vStringCatS(name, (const char *) line); vStringTerminate(name); makeAbcTag(name, FALSE); }*/ if (line[0] == 'T') { /*vStringClear(name);*/ vStringCatS(name, " / "); vStringCatS(name, (const char *) line); vStringTerminate(name); makeAbcTag(name, FALSE); } else { vStringClear (name); if (! isspace(*line)) vStringCatS(name, (const char*) line); vStringTerminate(name); } } vStringDelete (name); }
static boolean createTagsForWildcardEntry ( const char *const pattern, const size_t dirLength, const char *const entryName) { boolean resize = FALSE; /* we must not recurse into the directories "." or ".." */ if (strcmp (entryName, ".") != 0 && strcmp (entryName, "..") != 0) { vString *const filePath = vStringNew (); vStringNCopyS (filePath, pattern, dirLength); vStringCatS (filePath, entryName); resize = createTagsForEntry (vStringValue (filePath)); vStringDelete (filePath); } return resize; }
static void initPhpEntry (tagEntryInfo *const e, const tokenInfo *const token, const phpKind kind, const accessType access) { int parentKind = -1; vStringClear (FullScope); if (vStringLength (CurrentNamesapce) > 0) { parentKind = K_NAMESPACE; vStringCat (FullScope, CurrentNamesapce); } initTagEntry (e, vStringValue (token->string), kind); e->lineNumber = token->lineNumber; e->filePosition = token->filePosition; if (access != ACCESS_UNDEFINED) e->extensionFields.access = accessToString (access); if (vStringLength (token->scope) > 0) { parentKind = token->parentKind; if (vStringLength (FullScope) > 0) { const char* sep; sep = phpScopeSeparatorFor (parentKind, K_NAMESPACE); vStringCatS (FullScope, sep); } vStringCat (FullScope, token->scope); } if (vStringLength (FullScope) > 0) { Assert (parentKind >= 0); e->extensionFields.scopeKindIndex = parentKind; e->extensionFields.scopeName = vStringValue (FullScope); } if (token->anonymous) markTagExtraBit (e, XTAG_ANONYMOUS); }
/* * Returns a string describing the scope in 'nls'. * We record the current scope as a list of entered scopes. * Scopes corresponding to 'if' statements and the like are * represented by empty strings. Scopes corresponding to * modules and classes are represented by the name of the * module or class. */ static vString* nestingLevelsToScope (const NestingLevels* nls) { int i; unsigned int chunks_output = 0; vString* result = vStringNew (); for (i = 0; i < nls->n; ++i) { NestingLevel *nl = nestingLevelsGetNth (nls, i); tagEntryInfo *e = getEntryOfNestingLevel (nl); if (e && strlen (e->name) > 0 && (!e->placeholder)) { if (chunks_output++ > 0) vStringPut (result, SCOPE_SEPARATOR); vStringCatS (result, e->name); } } return result; }
/* TODO: parse overlining & underlining as distinct sections. */ static void findRstTags (void) { vString *name = vStringNew (); fpos_t filepos; const unsigned char *line; memset(&filepos, 0, sizeof(fpos_t)); memset(kindchars, 0, sizeof kindchars); nestingLevels = nestingLevelsNew(); while ((line = readLineFromInputFile ()) != NULL) { int line_len = strlen((const char*) line); int name_len_bytes = vStringLength(name); int name_len = utf8_strlen(vStringValue(name), name_len_bytes); /* if the name doesn't look like UTF-8, assume one-byte charset */ if (name_len < 0) name_len = name_len_bytes; /* underlines must be the same length or more */ if (line_len >= name_len && name_len > 0 && ispunct(line[0]) && issame((const char*) line)) { char c = line[0]; int kind = get_kind(c); if (kind >= 0) { makeRstTag(name, kind, filepos); continue; } } vStringClear (name); if (!isspace(*line)) { vStringCatS(name, (const char*)line); filepos = getInputFilePosition(); } vStringTerminate(name); } vStringDelete (name); nestingLevelsFree(nestingLevels); }
static void createContext (tokenInfo *const scope) { if (scope) { vString *contextName = vStringNew (); verbose ("Creating new context %s\n", vStringValue (scope->name)); /* Determine full context name */ if (currentContext->kind != K_UNDEFINED) { vStringCopy (contextName, currentContext->name); vStringCatS (contextName, "."); } vStringCat (contextName, scope->name); /* Create context */ currentContext = pushToken (currentContext, scope); vStringCopy (currentContext->name, contextName); vStringDelete (contextName); } }
static boolean createTagsForWildcardArg (const char *const arg) { boolean resize = FALSE; vString *const pattern = vStringNewInit (arg); char *patternS = vStringValue (pattern); #if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) /* We must transform the "." and ".." forms into something that can * be expanded by the findfirst/_findfirst functions. */ if (Option.recurse && (strcmp (patternS, ".") == 0 || strcmp (patternS, "..") == 0)) { vStringPut (pattern, OUTPUT_PATH_SEPARATOR); vStringCatS (pattern, "*.*"); } resize |= createTagsForWildcardUsingFindfirst (patternS); #endif vStringDelete (pattern); return resize; }
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; } }
static void parseMethodsImplemName (vString * const ident, objcToken what) { switch (what) { case Tok_PARL: toDoNext = &tillToken; comeAfter = &parseMethodsImplemName; waitedToken = Tok_PARR; break; case Tok_dpoint: vStringCat (fullMethodName, prevIdent); vStringCatS (fullMethodName, ":"); vStringClear (prevIdent); break; case ObjcIDENTIFIER: vStringCopy (prevIdent, ident); break; case Tok_CurlL: case Tok_semi: /* method name is not simple */ if (vStringLength (fullMethodName) != '\0') { addTag (fullMethodName, methodKind); vStringClear (fullMethodName); } else addTag (prevIdent, methodKind); toDoNext = &parseImplemMethods; parseImplemMethods (ident, what); vStringClear (prevIdent); break; default: break; } }
static void makeTag (tokenInfo *const token, const goKind kind, tokenInfo *const parent_token, const goKind parent_kind, const char *argList, const char *varType) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name); if (!GoKinds [kind].enabled) return; e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; e.kindName = GoKinds [kind].name; e.kind = GoKinds [kind].letter; if (argList) e.extensionFields.arglist = argList; if (varType) e.extensionFields.varType = varType; if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL) { e.extensionFields.scope[0] = GoKinds[parent_kind].name; e.extensionFields.scope[1] = vStringValue (parent_token->string); } makeTagEntry (&e); if (scope && Option.include.qualifiedTags) { vString *qualifiedName = vStringNew (); vStringCopy (qualifiedName, scope); vStringCatS (qualifiedName, "."); vStringCat (qualifiedName, token->string); e.name = vStringValue (qualifiedName); makeTagEntry (&e); vStringDelete (qualifiedName); } }
static void dropContext (tokenInfo *const token) { verbose ("current context %s; context kind %0d; nest level %0d\n", vStringValue (currentContext->name), currentContext->kind, currentContext->nestLevel); vString *endTokenName = vStringNewInit("end"); if ((currentContext->kind == K_COVERGROUP && strcmp (vStringValue (token->name), "endgroup") == 0) || (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0 && strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0) ) { verbose ("Dropping context %s\n", vStringValue (currentContext->name)); currentContext = popToken (currentContext); } else { vStringCatS (endTokenName, kindFromKind (currentContext->kind)->name); if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0) { verbose ("Dropping context %s\n", vStringValue (currentContext->name)); currentContext = popToken (currentContext); } } vStringDelete(endTokenName); }
static void parseFunction (const unsigned char *line) { vString *name = vStringNew (); /* boolean inFunction = FALSE; */ int scope; const unsigned char *cp = line; int index = CORK_NIL; if (*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 */ { char prefix[3] = { [0] = (char)scope, [1] = ':', [2] = '\0' }; if (scope == 's') vStringCatS (name, prefix); do { vStringPut (name, (int) *cp); ++cp; } while (isalnum ((int) *cp) || *cp == '_' || *cp == '.' || *cp == '#'); vStringTerminate (name); index = makeSimpleTag (name, VimKinds, K_FUNCTION); vStringClear (name); } } }
/* parses namespace declarations * namespace Foo {} * namespace Foo\Bar {} * namespace Foo; * namespace Foo\Bar; * namespace; * napespace {} */ static boolean parseNamespace (tokenInfo *const token) { tokenInfo *nsToken = newToken (); vStringClear (CurrentNamesapce); copyToken (nsToken, token, FALSE); do { readToken (token); if (token->type == TOKEN_IDENTIFIER) { if (vStringLength (CurrentNamesapce) > 0) { const char *sep; sep = phpScopeSeparatorFor(K_NAMESPACE, K_NAMESPACE); vStringCatS (CurrentNamesapce, sep); } vStringCat (CurrentNamesapce, token->string); } } while (token->type != TOKEN_EOF && token->type != TOKEN_SEMICOLON && token->type != TOKEN_OPEN_CURLY); vStringTerminate (CurrentNamesapce); if (vStringLength (CurrentNamesapce) > 0) makeNamespacePhpTag (nsToken, CurrentNamesapce); if (token->type == TOKEN_OPEN_CURLY) enterScope (token, NULL, -1); deleteToken (nsToken); return TRUE; }
static void makeTag (tokenInfo *const token, const goKind kind, tokenInfo *const parent_token, const goKind parent_kind, const char *argList) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name, &(GoKinds [kind])); if (!GoKinds [kind].enabled) return; e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; if (argList) e.extensionFields.signature = argList; if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL) { e.extensionFields.scopeKind = &(GoKinds[parent_kind]); e.extensionFields.scopeName = vStringValue (parent_token->string); } makeTagEntry (&e); if (scope && isXtagEnabled(XTAG_QUALIFIED_TAGS)) { vString *qualifiedName = vStringNew (); vStringCopy (qualifiedName, scope); vStringCatS (qualifiedName, "."); vStringCat (qualifiedName, token->string); e.name = vStringValue (qualifiedName); markTagExtraBit (&e, XTAG_QUALIFIED_TAGS); makeTagEntry (&e); vStringDelete (qualifiedName); } }
void cxxTokenChainJoinRangeInString( CXXToken * from, CXXToken * to, vString * s, const char * szSeparator, unsigned int uFlags ) { if(!from) return; CXXToken * t = from; cxxTokenAppendToString(s,t); if((!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) && t->bFollowedBySpace) vStringPut (s, ' '); while(t && (t != to)) { t = t->pNext; if(t) return; if(szSeparator) vStringCatS(s,szSeparator); cxxTokenAppendToString(s,t); if( (!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) && t->bFollowedBySpace ) vStringPut (s, ' '); } }
// In case of a lambda without parentheses this is the capture list token. boolean cxxParserHandleLambda(CXXToken * pParenthesis) { CXX_DEBUG_ENTER(); CXXToken * pIdentifier = cxxTokenCreateAnonymousIdentifier(CXXTagKindFUNCTION); CXXTokenChain * pSave = g_cxx.pTokenChain; CXXTokenChain * pNew = cxxTokenChainCreate(); g_cxx.pTokenChain = pNew; tagEntryInfo * tag = cxxTagBegin(CXXTagKindFUNCTION,pIdentifier); CXXToken * pAfterParenthesis = pParenthesis ? pParenthesis->pNext : NULL; CXXToken * pCaptureList = NULL; if(pParenthesis) { if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeSquareParenthesisChain)) { // form (4) of lambda (see cxxParserOpeningBracketIsLambda()). pCaptureList = pParenthesis; } else if( pParenthesis->pPrev && cxxTokenTypeIs(pParenthesis->pPrev,CXXTokenTypeSquareParenthesisChain) ) { // other forms of lambda (see cxxParserOpeningBracketIsLambda()). pCaptureList = pParenthesis->pPrev; } } if( pAfterParenthesis && cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypeKeyword) && (pAfterParenthesis->eKeyword == CXXKeywordCONST) ) pAfterParenthesis = pAfterParenthesis->pNext; CXXToken * pTypeStart = NULL; CXXToken * pTypeEnd; if( pAfterParenthesis && cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypePointerOperator) && pAfterParenthesis->pNext && !cxxTokenTypeIs(pAfterParenthesis->pNext,CXXTokenTypeOpeningBracket) ) { pTypeStart = pAfterParenthesis->pNext; pTypeEnd = pTypeStart; while( pTypeEnd->pNext && (!cxxTokenTypeIs(pTypeEnd->pNext,CXXTokenTypeOpeningBracket)) ) pTypeEnd = pTypeEnd->pNext; while( (pTypeStart != pTypeEnd) && cxxTokenTypeIs(pTypeStart,CXXTokenTypeKeyword) && cxxKeywordExcludeFromTypeNames(pTypeStart->eKeyword) ) pTypeStart = pTypeStart->pNext; } int iCorkQueueIndex = CORK_NIL; if(tag) { tag->isFileScope = TRUE; CXXToken * pTypeName; if(pTypeStart) pTypeName = cxxTagSetTypeField(pTypeStart,pTypeEnd); else pTypeName = NULL; if(pCaptureList && cxxTagCPPFieldEnabled(CXXTagCPPFieldLambdaCaptureList)) { CXX_DEBUG_ASSERT(pCaptureList->pChain,"The capture list must be a chain"); cxxTokenChainCondense(pCaptureList->pChain,0); CXX_DEBUG_ASSERT( cxxTokenChainFirst(pCaptureList->pChain), "Condensation should have created a single token in the chain" ); cxxTagSetCPPField( CXXTagCPPFieldLambdaCaptureList, vStringValue(cxxTokenChainFirst(pCaptureList->pChain)->pszWord) ); } // FIXME: Properties? vString * pszSignature = NULL; if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain)) pszSignature = cxxTokenChainJoin(pParenthesis->pChain,NULL,0); if(pszSignature) tag->extensionFields.signature = vStringValue(pszSignature); iCorkQueueIndex = cxxTagCommit(); if(pTypeName) cxxTokenDestroy(pTypeName); if(pszSignature) vStringDelete(pszSignature); } cxxScopePush( pIdentifier, CXXTagKindFUNCTION, CXXScopeAccessUnknown ); if( pParenthesis && cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain) && cxxTagKindEnabled(CXXTagKindPARAMETER) ) { CXXFunctionParameterInfo oParamInfo; if(cxxParserTokenChainLooksLikeFunctionParameterList( pParenthesis->pChain,&oParamInfo )) cxxParserEmitFunctionParameterTags(&oParamInfo); } boolean bRet = cxxParserParseBlock(TRUE); if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); cxxScopePop(); pNew = g_cxx.pTokenChain; // May have been destroyed and re-created g_cxx.pTokenChain = pSave; g_cxx.pToken = pSave->pTail; // change the type of token so following parsing code is not confused too much g_cxx.pToken->eType = CXXTokenTypeAngleBracketChain; g_cxx.pToken->pChain = pNew; cxxTokenChainClear(pNew); CXXToken * t = cxxTokenCreate(); t->eType = CXXTokenTypeOpeningBracket; vStringCatS(t->pszWord,"{"); cxxTokenChainAppend(pNew,t); t = cxxTokenCreate(); t->eType = CXXTokenTypeClosingBracket; vStringCatS(t->pszWord,"}"); cxxTokenChainAppend(pNew,t); CXX_DEBUG_LEAVE(); return bRet; }
static void readToken (tokenInfo *const token) { int c; static tokenType lastTokenType = TOKEN_NONE; boolean firstWhitespace = TRUE; boolean whitespace; token->type = TOKEN_NONE; token->keyword = KEYWORD_NONE; vStringClear (token->string); getNextChar: do { c = getcFromInputFile (); token->lineNumber = getInputLineNumber (); token->filePosition = getInputFilePosition (); if (c == '\n' && (lastTokenType == TOKEN_IDENTIFIER || lastTokenType == TOKEN_STRING || lastTokenType == TOKEN_OTHER || lastTokenType == TOKEN_CLOSE_PAREN || lastTokenType == TOKEN_CLOSE_CURLY || lastTokenType == TOKEN_CLOSE_SQUARE)) { c = ';'; // semicolon injection } whitespace = c == '\t' || c == ' ' || c == '\r' || c == '\n'; if (signature && whitespace && firstWhitespace && vStringLength (signature) < MAX_SIGNATURE_LENGTH) { firstWhitespace = FALSE; vStringPut(signature, ' '); } } while (whitespace); switch (c) { case EOF: token->type = TOKEN_EOF; break; case ';': token->type = TOKEN_SEMICOLON; break; case '/': { boolean hasNewline = FALSE; int d = getcFromInputFile (); switch (d) { case '/': skipToCharacterInInputFile ('\n'); /* Line comments start with the * character sequence // and * continue through the next * newline. A line comment acts * like a newline. */ ungetcToInputFile ('\n'); goto getNextChar; case '*': do { do { d = getcFromInputFile (); if (d == '\n') { hasNewline = TRUE; } } while (d != EOF && d != '*'); c = getcFromInputFile (); if (c == '/') break; else ungetcToInputFile (c); } while (c != EOF && c != '\0'); ungetcToInputFile (hasNewline ? '\n' : ' '); goto getNextChar; default: token->type = TOKEN_OTHER; ungetcToInputFile (d); break; } } break; case '"': case '\'': case '`': token->type = TOKEN_STRING; parseString (token->string, c); token->lineNumber = getInputLineNumber (); token->filePosition = getInputFilePosition (); break; case '<': { int d = getcFromInputFile (); if (d == '-') token->type = TOKEN_LEFT_ARROW; else { ungetcToInputFile (d); token->type = TOKEN_OTHER; } } break; case '(': token->type = TOKEN_OPEN_PAREN; break; case ')': token->type = TOKEN_CLOSE_PAREN; break; case '{': token->type = TOKEN_OPEN_CURLY; break; case '}': token->type = TOKEN_CLOSE_CURLY; break; case '[': token->type = TOKEN_OPEN_SQUARE; break; case ']': token->type = TOKEN_CLOSE_SQUARE; break; case '*': token->type = TOKEN_STAR; break; case '.': token->type = TOKEN_DOT; break; case ',': token->type = TOKEN_COMMA; break; default: if (isStartIdentChar (c)) { parseIdentifier (token->string, c); token->lineNumber = getInputLineNumber (); token->filePosition = getInputFilePosition (); token->keyword = lookupKeyword (vStringValue (token->string), Lang_go); if (isKeyword (token, KEYWORD_NONE)) token->type = TOKEN_IDENTIFIER; else token->type = TOKEN_KEYWORD; } else token->type = TOKEN_OTHER; break; } if (signature && vStringLength (signature) < MAX_SIGNATURE_LENGTH) { if (token->type == TOKEN_LEFT_ARROW) vStringCatS(signature, "<-"); else if (token->type == TOKEN_STRING) { // only struct member annotations can appear in function prototypes // so only `` type strings are possible vStringPut(signature, '`'); vStringCat(signature, token->string); vStringPut(signature, '`'); } else if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_KEYWORD) vStringCat(signature, token->string); else if (c != EOF) vStringPut(signature, c); } lastTokenType = token->type; }
/* parse a function * * if @name is NULL, parses a normal function * function myfunc($foo, $bar) {} * function &myfunc($foo, $bar) {} * function myfunc($foo, $bar) : type {} * * if @name is not NULL, parses an anonymous function with name @name * $foo = function($foo, $bar) {} * $foo = function&($foo, $bar) {} * $foo = function($foo, $bar) use ($x, &$y) {} * $foo = function($foo, $bar) use ($x, &$y) : type {} */ static boolean parseFunction (tokenInfo *const token, const tokenInfo *name) { boolean readNext = TRUE; accessType access = CurrentStatement.access; implType impl = CurrentStatement.impl; tokenInfo *nameFree = NULL; readToken (token); /* skip a possible leading ampersand (return by reference) */ if (token->type == TOKEN_AMPERSAND) readToken (token); if (! name) { if (token->type != TOKEN_IDENTIFIER && token->type != TOKEN_KEYWORD) return FALSE; name = nameFree = newToken (); copyToken (nameFree, token, TRUE); readToken (token); } if (token->type == TOKEN_OPEN_PAREN) { vString *arglist = vStringNew (); int depth = 1; vStringPut (arglist, '('); do { readToken (token); switch (token->type) { case TOKEN_OPEN_PAREN: depth++; break; case TOKEN_CLOSE_PAREN: depth--; break; default: break; } /* display part */ switch (token->type) { case TOKEN_AMPERSAND: vStringPut (arglist, '&'); break; case TOKEN_CLOSE_CURLY: vStringPut (arglist, '}'); break; case TOKEN_CLOSE_PAREN: vStringPut (arglist, ')'); break; case TOKEN_CLOSE_SQUARE: vStringPut (arglist, ']'); break; case TOKEN_COLON: vStringPut (arglist, ':'); break; case TOKEN_COMMA: vStringCatS (arglist, ", "); break; case TOKEN_EQUAL_SIGN: vStringCatS (arglist, " = "); break; case TOKEN_OPEN_CURLY: vStringPut (arglist, '{'); break; case TOKEN_OPEN_PAREN: vStringPut (arglist, '('); break; case TOKEN_OPEN_SQUARE: vStringPut (arglist, '['); break; case TOKEN_PERIOD: vStringPut (arglist, '.'); break; case TOKEN_SEMICOLON: vStringPut (arglist, ';'); break; case TOKEN_BACKSLASH: vStringPut (arglist, '\\'); break; case TOKEN_STRING: { vStringCatS (arglist, "'"); vStringCat (arglist, token->string); vStringCatS (arglist, "'"); break; } case TOKEN_IDENTIFIER: case TOKEN_KEYWORD: case TOKEN_VARIABLE: { switch (vStringLast (arglist)) { case 0: case ' ': case '{': case '(': case '[': case '.': case '\\': /* no need for a space between those and the identifier */ break; default: vStringPut (arglist, ' '); break; } if (token->type == TOKEN_VARIABLE) vStringPut (arglist, '$'); vStringCat (arglist, token->string); break; } default: break; } } while (token->type != TOKEN_EOF && depth > 0); vStringTerminate (arglist); makeFunctionTag (name, arglist, access, impl); vStringDelete (arglist); readToken (token); /* normally it's an open brace or "use" keyword */ } /* skip use(...) */ if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_use) { readToken (token); skipOverParens (token); } /* PHP7 return type declaration or if parsing Zephir, skip function return * type hint */ if ((getInputLanguage () == Lang_php && token->type == TOKEN_COLON) || (getInputLanguage () == Lang_zephir && token->type == TOKEN_OPERATOR)) { do readToken (token); while (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_BACKSLASH); } if (token->type == TOKEN_OPEN_CURLY) enterScope (token, name->string, K_FUNCTION); else readNext = FALSE; if (nameFree) deleteToken (nameFree); return readNext; }
/* Algorithm adapted from from GNU etags. * Perl support by Bart Robinson <*****@*****.**> * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/ */ static void findPerlTags (void) { vString *name = vStringNew (); vString *package = NULL; boolean skipPodDoc = FALSE; const unsigned char *line; /* Core modules AutoLoader and SelfLoader support delayed compilation * by allowing Perl code that follows __END__ and __DATA__ tokens, * respectively. When we detect that one of these modules is used * in the file, we continue processing even after we see the * corresponding token that would usually terminate parsing of the * file. */ enum { RESPECT_END = (1 << 0), RESPECT_DATA = (1 << 1), } respect_token = RESPECT_END | RESPECT_DATA; while ((line = fileReadLine ()) != NULL) { boolean spaceRequired = FALSE; boolean qualified = FALSE; const unsigned char *cp = line; perlKind kind = K_NONE; tagEntryInfo e; if (skipPodDoc) { if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0) skipPodDoc = FALSE; continue; } else if (line [0] == '=') { skipPodDoc = isPodWord ((const char*)line + 1); continue; } else if (strcmp ((const char*) line, "__DATA__") == 0) { if (respect_token & RESPECT_DATA) break; else continue; } else if (strcmp ((const char*) line, "__END__") == 0) { if (respect_token & RESPECT_END) break; else continue; } else if (line [0] == '#') continue; while (isspace (*cp)) cp++; if (strncmp((const char*) cp, "sub", (size_t) 3) == 0) { TRACE("this looks like a sub\n"); cp += 3; kind = K_SUBROUTINE; spaceRequired = TRUE; qualified = TRUE; } else if (strncmp((const char*) cp, "use", (size_t) 3) == 0) { cp += 3; if (!isspace(*cp)) continue; while (*cp && isspace (*cp)) ++cp; if (strncmp((const char*) cp, "AutoLoader", (size_t) 10) == 0) { respect_token &= ~RESPECT_END; continue; } if (strncmp((const char*) cp, "SelfLoader", (size_t) 10) == 0) { respect_token &= ~RESPECT_DATA; continue; } if (strncmp((const char*) cp, "constant", (size_t) 8) != 0) continue; cp += 8; /* Skip up to the first non-space character, skipping empty * and comment lines. */ while (isspace(*cp)) cp++; while (!*cp || '#' == *cp) { cp = fileReadLine (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } if ('{' == *cp) { ++cp; if (0 == parseConstantsFromHashRef(cp, name, package)) { vStringClear(name); continue; } else goto END_MAIN_WHILE; } kind = K_CONSTANT; spaceRequired = FALSE; qualified = TRUE; } else if (strncmp((const char*) cp, "package", (size_t) 7) == 0 && ('\0' == cp[7] || isspace(cp[7]))) { cp += 7; while (isspace (*cp)) cp++; while (!*cp || '#' == *cp) { cp = fileReadLine (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } if (package == NULL) package = vStringNew (); else vStringClear (package); const unsigned char *const first = cp; while (*cp && (int) *cp != ';' && !isspace ((int) *cp)) { vStringPut (package, (int) *cp); cp++; } vStringCatS (package, "::"); cp = first; /* Rewind */ kind = K_PACKAGE; spaceRequired = FALSE; qualified = TRUE; } else if (strncmp((const char*) cp, "format", (size_t) 6) == 0) { cp += 6; kind = K_FORMAT; spaceRequired = TRUE; qualified = TRUE; } else { if (isIdentifier1 (*cp)) { const unsigned char *p = cp; while (isIdentifier (*p)) ++p; while (isspace (*p)) ++p; if ((int) *p == ':' && (int) *(p + 1) != ':') kind = K_LABEL; } } if (kind != K_NONE) { TRACE("cp0: %s\n", (const char *) cp); if (spaceRequired && *cp && !isspace (*cp)) continue; TRACE("cp1: %s\n", (const char *) cp); while (isspace (*cp)) cp++; while (!*cp || '#' == *cp) { /* Gobble up empty lines and comments */ cp = fileReadLine (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } while (isIdentifier (*cp) || (K_PACKAGE == kind && ':' == *cp)) { vStringPut (name, (int) *cp); cp++; } if (K_FORMAT == kind && vStringLength (name) == 0 && /* cp did not advance */ '=' == *cp) { /* format's name is optional. If it's omitted, 'STDOUT' is assumed. */ vStringCatS (name, "STDOUT"); } vStringTerminate (name); TRACE("name: %s\n", name->buffer); if (0 == vStringLength(name)) { vStringClear(name); continue; } if (K_SUBROUTINE == kind) { /* * isSubroutineDeclaration() may consume several lines. So * we record line positions. */ initTagEntry(&e, vStringValue(name), NULL); if (TRUE == isSubroutineDeclaration(cp)) { if (TRUE == PerlKinds[K_SUBROUTINE_DECLARATION].enabled) { kind = K_SUBROUTINE_DECLARATION; } else { vStringClear (name); continue; } } else if (! PerlKinds[kind].enabled) { continue; } e.kind = &(PerlKinds[kind]); makeTagEntry(&e); if (Option.include.qualifiedTags && qualified && package != NULL && vStringLength (package) > 0) { vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); e.name = vStringValue(qualifiedName); makeTagEntry(&e); vStringDelete (qualifiedName); } } else if (vStringLength (name) > 0) { makeSimpleTag (name, PerlKinds, kind); if (Option.include.qualifiedTags && qualified && K_PACKAGE != kind && package != NULL && vStringLength (package) > 0) { vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); makeSimpleTag (qualifiedName, PerlKinds, kind); vStringDelete (qualifiedName); } } vStringClear (name); } } END_MAIN_WHILE: vStringDelete (name); if (package != NULL) vStringDelete (package); }
static boolean loadPathKinds (xcmdPath *const path, const langType language) { enum pcoprocError r; FILE* pp = NULL; char * argv[3]; int status; vString * opt; char file_kind = getLanguageFileKind (language)->letter; opt = vStringNewInit(XCMD_LIST_KIND_OPTION); vStringCatS (opt, "="); vStringCatS (opt, getLanguageName(language)); argv[2] = NULL; argv[1] = vStringValue (opt); argv[0] = vStringValue (path->path); errno = 0; if (getuid() == 0 || geteuid() == 0) { verbose ("all xcmd feature is disabled when running ctags in root privilege\n"); vStringDelete (opt); return FALSE; } if (! isSafeExecutable (argv [0])) { vStringDelete (opt); return FALSE; } verbose ("loading path kinds of %s from [%s %s]\n", getLanguageName(language), argv[0], argv[1]); r = pcoprocOpen (vStringValue (path->path), argv, &pp, NULL); switch (r) { case PCOPROC_ERROR_WPIPE: error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_RPIPE: error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_FORK: error (WARNING | PERROR, "failed to do fork: [%s %s]", argv[0], argv[1]); break; case PCOPROC_SUCCESSFUL: break; } if (pp) { vString* vline = vStringNew(); while (readLineRawWithNoSeek (vline, pp)) { char* line; char kind_letter; vStringStripNewline (vline); line = vStringValue (vline); if (!loadPathKind (path, line, argv)) break; kind_letter = path->kinds [path->n_kinds - 1].letter; if (kind_letter == file_kind) error (FATAL, "Kind letter \'%c\' returned from xcmd %s of %s language is reserved in ctags main", kind_letter, vStringValue (path->path), getLanguageName (language)); } vStringDelete (vline); status = pcoprocClose (pp); /* TODO: Decode status */ verbose(" status: %d\n", status); if (status != 0) { if (status > 0 && WIFEXITED (status) && (WEXITSTATUS (status) == path->not_available_status)) verbose ("xcmd: the %s backend is not available\n", argv[0]); else error (WARNING, "xcmd exits abnormally status(%d): [%s %s]", status, argv[0], argv[1]); vStringDelete (opt); return FALSE; } } else { error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]", argv[0], argv[1]); } vStringDelete (opt); return path->kinds == NULL? FALSE: TRUE; }
/* Adds a name to the end of the scope string */ static void addToScope (vString *scope, vString *name) { if (vStringLength(scope) > 0) vStringCatS(scope, "::"); vStringCat(scope, name); }
static vString* ext2ptrnNew (const char *const ext) { vString * ptrn = vStringNewInit ("*."); vStringCatS (ptrn, ext); return ptrn; }
static boolean parseTag (tokenInfo *const token, texKind kind) { tokenInfo *const name = newToken (); vString * fullname; boolean useLongName = TRUE; fullname = vStringNew (); vStringClear (fullname); /* * Tex tags are of these formats: * \keyword{any number of words} * \keyword[short desc]{any number of words} * \keyword*[short desc]{any number of words} * * When a keyword is found, loop through all words within * the curly braces for the tag name. */ if (isType (token, TOKEN_KEYWORD)) { copyToken (name, token); readToken (token); } if (isType (token, TOKEN_OPEN_SQUARE)) { useLongName = FALSE; readToken (token); while (! isType (token, TOKEN_CLOSE_SQUARE) ) { if (isType (token, TOKEN_IDENTIFIER)) { if (fullname->length > 0) vStringCatS (fullname, " "); vStringCatS (fullname, vStringValue (token->string)); } readToken (token); } vStringTerminate (fullname); vStringCopy (name->string, fullname); makeTexTag (name, kind); } if (isType (token, TOKEN_STAR)) { readToken (token); } if (isType (token, TOKEN_OPEN_CURLY)) { readToken (token); while (! isType (token, TOKEN_CLOSE_CURLY) ) { if (isType (token, TOKEN_IDENTIFIER) && useLongName) { if (fullname->length > 0) vStringCatS (fullname, " "); vStringCatS (fullname, vStringValue (token->string)); } readToken (token); } if (useLongName) { vStringTerminate (fullname); vStringCopy (name->string, fullname); makeTexTag (name, kind); } } deleteToken (name); vStringDelete (fullname); return TRUE; }
static void readTokenFull (tokenInfo *const token, boolean include_newlines, vString *const repr) { int c; int i; token->type = TOKEN_UNDEFINED; token->keyword = KEYWORD_NONE; vStringClear (token->string); getNextChar: i = 0; do { c = fileGetc (); i++; } while (c == '\t' || c == ' ' || ((c == '\r' || c == '\n') && ! include_newlines)); token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); if (repr) { if (i > 1) vStringPut (repr, ' '); vStringPut (repr, c); } switch (c) { case EOF: token->type = TOKEN_EOF; break; case '(': token->type = TOKEN_OPEN_PAREN; break; case ')': token->type = TOKEN_CLOSE_PAREN; break; case ';': token->type = TOKEN_SEMICOLON; break; case ',': token->type = TOKEN_COMMA; break; case '.': token->type = TOKEN_PERIOD; break; case ':': token->type = TOKEN_COLON; break; case '{': token->type = TOKEN_OPEN_CURLY; break; case '}': token->type = TOKEN_CLOSE_CURLY; break; case '=': token->type = TOKEN_EQUAL_SIGN; break; case '[': token->type = TOKEN_OPEN_SQUARE; break; case ']': token->type = TOKEN_CLOSE_SQUARE; break; case '+': case '-': { int d = fileGetc (); if (d == c) /* ++ or -- */ token->type = TOKEN_POSTFIX_OPERATOR; else { fileUngetc (d); token->type = TOKEN_BINARY_OPERATOR; } break; } case '*': case '%': case '?': case '>': case '<': case '^': case '|': case '&': token->type = TOKEN_BINARY_OPERATOR; break; case '\r': case '\n': /* This isn't strictly correct per the standard, but following the * real rules means understanding all statements, and that's not * what the parser currently does. What we do here is a guess, by * avoiding inserting semicolons that would make the statement on * the left invalid. Hopefully this should not have false negatives * (e.g. should not miss insertion of a semicolon) but might have * false positives (e.g. it will wrongfully emit a semicolon for the * newline in "foo\n+bar"). * This should however be mostly harmless as we only deal with * newlines in specific situations where we know a false positive * wouldn't hurt too bad. */ switch (LastTokenType) { /* these cannot be the end of a statement, so hold the newline */ case TOKEN_EQUAL_SIGN: case TOKEN_COLON: case TOKEN_PERIOD: case TOKEN_FORWARD_SLASH: case TOKEN_BINARY_OPERATOR: /* and these already end one, no need to duplicate it */ case TOKEN_SEMICOLON: case TOKEN_COMMA: case TOKEN_CLOSE_CURLY: case TOKEN_OPEN_CURLY: include_newlines = FALSE; /* no need to recheck */ goto getNextChar; break; default: token->type = TOKEN_SEMICOLON; } break; case '\'': case '"': token->type = TOKEN_STRING; parseString (token->string, c); token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); if (repr) { vStringCat (repr, token->string); vStringPut (repr, c); } break; case '\\': c = fileGetc (); if (c != '\\' && c != '"' && !isspace (c)) fileUngetc (c); token->type = TOKEN_CHARACTER; token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); break; case '/': { int d = fileGetc (); if ( (d != '*') && /* is this the start of a comment? */ (d != '/') ) /* is a one line comment? */ { fileUngetc (d); switch (LastTokenType) { case TOKEN_CHARACTER: case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_CLOSE_CURLY: case TOKEN_CLOSE_PAREN: case TOKEN_CLOSE_SQUARE: token->type = TOKEN_FORWARD_SLASH; break; default: token->type = TOKEN_REGEXP; parseRegExp (); token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); break; } } else { if (repr) /* remove the / we added */ repr->buffer[--repr->length] = 0; if (d == '*') { do { skipToCharacter ('*'); c = fileGetc (); if (c == '/') break; else fileUngetc (c); } while (c != EOF && c != '\0'); goto getNextChar; } else if (d == '/') /* is this the start of a comment? */ { skipToCharacter ('\n'); /* if we care about newlines, put it back so it is seen */ if (include_newlines) fileUngetc ('\n'); goto getNextChar; } } break; } case '#': /* skip shebang in case of e.g. Node.js scripts */ if (token->lineNumber > 1) token->type = TOKEN_UNDEFINED; else if ((c = fileGetc ()) != '!') { fileUngetc (c); token->type = TOKEN_UNDEFINED; } else { skipToCharacter ('\n'); goto getNextChar; } break; default: if (! isIdentChar (c)) token->type = TOKEN_UNDEFINED; else { parseIdentifier (token->string, c); token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); token->keyword = analyzeToken (token->string); if (isKeyword (token, KEYWORD_NONE)) token->type = TOKEN_IDENTIFIER; else token->type = TOKEN_KEYWORD; if (repr && vStringLength (token->string) > 1) vStringCatS (repr, vStringValue (token->string) + 1); } break; } LastTokenType = token->type; }
boolean cxxParserParseNextToken(void) { CXXToken * t = cxxTokenCreate(); // The token chain should not be allowed to grow arbitrairly large. // The token structures are quite big and it's easy to grow up to // 5-6GB or memory usage. However this limit should be large enough // to accomodate all the reasonable statements that could have some // information in them. This includes multiple function prototypes // in a single statement (ImageMagick has some examples) but probably // does NOT include large data tables. if(g_cxx.pTokenChain->iCount > 16384) cxxTokenChainDestroyLast(g_cxx.pTokenChain); cxxTokenChainAppend(g_cxx.pTokenChain,t); g_cxx.pToken = t; cxxParserSkipToNonWhiteSpace(); // FIXME: this cpp handling is kind of broken: // it works only because the moon is in the correct phase. cppBeginStatement(); // This must be done after getting char from input t->iLineNumber = getInputLineNumber(); t->oFilePosition = getInputFilePosition(); if(g_cxx.iChar == EOF) { t->eType = CXXTokenTypeEOF; t->bFollowedBySpace = FALSE; return FALSE; } unsigned int uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; //printf("Char %c %02x info %u\n",g_cxx.iChar,g_cxx.iChar,uInfo); if(uInfo & CXXCharTypeStartOfIdentifier) { // word t->eType = CXXTokenTypeIdentifier; t->bFollowedBySpace = FALSE; vStringPut(t->pszWord,g_cxx.iChar); // special case for tile, which may actually be an operator if(g_cxx.iChar == '~') { // may be followed by space! g_cxx.iChar = cppGetc(); if(isspace(g_cxx.iChar)) { t->bFollowedBySpace = TRUE; g_cxx.iChar = cppGetc(); while(isspace(g_cxx.iChar)) g_cxx.iChar = cppGetc(); } // non space uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; if(!(uInfo & CXXCharTypeStartOfIdentifier)) { // this is not an identifier after all t->eType = CXXTokenTypeOperator; if((!t->bFollowedBySpace) && g_cxx.iChar == '=') { // make ~= single token so it's not handled as // a separate assignment vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = isspace(g_cxx.iChar); } return TRUE; } } else { g_cxx.iChar = cppGetc(); } for(;;) { uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; if(!(uInfo & CXXCharTypePartOfIdentifier)) break; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); } int iCXXKeyword = lookupKeyword(t->pszWord->buffer,g_cxx.eLanguage); if(iCXXKeyword >= 0) { if( ( (iCXXKeyword == CXXKeywordFINAL) && (!g_cxx.bParsingClassStructOrUnionDeclaration) ) || ( ( (iCXXKeyword == CXXKeywordPUBLIC) || (iCXXKeyword == CXXKeywordPROTECTED) || (iCXXKeyword == CXXKeywordPRIVATE) ) && (!g_cxx.bEnablePublicProtectedPrivateKeywords) ) ) { t->eType = CXXTokenTypeIdentifier; } else { t->eType = CXXTokenTypeKeyword; t->eKeyword = (enum CXXKeyword)iCXXKeyword; if(iCXXKeyword == CXXKeyword__ATTRIBUTE__) { // special handling for __attribute__ return cxxParserParseNextTokenCondenseAttribute(); } } } else { boolean bIgnoreParens = FALSE; const char * szReplacement = NULL; if(isIgnoreToken( vStringValue(t->pszWord), &bIgnoreParens, &szReplacement )) { CXX_DEBUG_PRINT("Ignore token %s",vStringValue(t->pszWord)); // FIXME: Handle ignore parens! if(szReplacement && *szReplacement) { vStringClear(t->pszWord); vStringCatS(t->pszWord,szReplacement); } else { // skip cxxTokenChainDestroyLast(g_cxx.pTokenChain); return cxxParserParseNextToken(); } } } t->bFollowedBySpace = t->bFollowedBySpace | isspace(g_cxx.iChar); return TRUE; } if(g_cxx.iChar == '-') { // special case for pointer vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); if(g_cxx.iChar == '>') { t->eType = CXXTokenTypePointerOperator; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); } else { t->eType = CXXTokenTypeOperator; if(g_cxx.iChar == '-') { vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); } } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } #if 0 // As long as we use cppGetc() we don't need this if(g_cxx.iChar == '"') { // special case for strings t->eType = CXXTokenTypeStringConstant; vStringPut(t->pszWord,g_cxx.iChar); // We don't even care of storing the other chars: we don't need // them for parsing // FIXME: We might need them in signature:() tag.. maybe add // them up to a certain length only? for(;;) { g_cxx.iChar = cppGetc(); if(g_cxx.iChar == EOF) { t->bFollowedBySpace = FALSE; return TRUE; } if(g_cxx.iChar == '\\') { // escape g_cxx.iChar = cppGetc(); if(g_cxx.iChar == EOF) { t->bFollowedBySpace = FALSE; return TRUE; } } else if(g_cxx.iChar == '"') { g_cxx.iChar = cppGetc(); break; } } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } #else if(g_cxx.iChar == STRING_SYMBOL) { t->eType = CXXTokenTypeStringConstant; vStringPut(t->pszWord,'"'); vStringPut(t->pszWord,'"'); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } #endif #if 0 // As long as we use cppGetc() we don't need this if(g_cxx.iChar == '\'') { // special case for strings t->eType = CXXTokenTypeCharacterConstant; vStringPut(t->pszWord,g_cxx.iChar); // We don't even care storing the other chars: we don't // need them for parsing for(;;) { g_cxx.iChar = cppGetc(); if(g_cxx.iChar == EOF) { t->bFollowedBySpace = FALSE; return TRUE; } if(g_cxx.iChar == '\\') { // escape g_cxx.iChar = cppGetc(); if(g_cxx.iChar == EOF) { t->bFollowedBySpace = FALSE; return TRUE; } } else if(g_cxx.iChar == '\'') { g_cxx.iChar = cppGetc(); break; } } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } #else if(g_cxx.iChar == CHAR_SYMBOL) { t->eType = CXXTokenTypeCharacterConstant; vStringPut(t->pszWord,'\''); vStringPut(t->pszWord,'\''); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } #endif if(uInfo & CXXCharTypeDecimalDigit) { // number t->eType = CXXTokenTypeNumber; vStringPut(t->pszWord,g_cxx.iChar); for(;;) { g_cxx.iChar = cppGetc(); uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; if(!(uInfo & CXXCharTypeValidInNumber)) break; vStringPut(t->pszWord,g_cxx.iChar); } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } if(uInfo & CXXCharTypeNamedSingleOrRepeatedCharToken) { t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType; vStringPut(t->pszWord,g_cxx.iChar); int iChar = g_cxx.iChar; g_cxx.iChar = cppGetc(); if(g_cxx.iChar == iChar) { t->eType = g_aCharTable[g_cxx.iChar].uMultiTokenType; // We could signal a syntax error with more than two colons // or equal signs...but we're tolerant do { vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); } while(g_cxx.iChar == iChar); } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } if(uInfo & CXXCharTypeNamedSingleOrOperatorToken) { t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; if(uInfo & (CXXCharTypeOperator | CXXCharTypeNamedSingleOrOperatorToken)) { t->eType = CXXTokenTypeOperator; do { vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; } while( uInfo & (CXXCharTypeOperator | CXXCharTypeNamedSingleOrOperatorToken) ); } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } if(uInfo & CXXCharTypeNamedSingleCharToken) { t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } if(uInfo & CXXCharTypeOperator) { t->eType = CXXTokenTypeOperator; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; while(uInfo & CXXCharTypeOperator) { vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0; } t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; } t->eType = CXXTokenTypeUnknown; vStringPut(t->pszWord,g_cxx.iChar); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = isspace(g_cxx.iChar); return TRUE; }