void TPpContext::setInput(TInputScanner& input, bool versionWillBeError) { assert(inputStack.size() == 0); pushInput(new tStringInput(this, input)); errorOnVersion = versionWillBeError; versionSeen = false; }
// Handle #include int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; int token = scanToken(ppToken); if (token != PpAtomConstString) { // TODO: handle angle brackets. parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); } else { // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; token = scanToken(ppToken); if (token != '\n' && token != EndOfInput) { parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); } else { TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1); if (res && !res->file_name.empty()) { if (res->file_data && res->file_length) { const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream prologue; std::ostringstream epilogue; prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n"; epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); } // At EOF, there's no "current" location anymore. if (token != EndOfInput) parseContext.setCurrentColumn(0); // Don't accidentally return EndOfInput, which will end all preprocessing. return '\n'; } else { std::string message = res ? std::string(res->file_data, res->file_length) : std::string("Could not process include directive"); parseContext.ppError(directiveLoc, message.c_str(), "#include", ""); if (res) { includer.releaseInclude(res); } } } } return token; }
// Handle #include int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; int token = scanToken(ppToken); if (token != PpAtomConstString) { // TODO: handle angle brackets. parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); } else { // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; token = scanToken(ppToken); if (token != '\n' && token != EndOfInput) { parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); } else { std::string sourceName; std::string replacement; std::tie(sourceName, replacement) = includer.include(filename.c_str()); if (!sourceName.empty()) { if (!replacement.empty()) { const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream content; content << "#line " << forNextLine << " " << "\"" << sourceName << "\"\n"; content << replacement << (replacement.back() == '\n' ? "" : "\n"); content << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableString(directiveLoc, content.str(), this)); } // At EOF, there's no "current" location anymore. if (token != EndOfInput) parseContext.setCurrentColumn(0); // Don't accidentally return EndOfInput, which will end all preprocessing. return '\n'; } else { parseContext.ppError(directiveLoc, replacement.c_str(), "#include", ""); } } } return token; }
// Macro-expand a macro argument 'arg' to create 'expandedArg'. // Does not replace 'arg'. // Returns nullptr if no expanded argument is created. TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay) { // expand the argument TokenStream* expandedArg = new TokenStream; pushInput(new tMarkerInput(this)); pushTokenStreamInput(arg); int token; while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) { token = tokenPaste(token, *ppToken); if (token == PpAtomIdentifier) { switch (MacroExpand(ppToken, false, newLineOkay)) { case MacroExpandNotStarted: break; case MacroExpandError: // toss the rest of the pushed-input argument by scanning until tMarkerInput while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) ; break; case MacroExpandStarted: case MacroExpandUndef: continue; } } if (token == tMarkerInput::marker || token == EndOfInput) break; expandedArg->putToken(token, ppToken); } if (token != tMarkerInput::marker) { // Error, or MacroExpand ate the marker, so had bad input, recover delete expandedArg; expandedArg = nullptr; } return expandedArg; }
void TPpContext::UngetToken(int token, TPpToken* ppToken) { pushInput(new tUngotTokenInput(this, token, ppToken)); }
void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting) { pushInput(new tTokenInput(this, &ts, prepasting)); ts.reset(); }
int main(int argc, char **argv){ int inputsNumber = 0; int stdIn = 0;//stdIn pas utilise input* listOfInputs = NULL;// liste des entrees a traiter int maxThreads = 0; int i; //Parcoure tous les arguments de lancement du programme for(i = 1; i < argc; i++){ char* in = argv[i]; if(strcmp(in, MAX_THREADS_TK) == 0){ //maxthreads maxThreads = atoi(argv[i+1]); i++; //on passe 2 arguments puisqu'on a deja utilise le nombre // de threads max printf("Maxthreads set to %d\n",maxThreads); } else if (strcmp(in, STDIN_TK) == 0){ //stdIn stdIn = 1; // stdIn utilise inputsNumber++; printf("Stdin set \n"); } else if (strcmp(in, FILE_TK) == 0){ //fichier if(pushInput(&listOfInputs, argv[i+1]) != 0){ //probleme de malloc, arrete le programme exit(errno); } else{ printf("Added %s to inputs\n", argv[i+1]); i++; inputsNumber++; } } else if(strstr(in, URL_TK) != NULL){ //URL if(pushInput(&listOfInputs, argv[i]) != 0){ //probleme de malloc, arrete le programme exit(errno); } else{ printf("Added %s to inputs\n", argv[i]); inputsNumber++; } } else{ //erreur de format fprintf(stderr, "Erreur: mauvais format"); exit(-1); } } printf("Number of inputs %d\n", inputsNumber); if(maxThreads == 0){ /// a voir maxThreads = 10; printf("maxthread was 0, assigned to %d\n", maxThreads); } //initialisation des threads et semaphores pthread_t* threads; //threads utilises threads = (pthread_t*) malloc(sizeof(pthread_t) * maxThreads); sem_init(&available_switching, 0, 1); //switching disponible sem_init(&available_thread, 0, 0); // aucun thread n'a termine available_thread_index = -1; //lance tous les threads int err = launchAllThreads(maxThreads, &stdIn, &inputsNumber, &listOfInputs, &threads); if(err){ fprintf(stderr, "Erreur dans launchAllThreads: %d\n", err); exit(err); } printf("All threads launched, inputs left: %d\n", inputsNumber); setbuf(stdout, NULL); // stoppe le buffer while(inputsNumber > 0){ printf("Rentre ici \n"); sem_wait(&available_thread); // attend qu'un thread ait termine //zone critique printf("Zone critique\n"); err = pthread_join(threads[available_thread_index], NULL); if(err){ fprintf(stderr, "Erreur dans pthread_join: %d\n", err); exit(err); } char* file = popInput(&listOfInputs); printf("filename: %s\n", file); if (file == NULL){ fprintf(stderr, "Erreur dans popInput\n"); exit(-1); } thread_arg t_arg; t_arg.file = file; t_arg.fileType = getFileType(file); t_arg.threadIndex = available_thread_index; printf("switching producer number: %d , now on %s \n", available_thread_index, file); err = pthread_create(&threads[available_thread_index], NULL, &threadLauncher, &t_arg); if(err){ fprintf(stderr, "Erreur dans pthread_create: %d\n", errno); exit(errno); } available_thread_index = -1; // pas necessaire mais plus prudent inputsNumber--; sem_post(&available_switching); //permet aux thread de signaler //qu'ils ont fini } ///TODO every producer to consumer //free(threads); //ne pas oublier ! exit(EXIT_SUCCESS); }
void TPpContext::pushTokenStreamInput(TokenStream* ts) { pushInput(new tTokenInput(this, ts)); RewindTokenStream(ts); }
// // Check an identifier (atom) to see if it is a macro that should be expanded. // If it is, and defined, push a tInput that will produce the appropriate expansion // and return 1. // If it is, but undefined, and expandUndef is requested, push a tInput that will // expand to 0 and return -1. // Otherwise, return 0 to indicate no expansion, which is not necessarily an error. // int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; switch (atom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; sprintf(ppToken->name, "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; case PpAtomFileMacro: { if (parseContext.getCurrentLoc().name) parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); ppToken->ival = parseContext.getCurrentLoc().string; sprintf(ppToken->name, "%s", ppToken->loc.getStringNameOrNum().c_str()); UngetToken(PpAtomConstInt, ppToken); return 1; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; sprintf(ppToken->name, "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; default: break; } Symbol *sym = LookUpSymbol(atom); int token; int depth = 0; // no recursive expansions if (sym && sym->mac.busy) return 0; // not expanding undefined macros if ((! sym || sym->mac.undef) && ! expandUndef) return 0; // 0 is the value of an undefined macro if ((! sym || sym->mac.undef) && expandUndef) { pushInput(new tZeroInput(this)); return -1; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = &sym->mac; if (sym->mac.args) { token = scanToken(ppToken); if (newLineOkay) { while (token == '\n') token = scanToken(ppToken); } if (token != '(') { parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); UngetToken(token, ppToken); ppToken->atom = atom; delete in; return 0; } in->args.resize(in->mac->argc); for (int i = 0; i < in->mac->argc; i++) in->args[i] = new TokenStream; int arg = 0; bool tokenRecorded = false; do { depth = 0; while (1) { token = scanToken(ppToken); if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", GetAtomString(atom)); delete in; return 0; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); delete in; return 0; } if (in->mac->argc == 0 && token != ')') break; if (depth == 0 && (token == ',' || token == ')')) break; if (token == '(') depth++; if (token == ')') depth--; RecordToken(in->args[arg], token, ppToken); tokenRecorded = true; } if (token == ')') { if (in->mac->argc == 1 && tokenRecorded == 0) break; arg++; break; } arg++; } while (arg < in->mac->argc); if (arg < in->mac->argc) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); else if (token != ')') { depth=0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')') depth--; token = scanToken(ppToken); if (token == '(') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); } for (int i = 0; i < in->mac->argc; i++) in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay); } pushInput(in); sym->mac.busy = 1; RewindTokenStream(sym->mac.body); return 1; }
void DeviceFilter::handleInput(const std::string& device, const DataGroup& inputData) { filterInput(device, inputData, &getInputData()); pushInput(); }
// Handle #include ... // TODO: Handle macro expansions for the header name int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; bool startWithLocalSearch = true; // to additionally include the extra "" paths int token = scanToken(ppToken); // handle <header-name>-style #include if (token == '<') { startWithLocalSearch = false; token = scanHeaderName(ppToken, '>'); } // otherwise ppToken already has the header name and it was "header-name" style if (token != PpAtomConstString) { parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", ""); return token; } // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; // See if the directive was well formed token = scanToken(ppToken); if (token != '\n') { if (token == EndOfInput) parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str()); else parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str()); return token; } // Process well-formed directive // Find the inclusion, first look in "Local" ("") paths, if requested, // otherwise, only search the "System" (<>) paths. TShader::Includer::IncludeResult* res = nullptr; if (startWithLocalSearch) res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); if (res == nullptr || res->headerName.empty()) { includer.releaseInclude(res); res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); } // Process the results if (res != nullptr && !res->headerName.empty()) { if (res->headerData != nullptr && res->headerLength > 0) { // path for processing one or more tokens from an included header, hand off 'res' const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream prologue; std::ostringstream epilogue; prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n"; epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); // There's no "current" location anymore. parseContext.setCurrentColumn(0); } else { // things are okay, but there is nothing to process includer.releaseInclude(res); } } else { // error path, clean up std::string message = res != nullptr ? std::string(res->headerData, res->headerLength) : std::string("Could not process include directive"); parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str()); includer.releaseInclude(res); } return token; }
// // Check a token to see if it is a macro that should be expanded. // If it is, and defined, push a tInput that will produce the appropriate expansion // and return 1. // If it is, but undefined, and expandUndef is requested, push a tInput that will // expand to 0 and return -1. // Otherwise, return 0 to indicate no expansion, which is not necessarily an error. // int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; case PpAtomFileMacro: { if (parseContext.getCurrentLoc().name) parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); ppToken->ival = parseContext.getCurrentLoc().string; snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str()); UngetToken(PpAtomConstInt, ppToken); return 1; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; default: break; } MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); int token; int depth = 0; // no recursive expansions if (macro != nullptr && macro->busy) return 0; // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) return 0; // 0 is the value of an undefined macro if ((macro == nullptr || macro->undef) && expandUndef) { pushInput(new tZeroInput(this)); return -1; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = macro; if (macro->args.size() > 0 || macro->emptyArgs) { token = scanToken(ppToken); if (newLineOkay) { while (token == '\n') token = scanToken(ppToken); } if (token != '(') { parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom)); UngetToken(token, ppToken); delete in; return 0; } in->args.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; in->expandedArgs.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = nullptr; size_t arg = 0; bool tokenRecorded = false; do { depth = 0; while (1) { token = scanToken(ppToken); if (token == EndOfInput || token == tMarkerInput::marker) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } if (in->mac->args.size() == 0 && token != ')') break; if (depth == 0 && (token == ',' || token == ')')) break; if (token == '(') depth++; if (token == ')') depth--; in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } if (token == ')') { if (in->mac->args.size() == 1 && tokenRecorded == 0) break; arg++; break; } arg++; } while (arg < in->mac->args.size()); if (arg < in->mac->args.size()) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); else if (token != ')') { depth=0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')') depth--; token = scanToken(ppToken); if (token == '(') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } // We need both expanded and non-expanded forms of the argument, for whether or // not token pasting will be applied later when the argument is consumed next to ##. for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); macro->busy = 1; macro->body.reset(); return 1; }
/***************************************************************************** * First character of command id should be second char of line * Lexer returns a full line of data, needs to be parsed if .ce * In version 1.0, valid commands are: * .* (comment) followed by text to '\n' * .br (new line), nothing else allowed on line * .im (include file) 'filename' * .nameit (define text macro) symbol=[a-zA-Z0-9]+ (10 max) text='text string' * text may contain entity references, nameit references and tags * .ce (center) no tags, but text and both entity types * Version 2.0 only supports .*, .br, .im */ Lexer::Token Document::processCommand( Lexer* lexer, Tag* parent ) { if( lexer->cmdId() == Lexer::COMMENT ) ;//do nothing else if( lexer->cmdId() == Lexer::BREAK ) parent->appendChild( new BrCmd( this, parent, dataName(), dataLine(), dataCol() ) ); else if( lexer->cmdId() == Lexer::CENTER ) { CeCmd* cecmd( new CeCmd( this, parent, dataName(), dataLine(), dataCol() ) ); parent->appendChild( cecmd ); return cecmd->parse( lexer ); } else if( lexer->cmdId() == Lexer::IMBED ) { std::string env( Environment.value( "IPFCIMBED" ) ); std::vector< std::wstring > paths; std::wstring cwd; //empty string for current directory paths.push_back( cwd ); #ifdef __UNIX__ std::string separators( ":;" ); char slash( '/' ); #else std::string separators( ";" ); char slash( '\\' ); #endif std::string::size_type idx1( 0 ); std::string::size_type idx2( env.find_first_of( separators, idx1 ) ); std::wstring fbuffer; mbtowstring( env.substr( idx1, idx2 - idx1 ), fbuffer ); paths.push_back( fbuffer ); while( idx2 != std::string::npos ) { idx1 = idx2 + 1; idx2 = env.find_first_of( separators, idx1 ); fbuffer.clear(); mbtowstring( env.substr( idx1, idx2 - idx1 ), fbuffer ); paths.push_back( fbuffer ); } for( size_t count = 0; count < paths.size(); ++count ) { std::wstring* fname( new std::wstring( paths[ count ] ) ); if( !fname->empty() ) *fname += slash; *fname += lexer->text(); #ifndef __UNIX__ if( fname->size() > PATH_MAX ) { throw FatalError( ERR_PATH_MAX ); } #endif try { IpfFile* ipff( new IpfFile( fname ) ); fname = addFileName( fname ); pushInput( ipff ); break; } catch( FatalError& e ) { delete fname; if( count == paths.size() - 1 ) throw e; } catch( FatalIOError& e ) { delete fname; if( count == paths.size() - 1 ) throw e; } } } else if( lexer->cmdId() == Lexer::NAMEIT ) { std::wstring::size_type idx1( lexer->text().find( L"symbol=" ) ); std::wstring::size_type idx2( lexer->text().find( L' ', idx1 ) ); std::wstring sym( lexer->text().substr( idx1 + 7, idx2 - idx1 - 7 ) ); killQuotes( sym ); sym.insert( sym.begin(), L'&' ); sym += L'.'; std::wstring::size_type idx3( lexer->text().find( L"text=" ) ); //check for single quotes std::wstring::size_type idx4( lexer->text()[ idx3 + 5 ] == L'\'' ? \ lexer->text().find( L'\'', idx3 + 6 ) : \ lexer->text().find( L' ', idx3 + 5 ) ); std::wstring txt( lexer->text().substr( idx3 + 5, idx4 - idx3 - 5 ) ); killQuotes( txt ); if( !nls->isEntity( sym ) && nameIts.find( sym ) == nameIts.end() ) //add it to the list nameIts.insert( std::map< std::wstring, std::wstring >::value_type( sym, txt ) ); else printError( ERR3_DUPSYMBOL ); } else printError( ERR1_CMDNOTDEF ); return getNextToken(); }
void TextManager::input(int lin,int col, int code){ setInputPool(code); getInput(lin,col); pushInput(code); }
void TestDevice::pushInput(const std::string& data) { getInputData().strings().set("helloWorld", data); pushInput(); }
// // Check a token to see if it is a macro that should be expanded: // - If it is, and defined, push a tInput that will produce the appropriate // expansion and return MacroExpandStarted. // - If it is, but undefined, and expandUndef is requested, push a tInput // that will expand to 0 and return MacroExpandUndef. // - Otherwise, there is no expansion, and there are two cases: // * It might be okay there is no expansion, and no specific error was // detected. Returns MacroExpandNotStarted. // * The expansion was started, but could not be completed, due to an error // that cannot be recovered from. Returns MacroExpandError. // MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; case PpAtomFileMacro: { if (parseContext.getCurrentLoc().name) parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); ppToken->ival = parseContext.getCurrentLoc().string; snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str()); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; default: break; } MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); // no recursive expansions if (macro != nullptr && macro->busy) return MacroExpandNotStarted; // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) return MacroExpandNotStarted; // 0 is the value of an undefined macro if ((macro == nullptr || macro->undef) && expandUndef) { pushInput(new tZeroInput(this)); return MacroExpandUndef; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = macro; if (macro->functionLike) { // We don't know yet if this will be a successful call of a // function-like macro; need to look for a '(', but without trashing // the passed in ppToken, until we know we are no longer speculative. TPpToken parenToken; int token = scanToken(&parenToken); if (newLineOkay) { while (token == '\n') token = scanToken(&parenToken); } if (token != '(') { // Function-like macro called with object-like syntax: okay, don't expand. // (We ate exactly one token that might not be white space; put it back. UngetToken(token, &parenToken); delete in; return MacroExpandNotStarted; } in->args.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; in->expandedArgs.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = nullptr; size_t arg = 0; bool tokenRecorded = false; do { TVector<char> nestStack; while (true) { token = scanToken(ppToken); if (token == EndOfInput || token == tMarkerInput::marker) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (in->mac->args.size() == 0 && token != ')') break; if (nestStack.size() == 0 && (token == ',' || token == ')')) break; if (token == '(') nestStack.push_back(')'); else if (token == '{' && parseContext.isReadingHLSL()) nestStack.push_back('}'); else if (nestStack.size() > 0 && token == nestStack.back()) nestStack.pop_back(); in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } // end of single argument scan if (token == ')') { // closing paren of call if (in->mac->args.size() == 1 && !tokenRecorded) break; arg++; break; } arg++; } while (arg < in->mac->args.size()); // end of all arguments scan if (arg < in->mac->args.size()) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); else if (token != ')') { // Error recover code; find end of call, if possible int depth = 0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')' || token == '}') depth--; token = scanToken(ppToken); if (token == '(' || token == '{') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } // We need both expanded and non-expanded forms of the argument, for whether or // not token pasting will be applied later when the argument is consumed next to ##. for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); macro->busy = 1; macro->body.reset(); return MacroExpandStarted; }