@@ -294,8 +294,12 @@ void Parser::Get_Token ()
294294
295295 if (!GetRawToken (mToken .raw , fastForwardToDirective))
296296 {
297+ // End of current token stream reached.
298+
297299 if (maIncludeStack.empty ())
298300 {
301+ // Not in an include file, i.e. end of main scene file reached.
302+
299303 if (Cond_Stack.size () != 1 )
300304 Error (" End of file reached but #end expected." );
301305
@@ -305,12 +309,24 @@ void Parser::Get_Token ()
305309 }
306310
307311 // Returning from an include file.
312+ // NB: End of macro is marked by `#end` rather than EOF, so it won't take us here.
308313
309314 Got_EOF=false ;
310315
311316 mSymbolStack .PopTable ();
312317
313- GoToBookmark (maIncludeStack.back ()); // TODO handle errors
318+ if (Cond_Stack.size () != maIncludeStack.back ().condStackSize )
319+ Error (" Unbalanced #end directives in include file." );
320+ if (maBraceStack.size () > maIncludeStack.back ().braceStackSize )
321+ {
322+ // Include file has opened more braces/parentheses/etc. than it has closed.
323+ for (size_t i = maIncludeStack.back ().braceStackSize ; i < maBraceStack.size (); ++i)
324+ {
325+ BraceStackEntry& braceStackEntry = maBraceStack[i];
326+ Warning (braceStackEntry, " Unbalanced %s in include file" , Get_Token_String (braceStackEntry.openToken ));
327+ }
328+ }
329+ GoToBookmark (maIncludeStack.back ().returnToBookmark ); // TODO handle errors
314330 maIncludeStack.pop_back ();
315331
316332 continue ;
@@ -1881,9 +1897,9 @@ void Parser::Parse_Version()
18811897
18821898 if (maIncludeStack.empty ())
18831899 Error (" As of POV-Ray v3.7, the '#version' directive must be the first non-comment "
1884- " statement in the scene file. To indicate that your scene will dynamically "
1885- " adapt to whatever POV-Ray version is actually used, start your scene with "
1886- " '#version version;'." );
1900+ " statement in the scene file. To indicate that your scene will dynamically "
1901+ " adapt to whatever POV-Ray version is actually used, start your scene with "
1902+ " '#version version;'." );
18871903 }
18881904
18891905 // Initialize various defaults depending on language version specified.
@@ -1896,7 +1912,7 @@ void Parser::Parse_Version()
18961912
18971913 if (sceneData->explicitNoiseGenerator == false )
18981914 sceneData->noiseGenerator = (sceneData->EffectiveLanguageVersion () < 350 ?
1899- kNoiseGen_Original : kNoiseGen_RangeCorrected );
1915+ kNoiseGen_Original : kNoiseGen_RangeCorrected );
19001916 // [CLi] if assumed_gamma is not specified in a pre-v3.7 scene, gammaMode defaults to kPOVList_GammaMode_None;
19011917 // this is enforced later anyway after parsing, but we may need this information /now/ during parsing already
19021918 switch (sceneData->gammaMode )
@@ -1979,7 +1995,7 @@ void Parser::Open_Include()
19791995
19801996void Parser::Skip_Tokens (COND_TYPE cond)
19811997{
1982- int Temp = Cond_Stack.size ();
1998+ auto Temp = Cond_Stack.size ();
19831999 bool Prev_Skip = Skipping;
19842000
19852001 Skipping = true ;
@@ -3267,7 +3283,7 @@ void Parser::IncludeHeader(const UCS2String& formalFileName)
32673283 if (formalFileName.empty ())
32683284 return ;
32693285
3270- maIncludeStack.push_back (mTokenizer .GetHotBookmark ());
3286+ maIncludeStack.emplace_back (mTokenizer .GetHotBookmark (), int (Cond_Stack. size ()), int (maBraceStack. size () ));
32713287
32723288 shared_ptr<IStream> is = Locate_File (formalFileName.c_str (),POV_File_Text_INC,actualFileName,true );
32733289 if (is == nullptr )
0 commit comments