Index: Makefile.am
===================================================================
--- Makefile.am	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ Makefile.am	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -11,6 +11,6 @@
 ## Created On       : Sun May 31 22:14:18 2015
 ## Last Modified By : Peter A. Buhr
-## Last Modified On : Wed May 17 11:02:34 2023
-## Update Count     : 56
+## Last Modified On : Tue Jul 16 16:59:12 2024
+## Update Count     : 57
 ###############################################################################
 
@@ -35,5 +35,5 @@
 man1_MANS = doc/man/cfa.1
 
-EXTRA_DIST = LICENSE doc/man/cfa.1 libcfa/configure libcfa/Makefile.dist.am libcfa/Makefile.dist.in tools/build/distcc_hash tools/build/push2dist.sh
+EXTRA_DIST = LICENSE doc/man/cfa.1 libcfa/configure libcfa/Makefile.dist.am libcfa/Makefile.dist.in tools/build/distcc_hash tools/build/push2dist.sh tools/prettyprinter
 
 debug ?= yes
Index: doc/bibliography/pl.bib
===================================================================
--- doc/bibliography/pl.bib	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ doc/bibliography/pl.bib	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -1863,5 +1863,5 @@
     key		= {concurrent locking},
     author	= {Peter A. Buhr and David Dice and Wim H. Hesselink},
-    title	= {concurrent-locking},
+    title	= {Concurrent locking algorithms},
     howpublished= {\url{https://github.com/pabuhr/concurrent-locking}},
 }
@@ -4001,5 +4001,5 @@
     organization= {Google},
     year	= 2009,
-    note	= {\url{http://golang.org/ref/spec}},
+    note	= {\url{https://go.dev/ref/spec}},
 }
 
@@ -4180,5 +4180,4 @@
     number	= 12,
     pages	= {2463-2500},
-    note	= {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262}},
 }
 
@@ -7802,5 +7801,5 @@
 @book{Scott24,
     author	= {Michael L. Scott and Trevor Brown},
-    booktitle	= {Shared-Memory Synchronization},
+    title	= {Shared-Memory Synchronization},
     series	= {Synthesis Lectures on Computer Architecture},
     edition	= {2nd},
@@ -8532,5 +8531,5 @@
     key		= {TIOBE Index},
     author	= {{TIOBE Index}},
-    howpublished= {\url{http://www.tiobe.com/tiobe_index}},
+    howpublished= {\url{https://www.tiobe.com/tiobe-index}},
 }
 
Index: doc/user/Makefile
===================================================================
--- doc/user/Makefile	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ doc/user/Makefile	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -6,5 +6,6 @@
 TeXLIB = .:${Macros}:${Build}:
 LaTeX  = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}
-BibTeX = BIBINPUTS=../bibliography: && export BIBINPUTS && bibtex
+BibDir = ../bibliography
+BibTeX = BIBINPUTS=${BibDir}: && export BIBINPUTS && bibtex
 
 MAKEFLAGS = --no-print-directory --silent #
@@ -61,5 +62,5 @@
 
 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${Macros}/common.tex ${Macros}/common.sty \
-		${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
+		${Macros}/lstlang.sty ${Macros}/indexstyle ${BibDir}/pl.bib build/version | ${Build}
 	# Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
 	if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
Index: libcfa/src/enum.cfa
===================================================================
--- libcfa/src/enum.cfa	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ libcfa/src/enum.cfa	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -42,5 +42,6 @@
 	if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 
-	// Match input enumerator string to enumerator labels.
+	// Match longest input enumerator string to enumerator labels, where enumerator names are unique.
+
 	int N = Countof( e ), lnths[N], max = 0;
 //	printf( "N %d\n", N );
@@ -60,18 +61,20 @@
 	for ( c; max ) {
 		int args = fmt( is, "%c", &ch );				// read character
-		if ( eof( is ) ) {
+	  if ( eof( is ) ) {
 //			fprintf( stderr, "Eof1\n" );
 			if ( c == 0 ) return is;					// no characters read ?
-			clear( is );								// => reset EOF => detect again on next read
+			clear( is );								// => read something => reset EOF => detect again on next read
 //			fprintf( stderr, "Eof2\n" );
-			goto W;
-		}
+			break;
+		} // if
 		if ( args != 1 ) throwResume ExceptionInst( missing_data );
+
 //		printf( "read '%c'\n", ch );
-		for ( i; N ) {
+		for ( i; N ) {									// scan enumeration strings for winner
 //			printf( "%d %d %d\n", c, i, lnths[i] );
 			if ( c < lnths[i] ) {						// eligible for this checking round ?
 				char match = label( fromInt( i ) )[c];	// optimization
 //				printf( "%c '%c'\n", match, ch );
+				// Stop on first match, could be other matches.
 				if ( (match == ch) && (c == 0 || curr == label( fromInt( i ) )[c - 1]) ) {
 //					printf( "match %d %d %d '%c' '%c' '%c' '%c' 'c'\n", c, i, lnths[i], match, ch, prev, label( fromInt( i ) )[c - 1] );
@@ -92,6 +95,6 @@
 //		fprintf( stderr, "finished2 %d\n", win );
  	} // for
-  W :;
-	for ( i; N ) {										// scan for winner, must succeed
+  W: ;
+	for ( i; N ) {										// scan enumeration strings for winner
 		if ( win == lnths[i] - 1 ) {
 			char match = label( fromInt( i ) )[win];	// optimization
@@ -100,5 +103,5 @@
 				e = fromInt( i );
 				break;
-			}
+			} // if
 		} // if
 	} else {
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ libcfa/src/iostream.cfa	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 12 05:45:45 2024
-// Update Count     : 2019
+// Last Modified On : Mon Jul 15 08:16:48 2024
+// Update Count     : 2020
 //
 
@@ -781,5 +781,5 @@
 		// Optional leading whitespace at start of strings.
 		fmt( is, " " FALSE "%n", &len );				// try false
-		if ( len != sizeof( FALSE ) - 1 ) {				// remove null terminate
+		if ( len != sizeof( FALSE ) - 1 ) {				// -1 removes null terminate
 			fmt( is, " " TRUE "%n", &len );				// try true
 			if ( len != sizeof( TRUE ) - 1 ) throwResume ExceptionInst( missing_data );
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ src/AST/Print.cpp	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -566,6 +566,4 @@
 		++indent;
 		safe_print( node->cond );
-		os << indent-1 << "... with body:" << endl;
-		safe_print( node->body );
 
 		if ( ! node->inits.empty() ) {
@@ -573,4 +571,14 @@
 			printAll( node->inits );
 		}
+
+		os << indent-1 << "... with body:" << endl;
+		safe_print( node->body );
+
+		if ( node->else_ ) {
+			os << indent-1 << "... with else:" << endl;
+			os << indent;
+			node->else_->accept( *this );
+		}
+
 		--indent;
 
@@ -614,4 +622,13 @@
 			--indent;
 		}
+
+		if ( node->else_ ) {
+			os << indent << "... with else:" << endl;
+			++indent;
+			os << indent;
+			node->else_->accept( *this );
+			--indent;
+		}
+
 		os << endl;
 		print( node->labels );
Index: src/CodeGen/CodeGenerator.cpp
===================================================================
--- src/CodeGen/CodeGenerator.cpp	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ src/CodeGen/CodeGenerator.cpp	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -1195,10 +1195,12 @@
 	stmt->body->accept( *visitor );
 
-	output << indent;
-
 	if ( stmt->isDoWhile ) {
 		output << " while (";
 		stmt->cond->accept( *visitor );
-		output << ");";
+		output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
+	}
+	if ( stmt->else_ ) {
+		output << " else ";
+		stmt->else_->accept( *visitor );
 	}
 }
@@ -1225,4 +1227,10 @@
 		stmt->body->accept( *visitor );
 	}
+
+	if ( nullptr != stmt->else_ ) {
+		assertf( !options.genC, "Loop else should not reach code generation." );
+		output << " else ";
+		stmt->else_->accept( *visitor );
+	}
 }
 
Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -78,4 +78,5 @@
 		stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmtK ) {}
 
+	// Check if this entry can be the target of the given type of control flow.
 	bool isContTarget() const { return kind <= WhileDoStmtK; }
 	bool isBreakTarget() const { return kind != CaseClauseK; }
@@ -207,5 +208,5 @@
 
 	// If the label is empty, do not add unused attribute.
-  if ( originalTarget.empty() ) return size;
+	if ( originalTarget.empty() ) return size;
 
 	// Search for a label that matches the originalTarget.
@@ -343,4 +344,5 @@
 		assert(0);
 	}
+	assert( !exitLabel.empty() );
 
 	// Add unused attribute to silence warnings.
@@ -486,7 +488,5 @@
 		}
 
-		auto caseStmt = mutStmt->cases.back().get();
-		auto mutCase = mutate( caseStmt );
-		mutStmt->cases.back() = mutCase;
+		auto mutCase = mutStmt->cases.back().get_and_mutate();
 
 		Label label( mutCase->location, "breakLabel" );
@@ -597,14 +597,14 @@
 template<typename LoopNode>
 void MultiLevelExitCore::prehandleLoopStmt( const LoopNode * loopStmt ) {
-	// Remember is loop before going onto mutate the body.
+	// Create temporary labels and mark the enclosing loop before traversal.
 	// The labels will be folded in if they are used.
 	Label breakLabel = newLabel( "loopBreak", loopStmt );
 	Label contLabel = newLabel( "loopContinue", loopStmt );
 	enclosing_control_structures.emplace_back( loopStmt, breakLabel, contLabel );
-	// labels are added temporarily to see if they are used and then added permanently in postvisit if ther are used
-	// children will tag labels as being used during their traversal which occurs before postvisit
-
-	// GuardAction calls the lambda after the node is done being visited
+
 	GuardAction( [this](){ enclosing_control_structures.pop_back(); } );
+
+	// Because of fixBlock, this should be empty now (and must be).
+	assert( nullptr == loopStmt->else_ );
 }
 
@@ -617,7 +617,4 @@
 	// Now check if the labels are used and add them if so.
 	return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
-	// this call to mutate_field compares loopStmt->body and the result of mutateLoop
-	// 		if they are the same the node isn't mutated, if they differ then the new mutated node is returned
-	// 		the stmts will only differ if a label is used
 }
 
@@ -639,33 +636,46 @@
 
 		ptr<Stmt> else_stmt = nullptr;
-		const Stmt * loop_kid = nullptr;
+		const Stmt * to_visit;
 		// check if loop node and if so add else clause if it exists
-		const WhileDoStmt * whilePtr = kid.as<WhileDoStmt>();
-		if ( whilePtr && whilePtr->else_ ) {
-			else_stmt = whilePtr->else_;
-			loop_kid = mutate_field( whilePtr, &WhileDoStmt::else_, nullptr );
-		}
-		const ForStmt * forPtr = kid.as<ForStmt>();
-		if ( forPtr && forPtr->else_ ) {
-			else_stmt = forPtr->else_;
-			loop_kid = mutate_field( forPtr, &ForStmt::else_, nullptr );
-		}
-
+		if ( auto ptr = kid.as<WhileDoStmt>() ; ptr && ptr->else_ ) {
+			else_stmt = ptr->else_;
+			to_visit = mutate_field( ptr, &WhileDoStmt::else_, nullptr );
+		} else if ( auto ptr = kid.as<ForStmt>() ; ptr && ptr->else_ ) {
+			else_stmt = ptr->else_;
+			to_visit = mutate_field( ptr, &ForStmt::else_, nullptr );
+		} else {
+			to_visit = kid.get();
+		}
+
+		// This is the main (safe) visit of the child node.
 		try {
-			if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) );
-			else ret.push_back( kid->accept( *visitor ) );
+			ret.push_back( to_visit->accept( *visitor ) );
 		} catch ( SemanticErrorException & e ) {
 			errors.append( e );
 		}
 
-		if (else_stmt) ret.push_back(else_stmt);
-
-		if ( ! break_label.empty() ) {
+		// The following sections handle visiting loop else clause and makes
+		// sure breaking from a loop body does not execute that clause.
+		Label local_break_label = std::move( break_label );
+		break_label = Label( CodeLocation(), "" );
+
+		if ( else_stmt ) try {
+			ret.push_back( else_stmt->accept( *visitor ) );
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		}
+
+		if ( !break_label.empty() ) {
 			ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
 			break_label = Label( CodeLocation(), "" );
 		}
-	}
-
-	if ( ! errors.isEmpty() ) {
+
+		// This handles a break from the body or non-loop statement.
+		if ( !local_break_label.empty() ) {
+			ret.push_back( labelledNullStmt( ret.back()->location, local_break_label ) );
+		}
+	}
+
+	if ( !errors.isEmpty() ) {
 		throw errors;
 	}
Index: tests/ctrl-flow/.expect/loop_else.txt
===================================================================
--- tests/ctrl-flow/.expect/loop_else.txt	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ tests/ctrl-flow/.expect/loop_else.txt	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -63,2 +63,3 @@
 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)else
 
+before begin else after
Index: tests/ctrl-flow/loop_else.cfa
===================================================================
--- tests/ctrl-flow/loop_else.cfa	(revision 68ea8d208b6ee1a76e030b1697eecadeb86f4f63)
+++ tests/ctrl-flow/loop_else.cfa	(revision 97f9619fce73cf34248ece2d476986719a5e602d)
@@ -74,5 +74,5 @@
 		i -= 1.7;
 	} else { sout | "else"; }														sout | nl | nl;
-	
+
 	enum { N = 10 };
 	for ( N ) { sout | "N"; } else { sout | "else"; }							sout | nl;
@@ -109,4 +109,19 @@
 	for ( s; (S){0} -~  (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
 	for ( s; (S){0} -~= (S){10,10} ) { sout | s; } else { sout | "else"; }		 sout | nl;
-	for ( s; (S){0} -~= (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl | nl;
+	for ( s; (S){0} -~= (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
+	sout | nl;
+
+	// A break (or a continue) in an else clause should target an outer loop.
+	sout | "before";
+	while ( true ) {
+		sout | " begin";
+		while ( false ) {
+			sout | "never";
+		} else {
+			sout | " else";
+			break;
+		}
+		sout | " end";
+	}
+	sout | " after" | nl;
 }
