// ParseDefineDirective //------------------------------------------------------------------------------ bool BFFParser::ParseDefineDirective( BFFIterator & iter ) { if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } // parse out token const BFFIterator tokenStart( iter ); iter.SkipVariableName(); if ( tokenStart.GetCurrent() == iter.GetCurrent() ) { Error::Error_1007_ExpectedVariable( iter, nullptr ); return false; } const BFFIterator tokenEnd( iter ); AStackString<> token( tokenStart.GetCurrent(), tokenEnd.GetCurrent() ); if ( BFFMacros::Get().Define( token ) == false ) { Error::Error_1038_OverwritingTokenInDefine( tokenStart ); return false; } FLOG_INFO( "Define macro <%s>", token.Get() ); return true; }
// ParseImportDirective //------------------------------------------------------------------------------ bool BFFParser::ParseImportDirective( const BFFIterator & directiveStart, BFFIterator & iter ) { iter.SkipWhiteSpace(); // make sure we haven't hit the end of the file if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( directiveStart ); return false; } // make sure this is a variable name if ( iter.IsAtValidVariableNameCharacter() == false ) { Error::Error_1013_UnexpectedCharInVariableName( iter, nullptr ); return false; } // find the end of the variable name const BFFIterator varNameStart( iter ); iter.SkipVariableName(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } 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; } AStackString<> varName( varNameStart.GetCurrent(), varNameEnd.GetCurrent() ); // look for varName in system environment AStackString<> varValue; uint32_t varHash = 0; if ( FBuild::Get().ImportEnvironmentVar( varName.Get(), varValue, varHash ) == false ) { Error::Error_1009_UnknownVariable( varNameStart, nullptr ); return false; } // add the dot to variable name varName = "."; varName.Append( varNameStart.GetCurrent(), varNameLen ); // import variable in current scope BFFStackFrame::SetVarString( varName, varValue, nullptr ); FLOG_INFO( "Imported <string> variable '%s' with value '%s' from system environment", varName.Get(), varValue.Get() ); return true; }
// 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; } // 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() ); if ( parentScope ) { // exchange '^' with '.' ASSERT( BFF_DECLARE_VAR_PARENT == name[0] ); name[0] = BFF_DECLARE_VAR_INTERNAL; } return true; }
// ParseNamedVariableDeclaration //------------------------------------------------------------------------------ bool BFFParser::ParseNamedVariableDeclaration( BFFIterator & iter ) { // skip over the declaration symbol ASSERT( *iter == BFF_DECLARE_VAR_INTERNAL ); m_LastVarNameStart = 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; } // 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(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } m_LastVarNameEnd = iter; // sanity check it is a sensible length size_t varNameLen = m_LastVarNameStart.GetDistTo( m_LastVarNameEnd ); if ( varNameLen > MAX_VARIABLE_NAME_LENGTH ) { Error::Error_1014_VariableNameIsTooLong( iter, (uint32_t)varNameLen, (uint32_t)MAX_VARIABLE_NAME_LENGTH ); return false; } // find the start of the assignment iter.SkipWhiteSpaceAndComments(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } return ParseVariableDeclaration( iter, m_LastVarNameStart, m_LastVarNameEnd ); }
// ParseUndefDirective //------------------------------------------------------------------------------ bool BFFParser::ParseUndefDirective( BFFIterator & iter ) { if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } // parse out token const BFFIterator tokenStart( iter ); iter.SkipVariableName(); if ( tokenStart.GetCurrent() == iter.GetCurrent() ) { Error::Error_1007_ExpectedVariable( iter, nullptr ); return false; } const BFFIterator tokenEnd( iter ); AStackString<> token( tokenStart.GetCurrent(), tokenEnd.GetCurrent() ); if ( BFFMacros::Get().Undefine( token ) == false ) { if ( token.BeginsWith( "__" ) ) { Error::Error_1040_UndefOfBuiltInTokenNotAllowed( tokenStart ); } else { Error::Error_1039_UnknownTokenInUndef( tokenStart ); } return false; } FLOG_INFO( "Undefine macro <%s>", token.Get() ); return true; }
// ParseIfDirective //------------------------------------------------------------------------------ bool BFFParser::ParseIfDirective( const BFFIterator & directiveStart, BFFIterator & iter ) { if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } bool negate = false; if ( *iter == '!' ) { negate = true; // the condition will be inverted iter++; // skip '!' iter.SkipWhiteSpace(); // allow whitepace after '!' if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } } // parse out condition const BFFIterator conditionStart( iter ); iter.SkipVariableName(); if ( conditionStart.GetCurrent() == iter.GetCurrent() ) { Error::Error_1007_ExpectedVariable( directiveStart, nullptr ); return false; } const BFFIterator conditionEnd( iter ); // Evaluate the condition bool result; if ( CheckIfCondition( conditionStart, conditionEnd, result ) == false ) { return false; // CheckIfCondition will have emitted an error } // #ifndef ? if ( negate ) { result = !( result ); } if ( result ) { ++s_IfDepth; // Track that we're inside an if block return true; // continue parsing like normal } // Advance iterator past entire #if block size_t depth = 1; // handle nested ifs while ( depth > 0 ) { // did we hit the end of the file? if ( iter.IsAtEnd() ) { (void)directiveStart; // TODO: Show we're looking for matching endif to this Error::Error_1012_UnexpectedEndOfFile( iter ); // TODO:B better error for this? return false; } // find the next preprocessor directive iter.SkipWhiteSpace(); if ( *iter == BFF_PREPROCESSOR_START ) { iter++; // skip # iter.SkipWhiteSpace(); // allow whitespace between # and directive const BFFIterator directiveNameStart( iter ); while ( iter.IsAtValidDirectiveNameCharacter() ) { iter++; } const BFFIterator directiveNameEnd( iter ); AStackString<> directiveName( directiveNameStart.GetCurrent(), directiveNameEnd.GetCurrent() ); if ( directiveName == "endif" ) { --depth; } else if ( directiveName == "if" ) { ++depth; } // continue to skip rest of line.... } // skip rest of line while ( ( iter.IsAtEnd() == false ) && ( *iter != '\r' ) && ( *iter != '\n' ) ) { iter++; } } return true; }
// 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; }
// ParseVariableDeclaration //------------------------------------------------------------------------------ bool BFFParser::ParseVariableDeclaration( BFFIterator & iter, const BFFIterator & varNameStart, const BFFIterator & varNameEnd ) { m_SeenAVariable = true; // look for an appropriate operator BFFIterator operatorIter( iter ); bool concatenation = false; if ( *iter == BFF_VARIABLE_ASSIGNMENT ) { // assignment } else if ( *iter == BFF_VARIABLE_CONCATENATION ) { // concatenation concatenation = 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; } AStackString< 64 > varName( varNameStart.GetCurrent(), varNameEnd.GetCurrent() ); 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 ( concatenation ) { Error::Error_1027_CannotConcatenate( 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( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), i ); } 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 ( concatenation ) { Error::Error_1027_CannotConcatenate( operatorIter, varName, BFFVariable::VAR_ANY, BFFVariable::VAR_BOOL ); return false; } return StoreVariableBool( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), true ); } else if ( value == "false" ) { if ( concatenation ) { Error::Error_1027_CannotConcatenate( operatorIter, varName, BFFVariable::VAR_ANY, BFFVariable::VAR_BOOL ); return false; } return StoreVariableBool( m_LastVarNameStart.GetCurrent(), m_LastVarNameEnd.GetCurrent(), false ); } } } // not a valid bool value } else if ( *iter == '.' ) { // assignment of one variable to another BFFIterator varNameStartSrc( iter ); iter++; // skip '.' if ( iter.IsAtValidVariableNameCharacter() == false ) { Error::Error_1013_UnexpectedCharInVariableName( iter, nullptr ); return false; } iter.SkipVariableName(); return StoreVariableToVariable( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), varNameStartSrc, iter, operatorIter ); } 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( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), openTokenPos, iter, operatorIter ); } else { Error::Error_1002_MatchingClosingTokenNotFound( openTokenForError, nullptr, closeToken ); } } else if ( openToken == BFF_STRUCT_OPEN ) { if ( iter.ParseToMatchingBrace( openToken, closeToken ) ) { result = StoreVariableStruct( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), openTokenPos, iter, operatorIter ); } else { Error::Error_1002_MatchingClosingTokenNotFound( openTokenForError, nullptr, closeToken ); } } else { ASSERT( ( openToken == '\'' ) || ( openToken == '"' ) ); iter.SkipString( closeToken ); if ( *iter == closeToken ) { result = StoreVariableString( varNameStart.GetCurrent(), varNameEnd.GetCurrent(), openTokenPos, iter, operatorIter ); } 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; }