// Parse //------------------------------------------------------------------------------ bool BFFParser::Parse( BFFIterator & iter ) { for (;;) { iter.SkipWhiteSpace(); // is this a comment? if ( iter.IsAtComment() ) { iter.SkipComment(); continue; } const char c = *iter; switch ( c ) { case BFF_DECLARE_VAR_INTERNAL: case BFF_DECLARE_VAR_PARENT: { if ( ParseNamedVariableDeclaration( iter ) == false ) { return false; } continue; } case BFF_VARIABLE_CONCATENATION: case BFF_VARIABLE_SUBTRACTION: { // concatenation to last used variable if ( ParseUnnamedVariableModification( iter ) == false ) { return false; } continue; } case BFF_SCOPE_OPEN: { // start an unnamed scope if ( ParseUnnamedScope( iter ) == false ) { return false; } continue; } case BFF_PREPROCESSOR_START: { if ( ParsePreprocessorDirective( iter ) == false ) { return false; } continue; } default: { if ( iter.IsAtValidFunctionNameCharacter() ) { if ( ParseFunction( iter ) == false ) { return false; } continue; } } } iter.SkipWhiteSpace(); if ( iter.IsAtEnd() == false ) { Error::Error_1010_UnknownConstruct( iter ); return false; } break; // cleanly hit end of file } return true; }
// 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 );}