Code for Labeled Breaks in C
george at idis.UUCP
george at idis.UUCP
Fri Feb 1 01:50:21 AEST 1985
: 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
More information about the Comp.lang.c
mailing list