// StoreVariableStruct //------------------------------------------------------------------------------ bool BFFParser::StoreVariableStruct( const AString & name, const BFFIterator & valueStart, const BFFIterator & valueEnd, const BFFIterator & operatorIter, BFFStackFrame * frame ) { // are we concatenating? if ( *operatorIter == BFF_VARIABLE_CONCATENATION ) { // concatenation of structs not supported Error::Error_1027_CannotModify( operatorIter, name, BFFVariable::VAR_STRUCT, BFFVariable::VAR_ANY ); return false; } // create stack frame to capture variables BFFStackFrame stackFrame; // parse all the variables in the scope BFFParser subParser; BFFIterator subIter( valueStart ); subIter.SetMax( valueEnd.GetCurrent() ); // limit to closing token if ( subParser.Parse( subIter ) == false ) { return false; // error will be emitted by Parse } // get variables defined in the scope const Array< const BFFVariable * > & structMembers = stackFrame.GetLocalVariables(); // Register this variable BFFStackFrame::SetVarStruct( name, structMembers, frame ? frame : stackFrame.GetParent() ); FLOG_INFO( "Registered <struct> variable '%s' with %u members", name.Get(), structMembers.GetSize() ); return true; }
// ParseUnnamedScope //------------------------------------------------------------------------------ bool BFFParser::ParseUnnamedScope( BFFIterator & iter ) { // find the matching bracket BFFIterator scopeStart( iter ); if ( iter.ParseToMatchingBrace( BFF_SCOPE_OPEN, BFF_SCOPE_CLOSE ) == false ) { Error::Error_1025_MissingScopeCloseToken( scopeStart, nullptr ); return false; } // create stack for scope BFFStackFrame stackFrame; // parse the scoped part BFFParser subParser; BFFIterator subIter( scopeStart ); subIter++; // skip opening token subIter.SetMax( iter.GetCurrent() ); // limit to closing token if ( subParser.Parse( subIter ) == false ) { return false; } iter++; // skip closing } return true; }
// ParseFunction //------------------------------------------------------------------------------ /*virtual*/ bool Function::ParseFunction( const BFFIterator & functionNameStart, const BFFIterator * functionBodyStartToken, const BFFIterator * functionBodyStopToken, const BFFIterator * functionHeaderStartToken, const BFFIterator * functionHeaderStopToken ) const { m_AliasForFunction.Clear(); if ( AcceptsHeader() && functionHeaderStartToken && functionHeaderStopToken && ( functionHeaderStartToken->GetDistTo( *functionHeaderStopToken ) > 1 ) ) { // find opening quote BFFIterator start( *functionHeaderStartToken ); ASSERT( *start == BFFParser::BFF_FUNCTION_ARGS_OPEN ); start++; start.SkipWhiteSpace(); const char c = *start; if ( ( c != '"' ) && ( c != '\'' ) ) { Error::Error_1001_MissingStringStartToken( start, this ); return false; } BFFIterator stop( start ); stop.SkipString( c ); ASSERT( stop.GetCurrent() <= functionHeaderStopToken->GetCurrent() ); // should not be in this function if strings are not validly terminated if ( start.GetDistTo( stop ) <= 1 ) { Error::Error_1003_EmptyStringNotAllowedInHeader( start, this ); return false; } // store alias name for use in Commit start++; // skip past opening quote if ( BFFParser::PerformVariableSubstitutions( start, stop, m_AliasForFunction ) == false ) { return false; // substitution will have emitted an error } } // parse the function body BFFParser subParser; BFFIterator subIter( *functionBodyStartToken ); subIter++; // skip past opening body token subIter.SetMax( functionBodyStopToken->GetCurrent() ); // cap parsing to body end if ( subParser.Parse( subIter ) == false ) { return false; } // complete the function return Commit( functionNameStart ); }
// ParseIncludeDirective //------------------------------------------------------------------------------ bool BFFParser::ParseIncludeDirective( BFFIterator & iter ) { // Sanity check include depth to detect cyclic includes if ( s_Depth >= 128 ) { Error::Error_1035_ExcessiveDepthComplexity( iter ); return false; } // we expect a " quoted string if ( *iter != '"' ) { Error::Error_1031_UnexpectedCharFollowingDirectiveName( iter, AStackString<>( "include" ), '"' ); return false; } BFFIterator stringStart( iter ); stringStart++; // first actual character // find end of string if ( iter.ParseToNext( '"' ) == false ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } // unescape and substitute variables AStackString<> include; if ( PerformVariableSubstitutions( stringStart, iter, include ) == false ) { return false; } iter++; // skip closing quote before returning FLOG_INFO( "Including: %s\n", include.Get() ); // open include // 1) Try current directory AStackString<> includeToUse; if (PathUtils::IsFullPath(include) == false) { const char * lastSlash = iter.GetFileName().FindLast( NATIVE_SLASH ); lastSlash = lastSlash ? lastSlash : iter.GetFileName().FindLast( OTHER_SLASH ); lastSlash = lastSlash ? ( lastSlash + 1 ): iter.GetFileName().Get(); // file only, truncate to empty includeToUse.Assign( iter.GetFileName().Get(), lastSlash ); } includeToUse += include; AStackString<> includeToUseClean; NodeGraph::CleanPath( includeToUse, includeToUseClean ); FileStream f; if ( f.Open( includeToUseClean.Get(), FileStream::READ_ONLY ) == false ) { Error::Error_1032_UnableToOpenInclude( stringStart, includeToUseClean ); return false; } // check if include uses "once" pragma if ( FBuild::Get().GetDependencyGraph().IsOneUseFile( includeToUseClean ) ) { // already seen, and uses #once : don't include again return true; } uint64_t includeTimeStamp = FileIO::GetFileLastWriteTime( includeToUseClean ); // read content of include const uint32_t fileSize = (uint32_t)f.GetFileSize(); AutoPtr< char > mem( (char *)ALLOC( fileSize + 1 ) ); if ( f.Read( mem.Get(), fileSize ) != fileSize ) { Error::Error_1033_ErrorReadingInclude( stringStart, include, Env::GetLastErr() ); return false; } mem.Get()[ fileSize ] = '\000'; // sentinel BFFParser parser; const bool pushStackFrame = false; // include is treated as if injected at this point return parser.Parse( mem.Get(), fileSize, includeToUseClean.Get(), includeTimeStamp, pushStackFrame ); }