예제 #1
0
// StoreVariableString
//------------------------------------------------------------------------------
bool BFFParser::StoreVariableString( const AString & name,
									 const BFFIterator & valueStart, const BFFIterator & valueEnd,
									 const BFFIterator & operatorIter,
									 BFFStackFrame * frame )
{
	// unescape and subsitute embedded variables
	AStackString< 2048 > value;
	if ( PerformVariableSubstitutions( valueStart, valueEnd, value ) == false )
	{
		return false;
	}

	// are we concatenating?
	const BFFVariable * varToConcat = nullptr;
	if ( *operatorIter == BFF_VARIABLE_CONCATENATION )
	{
		// find existing
		varToConcat = BFFStackFrame::GetVar( name, frame );
		if ( varToConcat == nullptr )
		{
			Error::Error_1026_VariableNotFoundForConcatenation( operatorIter, name );
			return false;
		}

		// make sure types are compatible
		if ( varToConcat->IsString() )
		{
			// OK - can concat String to String
			AStackString< 1024 > finalValue( varToConcat->GetString() );
			finalValue += value;

			BFFStackFrame::SetVarString( name, finalValue, frame );
			FLOG_INFO( "Appended '%s' to <String> variable '%s' with result '%s'", value.Get(), name.Get(), finalValue.Get() );
			return true;
		}
		else if ( varToConcat->IsArrayOfStrings() )
		{
			// OK - can concat String to ArrayOfStrings
			Array< AString > finalValues( varToConcat->GetArrayOfStrings().GetSize() + 1, false );
			finalValues = varToConcat->GetArrayOfStrings();
			finalValues.Append( value );

			BFFStackFrame::SetVarArrayOfStrings( name, finalValues, frame );
			FLOG_INFO( "Appended '%s' to <ArrayOfStrings> variable '%s' with result of %i items", value.Get(), name.Get(), finalValues.GetSize() );
			return true;
		}
		else
		{
			Error::Error_1027_CannotConcatenate( operatorIter, name, varToConcat->GetType(), BFFVariable::VAR_STRING );
			return false;
		}
	}

	// handle regular assignment of string
	BFFStackFrame::SetVarString( name, value, frame );
	FLOG_INFO( "Registered <string> variable '%s' with value '%s'", name.Get(), value.Get() );
	return true;
}
예제 #2
0
// 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 ); 
}
예제 #3
0
// ParseNamedVariableName
//------------------------------------------------------------------------------
/*static*/ bool BFFParser::ParseVariableName( BFFIterator & iter, AString & name, bool & parentScope )
{
	// skip over the declaration symbol
	ASSERT( *iter == BFF_DECLARE_VAR_INTERNAL ||
			*iter == BFF_DECLARE_VAR_PARENT );

	parentScope = ( *iter == BFF_DECLARE_VAR_PARENT );

	const BFFIterator varNameStart = iter; // include type token in var name
	iter++;

	// make sure we haven't hit the end of the file
	if ( iter.IsAtEnd() )
	{
		Error::Error_1012_UnexpectedEndOfFile( iter );
		return false;
	}

	if ( *iter == '\'' || *iter == '"' )
	{
		// parse the string
		const BFFIterator openToken = iter;
		iter.SkipString( *openToken );
		if ( *iter != *openToken )
		{
			Error::Error_1002_MatchingClosingTokenNotFound( openToken, nullptr, *openToken );
			return false;
		}
		BFFIterator stringStart = openToken;
		stringStart++;

		// unescape and subsitute embedded variables
		AStackString< 256 > value;
		if ( PerformVariableSubstitutions( stringStart, iter, value ) == false )
		{
			return false;
		}
		iter++; // skip close token

		BFFIterator varNameIter( value.Get(), value.GetLength(), iter.GetFileName().Get(), iter.GetFileTimeStamp() );

		// sanity check it is a sensible length
		if ( value.GetLength() + 1/* '.' will be added */  > MAX_VARIABLE_NAME_LENGTH )
		{
			Error::Error_1014_VariableNameIsTooLong( varNameIter, (uint32_t)value.GetLength(), (uint32_t)MAX_VARIABLE_NAME_LENGTH );
			return false;
		}

		// sanity check it is a valid variable name
		while ( varNameIter.IsAtEnd() == false )
		{
			if ( varNameIter.IsAtValidVariableNameCharacter() == false )
			{
				Error::Error_1013_UnexpectedCharInVariableName( varNameIter, nullptr );
				return false;
			}
			varNameIter++;
		}

		// append '.' to variable name
		name = ".";
		name.Append( value );
	}
	else
	{
		// make sure immediately after the symbol starts a variable name
		if ( iter.IsAtValidVariableNameCharacter() == false )
		{
			Error::Error_1013_UnexpectedCharInVariableName( iter, nullptr );
			return false;
		}

		// find the end of the variable name
		iter.SkipVariableName();
		const BFFIterator varNameEnd = iter;

		// sanity check it is a sensible length
		size_t varNameLen = varNameStart.GetDistTo( varNameEnd );
		if ( varNameLen > MAX_VARIABLE_NAME_LENGTH )
		{
			Error::Error_1014_VariableNameIsTooLong( iter, (uint32_t)varNameLen, (uint32_t)MAX_VARIABLE_NAME_LENGTH );
			return false;
		}

		// store variable name
		name.Assign( varNameStart.GetCurrent(), varNameEnd.GetCurrent() );
	}

	ASSERT( name.GetLength() > 0 );
	if ( parentScope )
	{
		// exchange '^' with '.'
		ASSERT( BFF_DECLARE_VAR_PARENT == name[0] );
		name[0] = BFF_DECLARE_VAR_INTERNAL;
	}

	return true;
}
예제 #4
0
// StoreVariableArray
//------------------------------------------------------------------------------
bool BFFParser::StoreVariableArray( const AString & name,
									const BFFIterator & valueStart, const BFFIterator & valueEnd,
									const BFFIterator & operatorIter,
									BFFStackFrame * frame )
{
	Array< AString > values( 32, true );
	Array< const BFFVariable * > structValues( 32, true );

	// are we concatenating?
	if ( ( *operatorIter == BFF_VARIABLE_CONCATENATION ) ||
		 ( *operatorIter == BFF_VARIABLE_SUBTRACTION ) )
	{
		// find existing
		const BFFVariable * var = BFFStackFrame::GetVar( name, frame );
		if ( var == nullptr )
		{
			Error::Error_1026_VariableNotFoundForModification( operatorIter, name );
			return false;
		}

		// make sure existing is an array
		if ( var->IsArrayOfStrings() )
		{
			// get values to start with
			values = var->GetArrayOfStrings();
		}
		else if ( var->IsArrayOfStructs() )
		{
			// get values to start with
			structValues = var->GetArrayOfStructs();
		}
		else
		{
			// TODO:B Improve this error to handle ArrayOfStructs case
			Error::Error_1027_CannotModify( operatorIter, name, var->GetType(), BFFVariable::VAR_ARRAY_OF_STRINGS );
			return false;
		}
	}

	// Parse array of variables
	BFFIterator iter( valueStart );
	for (;;)
	{
		iter.SkipWhiteSpaceAndComments();

		// end?
		if ( iter.GetCurrent() == valueEnd.GetCurrent() )
		{
			break;
		}

		const char c = *iter;
		if ( ( c == '"' ) || ( c == '\'' ) )
		{
			// a quoted string

			// detect mistmatches
			if ( structValues.IsEmpty() == false )
			{
				// Mixed types in vector
				Error::Error_1034_OperationNotSupported( iter, 
														 BFFVariable::VAR_ARRAY_OF_STRUCTS,
														 BFFVariable::VAR_STRING,
														 operatorIter );
				return false;
			}

			// subtraction not supported on arrays
			if ( *operatorIter == BFF_VARIABLE_SUBTRACTION )
			{
				Error::Error_1034_OperationNotSupported( iter, BFFVariable::VAR_ARRAY_OF_STRINGS, BFFVariable::VAR_STRING, operatorIter );
				return false;
			}

			// a string
			BFFIterator elementValueStart( iter );
			iter.SkipString( c );
			ASSERT( iter.GetCurrent() <= valueEnd.GetCurrent() ); // should not be in this function if string is not terminated
			elementValueStart++; // move to start of actual content
			AStackString< 2048 > elementValue;

			// unescape and subsitute embedded variables
			if ( PerformVariableSubstitutions( elementValueStart, iter, elementValue ) == false )
			{
				return false;
			}

			values.Append( elementValue );

			iter++; // pass closing quote
		}
		else if ( c == BFF_DECLARE_VAR_INTERNAL ||
				  c == BFF_DECLARE_VAR_PARENT )
		{
			const BFFIterator elementStartValue = iter;

			// a variable
			AStackString< MAX_VARIABLE_NAME_LENGTH > varName;
			bool parentScope = false; // ignored, the behavior is the same
			if ( ParseVariableName( iter, varName, parentScope ) == false )
			{
				return false;
			}

			// Determine stack frame to use for Src var
			BFFStackFrame * srcFrame = BFFStackFrame::GetCurrent();			
			if ( c == BFF_DECLARE_VAR_PARENT )
			{
				srcFrame = BFFStackFrame::GetCurrent()->GetParent();
			}

			// get the variable
			const BFFVariable * var = srcFrame->GetVariableRecurse( varName );
			if ( var == nullptr )
			{
				Error::Error_1026_VariableNotFoundForModification( operatorIter, varName );
				return false;
			}

			// subtraction not supported on arrays
			if ( *operatorIter == BFF_VARIABLE_SUBTRACTION )
			{
				const BFFVariable::VarType dstType = structValues.IsEmpty() ? BFFVariable::VAR_ARRAY_OF_STRINGS : BFFVariable::VAR_ARRAY_OF_STRUCTS;
				const BFFVariable::VarType srcType = var->GetType();
				Error::Error_1034_OperationNotSupported( elementStartValue, dstType, srcType, operatorIter );
				return false;
    		}

			if ( var->IsString() || var->IsArrayOfStrings() )
			{
				// dest is consistent?
				if ( structValues.IsEmpty() == false )
				{
					// inconsistency
					Error::Error_1034_OperationNotSupported( elementStartValue, 
															 BFFVariable::VAR_ARRAY_OF_STRUCTS,
															 var->GetType(),
															 operatorIter );
					return false;
				}

				if ( var->IsString() )
				{
					values.Append( var->GetString() );
				}
				else
				{
					values.Append( var->GetArrayOfStrings() );
				}
			}
			else if ( var->IsStruct() || var->IsArrayOfStructs() )
			{
				// dest is consistent?
				if ( values.IsEmpty() == false )
				{
					// inconsistency
					Error::Error_1034_OperationNotSupported( elementStartValue, 
															 BFFVariable::VAR_ARRAY_OF_STRINGS,
															 var->GetType(),
															 operatorIter );
					return false;
				}

				if ( var->IsStruct() )
				{
					structValues.Append( var );
				}
				else
				{
					structValues.Append( var->GetArrayOfStructs() );
				}
			}
			else
			{
				Error::Error_1050_PropertyMustBeOfType( iter, nullptr, name.Get(), 
														var->GetType(),
														BFFVariable::VAR_STRING,
														BFFVariable::VAR_STRUCT );
				return false;
			}
		}
		else
		{
			Error::Error_1001_MissingStringStartToken( iter, nullptr );
			return false;
		}

		iter.SkipWhiteSpaceAndComments();
		if ( *iter == ',' ) // comma seperators are optional
		{ 
			iter++; 
		}

		// continue looking for more vars...
	}

	// should only have one populated array
	ASSERT( values.IsEmpty() || structValues.IsEmpty() );

	// Register this variable
	if ( structValues.IsEmpty() == false )
	{
		// structs
		BFFStackFrame::SetVarArrayOfStructs( name, structValues, frame );
		FLOG_INFO( "Registered <ArrayOfStructs> variable '%s' with %u elements", name.Get(), structValues.GetSize() );
	}
	else
	{
		// strings (or unknown, so default to strings)
		BFFStackFrame::SetVarArrayOfStrings( name, values, frame );
		FLOG_INFO( "Registered <ArrayOfStrings> variable '%s' with %u elements", name.Get(), values.GetSize() );
	}

	return true;
}
예제 #5
0
// StoreVariableString
//------------------------------------------------------------------------------
bool BFFParser::StoreVariableString( const AString & name,
									 const BFFIterator & valueStart, const BFFIterator & valueEnd,
									 const BFFIterator & operatorIter,
									 BFFStackFrame * frame )
{
	// unescape and subsitute embedded variables
	AStackString< 2048 > value;
	if ( PerformVariableSubstitutions( valueStart, valueEnd, value ) == false )
	{
		return false;
	}

	// are we concatenating?
	const BFFVariable * varToConcat = nullptr;
	if ( ( *operatorIter == BFF_VARIABLE_CONCATENATION ) || 
		 ( *operatorIter == BFF_VARIABLE_SUBTRACTION ) )
	{
		// find existing
		varToConcat = BFFStackFrame::GetVar( name, frame );
		if ( varToConcat == nullptr )
		{
			Error::Error_1026_VariableNotFoundForModification( operatorIter, name );
			return false;
		}

		// make sure types are compatible
		if ( varToConcat->IsString() )
		{
			// OK - can concat String to String
			AStackString< 1024 > finalValue( varToConcat->GetString() );
			if ( *operatorIter == BFF_VARIABLE_CONCATENATION )
			{
				finalValue += value;
			}
			else
			{
				finalValue.Replace( value.Get(), "" );
			}

			BFFStackFrame::SetVarString( name, finalValue, frame );
			FLOG_INFO( "%s '%s' %s <String> variable '%s' with result '%s'", 
						( *operatorIter == BFF_VARIABLE_CONCATENATION ) ? "Appending" : "Removing",
						value.Get(), 
						( *operatorIter == BFF_VARIABLE_CONCATENATION ) ? "to" : "from",
						name.Get(), 
						finalValue.Get() );
			return true;
		}
		else if ( varToConcat->IsArrayOfStrings() )
		{
			// OK - can concat String to ArrayOfStrings
			Array< AString > finalValues( varToConcat->GetArrayOfStrings().GetSize() + 1, false );
			if ( *operatorIter == BFF_VARIABLE_CONCATENATION )
			{
				finalValues = varToConcat->GetArrayOfStrings();
				finalValues.Append( value );
			}
			else
			{
				auto end = varToConcat->GetArrayOfStrings().End();
				for ( auto it=varToConcat->GetArrayOfStrings().Begin(); it!=end; ++it )
				{
					if ( *it != value ) // remove equal strings
					{
						finalValues.Append( *it );
					}
				}
			}

			BFFStackFrame::SetVarArrayOfStrings( name, finalValues, frame );
			FLOG_INFO( "%s '%s' %s <ArrayOfStrings> variable '%s' with result of %i items", 
						( *operatorIter == BFF_VARIABLE_CONCATENATION ) ? "Appending" : "Removing",
						value.Get(), 
						( *operatorIter == BFF_VARIABLE_CONCATENATION ) ? "to" : "from",
						name.Get(), 
						finalValues.GetSize() );
			return true;
		}
		else
		{
			Error::Error_1027_CannotModify( operatorIter, name, varToConcat->GetType(), BFFVariable::VAR_STRING );
			return false;
		}
	}

	// handle regular assignment of string
	BFFStackFrame::SetVarString( name, value, frame );
	FLOG_INFO( "Registered <string> variable '%s' with value '%s'", name.Get(), value.Get() );
	return true;
}