// 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 ); }
// ParseVariableDeclaration //------------------------------------------------------------------------------ bool BFFParser::ParseVariableDeclaration( BFFIterator & iter, const AString & varName, BFFStackFrame * frame ) { m_SeenAVariable = true; // look for an appropriate operator BFFIterator operatorIter( iter ); bool modification = false; if ( *iter == BFF_VARIABLE_ASSIGNMENT ) { // assignment } else if ( ( *iter == BFF_VARIABLE_CONCATENATION ) || ( *iter == BFF_VARIABLE_SUBTRACTION ) ) { // concatenation modification = true; } else { Error::Error_1016_UnexepectedCharFollowingVariableName( iter ); return false; } // skip the assignment symbol and whitespace iter++; iter.SkipWhiteSpaceAndComments(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } char openToken = *iter; char closeToken = 0; bool ok = false; if ( ( openToken == '"' ) || ( openToken == '\'' ) ) { closeToken = openToken; ok = true; } else if ( openToken == BFF_SCOPE_OPEN ) { closeToken = BFF_SCOPE_CLOSE; ok = true; } else if ( openToken == BFF_STRUCT_OPEN ) { closeToken = BFF_STRUCT_CLOSE; ok = true; } else if ( ( openToken >= '0' ) && ( openToken <= '9' ) ) { if ( modification ) { Error::Error_1027_CannotModify( operatorIter, varName, BFFVariable::VAR_ANY, BFFVariable::VAR_INT ); return false; } // integer value? BFFIterator startIntValue( iter ); while ( iter.IsAtEnd() == false ) { iter++; if ( ( *iter < '0' ) || ( *iter > '9' ) ) { break; // end of integer } } if ( startIntValue.GetDistTo( iter ) > 10 ) { Error::Error_1018_IntegerValueCouldNotBeParsed( startIntValue ); return false; } AStackString<> intAsString( startIntValue.GetCurrent(), iter.GetCurrent() ); int i = 0; if ( sscanf( intAsString.Get(), "%i", &i ) != 1 ) { Error::Error_1018_IntegerValueCouldNotBeParsed( startIntValue ); return false; } return StoreVariableInt( varName, i, frame ); } else if ( ( *iter == 't' ) || ( *iter == 'f' ) ) { // might be 'true' or 'false' BFFIterator startBoolValue( iter ); if ( iter.ParseToNext( 'e' ) == true ) { iter++; if ( ( startBoolValue.GetDistTo( iter ) <= 5 ) ) { AStackString<8> value( startBoolValue.GetCurrent(), iter.GetCurrent() ); if ( value == "true" ) { if ( modification ) { Error::Error_1027_CannotModify( operatorIter, varName, BFFVariable::VAR_ANY, BFFVariable::VAR_BOOL ); return false; } return StoreVariableBool( varName, true, frame ); } else if ( value == "false" ) { if ( modification ) { Error::Error_1027_CannotModify( operatorIter, varName, BFFVariable::VAR_ANY, BFFVariable::VAR_BOOL ); return false; } return StoreVariableBool( varName, false, frame ); } } } // not a valid bool value } else if ( *iter == BFF_DECLARE_VAR_INTERNAL || *iter == BFF_DECLARE_VAR_PARENT ) { return StoreVariableToVariable( varName, iter, operatorIter, frame ); } if ( !ok ) { Error::Error_1017_UnexepectedCharInVariableValue( iter ); return false; } bool result = false; // find closing token BFFIterator openTokenPos( iter ); BFFIterator openTokenForError( iter ); // take note of opening token pos for possible error openTokenPos++; // more start iter to first char of value if ( openToken == BFF_SCOPE_OPEN ) { if ( iter.ParseToMatchingBrace( openToken, closeToken ) ) { result = StoreVariableArray( varName, openTokenPos, iter, operatorIter, frame ); } else { Error::Error_1002_MatchingClosingTokenNotFound( openTokenForError, nullptr, closeToken ); } } else if ( openToken == BFF_STRUCT_OPEN ) { if ( iter.ParseToMatchingBrace( openToken, closeToken ) ) { result = StoreVariableStruct( varName, openTokenPos, iter, operatorIter, frame ); } else { Error::Error_1002_MatchingClosingTokenNotFound( openTokenForError, nullptr, closeToken ); } } else { ASSERT( ( openToken == '\'' ) || ( openToken == '"' ) ); iter.SkipString( closeToken ); if ( *iter == closeToken ) { result = StoreVariableString( varName, openTokenPos, iter, operatorIter, frame ); } else { Error::Error_1002_MatchingClosingTokenNotFound( openTokenForError, nullptr, closeToken ); } } if ( result ) { iter++; // skip over the end token } // StoreVariable will have emitted an error if there was one return result; }