// 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 ); }
// ParseNamedVariableDeclaration //------------------------------------------------------------------------------ bool BFFParser::ParseNamedVariableDeclaration( BFFIterator & iter ) { const BFFIterator varNameStart( iter ); bool parentScope = false; if ( ParseVariableName( iter, m_LastVarName, parentScope ) == false ) { return false; // ParseVariableName() would have display an error } // find the start of the assignment iter.SkipWhiteSpaceAndComments(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } // check if points to a previous declaration in a parent scope const BFFVariable * parentVar = nullptr; m_LastVarFrame = ( parentScope ) ? BFFStackFrame::GetParentDeclaration( m_LastVarName, nullptr, parentVar ) : nullptr; if ( parentScope ) { // check if a parent definition exists if ( nullptr == m_LastVarFrame ) { Error::Error_1009_UnknownVariable( varNameStart, nullptr ); return false; } ASSERT( nullptr != parentVar ); // check if the parent definition is frozen if ( parentVar->Frozen() ) { Error::Error_1060_CantModifyFrozenVar( varNameStart, nullptr, parentVar ); return false; } } return ParseVariableDeclaration( iter, m_LastVarName, m_LastVarFrame ); }
// ParseFunction //------------------------------------------------------------------------------ bool BFFParser::ParseFunction( BFFIterator & iter ) { ASSERT( iter.IsAtValidFunctionNameCharacter() ); // for variables to be used by this function BFFStackFrame stackFrame; BFFIterator functionNameStart( iter ); iter.SkipFunctionName(); if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } // check length if ( functionNameStart.GetDistTo( iter ) > MAX_FUNCTION_NAME_LENGTH ) { // if it's too long, then it can't be a valid function Error::Error_1015_UnknownFunction( functionNameStart ); return false; } // store function name AStackString<MAX_FUNCTION_NAME_LENGTH> functionName( functionNameStart.GetCurrent(), iter.GetCurrent() ); const Function * func = Function::Find( functionName ); if ( func == nullptr ) { Error::Error_1015_UnknownFunction( functionNameStart ); return false; } iter.SkipWhiteSpace(); if ( func->IsUnique() && func->GetSeen() ) { Error::Error_1020_FunctionCanOnlyBeInvokedOnce( functionNameStart, func ); return false; } func->SetSeen(); FLOG_INFO( "Function call '%s'", functionName.Get() ); // header, or body? bool hasHeader = false; BFFIterator functionArgsStartToken( iter ); BFFIterator functionArgsStopToken( iter ); if ( *iter == BFF_FUNCTION_ARGS_OPEN ) { // can this function accept a header? if ( func->AcceptsHeader() == false ) { Error::Error_1021_UnexpectedHeaderForFunction( iter, func ); return false; } // args if ( iter.ParseToMatchingBrace( BFF_FUNCTION_ARGS_OPEN, BFF_FUNCTION_ARGS_CLOSE ) == false ) { Error::Error_1022_MissingFunctionHeaderCloseToken( functionArgsStartToken, func ); return false; } functionArgsStopToken = iter; hasHeader = true; iter++; // skip over closing token iter.SkipWhiteSpaceAndComments(); } if ( func->NeedsHeader() && ( hasHeader == false ) ) { Error::Error_1023_FunctionRequiresAHeader( iter, func ); return false; } // some functions have no body bool hasBody = false; BFFIterator functionBodyStartToken( iter ); BFFIterator functionBodyStopToken( iter ); if ( func->NeedsBody() ) { // find body if ( *iter != BFF_SCOPE_OPEN ) { Error::Error_1024_FunctionRequiresABody( functionNameStart, func ); return false; } if ( iter.ParseToMatchingBrace( BFF_SCOPE_OPEN, BFF_SCOPE_CLOSE ) == false ) { Error::Error_1025_MissingScopeCloseToken( functionBodyStartToken, func ); return false; } functionBodyStopToken = iter; iter++; hasBody = true; } return func->ParseFunction( functionNameStart, hasBody ? &functionBodyStartToken : nullptr, hasBody ? &functionBodyStopToken : nullptr, hasHeader ? &functionArgsStartToken : nullptr, hasHeader ? &functionArgsStopToken : nullptr );}
// 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; }