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