Module Name:    src
Committed By:   rillig
Date:           Sat Sep  3 00:50:07 UTC 2022

Modified Files:
        src/usr.bin/make: for.c make.1 parse.c
        src/usr.bin/make/unit-tests: directive-for-break.exp
            directive-for-break.mk

Log Message:
make: clean up handling of .break in .for loops

Move For_Break further up, as the functions in that file are sorted from
small to big.  The cast from size_t to unsigned int is required by lint.

In parse.c, move the code into a separate function to keep
ParseDirective small.  Its only job is to parse the directive and then
delegate to another function doing the actual work.

In the manual page, remove empty lines.

In the test, ensure that .break stops processing of the .for loop
immediately; anything after the .break is not processed anymore.
Replace ':=' with '=', as there is no need to evaluate '$i' early.
Check the expected value in the .mk file instead of the .exp file, to
keep the reading scope as small as possible.


To generate a diff of this commit:
cvs rdiff -u -r1.169 -r1.170 src/usr.bin/make/for.c
cvs rdiff -u -r1.331 -r1.332 src/usr.bin/make/make.1
cvs rdiff -u -r1.682 -r1.683 src/usr.bin/make/parse.c
cvs rdiff -u -r1.1 -r1.2 src/usr.bin/make/unit-tests/directive-for-break.exp \
    src/usr.bin/make/unit-tests/directive-for-break.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/for.c
diff -u src/usr.bin/make/for.c:1.169 src/usr.bin/make/for.c:1.170
--- src/usr.bin/make/for.c:1.169	Fri Sep  2 16:24:31 2022
+++ src/usr.bin/make/for.c	Sat Sep  3 00:50:07 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: for.c,v 1.169 2022/09/02 16:24:31 sjg Exp $	*/
+/*	$NetBSD: for.c,v 1.170 2022/09/03 00:50:07 rillig Exp $	*/
 
 /*
  * Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
 #include "make.h"
 
 /*	"@(#)for.c	8.1 (Berkeley) 6/6/93"	*/
-MAKE_RCSID("$NetBSD: for.c,v 1.169 2022/09/02 16:24:31 sjg Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.170 2022/09/03 00:50:07 rillig Exp $");
 
 
 typedef struct ForLoop {
@@ -490,6 +490,13 @@ For_NextIteration(ForLoop *f, Buffer *bo
 	return true;
 }
 
+/* Break out of the .for loop. */
+void
+For_Break(ForLoop *f)
+{
+	f->nextItem = (unsigned int)f->items.len;
+}
+
 /* Run the .for loop, imitating the actions of an include file. */
 void
 For_Run(unsigned headLineno, unsigned bodyReadLines)
@@ -504,11 +511,3 @@ For_Run(unsigned headLineno, unsigned bo
 	} else
 		ForLoop_Free(f);
 }
-
-/* Breaking out of a .for loop */
-void
-For_Break(ForLoop *f)
-{
-    f->nextItem = f->items.len;
-}
-     

Index: src/usr.bin/make/make.1
diff -u src/usr.bin/make/make.1:1.331 src/usr.bin/make/make.1:1.332
--- src/usr.bin/make/make.1:1.331	Fri Sep  2 16:24:31 2022
+++ src/usr.bin/make/make.1	Sat Sep  3 00:50:07 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: make.1,v 1.331 2022/09/02 16:24:31 sjg Exp $
+.\"	$NetBSD: make.1,v 1.332 2022/09/03 00:50:07 rillig Exp $
 .\"
 .\" Copyright (c) 1990, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -2084,14 +2084,12 @@ inside the body of the for loop.
 The number of words must come out even; that is, if there are three
 iteration variables, the number of words provided must be a multiple
 of three.
-
+.Pp
 If
 .Sq Ic .break
 is encountered within a
 .Cm \&.for
-loop, it causes early termination of the loop,
-otherwise a parse error.
-
+loop, it causes early termination of the loop, otherwise a parse error.
 .Sh COMMENTS
 Comments begin with a hash
 .Pq Ql \&#

Index: src/usr.bin/make/parse.c
diff -u src/usr.bin/make/parse.c:1.682 src/usr.bin/make/parse.c:1.683
--- src/usr.bin/make/parse.c:1.682	Fri Sep  2 16:24:31 2022
+++ src/usr.bin/make/parse.c	Sat Sep  3 00:50:07 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.c,v 1.682 2022/09/02 16:24:31 sjg Exp $	*/
+/*	$NetBSD: parse.c,v 1.683 2022/09/03 00:50:07 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -105,7 +105,7 @@
 #include "pathnames.h"
 
 /*	"@(#)parse.c	8.3 (Berkeley) 3/19/94"	*/
-MAKE_RCSID("$NetBSD: parse.c,v 1.682 2022/09/02 16:24:31 sjg Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.683 2022/09/03 00:50:07 rillig Exp $");
 
 /*
  * A file being read.
@@ -2661,6 +2661,20 @@ ParseLine_ShellCommand(const char *p)
 	}
 }
 
+static void
+HandleBreak(void)
+{
+	IncludedFile *curFile = CurFile();
+
+	if (curFile->forLoop != NULL) {
+		/* pretend we reached EOF */
+		For_Break(curFile->forLoop);
+		Cond_reset_depth(curFile->cond_depth);
+		ParseEOF();
+	} else
+		Parse_Error(PARSE_FATAL, "break outside of for loop");
+}
+
 /*
  * See if the line starts with one of the known directives, and if so, handle
  * the directive.
@@ -2689,17 +2703,9 @@ ParseDirective(char *line)
 	pp_skip_whitespace(&cp);
 	arg = cp;
 
-	if (Substring_Equals(dir, "break")) {
-		IncludedFile *curFile = CurFile();
-
-		if (curFile->forLoop != NULL) {
-			/* pretend we reached EOF */
-			For_Break(curFile->forLoop);
-			Cond_reset_depth(curFile->cond_depth);
-			ParseEOF();
-		} else
-			Parse_Error(PARSE_FATAL, "break outside of for loop");
-	} else if (Substring_Equals(dir, "undef"))
+	if (Substring_Equals(dir, "break"))
+		HandleBreak();
+	else if (Substring_Equals(dir, "undef"))
 		Var_Undef(arg);
 	else if (Substring_Equals(dir, "export"))
 		Var_Export(VEM_PLAIN, arg);

Index: src/usr.bin/make/unit-tests/directive-for-break.exp
diff -u src/usr.bin/make/unit-tests/directive-for-break.exp:1.1 src/usr.bin/make/unit-tests/directive-for-break.exp:1.2
--- src/usr.bin/make/unit-tests/directive-for-break.exp:1.1	Fri Sep  2 16:24:31 2022
+++ src/usr.bin/make/unit-tests/directive-for-break.exp	Sat Sep  3 00:50:07 2022
@@ -1,5 +1,4 @@
-make: "directive-for-break.mk" line 16: I=3
-make: "directive-for-break.mk" line 24: break outside of for loop
+make: "directive-for-break.mk" line 45: break outside of for loop
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1
Index: src/usr.bin/make/unit-tests/directive-for-break.mk
diff -u src/usr.bin/make/unit-tests/directive-for-break.mk:1.1 src/usr.bin/make/unit-tests/directive-for-break.mk:1.2
--- src/usr.bin/make/unit-tests/directive-for-break.mk:1.1	Fri Sep  2 16:24:31 2022
+++ src/usr.bin/make/unit-tests/directive-for-break.mk	Sat Sep  3 00:50:07 2022
@@ -1,25 +1,46 @@
-# $NetBSD: directive-for-break.mk,v 1.1 2022/09/02 16:24:31 sjg Exp $
+# $NetBSD: directive-for-break.mk,v 1.2 2022/09/03 00:50:07 rillig Exp $
 #
-# Tests for .break in .for loops
+# Tests for .break in .for loops, which immediately terminates processing of
+# the surrounding .for loop.
 
-I= 0
-LIST= 1 2 3 4 5 6 7 8
 
-# .break terminates the loop early
-# this is usually done within a conditional
-.for i in ${LIST}
-.if $i == 3
-I:= $i
-.break
+# .break terminates the loop early.
+# This is usually done within a conditional.
+.for i in 1 2 3 4 5 6 7 8
+.  if $i == 3
+I=	$i
+.    break
+I=	unreached
+.  endif
+.endfor
+.if $I != "3"
+.  error
 .endif
+
+
+# The .break only breaks out of the immediately surrounding .for loop, any
+# other .for loops are continued normally.
+.for outer in o1 o2 o3
+.  for inner in i1 i2 i3
+.    if ${outer} == o2 && ${inner} == i2
+.      break
+.    endif
+COMBINED+=	${outer}-${inner}
+.  endfor
 .endfor
-.info I=$I
+# Only o2-i2 and o2-i3 are missing.
+.if ${COMBINED} != "o1-i1 o1-i2 o1-i3 o2-i1 o3-i1 o3-i2 o3-i3"
+.  error
+.endif
+
 
-# .break outside the context of a .for loop is an error
+# A .break outside the context of a .for loop is an error.
 .if $I == 0
-# harmless
-.break
+# No parse error, even though the .break occurs outside a .for loop, since
+# lines from inactive branches are only parsed as far as necessary to see
+# whether they belong to an .if/.elif/.else/.endif chain.
+.  break
 .else
-# error
-.break
+# expect+1: break outside of for loop
+.  break
 .endif

Reply via email to