11/*
2- * Copyright 2019-2022 Diligent Graphics LLC
2+ * Copyright 2019-2024 Diligent Graphics LLC
33 * Copyright 2015-2019 Egor Yusov
44 *
55 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -813,8 +813,18 @@ void HLSL2GLSLConverterImpl::ConversionStream::InsertIncludes(String& GLSLSource
813813// The function converts source code into a token list
814814void HLSL2GLSLConverterImpl::ConversionStream::Tokenize (const String& Source)
815815{
816+ size_t TokenIdx = 0 ;
817+
816818 m_Tokens = Parsing::Tokenize<TokenInfo, decltype (m_Tokens)>(
817- Source.begin (), Source.end (), TokenInfo::Create,
819+ Source.begin (), Source.end (),
820+ [&TokenIdx](TokenType Type,
821+ const std::string::const_iterator& DelimStart,
822+ const std::string::const_iterator& DelimEnd,
823+ const std::string::const_iterator& LiteralStart,
824+ const std::string::const_iterator& LiteralEnd) //
825+ {
826+ return TokenInfo::Create (Type, DelimStart, DelimEnd, LiteralStart, LiteralEnd, TokenIdx++);
827+ },
818828 [&](const std::string::const_iterator& Start, const std::string::const_iterator& End) //
819829 {
820830 auto KeywordIt = m_Converter.m_HLSLKeywords .find (HashMapStringKey{std::string{Start, End}});
@@ -827,6 +837,71 @@ void HLSL2GLSLConverterImpl::ConversionStream::Tokenize(const String& Source)
827837 });
828838}
829839
840+ void HLSL2GLSLConverterImpl::ConversionStream::ParseGlobalPreprocessorDefines ()
841+ {
842+ auto Token = m_Tokens.begin ();
843+
844+ // Collect global-scope preprocessor definitions
845+ int PreprocessorScopeLevel = 0 ;
846+ while (Token != m_Tokens.end ())
847+ {
848+ if (Token->Type != TokenType::PreprocessorDirective)
849+ {
850+ ++Token;
851+ continue ;
852+ }
853+
854+ const auto Directive = RefinePreprocessorDirective (Token->Literal );
855+
856+ if (Directive == " if" ||
857+ Directive == " ifdef" ||
858+ Directive == " ifndef" )
859+ {
860+ ++PreprocessorScopeLevel;
861+ }
862+ else if (Directive == " endif" )
863+ {
864+ if (PreprocessorScopeLevel > 0 )
865+ {
866+ --PreprocessorScopeLevel;
867+ }
868+ else
869+ {
870+ LOG_ERROR_MESSAGE (" No matching #if directive\n " , PrintTokenContext (Token, 4 ));
871+ }
872+ }
873+ else if (Directive == " define" )
874+ {
875+ // #define MACRO
876+ // ^
877+
878+ // Only process macros in the global scope as we don't
879+ // handle conditional compilation
880+ if (PreprocessorScopeLevel == 0 )
881+ {
882+ auto MacroNameToken = Token;
883+ ++MacroNameToken;
884+ // #define MACRO
885+ // ^
886+ if (MacroNameToken != m_Tokens.end () &&
887+ // The name should be an identifier
888+ MacroNameToken->Type == TokenType::Identifier &&
889+ // Check that the name is on the same line
890+ MacroNameToken->Delimiter .find_first_of (" \r\n " ) == std::string::npos)
891+ {
892+ m_PreprocessorDefinitions.emplace (MacroNameToken->Literal , Token);
893+ }
894+ }
895+ }
896+
897+ ++Token;
898+ }
899+
900+ if (PreprocessorScopeLevel > 0 )
901+ {
902+ LOG_ERROR_MESSAGE (" Missing #endif directive at the end of the file. Current preprocessor scope level: " , PreprocessorScopeLevel);
903+ }
904+ }
830905
831906// The function replaces cbuffer with uniform and adds semicolon if it is missing after the closing brace:
832907// cbuffer
@@ -2270,60 +2345,63 @@ void HLSL2GLSLConverterImpl::ConversionStream::ParseShaderParameter(TokenListTyp
22702345 auto TypeToken = Token;
22712346 ParamInfo.Type = Token->Literal ;
22722347
2273- ++Token;
2274- // out float4 Color : SV_Target,
2275- // ^
2276- VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF while parsing argument list" );
2277- VERIFY_PARSER_STATE (Token, Token->Type == TokenType::Identifier, " Missing argument name after " , ParamInfo.Type );
2278- ParamInfo.Name = Token->Literal ;
2279-
2280- ++Token;
2281- VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF" );
2282-
2283- if (Token->Type == TokenType::OpenSquareBracket)
2348+ if (ParamInfo.storageQualifier != ShaderParameterInfo::StorageQualifier::Ret)
22842349 {
2285- // triangle VSOut In[3]
2286- // ^
2287- ProcessScope (
2288- Token, m_Tokens.end (), TokenType::OpenSquareBracket, TokenType::ClosingSquareBracket,
2289- [&](TokenListType::iterator& tkn, int ) {
2290- ParamInfo.ArraySize .append (tkn->Delimiter );
2291- ParamInfo.ArraySize .append (tkn->Literal );
2292- ++tkn;
2293- } //
2294- );
2295- VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF" );
2296- // triangle VSOut In[3],
2297- // ^
2298- VERIFY_PARSER_STATE (Token, Token->Type == TokenType::ClosingSquareBracket, " Closing staple expected" );
2350+ ++Token;
2351+ // out float4 Color : SV_Target,
2352+ // ^
2353+ VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF while parsing argument list" );
2354+ VERIFY_PARSER_STATE (Token, Token->Type == TokenType::Identifier, " Missing argument name after " , ParamInfo.Type );
2355+ ParamInfo.Name = Token->Literal ;
22992356
23002357 ++Token;
23012358 VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF" );
2302- VERIFY_PARSER_STATE (Token, Token->Type != TokenType::OpenSquareBracket, " Multi-dimensional arrays are not supported" );
2303- }
23042359
2305-
2306- if (TypeToken->IsBuiltInType ())
2307- {
2308- // out float4 Color : SV_Target,
2309- // ^
2310- VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected end of file after argument \" " , ParamInfo.Name , ' \" ' );
2311- if (Token->Literal == " :" )
2360+ if (Token->Type == TokenType::OpenSquareBracket)
23122361 {
2313- ++Token;
2314- // out float4 Color : SV_Target,
2315- // ^
2316- VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected end of file while looking for semantic for argument \" " , ParamInfo.Name , ' \" ' );
2317- VERIFY_PARSER_STATE (Token, Token->Type == TokenType::Identifier, " Missing semantic for argument \" " , ParamInfo.Name , ' \" ' );
2318- // Transform to lower case - semantics are case-insensitive
2319- ParamInfo.Semantic = StrToLower (Token->Literal );
2362+ // triangle VSOut In[3]
2363+ // ^
2364+ ProcessScope (
2365+ Token, m_Tokens.end (), TokenType::OpenSquareBracket, TokenType::ClosingSquareBracket,
2366+ [&](TokenListType::iterator& tkn, int ) {
2367+ ParamInfo.ArraySize .append (tkn->Delimiter );
2368+ ParamInfo.ArraySize .append (tkn->Literal );
2369+ ++tkn;
2370+ } //
2371+ );
2372+ VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF" );
2373+ // triangle VSOut In[3],
2374+ // ^
2375+ VERIFY_PARSER_STATE (Token, Token->Type == TokenType::ClosingSquareBracket, " Closing staple expected" );
23202376
23212377 ++Token;
2378+ VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected EOF" );
2379+ VERIFY_PARSER_STATE (Token, Token->Type != TokenType::OpenSquareBracket, " Multi-dimensional arrays are not supported" );
2380+ }
2381+
2382+ if (TypeToken->IsBuiltInType ())
2383+ {
23222384 // out float4 Color : SV_Target,
2323- // ^
2385+ // ^
2386+ VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected end of file after argument \" " , ParamInfo.Name , ' \" ' );
2387+ if (Token->Literal == " :" )
2388+ {
2389+ ++Token;
2390+ // out float4 Color : SV_Target,
2391+ // ^
2392+ VERIFY_PARSER_STATE (Token, Token != m_Tokens.end (), " Unexpected end of file while looking for semantic for argument \" " , ParamInfo.Name , ' \" ' );
2393+ VERIFY_PARSER_STATE (Token, Token->Type == TokenType::Identifier, " Missing semantic for argument \" " , ParamInfo.Name , ' \" ' );
2394+ // Transform to lower case - semantics are case-insensitive
2395+ ParamInfo.Semantic = StrToLower (Token->Literal );
2396+
2397+ ++Token;
2398+ // out float4 Color : SV_Target,
2399+ // ^
2400+ }
23242401 }
23252402 }
2326- else
2403+
2404+ if (!TypeToken->IsBuiltInType ())
23272405 {
23282406 const auto & StructName = TypeToken->Literal ;
23292407 auto it = m_StructDefinitions.find (StructName.c_str ());
@@ -2349,8 +2427,11 @@ void HLSL2GLSLConverterImpl::ConversionStream::ParseShaderParameter(TokenListTyp
23492427 while (TypeToken != m_Tokens.end () && TypeToken->Type != TokenType::ClosingBrace)
23502428 {
23512429 ShaderParameterInfo MemberInfo;
2352- MemberInfo.storageQualifier = ParamInfo.storageQualifier ;
23532430 ParseShaderParameter (TypeToken, MemberInfo);
2431+ // Set storage qualifier after we process the member as otherwise
2432+ // members of a struct with the StorageQualifier::Ret qualifier
2433+ // will not be processed.
2434+ MemberInfo.storageQualifier = ParamInfo.storageQualifier ;
23542435 ParamInfo.members .emplace_back (std::move (MemberInfo));
23552436 // struct VSOutput
23562437 // {
@@ -2376,11 +2457,48 @@ void HLSL2GLSLConverterImpl::ConversionStream::ProcessFunctionParameters(TokenLi
23762457 // ^
23772458 auto FuncNameToken = Token;
23782459
2379- bIsVoid = TypeToken->Type == TokenType::kw_void;
2460+ auto ActualTypeToken = TypeToken;
2461+ {
2462+ // PS_OUTPUT TestPS ( in VSOutput In,
2463+
2464+ auto define_it = m_PreprocessorDefinitions.find (ActualTypeToken->Literal .c_str ());
2465+ if (define_it != m_PreprocessorDefinitions.end ())
2466+ {
2467+ auto DefinedTypeToken = define_it->second ;
2468+ // #define PS_OUTPUT PSOutput
2469+ // ^
2470+ // DefinedTypeToken
2471+
2472+ // Check that the define directive is before the type token
2473+ if (DefinedTypeToken->Idx < TypeToken->Idx )
2474+ {
2475+ ++DefinedTypeToken;
2476+ // #define PS_OUTPUT PSOutput
2477+ // ^
2478+ // DefinedTypeToken
2479+ if (DefinedTypeToken != m_Tokens.end () && DefinedTypeToken->Literal == TypeToken->Literal )
2480+ {
2481+ ++DefinedTypeToken;
2482+ // #define PS_OUTPUT PSOutput
2483+ // ^
2484+ // DefinedTypeToken
2485+ if (DefinedTypeToken != m_Tokens.end () &&
2486+ // Check that the definition is on the same line (we don't handle backslash at the moment)
2487+ DefinedTypeToken->Delimiter .find_first_of (" \r\n " ) == std::string::npos &&
2488+ (DefinedTypeToken->IsBuiltInType () || DefinedTypeToken->Type == TokenType::Identifier))
2489+ {
2490+ ActualTypeToken = DefinedTypeToken;
2491+ }
2492+ }
2493+ }
2494+ }
2495+ }
2496+
2497+ bIsVoid = ActualTypeToken->Type == TokenType::kw_void;
23802498 if (!bIsVoid)
23812499 {
23822500 ShaderParameterInfo RetParam;
2383- RetParam.Type = TypeToken ->Literal ;
2501+ RetParam.Type = ActualTypeToken ->Literal ;
23842502 RetParam.Name = FuncNameToken->Literal ;
23852503 RetParam.storageQualifier = ShaderParameterInfo::StorageQualifier::Ret;
23862504 Params.emplace_back (std::move (RetParam));
@@ -2637,7 +2755,7 @@ void HLSL2GLSLConverterImpl::ConversionStream::ProcessFunctionParameters(TokenLi
26372755 else
26382756 {
26392757 // VSOut TestVS ()
2640- auto TmpTypeToken = TypeToken ;
2758+ auto TmpTypeToken = ActualTypeToken ;
26412759 ParseShaderParameter (TmpTypeToken, RetParam);
26422760 }
26432761 TypeToken->Type = TokenType::Identifier;
@@ -4482,6 +4600,8 @@ String HLSL2GLSLConverterImpl::ConversionStream::Convert(const Char* EntryPoint,
44824600 }
44834601 }
44844602
4603+ ParseGlobalPreprocessorDefines ();
4604+
44854605 auto ShaderEntryPointToken = m_Tokens.end ();
44864606 // Process textures and search for the shader entry point.
44874607 // GLSL does not allow local variables of sampler type, so the
@@ -4665,6 +4785,7 @@ String HLSL2GLSLConverterImpl::ConversionStream::Convert(const Char* EntryPoint,
46654785 {
46664786 m_Tokens.swap (TokensCopy);
46674787 m_StructDefinitions.clear ();
4788+ m_PreprocessorDefinitions.clear ();
46684789 m_Objects.clear ();
46694790 }
46704791
0 commit comments