george@idis.UUCP (01/31/85)
: Labeled Breaks and Continues for C : : 'This is a shell archive. Remove anything before this line,' : 'then unpack it by saving it in a file and typing "sh file".' : : Wrapped by idis!george on Thu Jan 31 10:18:49 EST 1985 : Contents: break/ break/Makefile break/Read-me break/break1.h break/break2.h : break/break3.h break/bsdsize break/goto.c break/mbreak.c : break/regtst.ed break/select.ed break/tst.c echo mkdir - break mkdir break chmod u=rwx,g=rx,o=rx break echo x - break/Makefile sed 's/^@//' > "break/Makefile" <<'@//E*O*F break/Makefile//' CFLAGS= -O LIB=/lib LIBC=${LIB}/libc.a INCLUDE=/usr/include REG=-DCLASS=register H=break.h I=${INCLUDE}/$H all: break.h mbreak.o break.h: select rm -f break.h sh ./select select: select.ed regtst sort -n +9 -10 +3 -4 regtst >select ed select <select.ed regtst: regtst.ed tst1.o tst2.o tst3.o reg1.o reg2.o reg3.o bsdsize rm -f tst.o bsdsize tst?.o reg?.o | grep -v text | sort +5.3 -5.4 +5 >regtst ed regtst <regtst.ed tst1.o: tst.c break1.h rm -f break.h ln break1.h break.h ${CC} ${CFLAGS} -c tst.c cp tst.o tst1.o tst2.o: tst.c break2.h rm -f break.h ln break2.h break.h ${CC} ${CFLAGS} -c tst.c cp tst.o tst2.o tst3.o: tst.c break3.h rm -f break.h ln break3.h break.h ${CC} ${CFLAGS} -c tst.c cp tst.o tst3.o reg1.o: tst.c break1.h rm -f break.h ln break1.h break.h ${CC} ${CFLAGS} -c ${REG} tst.c cp tst.o reg1.o reg2.o: tst.c break2.h rm -f break.h ln break2.h break.h ${CC} ${CFLAGS} -c ${REG} tst.c cp tst.o reg2.o reg3.o: tst.c break3.h rm -f break.h ln break3.h break.h ${CC} ${CFLAGS} -c ${REG} tst.c cp tst.o reg3.o measure: all goto.o rm -rf tst.o ${CC} ${CFLAGS} -c tst.c size tst.o goto.o install: all rm -f $I if ln $H $I; then :; elif ln -s `pwd`/$H $I; then :; else cp $H $I; fi if ar ru ${LIBC} mbreak.o ; then ranlib ${LIBC} ; : ; fi clean: rm -f regtst select tst*.o reg?.o goto.o pristine: clean rm -f break.h mbreak.o sterile: pristine ; @//E*O*F break/Makefile// chmod u=rw,g=r,o=r break/Makefile echo x - break/Read-me sed 's/^@//' > "break/Read-me" <<'@//E*O*F break/Read-me//' Labeled Breaks and Continues for C 15 Jan 85 George Rosenberg Note: I currently consider this code experimental and its specifications are subject to change. Since I have recently written the macros, and one rarely has use for multi-level breaks or continues in C programs, I have not yet had occasion to actually use them. This is a set of macros to perform labeled multi-level breaks and continues in C programs. There are three versions, "break1.h", "break2.h", and "break3.h". They all have the same specifications. The preferred version is dependent on your compiler with optimizer. That one should be called (linked to) "break.h". There is a Makefile provided to do this. The macros are: Labels Label(id) Break(id) Continue(id) "Break(id) ;" is a statement that causes control to flow past a "labeled-breakable-statement", S, labeled with identifier "id" via "Label(id)". The "Break" must be contained in the scope of the body of statement S. "Continue(id) ;" is a statement that causes control to flow to the beginning of a "labeled-continuable-statement", W, labeled with identifier "id" via "Label(id)". The underlying statement in W must be a "while" statement. It must not be a "for" statement or a "do" statement. The "Continue" must be contained in the scope of the body of statement W. The macro "Label(id)" is prefixed to a statement to be used in conjunction with "Break" or "Continue" as described above. The syntax for using "Label" is below. label-macro: Label left-parenthesis identifier right-parenthesis labeled-continuable-statement: label-macro while-statement label-macro labeled-continuable-statement labeled-breakable-statement: label-macro breakable-statement label-macro labeled-breakable-statement breakable-statement: for-statement while-statement do-statement switch-statement conditional-statement compound-statement "Labels" is part of an optional declaration. "Labels ;" or "register Labels ;" may occur in the declaration section of a block. This declaration is not intended to be used outside the scope of a routine (i.e. at the top level). Presumably this block will contain one or more occurrences of the macro "Label". All references to the same "id" must be within the scope of the same "Labels" declaration or they must all be free. This declaration may be necessary if there is asynchronous control flow. Use of this declaration may result in the compiler and optimizer producing better code. It is recommended that this declaration always be used. The file "mbreak.c" contains a global object that may be used with free occurrences of "Label". It may be desirable to have this in the library (i.e. "libc.a"). See the file "tst.c" for an example. Although there is apparent overhead involved with these macros, it is not unreasonable for a simple (e.g. "c2" like) optimizer to eliminate much of that overhead. Of course, just because it is not unreasonable, does not mean it will be optimized on any particular system. Below are the make options: make default = make all make all make locally: break.h mbreak.o make measure size tst.o goto.o make install modify /usr/include/break.h and /lib/libc.a make clean delete intermediary objects make pristine put local things back to their pristine state The "install" option is untested. The shell script "bsdsize" may need to be modified if your "size" command formats its output inappropriately. It currently works with both the vax-11 4.2 BSD unix "size" command and the pdp-11 v7 unix "size" command. @//E*O*F break/Read-me// chmod u=rw,g=r,o=r break/Read-me echo x - break/break1.h sed 's/^@//' > "break/break1.h" <<'@//E*O*F break/break1.h//' /* * break.h * version 1 * 12 Jan 85 * George Rosenberg * * Warning: Continue(id) will only work with a while statement. */ #ifndef Break #define Labels int Breaking = 0 #define Label(id) id: if (Breaking) Breaking=0; else #define Break(id) for (Breaking=1;;) goto id #define Continue(id) goto id extern Breaking ; #endif @//E*O*F break/break1.h// chmod u=rw,g=r,o=r break/break1.h echo x - break/break2.h sed 's/^@//' > "break/break2.h" <<'@//E*O*F break/break2.h//' /* * break.h * version 2 * 12 Jan 85 * George Rosenberg * * Warning: Continue(id) will only work with a while statement. */ #ifndef Break #define Labels int Breaking #define Label(id) if (Breaking=0) ; else id: if (Breaking) Breaking=0; else #define Break(id) for (Breaking=1;;) goto id #define Continue(id) goto id extern Breaking ; #endif @//E*O*F break/break2.h// chmod u=rw,g=r,o=r break/break2.h echo x - break/break3.h sed 's/^@//' > "break/break3.h" <<'@//E*O*F break/break3.h//' /* * break.h * version 3 * 12 Jan 85 * George Rosenberg * * Warning: Continue(id) will only work with a while statement. */ #ifndef Break #define Labels int Breaking = 0 #define Label(id) id: if (Breaking) Breaking=0; else #define Break(id) for (++Breaking;;) goto id #define Continue(id) goto id extern Breaking ; #endif @//E*O*F break/break3.h// chmod u=rw,g=r,o=r break/break3.h echo x - break/bsdsize sed 's/^@//' > "break/bsdsize" <<'@//E*O*F break/bsdsize//' : This is supposed to : produce size output in bsd format : from either v7 size or 4.2bsd size. : It garbles error messages. : It is untested. TMP=/tmp/'#'size.$$ trap 'rm -f $TMP' 0 1 2 13 15 size $@ >$TMP ed $TMP >/dev/null <<EOF g/text data bss/q g/b$/s/// g/+/s// /g g/b = /s// /g g/ = /s// /g g/:/s/\(.*\)\(:[ ]*\)\(.*\)/\3 \1/ 1i text data bss dec oct @. w q EOF cat $TMP /dev/null @//E*O*F break/bsdsize// chmod u=rwx,g=rx,o=rx break/bsdsize echo x - break/goto.c sed 's/^@//' > "break/goto.c" <<'@//E*O*F break/goto.c//' test() { for (;;) { fun1() ; while (fun2()) if (fun3()) goto out ; fun4() ; } out: fun5() ; } @//E*O*F break/goto.c// chmod u=rw,g=r,o=r break/goto.c echo x - break/mbreak.c sed 's/^@//' > "break/mbreak.c" <<'@//E*O*F break/mbreak.c//' int Breaking = 0 ; @//E*O*F break/mbreak.c// chmod u=rw,g=r,o=r break/mbreak.c echo x - break/regtst.ed sed 's/^@//' > "break/regtst.ed" <<'@//E*O*F break/regtst.ed//' g/reg/s/$/ / g/reg/j w q @//E*O*F break/regtst.ed// chmod u=rw,g=r,o=r break/regtst.ed echo x - break/select.ed sed 's/^@//' > "break/select.ed" <<'@//E*O*F break/select.ed//' 2,$d s/.*tst/ln break/ s/o.*/h break.h/ w q @//E*O*F break/select.ed// chmod u=rw,g=r,o=r break/select.ed echo x - break/tst.c sed 's/^@//' > "break/tst.c" <<'@//E*O*F break/tst.c//' #include "break.h" #ifndef CLASS #define CLASS #endif test() { CLASS Labels ; Label(outer) for (;;) { fun1() ; while (fun2()) if (fun3()) Break(outer) ; fun4() ; } fun5() ; } @//E*O*F break/tst.c// chmod u=rw,g=r,o=r break/tst.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 77 225 1416 Makefile 101 532 3572 Read-me 19 54 333 break1.h 19 56 352 break2.h 19 54 333 break3.h 26 76 392 bsdsize 16 21 118 goto.c 1 5 19 mbreak.c 4 5 25 regtst.ed 5 7 44 select.ed 24 30 203 tst.c 311 1065 6807 total !!! wc break/Makefile break/Read-me break/break1.h break/break2.h break/break3.h break/bsdsize break/goto.c break/mbreak.c break/regtst.ed break/select.ed break/tst.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0