Changeset 54dd994
- Timestamp:
- Jun 24, 2019, 10:30:47 AM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 84917e2
- Parents:
- 3c6e417 (diff), 9e0a360 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Files:
-
- 5 added
- 80 edited
-
benchmark/Makefile.am (modified) (14 diffs)
-
benchmark/Makefile.in (modified) (10 diffs)
-
benchmark/bench.h (modified) (1 diff)
-
benchmark/creation/cfa_cor.cfa (modified) (2 diffs)
-
benchmark/creation/cfa_thrd.cfa (modified) (2 diffs)
-
benchmark/creation/pthreads.c (modified) (1 diff)
-
benchmark/creation/qthreads.c (added)
-
benchmark/creation/upp_cor.cc (modified) (1 diff)
-
benchmark/creation/upp_thrd.cc (modified) (1 diff)
-
benchmark/ctxswitch/cfa_cor.cfa (modified) (3 diffs)
-
benchmark/ctxswitch/cfa_cor_then.cfa (modified) (3 diffs)
-
benchmark/ctxswitch/cfa_gen.cfa (added)
-
benchmark/ctxswitch/cfa_thrd.cfa (modified) (3 diffs)
-
benchmark/ctxswitch/cfa_thrd2.cfa (modified) (3 diffs)
-
benchmark/ctxswitch/kos_fibre.cpp (modified) (1 diff)
-
benchmark/ctxswitch/kos_fibre2.cpp (modified) (1 diff)
-
benchmark/ctxswitch/pthreads.c (modified) (1 diff)
-
benchmark/ctxswitch/qthreads.c (added)
-
benchmark/ctxswitch/upp_cor.cc (modified) (1 diff)
-
benchmark/ctxswitch/upp_thrd.cc (modified) (1 diff)
-
benchmark/fetch_add.c (modified) (1 diff)
-
benchmark/function.c (modified) (1 diff)
-
benchmark/loop.c (modified) (1 diff)
-
benchmark/mutex/cfa1.cfa (modified) (2 diffs)
-
benchmark/mutex/cfa2.cfa (modified) (2 diffs)
-
benchmark/mutex/cfa4.cfa (modified) (2 diffs)
-
benchmark/mutex/pthreads.c (modified) (1 diff)
-
benchmark/mutex/upp.cc (modified) (1 diff)
-
benchmark/schedext/cfa1.cfa (modified) (4 diffs)
-
benchmark/schedext/cfa2.cfa (modified) (4 diffs)
-
benchmark/schedext/cfa4.cfa (modified) (4 diffs)
-
benchmark/schedext/upp.cc (modified) (1 diff)
-
benchmark/schedint/cfa1.cfa (modified) (4 diffs)
-
benchmark/schedint/cfa2.cfa (modified) (4 diffs)
-
benchmark/schedint/cfa4.cfa (modified) (4 diffs)
-
benchmark/schedint/pthreads.c (modified) (3 diffs)
-
benchmark/schedint/upp.cc (modified) (2 diffs)
-
benchmark/tls-fetch_add.c (modified) (1 diff)
-
benchmark/ttst_lock.c (added)
-
doc/bibliography/pl.bib (modified) (6 diffs)
-
doc/papers/AMA/AMA-stix/ama/WileyNJD-v2.cls (modified) (1 diff)
-
doc/papers/concurrency/Paper.tex (modified) (40 diffs)
-
doc/papers/concurrency/annex/local.bib (modified) (1 diff)
-
doc/papers/concurrency/examples/Fib.cfa (modified) (2 diffs)
-
doc/user/user.tex (modified) (146 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (4 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (2 diffs)
-
src/AST/Expr.hpp (modified) (2 diffs)
-
src/AST/Init.hpp (modified) (4 diffs)
-
src/AST/Node.hpp (modified) (2 diffs)
-
src/AST/Stmt.hpp (modified) (2 diffs)
-
src/Common/utility.h (modified) (3 diffs)
-
src/InitTweak/FixInit.cc (modified) (1 diff)
-
src/InitTweak/GenInit.cc (modified) (4 diffs)
-
src/InitTweak/GenInit.h (modified) (2 diffs)
-
src/InitTweak/InitTweak.cc (modified) (11 diffs)
-
src/InitTweak/InitTweak.h (modified) (3 diffs)
-
src/ResolvExpr/Alternative.cc (modified) (1 diff)
-
src/ResolvExpr/Alternative.h (modified) (1 diff)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (1 diff)
-
src/ResolvExpr/Candidate.hpp (modified) (1 diff)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (5 diffs)
-
src/ResolvExpr/Cost.h (modified) (3 diffs)
-
src/ResolvExpr/RenameVars.cc (modified) (5 diffs)
-
src/ResolvExpr/Resolver.cc (modified) (3 diffs)
-
src/ResolvExpr/Resolver.h (modified) (2 diffs)
-
src/SymTab/Autogen.cc (modified) (3 diffs)
-
src/SymTab/Autogen.h (modified) (8 diffs)
-
src/SymTab/FixFunction.cc (modified) (4 diffs)
-
src/SymTab/FixFunction.h (modified) (1 diff)
-
src/SymTab/Validate.cc (modified) (27 diffs)
-
src/Tuples/Explode.cc (modified) (4 diffs)
-
src/Tuples/Explode.h (modified) (2 diffs)
-
src/Tuples/TupleAssignment.cc (modified) (13 diffs)
-
tests/concurrent/examples/boundedBufferEXT.cfa (modified) (4 diffs)
-
tests/concurrent/examples/boundedBufferINT.cfa (modified) (4 diffs)
-
tests/concurrent/examples/boundedBufferTHREAD.cfa (added)
-
tests/concurrent/examples/datingService.cfa (modified) (2 diffs)
-
tests/concurrent/examples/gortn.cfa (modified) (3 diffs)
-
tests/concurrent/examples/quickSort.cfa (modified) (5 diffs)
-
tests/concurrent/examples/quickSort.generic.cfa (modified) (5 diffs)
-
tools/stat.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Makefile.am
r3c6e417 r54dd994 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Tue Nov 6 09:01:23 201814 ## Update Count : 2613 ## Last Modified On : Sun Jun 23 12:34:29 2019 14 ## Update Count : 52 15 15 ############################################################################### 16 16 … … 21 21 include $(top_srcdir)/src/cfa.make 22 22 23 AM_CFLAGS = -O2 -Wall -Wextra - Werror -I$(srcdir) -lrt -pthread23 AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror 24 24 AM_CFAFLAGS = -quiet -nodebug -in-tree 25 25 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14 … … 31 31 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet)) 32 32 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet)) 33 BENCH_V_QTHREAD = $(__bench_v_QTHREAD_$(__quiet)) 33 34 34 35 __quiet = verbose … … 45 46 __bench_v_JAVAC_verbose = $(AM_V_JAVAC) 46 47 __bench_v_UPP_verbose = $(AM_V_UPP) 47 48 __bench_v_QTHREAD_verbose = $(AM_V_CC) 48 49 49 50 … … 51 52 REPEAT = ${abs_top_builddir}/tools/repeat 52 53 STATS = ${abs_top_srcdir}/tools/stat.py 53 repeats = 3 054 repeats = 3 # 30 54 55 skipcompile = no 55 56 TIME_FORMAT = "%E" … … 124 125 125 126 ctxswitch.csv: 126 @echo "coroutine,thread" > $@ 127 @echo "generator,coroutine,thread" > $@ 128 @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@ 127 129 @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@ 128 130 @+make ctxswitch-cfa_thread.runquiet >> $@ … … 153 155 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 154 156 157 ttst_lock$(EXEEXT): 158 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/ttst_lock.c 159 155 160 tls-fetch_add$(EXEEXT): 156 161 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c … … 161 166 function.run \ 162 167 fetch_add.run \ 168 ttst_lock.run \ 163 169 tls-fetch_add.run \ 164 170 ctxswitch-pthread.run \ 171 ctxswitch-cfa_generator.run \ 165 172 ctxswitch-cfa_coroutine.run \ 166 173 ctxswitch-cfa_thread.run \ … … 169 176 ctxswitch-upp_thread.run \ 170 177 ctxswitch-goroutine.run \ 171 ctxswitch-java_thread.run 178 ctxswitch-java_thread.run \ 179 ctxswitch-qthreads.run 180 172 181 173 182 if WITH_LIBFIBRE … … 188 197 ctxswitch-pthread$(EXEEXT): 189 198 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 199 200 ctxswitch-cfa_generator$(EXEEXT): 201 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa 190 202 191 203 ctxswitch-cfa_coroutine$(EXEEXT): … … 212 224 @echo "java JavaThread" >> a.out 213 225 @chmod a+x a.out 226 227 ctxswitch-qthreads$(EXEEXT): 228 $(BENCH_V_QTHREADS)$(COMPILE) -DBENCH_N=50000000 -I/u/pabuhr/software/qthreads/include -L/u/pabuhr/software/qthreads/lib -Xlinker -R/u/pabuhr/software/qthreads/lib $(srcdir)/ctxswitch/qthreads.c -lqthread 214 229 215 230 ## ========================================================================================================= … … 305 320 creation-upp_thread.run \ 306 321 creation-goroutine.run \ 307 creation-java_thread.run 322 creation-java_thread.run \ 323 creation-qthreads.run 308 324 309 325 creation-cfa_coroutine$(EXEEXT): … … 333 349 @echo "java JavaThread" >> a.out 334 350 @chmod a+x a.out 351 352 creation-qthreads$(EXEEXT): 353 $(BENCH_V_QTHREADS)$(COMPILE) -DBENCH_N=50000000 -I/u/pabuhr/software/qthreads/include -L/u/pabuhr/software/qthreads/lib -Xlinker -R/u/pabuhr/software/qthreads/lib $(srcdir)/ctxswitch/qthreads.c -lqthread 335 354 336 355 ## ========================================================================================================= … … 375 394 compile-typeof$(EXEEXT): 376 395 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa 377 -
benchmark/Makefile.in
r3c6e417 r54dd994 371 371 372 372 # applies to both programs 373 AM_CFLAGS = -O2 -Wall -Wextra - Werror -I$(srcdir) -lrt -pthread373 AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror 374 374 AM_CFAFLAGS = -quiet -nodebug -in-tree 375 375 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14 … … 380 380 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet)) 381 381 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet)) 382 BENCH_V_QTHREAD = $(__bench_v_QTHREAD_$(__quiet)) 382 383 __quiet = verbose 383 384 __bench_v_CC_quiet = @ … … 393 394 __bench_v_JAVAC_verbose = $(AM_V_JAVAC) 394 395 __bench_v_UPP_verbose = $(AM_V_UPP) 396 __bench_v_QTHREAD_verbose = $(AM_V_CC) 395 397 TOOLSDIR = ${abs_top_builddir}/tools/ 396 398 REPEAT = ${abs_top_builddir}/tools/repeat 397 399 STATS = ${abs_top_srcdir}/tools/stat.py 398 repeats = 3 0400 repeats = 3 # 30 399 401 skipcompile = no 400 402 TIME_FORMAT = "%E" … … 402 404 dummy_SOURCES = dummyC.c dummyCXX.cpp 403 405 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@ 404 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \406 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run ttst_lock.run \ 405 407 tls-fetch_add.run ctxswitch-pthread.run \ 406 ctxswitch-cfa_coroutine.run ctxswitch-cfa_thread.run \ 407 ctxswitch-cfa_thread2.run ctxswitch-upp_coroutine.run \ 408 ctxswitch-upp_thread.run ctxswitch-goroutine.run \ 409 ctxswitch-java_thread.run $(am__append_1) 408 ctxswitch-cfa_generator.run ctxswitch-cfa_coroutine.run \ 409 ctxswitch-cfa_thread.run ctxswitch-cfa_thread2.run \ 410 ctxswitch-upp_coroutine.run ctxswitch-upp_thread.run \ 411 ctxswitch-goroutine.run ctxswitch-java_thread.run \ 412 ctxswitch-qthreads.run $(am__append_1) 410 413 testdir = $(top_srcdir)/tests 411 414 all: all-am … … 784 787 785 788 ctxswitch.csv: 786 @echo "coroutine,thread" > $@ 789 @echo "generator,coroutine,thread" > $@ 790 @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@ 787 791 @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@ 788 792 @+make ctxswitch-cfa_thread.runquiet >> $@ … … 812 816 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 813 817 818 ttst_lock$(EXEEXT): 819 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/ttst_lock.c 820 814 821 tls-fetch_add$(EXEEXT): 815 822 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c … … 825 832 ctxswitch-pthread$(EXEEXT): 826 833 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 834 835 ctxswitch-cfa_generator$(EXEEXT): 836 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa 827 837 828 838 ctxswitch-cfa_coroutine$(EXEEXT): … … 849 859 @echo "java JavaThread" >> a.out 850 860 @chmod a+x a.out 861 862 ctxswitch-qthreads$(EXEEXT): 863 $(BENCH_V_QTHREADS)$(COMPILE) -DBENCH_N=50000000 -I/u/pabuhr/software/qthreads/include -L/u/pabuhr/software/qthreads/lib -Xlinker -R/u/pabuhr/software/qthreads/lib $(srcdir)/ctxswitch/qthreads.c -lqthread 851 864 852 865 mutex$(EXEEXT) :\ … … 937 950 creation-upp_thread.run \ 938 951 creation-goroutine.run \ 939 creation-java_thread.run 952 creation-java_thread.run \ 953 creation-qthreads.run 940 954 941 955 creation-cfa_coroutine$(EXEEXT): … … 965 979 @echo "java JavaThread" >> a.out 966 980 @chmod a+x a.out 981 982 creation-qthreads$(EXEEXT): 983 $(BENCH_V_QTHREADS)$(COMPILE) -DBENCH_N=50000000 -I/u/pabuhr/software/qthreads/include -L/u/pabuhr/software/qthreads/lib -Xlinker -R/u/pabuhr/software/qthreads/lib $(srcdir)/ctxswitch/qthreads.c -lqthread 967 984 968 985 compile$(EXEEXT) :\ -
benchmark/bench.h
r3c6e417 r54dd994 45 45 statement; \ 46 46 EndTime = bench_time(); \ 47 unsigned long long intoutput = \48 ( EndTime - StartTime ) / n;47 double output = \ 48 (double)( EndTime - StartTime ) / n; 49 49 50 50 #if defined(__cforall) -
benchmark/creation/cfa_cor.cfa
r3c6e417 r54dd994 10 10 #endif 11 11 } 12 void main(MyCoroutine & this) {}12 void main(MyCoroutine &) {} 13 13 14 14 int main(int argc, char* argv[]) { 15 15 BENCH( 16 for ( size_t i = 0; i < n; i++) {16 for ( i; n ) { 17 17 MyCoroutine m; 18 18 }, … … 20 20 ) 21 21 22 printf("% llu\n", result);22 printf("%g\n", result); 23 23 } -
benchmark/creation/cfa_thrd.cfa
r3c6e417 r54dd994 5 5 6 6 thread MyThread {}; 7 void main(MyThread & this) {}7 void main(MyThread &) {} 8 8 9 9 int main(int argc, char* argv[]) { 10 10 BENCH( 11 for ( size_t i = 0; i < n; i++) {11 for ( i; n ) { 12 12 MyThread m; 13 13 }, … … 15 15 ) 16 16 17 printf("% llu\n", result);17 printf("%g\n", result); 18 18 } -
benchmark/creation/pthreads.c
r3c6e417 r54dd994 25 25 ) 26 26 27 printf("% llu\n", result);27 printf("%g\n", result); 28 28 } -
benchmark/creation/upp_cor.cc
r3c6e417 r54dd994 15 15 ) 16 16 17 printf("% llu\n", result);17 printf("%g\n", result); 18 18 } -
benchmark/creation/upp_thrd.cc
r3c6e417 r54dd994 15 15 ) 16 16 17 printf("% llu\n", result);17 printf("%g\n", result); 18 18 } -
benchmark/ctxswitch/cfa_cor.cfa
r3c6e417 r54dd994 1 #include <stdio.h>2 1 #include <kernel.hfa> 3 2 #include <thread.hfa> … … 21 20 22 21 BENCH( 23 for ( size_t i = 0; i < n; i++) {22 for ( i; n ) { 24 23 resume( s ); 25 24 }, … … 27 26 ) 28 27 29 printf("% llu\n", result);28 printf("%g\n", result); 30 29 } -
benchmark/ctxswitch/cfa_cor_then.cfa
r3c6e417 r54dd994 1 #include <stdio.h>2 1 #include <kernel.hfa> 3 2 #include <thread.hfa> … … 23 22 24 23 BENCH( 25 for ( size_t i = 0; i < n; i++) {24 for ( i; n ) { 26 25 resume( s ); 27 26 }, … … 29 28 ) 30 29 31 printf("% llu\n", result);30 printf("%g\n", result); 32 31 } -
benchmark/ctxswitch/cfa_thrd.cfa
r3c6e417 r54dd994 1 #include <stdio.h>2 1 #include <thread.hfa> 3 2 … … 6 5 int main(int argc, char* argv[]) { 7 6 BENCH( 8 for ( size_t i = 0; i < n; i++) {7 for ( i; n ) { 9 8 yield(); 10 9 }, … … 12 11 ) 13 12 14 printf("% llu\n", result);13 printf("%g\n", result); 15 14 } -
benchmark/ctxswitch/cfa_thrd2.cfa
r3c6e417 r54dd994 1 #include <stdio.h>2 1 #include <thread.hfa> 3 2 … … 17 16 Fibre f1; 18 17 BENCH( 19 for ( size_t i = 0; i < n; i++) {18 for ( i; n ) { 20 19 yield(); 21 20 }, … … 23 22 ) 24 23 25 printf("% llu\n", result);24 printf("%g\n", result); 26 25 done = true; 27 26 return 0; -
benchmark/ctxswitch/kos_fibre.cpp
r3c6e417 r54dd994 10 10 result 11 11 ) 12 printf("% llu\n", result);12 printf("%g\n", result); 13 13 return 0; 14 14 } -
benchmark/ctxswitch/kos_fibre2.cpp
r3c6e417 r54dd994 19 19 result 20 20 ) 21 printf("% llu\n", result);21 printf("%g\n", result); 22 22 done = true; 23 23 Fibre::yield(); -
benchmark/ctxswitch/pthreads.c
r3c6e417 r54dd994 14 14 ) 15 15 16 printf("% llu\n", result);16 printf("%g\n", result); 17 17 } -
benchmark/ctxswitch/upp_cor.cc
r3c6e417 r54dd994 30 30 ) 31 31 32 printf("% llu\n", result);32 printf("%g\n", result); 33 33 } -
benchmark/ctxswitch/upp_thrd.cc
r3c6e417 r54dd994 11 11 ) 12 12 13 printf("% llu\n", result);13 printf("%g\n", result); 14 14 } -
benchmark/fetch_add.c
r3c6e417 r54dd994 19 19 ) 20 20 21 printf("% llu\n", result);21 printf("%g\n", result); 22 22 } -
benchmark/function.c
r3c6e417 r54dd994 15 15 ) 16 16 17 printf("% llu\n", result);17 printf("%g\n", result); 18 18 } -
benchmark/loop.c
r3c6e417 r54dd994 11 11 ) 12 12 13 printf("% llu\n", result);13 printf("%g\n", result); 14 14 } -
benchmark/mutex/cfa1.cfa
r3c6e417 r54dd994 10 10 M m; 11 11 BENCH( 12 for ( size_t i = 0; i < n; i++) {12 for ( i; n ) { 13 13 call(m); 14 14 }, … … 16 16 ) 17 17 18 printf("% llu\n", result);18 printf("%g\n", result); 19 19 } -
benchmark/mutex/cfa2.cfa
r3c6e417 r54dd994 10 10 M m1, m2; 11 11 BENCH( 12 for ( size_t i = 0; i < n; i++) {12 for ( i; n ) { 13 13 call(m1, m2); 14 14 }, … … 16 16 ) 17 17 18 printf("% llu\n", result);18 printf("%g\n", result); 19 19 } -
benchmark/mutex/cfa4.cfa
r3c6e417 r54dd994 11 11 M m1, m2, m3, m4; 12 12 BENCH( 13 for ( size_t i = 0; i < n; i++) {13 for ( i; n ) { 14 14 call(m1, m2, m3, m4); 15 15 }, … … 17 17 ) 18 18 19 printf("% llu\n", result);19 printf("%g\n", result); 20 20 } -
benchmark/mutex/pthreads.c
r3c6e417 r54dd994 19 19 ) 20 20 21 printf("% llu\n", result);21 printf("%g\n", result); 22 22 } -
benchmark/mutex/upp.cc
r3c6e417 r54dd994 17 17 ) 18 18 19 printf("% llu\n", result);19 printf("%g\n", result); 20 20 } -
benchmark/schedext/cfa1.cfa
r3c6e417 r54dd994 18 18 go = 1; 19 19 BENCH( 20 for ( size_t i = 0; i < n; i++) {20 for ( i; n ) { 21 21 waitfor(call, a1); 22 22 }, … … 24 24 ) 25 25 26 printf("% llu\n", result);26 printf("%g\n", result); 27 27 go = 0; 28 28 return 0; … … 31 31 thread T {}; 32 32 void ^?{}( T & mutex this ) {} 33 void main( T & this) {33 void main( T & ) { 34 34 while(go == 0) { yield(); } 35 35 while(go == 1) { call(m1); } … … 37 37 } 38 38 39 int main(int margc, char* margv[]) { 40 argc = margc; 41 argv = margv; 39 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 42 40 T t; 43 41 return wait(m1); -
benchmark/schedext/cfa2.cfa
r3c6e417 r54dd994 18 18 go = 1; 19 19 BENCH( 20 for ( size_t i = 0; i < n; i++) {20 for ( i; n ) { 21 21 waitfor(call, a1, a2); 22 22 }, … … 24 24 ) 25 25 26 printf("% llu\n", result);26 printf("%g\n", result); 27 27 go = 0; 28 28 return 0; … … 31 31 thread T {}; 32 32 void ^?{}( T & mutex this ) {} 33 void main( T & this) {33 void main( T & ) { 34 34 while(go == 0) { yield(); } 35 35 while(go == 1) { call(m1, m2); } … … 37 37 } 38 38 39 int main(int margc, char* margv[]) { 40 argc = margc; 41 argv = margv; 39 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 42 40 T t; 43 41 return wait(m1, m2); -
benchmark/schedext/cfa4.cfa
r3c6e417 r54dd994 18 18 go = 1; 19 19 BENCH( 20 for ( size_t i = 0; i < n; i++) {20 for ( i; n ) { 21 21 waitfor(call, a1, a2, a3, a4); 22 22 }, … … 24 24 ) 25 25 26 printf("% llu\n", result);26 printf("%g\n", result); 27 27 go = 0; 28 28 return 0; … … 31 31 thread T {}; 32 32 void ^?{}( T & mutex this ) {} 33 void main( T & this) {33 void main( T & ) { 34 34 while(go == 0) { yield(); } 35 35 while(go == 1) { call(m1, m2, m3, m4); } … … 37 37 } 38 38 39 int main(int margc, char* margv[]) { 40 argc = margc; 41 argv = margv; 39 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 42 40 T t; 43 41 return wait(m1, m2, m3, m4); -
benchmark/schedext/upp.cc
r3c6e417 r54dd994 20 20 ) 21 21 22 printf("% llu\n", result);22 printf("%g\n", result); 23 23 go = 0; 24 24 return 0; -
benchmark/schedint/cfa1.cfa
r3c6e417 r54dd994 21 21 go = 1; 22 22 BENCH( 23 for ( size_t i = 0; i < n; i++) {23 for ( i; n ) { 24 24 wait(c); 25 25 }, … … 27 27 ) 28 28 29 printf("% llu\n", result);29 printf("%g\n", result); 30 30 go = 0; 31 31 return 0; … … 33 33 34 34 thread T {}; 35 void ^?{}( T & mutex this) {}36 void main( T & this) {35 void ^?{}( T & mutex ) {} 36 void main( T & ) { 37 37 while(go == 0) { yield(); } 38 38 while(go == 1) { call(m1); } … … 40 40 } 41 41 42 int main(int margc, char* margv[]) { 43 argc = margc; 44 argv = margv; 42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 45 43 T t; 46 44 return wait(m1); -
benchmark/schedint/cfa2.cfa
r3c6e417 r54dd994 21 21 go = 1; 22 22 BENCH( 23 for ( size_t i = 0; i < n; i++) {23 for ( i; n ) { 24 24 wait(c); 25 25 }, … … 27 27 ) 28 28 29 printf("% llu\n", result);29 printf("%g\n", result); 30 30 go = 0; 31 31 return 0; … … 34 34 thread T {}; 35 35 void ^?{}( T & mutex this ) {} 36 void main( T & this) {36 void main( T & ) { 37 37 while(go == 0) { yield(); } 38 38 while(go == 1) { call(m1, m2); } … … 40 40 } 41 41 42 int main(int margc, char* margv[]) { 43 argc = margc; 44 argv = margv; 42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 45 43 T t; 46 44 return wait(m1, m2); -
benchmark/schedint/cfa4.cfa
r3c6e417 r54dd994 21 21 go = 1; 22 22 BENCH( 23 for ( size_t i = 0; i < n; i++) {23 for ( i; n ) { 24 24 wait(c); 25 25 }, … … 27 27 ) 28 28 29 printf("% llu\n", result);29 printf("%g\n", result); 30 30 go = 0; 31 31 return 0; … … 34 34 thread T {}; 35 35 void ^?{}( T & mutex this ) {} 36 void main( T & this) {36 void main( T & ) { 37 37 while(go == 0) { yield(); } 38 38 while(go == 1) { call(m1, m2, m3, m4); } … … 40 40 } 41 41 42 int main(int margc, char* margv[]) { 43 argc = margc; 44 argv = margv; 42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 45 43 T t; 46 44 return wait(m1, m2, m3, m4); -
benchmark/schedint/pthreads.c
r3c6e417 r54dd994 27 27 ) 28 28 29 printf("% llu\n", result);29 printf("%g\n", result); 30 30 go = 0; 31 31 pthread_mutex_unlock(&m); … … 33 33 } 34 34 35 void* thread_main( void * a) {35 void* thread_main(__attribute__((unused)) void * arg ) { 36 36 while(go == 0) { sched_yield(); } 37 37 while(go == 1) { call(); } … … 39 39 } 40 40 41 int main(int margc, char* margv[]) { 42 argc = margc; 43 argv = margv; 41 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 44 42 pthread_t thread; 45 43 if (pthread_create(&thread, NULL, thread_main, NULL) < 0) { -
benchmark/schedint/upp.cc
r3c6e417 r54dd994 23 23 ) 24 24 25 printf("% llu\n", result);25 printf("%g\n", result); 26 26 go = 0; 27 27 return 0; … … 39 39 }; 40 40 41 int main(int margc, char* margv[]) { 42 argc = margc; 43 argv = margv; 41 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) { 44 42 T t; 45 43 return m.wait(); -
benchmark/tls-fetch_add.c
r3c6e417 r54dd994 24 24 ) 25 25 26 printf("% llu\n", result);26 printf("%g\n", result); 27 27 } -
doc/bibliography/pl.bib
r3c6e417 r54dd994 948 948 author = {{\textsf{C}{$\mathbf{\forall}$} Features}}, 949 949 howpublished= {\href{https://plg.uwaterloo.ca/~cforall/features}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-features}}, 950 } 951 952 @misc{CforallBenchMarks, 953 contributer = {pabuhr@plg}, 954 key = {Cforall Benchmarks}, 955 author = {{\textsf{C}{$\mathbf{\forall}$} Benchmarks}}, 956 howpublished= {\href{https://plg.uwaterloo.ca/~cforall/benchmarks}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-benchmarks}}, 950 957 } 951 958 … … 1919 1926 year = 1965, 1920 1927 note = {Reprinted in \cite{Genuys68} pp. 43--112.} 1928 } 1929 1930 @inproceedings{Adya02, 1931 contributer = {pabuhr@plg}, 1932 author = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.}, 1933 title = {Cooperative Task Management Without Manual Stack Management}, 1934 booktitle = {Proceedings of the General Track of the Annual Conference on USENIX Annual Technical Conference}, 1935 series = {ATEC '02}, 1936 year = {2002}, 1937 pages = {289-302}, 1938 publisher = {USENIX Association}, 1939 address = {Berkeley, CA, USA}, 1940 } 1941 1942 @misc{CoroutineTS, 1943 keywords = {Coroutines TS, C++20, working draft}, 1944 contributer = {pabuhr@plg}, 1945 author = {Gor Nishanov}, 1946 title = {Merge Coroutines TS into C++20 Working Draft}, 1947 year = 2019, 1948 month = feb, 1949 howpublished= {\href{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0912r5.html} 1950 {http://\-www.open-std.org/\-jtc1/\-sc22/\-wg21/\-docs/\-papers/\-2019/p0912r5.html}}, 1921 1951 } 1922 1952 … … 4359 4389 } 4360 4390 4391 4361 4392 @article{Liskov86, 4362 4393 keywords = {synchronous communication, concurrency}, … … 4371 4402 year = {}, 4372 4403 pages = {}, 4404 } 4405 4406 @misc{libdill, 4407 keywords = {libdill/libmill Thread Library}, 4408 contributer = {pabuhr@plg}, 4409 author = {Alex Cornejo, et al}, 4410 title = {libdill Thread Library}, 4411 year = 2019, 4412 howpublished= {\href{http://libdill.org/libdill-2.14.tar.gz} 4413 {http://\-libdill.org/\-libdill-2.14.tar.gz}}, 4373 4414 } 4374 4415 … … 4493 4534 year = 2016, 4494 4535 howpublished= {\href{http://blog.reverberate.org/2016/01/making-arbitrarily-large-binaries-from.html} 4495 { 4496 {http://blog.reverberate.org/\-2016/\-01/\-making-arbitrarily-large-binaries-from.html} 4497 }}, 4536 {http://blog.reverberate.org/\-2016/\-01/\-making-arbitrarily-large-binaries-from.html}}, 4498 4537 optnote = {Accessed: 2016-09}, 4499 4538 } … … 4517 4556 trivial changes to the source code of the library. 4518 4557 } 4558 } 4559 4560 @misc{Marcel, 4561 keywords = {Marcel Thread Library}, 4562 contributer = {pabuhr@plg}, 4563 author = {Gabriel Antoniu, et al}, 4564 title = {Marcel Thread Library}, 4565 year = 2011, 4566 howpublished= {\href{https://gforge.inria.fr/frs/download.php/file/28643/marcel-2.99.3.tar.gz} 4567 {https://\-gforge.inria.fr/\-frs/\-download.php/\-file/\-28643/\-marcel-2.99.3.tar.gz}}, 4519 4568 } 4520 4569 -
doc/papers/AMA/AMA-stix/ama/WileyNJD-v2.cls
r3c6e417 r54dd994 2444 2444 \@afterheading} 2445 2445 2446 \renewcommand\section{\@startsection{section}{1}{\z@}{-2 7pt \@plus -2pt \@minus -2pt}{12\p@}{\sectionfont}}%2447 \renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-2 3pt \@plus -2pt \@minus -2pt}{5\p@}{\subsectionfont}}%2446 \renewcommand\section{\@startsection{section}{1}{\z@}{-25pt \@plus -2pt \@minus -2pt}{12\p@}{\sectionfont}}% 2447 \renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-22pt \@plus -2pt \@minus -2pt}{5\p@}{\subsectionfont}}% 2448 2448 \renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-20pt \@plus -2pt \@minus -2pt}{2\p@}{\subsubsectionfont}}% 2449 2449 % -
doc/papers/concurrency/Paper.tex
r3c6e417 r54dd994 157 157 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__, 158 158 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or, 159 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend,thread,159 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, thread, 160 160 _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__, 161 161 virtual, __volatile, __volatile__, waitfor, when, with, zero_t}, … … 303 303 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}, and \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone; 304 304 no high-level language concurrency features are defined. 305 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang- 8nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach.305 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach. 306 306 Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}. 307 307 … … 313 313 From 2000 onwards, languages like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book} have championed the M:N user-threading model, and many user-threading libraries have appeared~\cite{Qthreads,MPC,Marcel}, including putting green threads back into Java~\cite{Quasar}. 314 314 The main argument for user-level threading is that they are lighter weight than kernel threads (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourage large numbers of threads performing medium work-units to facilitate load balancing by the runtime~\cite{Verch12}. 315 As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{ vonBehren03}.315 As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{Adya02,vonBehren03}. 316 316 Finally, performant user-threading implementations (both time and space) meet or exceed direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety. 317 317 … … 613 613 Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types. 614 614 \begin{cfa} 615 int ?()( Fib & fib ) with( fib ) { return `resume( fib )`.fn; } // function-call interface616 int ?()( Fib & fib, int N ) with( fib ) { for ( N - 1 ) `fib()`; return `fib()`; } // use simple interface617 double ?()( Fib & fib ) with( fib ) { return (int)`fib()` / 3.14159; } // cast prevents recursive call618 sout | (int)f1() | (double)f1() | f2( 2 ); // simple interface, cast selects call based on return type, step 2 values615 int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$ 616 int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// use function-call interface to skip N values}$ 617 double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}\CRT$ 618 sout | (int)f1() | (double)f1() | f2( 2 ); // alternative interface, cast selects call based on return type, step 2 values 619 619 \end{cfa} 620 620 Now, the generator can be a separately-compiled opaque-type only accessed through its interface functions. … … 628 628 With respect to safety, we believe static analysis can discriminate local state from temporary variables in a generator, \ie variable usage spanning @suspend@, and generate a compile-time error. 629 629 Finally, our current experience is that most generator problems have simple data state, including local state, but complex execution state, so the burden of creating the generator type is small. 630 As well, C programmers are not afraid withthis kind of semantic programming requirement, if it results in very small, fast generators.630 As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small, fast generators. 631 631 632 632 Figure~\ref{f:CFAFormatGen} shows an asymmetric \newterm{input generator}, @Fmt@, for restructuring text into groups of characters of fixed-size blocks, \ie the input on the left is reformatted into the output on the right, where newlines are ignored. … … 796 796 This semantics is basically a tail-call optimization, which compilers already perform. 797 797 The example shows the assembly code to undo the generator's entry code before the direct jump. 798 This assembly code depends on what entry code is generated, specifically if there are local variables and the level of optimization.798 This assembly code depends on what entry code is generated, specifically if there are local variables, and the level of optimization. 799 799 To provide this new calling convention requires a mechanism built into the compiler, which is beyond the scope of \CFA at this time. 800 800 Nevertheless, it is possible to hand generate any symmetric generators for proof of concept and performance testing. 801 A compiler could also eliminate other artifacts in the generator simulation to further increase performance .801 A compiler could also eliminate other artifacts in the generator simulation to further increase performance, \eg LLVM has various coroutine support~\cite{CoroutineTS}, and \CFA can leverage this support should it fork @clang@. 802 802 803 803 \begin{figure} … … 1213 1213 Hence, a compromise solution is necessary that works for asymmetric (acyclic) and symmetric (cyclic) coroutines. 1214 1214 1215 Our solution for coroutine termination works well for the most common asymmetric and symmetric coroutine usage-patterns. 1215 Our solution is to context switch back to the first resumer (starter) once the coroutine ends. 1216 This semantics works well for the most common asymmetric and symmetric coroutine usage-patterns. 1216 1217 For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer. 1217 1218 All previous generators converted to coroutines have this property. … … 1245 1246 1246 1247 1247 \subsection{ (Generator)Coroutine Implementation}1248 \subsection{Generator / Coroutine Implementation} 1248 1249 1249 1250 A significant implementation challenge for generators/coroutines (and threads in Section~\ref{s:threads}) is adding extra fields to the custom types and related functions, \eg inserting code after/before the coroutine constructor/destructor and @main@ to create/initialize/de-initialize/destroy any extra fields, \eg stack. … … 1254 1255 class myCoroutine inherits baseCoroutine { ... } 1255 1256 \end{cfa} 1256 The problem is that the programming language and its tool chain, \eg debugger, @valgrind@, need to understand @baseCoroutine@ because it infers special property, so type @baseCoroutine@ becomes a de facto keyword and all types inheriting from it are implicitly custom types.1257 As well,some special properties are not handled by existing language semantics, \eg the execution of constructors/destructors is in the wrong order to implicitly start threads because the thread must start \emph{after} all constructors as it relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived.1257 % The problem is that the programming language and its tool chain, \eg debugger, @valgrind@, need to understand @baseCoroutine@ because it infers special property, so type @baseCoroutine@ becomes a de facto keyword and all types inheriting from it are implicitly custom types. 1258 The problem is that some special properties are not handled by existing language semantics, \eg the execution of constructors/destructors is in the wrong order to implicitly start threads because the thread must start \emph{after} all constructors as it relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived. 1258 1259 Alternatives, such as explicitly starting threads as in Java, are repetitive and forgetting to call start is a common source of errors. 1259 1260 An alternative is composition: … … 1267 1268 However, there is nothing preventing wrong placement or multiple declarations. 1268 1269 1269 \CFA custom types make any special properties explicit to the language and its tool chain, \eg the language code-generator knows where to inject code and when it is unsafe to perform certain optimizations, and IDEs using simple parsing can find and manipulate types with special properties. 1270 \CFA custom types make any special properties explicit to the language and its tool chain, \eg the language code-generator knows where to inject code 1271 % and when it is unsafe to perform certain optimizations, 1272 and IDEs using simple parsing can find and manipulate types with special properties. 1270 1273 The downside of this approach is that it makes custom types a special case in the language. 1271 1274 Users wanting to extend custom types or build their own can only do so in ways offered by the language. … … 1282 1285 \end{cfa} 1283 1286 Note, copying generators/coroutines/threads is not meaningful. 1284 For example, a coroutine retains its last resumer and suspends back to it;1285 having a copy also suspend back to the same resumer is undefined semantics.1287 For example, both the resumer and suspender descriptors can have bi-directional pointers; 1288 copying these coroutines does not update the internal pointers so behaviour of both copies would be difficult to understand. 1286 1289 Furthermore, two coroutines cannot logically execute on the same stack. 1287 1290 A deep coroutine copy, which copies the stack, is also meaningless in an unmanaged language (no garbage collection), like C, because the stack may contain pointers to object within it that require updating for the copy. 1288 1291 The \CFA @dtype@ property provides no \emph{implicit} copying operations and the @is_coroutine@ trait provides no \emph{explicit} copying operations, so all coroutines must be passed by reference (pointer). 1289 The function definitions ensures there is a statically-typed @main@ function that is the starting point (first stack frame) of a coroutine, and a mechanism to get (read) the c urrently executing coroutinehandle.1292 The function definitions ensures there is a statically-typed @main@ function that is the starting point (first stack frame) of a coroutine, and a mechanism to get (read) the coroutine descriptor from its handle. 1290 1293 The @main@ function has no return value or additional parameters because the coroutine type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values versus fixed ones. 1291 1294 The advantage of this approach is that users can easily create different types of coroutines, \eg changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ function, and possibly redefining \textsf{suspend} and @resume@. … … 1493 1496 \end{tabular} 1494 1497 \end{cquote} 1495 Like coroutines, the @dtype@ property prevents \emph{implicit} copy operations and the @is_ coroutine@ trait provides no \emph{explicit} copy operations, so threads must be passed by reference (pointer).1496 Similarly, the function definitions ensures there is a statically-typed @main@ function that is the thread starting point (first stack frame), a mechanism to get (read) the currently executing threadhandle, and a special destructor to prevent deallocation while the thread is executing.1498 Like coroutines, the @dtype@ property prevents \emph{implicit} copy operations and the @is_thread@ trait provides no \emph{explicit} copy operations, so threads must be passed by reference (pointer). 1499 Similarly, the function definitions ensures there is a statically-typed @main@ function that is the thread starting point (first stack frame), a mechanism to get (read) the thread descriptor from its handle, and a special destructor to prevent deallocation while the thread is executing. 1497 1500 (The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitor}.) 1498 1501 The difference between the coroutine and thread is that a coroutine borrows a thread from its caller, so the first thread resuming a coroutine creates the coroutine's stack and starts running the coroutine main on the stack; … … 1617 1620 % Copying a lock is insecure because it is possible to copy an open lock and then use the open copy when the original lock is closed to simultaneously access the shared data. 1618 1621 % Copying a monitor is secure because both the lock and shared data are copies, but copying the shared data is meaningless because it no longer represents a unique entity. 1619 Similarly, the function definitions ensures there is a mechanism to get (read) the currently executing monitorhandle, and a special destructor to prevent deallocation if a thread using the shared data.1622 Similarly, the function definitions ensures there is a mechanism to get (read) the monitor descriptor from its handle, and a special destructor to prevent deallocation if a thread using the shared data. 1620 1623 The custom monitor type also inserts any locks needed to implement the mutual exclusion semantics. 1621 1624 … … 1656 1659 called \newterm{bulk acquire}. 1657 1660 \CFA guarantees acquisition order is consistent across calls to @mutex@ functions using the same monitors as arguments, so acquiring multiple monitors is safe from deadlock. 1658 Figure~\ref{f:BankTransfer} shows a trivial solution to the bank transfer problem , where two resources must be locked simultaneously, using \CFA monitors with implicit locking and \CC with explicit locking.1661 Figure~\ref{f:BankTransfer} shows a trivial solution to the bank transfer problem~\cite{BankTransfer}, where two resources must be locked simultaneously, using \CFA monitors with implicit locking and \CC with explicit locking. 1659 1662 A \CFA programmer only has to manage when to acquire mutual exclusion; 1660 1663 a \CC programmer must select the correct lock and acquisition mechanism from a panoply of locking options. … … 1800 1803 Figure~\ref{f:MonitorScheduling} shows general internal/external scheduling (for the bounded-buffer example in Figure~\ref{f:InternalExternalScheduling}). 1801 1804 External calling threads block on the calling queue, if the monitor is occupied, otherwise they enter in FIFO order. 1802 Internal threads block on condition queues via @wait@ and they reenter from the condition in FIFO order, or they block on urgent via @signal_block@ or @waitfor@ and reenter implicit when the monitor becomes empty, \ie, the thread in the monitor exits or waits. 1805 Internal threads block on condition queues via @wait@ and reenter from the condition in FIFO order. 1806 Alternatively, internal threads block on urgent from the @signal_block@ or @waitfor@, and reenter implicitly when the monitor becomes empty, \ie, the thread in the monitor exits or waits. 1803 1807 1804 1808 There are three signalling mechanisms to unblock waiting threads to enter the monitor. 1805 Note, signalling cannot have the signaller and signalled thread in the monitor simultaneously because of the mutual exclusion so only one can proceed.1809 Note, signalling cannot have the signaller and signalled thread in the monitor simultaneously because of the mutual exclusion, so either the signaller or signallee can proceed. 1806 1810 For internal scheduling, threads are unblocked from condition queues using @signal@, where the signallee is moved to urgent and the signaller continues (solid line). 1807 1811 Multiple signals move multiple signallees to urgent, until the condition is empty. … … 1843 1847 It is common to declare condition variables as monitor fields to prevent shared access, hence no locking is required for access as the conditions are protected by the monitor lock. 1844 1848 In \CFA, a condition variable can be created/stored independently. 1845 To still prevent expensive locking on access, a condition variable is tied to a \emph{group} of monitors on first use, called \newterm{branding}, resulting in a low-cost boolen test to detect sharing from other monitors.1849 % To still prevent expensive locking on access, a condition variable is tied to a \emph{group} of monitors on first use, called \newterm{branding}, resulting in a low-cost boolean test to detect sharing from other monitors. 1846 1850 1847 1851 % Signalling semantics cannot have the signaller and signalled thread in the monitor simultaneously, which means: … … 1852 1856 % The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait). 1853 1857 % \item 1854 % The signalling thread blocks but is marked for urg rent unblocking at the next scheduling point and the signalled thread continues.1858 % The signalling thread blocks but is marked for urgent unblocking at the next scheduling point and the signalled thread continues. 1855 1859 % \end{enumerate} 1856 1860 % The first approach is too restrictive, as it precludes solving a reasonable class of problems, \eg dating service (see Figure~\ref{f:DatingService}). … … 1961 1965 External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the function calls that can next acquire mutual exclusion. 1962 1966 If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer. 1963 Calls threads to functions that are currently excludedblock outside of (external to) the monitor on the calling queue, versus blocking on condition queues inside of (internal to) the monitor.1967 Threads calling excluded functions block outside of (external to) the monitor on the calling queue, versus blocking on condition queues inside of (internal to) the monitor. 1964 1968 Figure~\ref{f:RWExt} shows a readers/writer lock written using external scheduling, where a waiting reader detects a writer using the resource and restricts further calls until the writer exits by calling @EndWrite@. 1965 1969 The writer does a similar action for each reader or writer using the resource. … … 2076 2080 For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex parameters, \ie @wait( e, m1, m2 )@. 2077 2081 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@. 2078 Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe.2082 Wait cannot statically verifies the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@. 2079 2083 While \CC supports bulk locking, @wait@ only accepts a single lock for a condition variable, so bulk locking with condition variables is asymmetric. 2080 2084 Finally, a signaller, … … 2088 2092 Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn, m1, m2 )@. 2089 2093 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@. 2090 @waitfor@ statically verifies the released monitors are the same as the acquired mutex-parameters of the given function or function pointer. 2091 To statically verify the released monitors match with the accepted function's mutex parameters, the function (pointer) prototype must be accessible. 2094 @waitfor@ does statically verify the monitor types passed are the same as the acquired mutex-parameters of the given function or function pointer, hence the function (pointer) prototype must be accessible. 2092 2095 % When an overloaded function appears in an @waitfor@ statement, calls to any function with that name are accepted. 2093 2096 % The rationale is that members with the same name should perform a similar function, and therefore, all should be eligible to accept a call. … … 2148 2151 The right example accepts either @mem1@ or @mem2@ if @C1@ and @C2@ are true. 2149 2152 2150 An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated. 2151 \begin{cfa} 2152 void insert( Buffer(T) & mutex buffer, T elem ) with( buffer ) { 2153 if ( count == 10 ) 2154 waitfor( remove, buffer ) { 2155 // insert elem into buffer 2156 } or `waitfor( ^?{}, buffer )` throw insertFail; 2157 } 2158 \end{cfa} 2159 When the buffer is deallocated, the current waiter is unblocked and informed, so it can perform an appropriate action. 2160 However, the basic @waitfor@ semantics do not support this functionality, since using an object after its destructor is called is undefined. 2161 Therefore, to make this useful capability work, the semantics for accepting the destructor is the same as @signal@, \ie the call to the destructor is placed on the urgent queue and the acceptor continues execution, which throws an exception to the acceptor and then the caller is unblocked from the urgent queue to deallocate the object. 2162 Accepting the destructor is the idiomatic way to terminate a thread in \CFA. 2153 An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated, \eg assume the bounded buffer is restructred from a monitor to a thread with the following @main@. 2154 \begin{cfa} 2155 void main( Buffer(T) & buffer ) with(buffer) { 2156 for () { 2157 `waitfor( ^?{}, buffer )` break; 2158 or when ( count != 20 ) waitfor( insert, buffer ) { ... } 2159 or when ( count != 0 ) waitfor( remove, buffer ) { ... } 2160 } 2161 // clean up 2162 } 2163 \end{cfa} 2164 When the program main deallocates the buffer, it first calls the buffer's destructor, which is accepted, the destructor runs, and the buffer is deallocated. 2165 However, the buffer thread cannot continue after the destructor call because the object is gone; 2166 hence, clean up in @main@ cannot occur, which means destructors for local objects are not run. 2167 To make this useful capability work, the semantics for accepting the destructor is the same as @signal@, \ie the destructor call is placed on urgent and the acceptor continues execution, which ends the loop, cleans up, and the thread terminates. 2168 Then, the destructor caller unblocks from urgent to deallocate the object. 2169 Accepting the destructor is the idiomatic way in \CFA to terminate a thread performing direct communication. 2163 2170 2164 2171 … … 2357 2364 2358 2365 struct Msg { int i, j; }; 2359 thread Go rtn { int i; float f; Msg m; };2360 void mem1( Go rtn & mutex gortn, int i ) { gortn.i = i; }2361 void mem2( Go rtn & mutex gortn, float f ) { gortn.f = f; }2362 void mem3( Go rtn & mutex gortn, Msg m ) { gortn.m = m; }2363 void ^?{}( Go rtn & mutex ) {}2364 2365 void main( Go rtn & gortn ) with( gortn ) { // thread starts2366 thread GoRtn { int i; float f; Msg m; }; 2367 void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; } 2368 void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; } 2369 void mem3( GoRtn & mutex gortn, Msg m ) { gortn.m = m; } 2370 void ^?{}( GoRtn & mutex ) {} 2371 2372 void main( GoRtn & gortn ) with( gortn ) { // thread starts 2366 2373 2367 2374 for () { … … 2376 2383 } 2377 2384 int main() { 2378 Go rtn gortn; $\C[2.0in]{// start thread}$2385 GoRtn gortn; $\C[2.0in]{// start thread}$ 2379 2386 `mem1( gortn, 0 );` $\C{// different calls}\CRT$ 2380 2387 `mem2( gortn, 2.5 );` … … 2534 2541 % However, preemption is necessary for fairness and to reduce tail-latency. 2535 2542 % For concurrency that relies on spinning, if all cores spin the system is livelocked, whereas preemption breaks the livelock. 2536 % 2537 % 2538 % \subsection{Thread Pools} 2539 % 2540 % In contrast to direct threading is indirect \newterm{thread pools}, \eg Java @executor@, where small jobs (work units) are inserted into a work pool for execution. 2541 % If the jobs are dependent, \ie interact, there is an implicit/explicit dependency graph that ties them together. 2542 % While removing direct concurrency, and hence the amount of context switching, thread pools significantly limit the interaction that can occur among jobs. 2543 % Indeed, jobs should not block because that also blocks the underlying thread, which effectively means the CPU utilization, and therefore throughput, suffers. 2544 % While it is possible to tune the thread pool with sufficient threads, it becomes difficult to obtain high throughput and good core utilization as job interaction increases. 2545 % As well, concurrency errors return, which threads pools are suppose to mitigate. 2543 2544 2545 \begin{comment} 2546 \subsection{Thread Pools} 2547 2548 In contrast to direct threading is indirect \newterm{thread pools}, \eg Java @executor@, where small jobs (work units) are inserted into a work pool for execution. 2549 If the jobs are dependent, \ie interact, there is an implicit/explicit dependency graph that ties them together. 2550 While removing direct concurrency, and hence the amount of context switching, thread pools significantly limit the interaction that can occur among jobs. 2551 Indeed, jobs should not block because that also blocks the underlying thread, which effectively means the CPU utilization, and therefore throughput, suffers. 2552 While it is possible to tune the thread pool with sufficient threads, it becomes difficult to obtain high throughput and good core utilization as job interaction increases. 2553 As well, concurrency errors return, which threads pools are suppose to mitigate. 2554 2555 \begin{figure} 2556 \centering 2557 \begin{tabular}{@{}l|l@{}} 2558 \begin{cfa} 2559 struct Adder { 2560 int * row, cols; 2561 }; 2562 int operator()() { 2563 subtotal = 0; 2564 for ( int c = 0; c < cols; c += 1 ) 2565 subtotal += row[c]; 2566 return subtotal; 2567 } 2568 void ?{}( Adder * adder, int row[$\,$], int cols, int & subtotal ) { 2569 adder.[rows, cols, subtotal] = [rows, cols, subtotal]; 2570 } 2571 2572 2573 2574 2575 \end{cfa} 2576 & 2577 \begin{cfa} 2578 int main() { 2579 const int rows = 10, cols = 10; 2580 int matrix[rows][cols], subtotals[rows], total = 0; 2581 // read matrix 2582 Executor executor( 4 ); // kernel threads 2583 Adder * adders[rows]; 2584 for ( r; rows ) { // send off work for executor 2585 adders[r] = new( matrix[r], cols, &subtotal[r] ); 2586 executor.send( *adders[r] ); 2587 } 2588 for ( r; rows ) { // wait for results 2589 delete( adders[r] ); 2590 total += subtotals[r]; 2591 } 2592 sout | total; 2593 } 2594 \end{cfa} 2595 \end{tabular} 2596 \caption{Executor} 2597 \end{figure} 2598 \end{comment} 2546 2599 2547 2600 … … 2567 2620 The purpose of a cluster is to control the amount of parallelism that is possible among threads, plus scheduling and other execution defaults. 2568 2621 The default cluster-scheduler is single-queue multi-server, which provides automatic load-balancing of threads on processors. 2569 However, the scheduler is pluggable, supporting alternative schedulers, such as multi-queue multi-server,with work-stealing/sharing across the virtual processors.2622 However, the design allows changing the scheduler, \eg multi-queue multi-server with work-stealing/sharing across the virtual processors. 2570 2623 If several clusters exist, both threads and virtual processors, can be explicitly migrated from one cluster to another. 2571 2624 No automatic load balancing among clusters is performed by \CFA. … … 2574 2627 The user cluster is created to contain the application user-threads. 2575 2628 Having all threads execute on the one cluster often maximizes utilization of processors, which minimizes runtime. 2576 However, because of limitations of the underlying operating system, heterogeneous hardware, or scheduling requirements (real-time), multiple clusters are sometimes necessary.2629 However, because of limitations of scheduling requirements (real-time), NUMA architecture, heterogeneous hardware, or issues with the underlying operating system, multiple clusters are sometimes necessary. 2577 2630 2578 2631 … … 2618 2671 \subsection{Preemption} 2619 2672 2620 Nondeterministic preemption provides fairness from long running threads, and forces concurrent programmers to write more robust programs, rather than relying on section of code between cooperative scheduling to be atomic. 2621 A separate reason for not supporting preemption is that it significantly complicates the runtime system. 2673 Nondeterministic preemption provides fairness from long running threads, and forces concurrent programmers to write more robust programs, rather than relying on code between cooperative scheduling to be atomic. 2674 This atomic reliance can fail on multi-core machines, because execution across cores is nondeterministic. 2675 A different reason for not supporting preemption is that it significantly complicates the runtime system, \eg Microsoft runtime does not support interrupts and on Linux systems, interrupts are complex (see below). 2622 2676 Preemption is normally handled by setting a count-down timer on each virtual processor. 2623 2677 When the timer expires, an interrupt is delivered, and the interrupt handler resets the count-down timer, and if the virtual processor is executing in user code, the signal handler performs a user-level context-switch, or if executing in the language runtime-kernel, the preemption is ignored or rolled forward to the point where the runtime kernel context switches back to user code. … … 2628 2682 Because preemption frequency is usually long (1 millisecond) performance cost is negligible. 2629 2683 2630 However, on current Linux systems: 2684 Linux switched a decade ago from specific to arbitrary process signal-delivery for applications with multiple kernel threads. 2631 2685 \begin{cquote} 2632 2686 A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked. … … 2634 2688 SIGNAL(7) - Linux Programmer's Manual 2635 2689 \end{cquote} 2636 Hence, the timer-expiry signal, which is generated \emph{externally} by the Linux kernel to the Linux process, is delivered to any of its Linux subprocesses (kernel threads).2637 To ensure each virtual processor receives its own preemption signals, a discrete-event simulation is run on a special virtual processor, and only it sets and receives timer events.2690 Hence, the timer-expiry signal, which is generated \emph{externally} by the Linux kernel to an application, is delivered to any of its Linux subprocesses (kernel threads). 2691 To ensure each virtual processor receives a preemption signal, a discrete-event simulation is run on a special virtual processor, and only it sets and receives timer events. 2638 2692 Virtual processors register an expiration time with the discrete-event simulator, which is inserted in sorted order. 2639 2693 The simulation sets the count-down timer to the value at the head of the event list, and when the timer expires, all events less than or equal to the current time are processed. … … 2652 2706 2653 2707 To verify the implementation of the \CFA runtime, a series of microbenchmarks are performed comparing \CFA with Java OpenJDK-9, Go 1.9.2 and \uC 7.0.0. 2654 The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04. 3 LTS and \uC and \CFA are compiled with gcc 6.3.2708 The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and \uC/\CFA are compiled with gcc 6.5. 2655 2709 2656 2710 \begin{comment} … … 2707 2761 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2708 2762 \begin{cfa} 2709 threadMyThread {};2710 void main( MyThread & ) {}2763 @thread@ MyThread {}; 2764 void @main@( MyThread & ) {} 2711 2765 int main() { 2712 2766 BENCH( for ( N ) { @MyThread m;@ } ) … … 2750 2804 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2751 2805 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 2752 coroutineC {} c;2806 @coroutine@ C {} c; 2753 2807 void main( C & ) { for ( ;; ) { @suspend;@ } } 2754 2808 int main() { // coroutine test … … 2771 2825 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2772 2826 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2773 Kernel Thread & 333.5 & 332.96 & 4.1 \\ 2827 C function & 2 & 2 & 0 \\ 2828 \CFA generator & 2 & 2 & 0 \\ 2774 2829 \CFA Coroutine & 49 & 48.68 & 0.47 \\ 2775 2830 \CFA Thread & 105 & 105.57 & 1.37 \\ … … 2777 2832 \uC Thread & 100 & 99.29 & 0.96 \\ 2778 2833 Goroutine & 145 & 147.25 & 4.15 \\ 2779 Java Thread & 373.5 & 375.14 & 8.72 2834 Java Thread & 373.5 & 375.14 & 8.72 \\ 2835 Pthreads Thread & 333.5 & 332.96 & 4.1 2780 2836 \end{tabular} 2781 2837 \end{multicols} … … 2793 2849 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2794 2850 \begin{cfa} 2795 monitorM {} m1/*, m2, m3, m4*/;2851 @monitor@ M {} m1/*, m2, m3, m4*/; 2796 2852 void __attribute__((noinline)) 2797 do_call( M & mutex m/*, m2, m3, m4*/) {}2853 do_call( M & @mutex m/*, m2, m3, m4*/@ ) {} 2798 2854 int main() { 2799 2855 BENCH( 2800 for( N ) @do_call( m1/*, m2, m3, m4*/ );@2856 for( N ) do_call( m1/*, m2, m3, m4*/ ); 2801 2857 ) 2802 2858 sout | result`ns; … … 2813 2869 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2814 2870 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2815 C function & 2 & 2 & 0 \\ 2816 FetchAdd + FetchSub & 26 & 26 & 0 \\ 2871 test and test-and-test lock & 26 & 26 & 0 \\ 2817 2872 Pthreads Mutex Lock & 31 & 31.71 & 0.97 \\ 2818 2873 \uC @monitor@ member rtn. & 31 & 31 & 0 \\ … … 2820 2875 \CFA @mutex@ function, 2 arg. & 84 & 85.36 & 1.99 \\ 2821 2876 \CFA @mutex@ function, 4 arg. & 158 & 161 & 4.22 \\ 2822 Java synchronized function& 27.5 & 29.79 & 2.932877 Java synchronized method & 27.5 & 29.79 & 2.93 2823 2878 \end{tabular} 2824 2879 \end{multicols} … … 2836 2891 \begin{cfa} 2837 2892 volatile int go = 0; 2838 monitor M { condition c;} m;2893 @monitor@ M { @condition c;@ } m; 2839 2894 void __attribute__((noinline)) 2840 do_call( M & mutexa1 ) { @signal( c );@ }2895 do_call( M & @mutex@ a1 ) { @signal( c );@ } 2841 2896 thread T {}; 2842 2897 void main( T & this ) { … … 2869 2924 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2870 2925 Pthreads Cond. Variable & 6005 & 5681.43 & 835.45 \\ 2871 \uC @signal@ & 324 & 325.54 & 3 ,02 \\2926 \uC @signal@ & 324 & 325.54 & 3.02 \\ 2872 2927 \CFA @signal@, 1 @monitor@ & 368.5 & 370.61 & 4.77 \\ 2873 2928 \CFA @signal@, 2 @monitor@ & 467 & 470.5 & 6.79 \\ … … 2889 2944 \begin{cfa} 2890 2945 volatile int go = 0; 2891 monitorM {} m;2946 @monitor@ M {} m; 2892 2947 thread T {}; 2893 2948 void __attribute__((noinline)) 2894 do_call( M & mutex) {}2949 do_call( M & @mutex@ ) {} 2895 2950 void main( T & ) { 2896 2951 while ( go == 0 ) { yield(); } 2897 while ( go == 1 ) { @do_call( m );@}2952 while ( go == 1 ) { do_call( m ); } 2898 2953 } 2899 2954 int __attribute__((noinline)) 2900 do_wait( M & mutexm ) {2955 do_wait( M & @mutex@ m ) { 2901 2956 go = 1; // continue other thread 2902 2957 BENCH( for ( N ) { @waitfor( do_call, m );@ } ) -
doc/papers/concurrency/annex/local.bib
r3c6e417 r54dd994 66 66 } 67 67 68 @ article{BankTransfer,68 @misc{BankTransfer, 69 69 key = {Bank Transfer}, 70 70 keywords = {Bank Transfer}, 71 71 title = {Bank Account Transfer Problem}, 72 publisher = {Wiki Wiki Web}, 73 address = {http://wiki.c2.com}, 72 howpublished = {Wiki Wiki Web, \url{http://wiki.c2.com/?BankAccountTransferProblem}}, 74 73 year = 2010 75 74 } -
doc/papers/concurrency/examples/Fib.cfa
r3c6e417 r54dd994 13 13 } 14 14 15 #define FibCtor { 0, 1}16 typedef struct { int fn , fn1; } Fib;17 int fib_state( Fib & f ) with( f) {18 int fn0 = fn1 + fn2; fn2 = fn1; fn = fn0;19 return fn1;15 #define FibCtor { 1, 0 } 16 typedef struct { int fn1, fn; } Fib; 17 int fib_state( Fib & f ) with(f) { 18 int ret = fn; fn = fn1; fn1 = fn + ret; 19 return ret; 20 20 } 21 21 … … 32 32 coroutine Fib2 { int fn; }; // used for communication 33 33 void main( Fib2 & fib ) with( fib ) { // called on first resume 34 int fn1 = 1, fn2 = 0; // precompute first two states 34 int fn1; // precompute first two states 35 [fn1, fn] = [1, 0]; 35 36 for () { 36 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case37 37 suspend(); // restart last resume 38 [fn1, fn] = [fn, fn + fn1]; 38 39 } 39 40 } 40 int ?()( Fib2 & fib ) with( fib ) {41 int ?()( Fib2 & fib ) { // function-call interface 41 42 return resume( fib ).fn; // restart last suspend 42 43 } 43 int ?()( Fib2 & fib, int N ) with( fib ) {44 for ( N - 1 ) fib(); 44 int ?()( Fib2 & fib, int N ) { // skip N values 45 for ( N - 1 ) fib(); // use function-call interface 45 46 return fib(); 46 47 } 47 double ?()( Fib2 & fib ) with( fib ) {48 return (int)(fib()) / 3.14159; // restart last suspend48 double ?()( Fib2 & fib ) { // different return type 49 return (int)(fib()) / 3.14159; // cast prevents recursive call 49 50 } 50 51 -
doc/user/user.tex
r3c6e417 r54dd994 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : S un May 5 18:24:50201914 %% Update Count : 3 48913 %% Last Modified On : Sat Jun 15 16:29:45 2019 14 %% Update Count : 3847 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 254 254 \begin{lstlisting} 255 255 ®forall( otype T )® T identity( T val ) { return val; } 256 int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§256 int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§ 257 257 \end{lstlisting} 258 258 % extending the C type system with parametric polymorphism and overloading, as opposed to the \Index*[C++]{\CC{}} approach of object-oriented extensions. … … 282 282 283 283 double key = 5.0, vals[10] = { /* 10 sorted floating values */ }; 284 double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§284 double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§ 285 285 \end{lstlisting} 286 286 which can be augmented simply with a polymorphic, type-safe, \CFA-overloaded wrappers: … … 291 291 292 292 forall( otype T | { int ?<?( T, T ); } ) unsigned int bsearch( T key, const T * arr, size_t size ) { 293 T * result = bsearch( key, arr, size ); §\C{// call first version}§294 return result ? result - arr : size; } §\C{// pointer subtraction includes sizeof(T)}§295 296 double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§293 T * result = bsearch( key, arr, size ); §\C{// call first version}§ 294 return result ? result - arr : size; } §\C{// pointer subtraction includes sizeof(T)}§ 295 296 double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§ 297 297 int posn = bsearch( 5.0, vals, 10 ); 298 298 \end{lstlisting} … … 306 306 \begin{lstlisting} 307 307 forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); } 308 int * ip = malloc(); §\C{// select type and size from left-hand side}§308 int * ip = malloc(); §\C{// select type and size from left-hand side}§ 309 309 double * dp = malloc(); 310 310 struct S {...} * sp = malloc(); … … 318 318 \begin{cfa} 319 319 char ®abs®( char ); 320 extern "C" { int ®abs®( int ); } §\C{// use default C routine for int}§320 extern "C" { int ®abs®( int ); } §\C{// use default C routine for int}§ 321 321 long int ®abs®( long int ); 322 322 long long int ®abs®( long long int ); … … 426 426 \begin{cfa} 427 427 #ifndef __CFORALL__ 428 #include <stdio.h>§\indexc{stdio.h}§ §\C{// C header file}§428 #include <stdio.h>§\indexc{stdio.h}§ §\C{// C header file}§ 429 429 #else 430 #include <fstream>§\indexc{fstream}§ §\C{// \CFA header file}§430 #include <fstream>§\indexc{fstream}§ §\C{// \CFA header file}§ 431 431 #endif 432 432 \end{cfa} … … 512 512 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism: 513 513 \begin{cfa} 514 int ®`®otype®`® = 3; §\C{// make keyword an identifier}§514 int ®`®otype®`® = 3; §\C{// make keyword an identifier}§ 515 515 double ®`®forall®`® = 3.5; 516 516 \end{cfa} … … 523 523 \begin{cfa} 524 524 // include file uses the CFA keyword "with". 525 #if ! defined( with ) §\C{// nesting ?}§526 #define with ®`®with®`® §\C{// make keyword an identifier}§525 #if ! defined( with ) §\C{// nesting ?}§ 526 #define with ®`®with®`® §\C{// make keyword an identifier}§ 527 527 #define __CFA_BFD_H__ 528 528 #endif 529 529 530 ®#include_next <bfdlink.h> §\C{// must have internal check for multiple expansion}§530 ®#include_next <bfdlink.h> §\C{// must have internal check for multiple expansion}§ 531 531 ® 532 532 #if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§ … … 544 544 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore}, \eg: 545 545 \begin{cfa} 546 2®_®147®_®483®_®648; §\C{// decimal constant}§547 56®_®ul; §\C{// decimal unsigned long constant}§548 0®_®377; §\C{// octal constant}§549 0x®_®ff®_®ff; §\C{// hexadecimal constant}§550 0x®_®ef3d®_®aa5c; §\C{// hexadecimal constant}§551 3.141®_®592®_®654; §\C{// floating constant}§552 10®_®e®_®+1®_®00; §\C{// floating constant}§553 0x®_®ff®_®ff®_®p®_®3; §\C{// hexadecimal floating}§554 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; §\C{// hexadecimal floating long constant}§555 L®_®§"\texttt{\textbackslash{x}}§®_®§\texttt{ff}§®_®§\texttt{ee}"§; §\C{// wide character constant}§546 2®_®147®_®483®_®648; §\C{// decimal constant}§ 547 56®_®ul; §\C{// decimal unsigned long constant}§ 548 0®_®377; §\C{// octal constant}§ 549 0x®_®ff®_®ff; §\C{// hexadecimal constant}§ 550 0x®_®ef3d®_®aa5c; §\C{// hexadecimal constant}§ 551 3.141®_®592®_®654; §\C{// floating constant}§ 552 10®_®e®_®+1®_®00; §\C{// floating constant}§ 553 0x®_®ff®_®ff®_®p®_®3; §\C{// hexadecimal floating}§ 554 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; §\C{// hexadecimal floating long constant}§ 555 L®_®§"\texttt{\textbackslash{x}}§®_®§\texttt{ff}§®_®§\texttt{ee}"§; §\C{// wide character constant}§ 556 556 \end{cfa} 557 557 The rules for placement of underscores are: … … 612 612 (Does not make sense for ©do©-©while©.) 613 613 \begin{cfa} 614 if ( ®int x = f()® ) ... §\C{// x != 0}§615 if ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§616 if ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§614 if ( ®int x = f()® ) ... §\C{// x != 0}§ 615 if ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§ 616 if ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§ 617 617 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) §\C{// relational expression}§ 618 618 619 while ( ®int x = f()® ) ... §\C{// x != 0}§620 while ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§619 while ( ®int x = f()® ) ... §\C{// x != 0}§ 620 while ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§ 621 621 while ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§ 622 622 while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... §\C{// relational expression}§ … … 892 892 \begin{cfa} 893 893 switch ( x ) { 894 ®int y = 1;® §\C{// unreachable initialization}§895 ®x = 7;® §\C{// unreachable code without label/branch}§894 ®int y = 1;® §\C{// unreachable initialization}§ 895 ®x = 7;® §\C{// unreachable code without label/branch}§ 896 896 case 0: ... 897 897 ... 898 ®int z = 0;® §\C{// unreachable initialization, cannot appear after case}§898 ®int z = 0;® §\C{// unreachable initialization, cannot appear after case}§ 899 899 z = 2; 900 900 case 1: 901 ®x = z;® §\C{// without fall through, z is uninitialized}§901 ®x = z;® §\C{// without fall through, z is uninitialized}§ 902 902 } 903 903 \end{cfa} … … 937 937 ®case 5: 938 938 ... 939 ®fallthru®; §\C{// explicit fall through}§939 ®fallthru®; §\C{// explicit fall through}§ 940 940 case 7: 941 941 ... 942 ®break® §\C{// explicit end of switch (redundant)}§942 ®break® §\C{// explicit end of switch (redundant)}§ 943 943 default: 944 944 j = 3; … … 961 961 \begin{cfa} 962 962 switch ( x ) { 963 ®int i = 0;® §\C{// allowed only at start}§963 ®int i = 0;® §\C{// allowed only at start}§ 964 964 case 0: 965 965 ... 966 ®int j = 0;® §\C{// disallowed}§966 ®int j = 0;® §\C{// disallowed}§ 967 967 case 1: 968 968 { 969 ®int k = 0;® §\C{// allowed at different nesting levels}§969 ®int k = 0;® §\C{// allowed at different nesting levels}§ 970 970 ... 971 ®case 2:® §\C{// disallow case in nested statements}§971 ®case 2:® §\C{// disallow case in nested statements}§ 972 972 } 973 973 ... … … 1019 1019 \begin{cfa} 1020 1020 switch ( i ) { 1021 case ®1~5:® §\C{// 1, 2, 3, 4, 5}§1021 case ®1~5:® §\C{// 1, 2, 3, 4, 5}§ 1022 1022 ... 1023 case ®10~15:® §\C{// 10, 11, 12, 13, 14, 15}§1023 case ®10~15:® §\C{// 10, 11, 12, 13, 14, 15}§ 1024 1024 ... 1025 1025 } … … 1152 1152 Grouping heterogeneous data into \newterm{aggregate}s (structure/union) is a common programming practice, and an aggregate can be further organized into more complex structures, such as arrays and containers: 1153 1153 \begin{cfa} 1154 struct S { §\C{// aggregate}§1155 char c; §\C{// fields}§1154 struct S { §\C{// aggregate}§ 1155 char c; §\C{// fields}§ 1156 1156 int i; 1157 1157 double d; … … 1162 1162 \begin{cfa} 1163 1163 void f( S s ) { 1164 ®s.®c; ®s.®i; ®s.®d; §\C{// access containing fields}§1164 ®s.®c; ®s.®i; ®s.®d; §\C{// access containing fields}§ 1165 1165 } 1166 1166 \end{cfa} … … 1169 1169 \begin{C++} 1170 1170 struct S { 1171 char c; §\C{// fields}§1171 char c; §\C{// fields}§ 1172 1172 int i; 1173 1173 double d; 1174 void f() { §\C{// implicit ``this'' aggregate}§1175 ®this->®c; ®this->®i; ®this->®d; §\C{// access containing fields}§1174 void f() { §\C{// implicit ``this'' aggregate}§ 1175 ®this->®c; ®this->®i; ®this->®d; §\C{// access containing fields}§ 1176 1176 } 1177 1177 } … … 1181 1181 \begin{cfa} 1182 1182 struct T { double m, n; }; 1183 int S::f( T & t ) { §\C{// multiple aggregate parameters}§1184 c; i; d; §\C{\color{red}// this--{\textgreater}.c, this--{\textgreater}.i, this--{\textgreater}.d}§1185 ®t.®m; ®t.®n; §\C{// must qualify}§1183 int S::f( T & t ) { §\C{// multiple aggregate parameters}§ 1184 c; i; d; §\C{\color{red}// this--{\textgreater}.c, this--{\textgreater}.i, this--{\textgreater}.d}§ 1185 ®t.®m; ®t.®n; §\C{// must qualify}§ 1186 1186 } 1187 1187 \end{cfa} … … 1190 1190 Hence, the qualified fields become variables with the side-effect that it is easier to optimizing field references in a block. 1191 1191 \begin{cfa} 1192 void f( S & this ) ®with ( this )® { §\C{// with statement}§1193 c; i; d; §\C{\color{red}// this.c, this.i, this.d}§1192 void f( S & this ) ®with ( this )® { §\C{// with statement}§ 1193 c; i; d; §\C{\color{red}// this.c, this.i, this.d}§ 1194 1194 } 1195 1195 \end{cfa} 1196 1196 with the generality of opening multiple aggregate-parameters: 1197 1197 \begin{cfa} 1198 void f( S & s, T & t ) ®with ( s, t )® { §\C{// multiple aggregate parameters}§1199 c; i; d; §\C{\color{red}// s.c, s.i, s.d}§1200 m; n; §\C{\color{red}// t.m, t.n}§1198 void f( S & s, T & t ) ®with ( s, t )® { §\C{// multiple aggregate parameters}§ 1199 c; i; d; §\C{\color{red}// s.c, s.i, s.d}§ 1200 m; n; §\C{\color{red}// t.m, t.n}§ 1201 1201 } 1202 1202 \end{cfa} … … 1220 1220 struct T { int ®i®; int k; int m; } t, w; 1221 1221 with ( s, t ) { 1222 j + k; §\C{// unambiguous, s.j + t.k}§1223 m = 5.0; §\C{// unambiguous, t.m = 5.0}§1224 m = 1; §\C{// unambiguous, s.m = 1}§1225 int a = m; §\C{// unambiguous, a = s.i }§1226 double b = m; §\C{// unambiguous, b = t.m}§1227 int c = s.i + t.i; §\C{// unambiguous, qualification}§1228 (double)m; §\C{// unambiguous, cast}§1222 j + k; §\C{// unambiguous, s.j + t.k}§ 1223 m = 5.0; §\C{// unambiguous, t.m = 5.0}§ 1224 m = 1; §\C{// unambiguous, s.m = 1}§ 1225 int a = m; §\C{// unambiguous, a = s.i }§ 1226 double b = m; §\C{// unambiguous, b = t.m}§ 1227 int c = s.i + t.i; §\C{// unambiguous, qualification}§ 1228 (double)m; §\C{// unambiguous, cast}§ 1229 1229 } 1230 1230 \end{cfa} … … 1236 1236 There is an interesting problem between parameters and the function-body ©with©, \eg: 1237 1237 \begin{cfa} 1238 void ?{}( S & s, int i ) with ( s ) { §\C{// constructor}§1239 ®s.i = i;® j = 3; m = 5.5; §\C{// initialize fields}§1238 void ?{}( S & s, int i ) with ( s ) { §\C{// constructor}§ 1239 ®s.i = i;® j = 3; m = 5.5; §\C{// initialize fields}§ 1240 1240 } 1241 1241 \end{cfa} … … 1256 1256 Finally, a cast may be used to disambiguate among overload variables in a ©with© expression: 1257 1257 \begin{cfa} 1258 with ( w ) { ... } §\C{// ambiguous, same name and no context}§1259 with ( (S)w ) { ... } §\C{// unambiguous, cast}§1258 with ( w ) { ... } §\C{// ambiguous, same name and no context}§ 1259 with ( (S)w ) { ... } §\C{// unambiguous, cast}§ 1260 1260 \end{cfa} 1261 1261 and ©with© expressions may be complex expressions with type reference (see Section~\ref{s:References}) to aggregate: 1262 1262 % \begin{cfa} 1263 1263 % struct S { int i, j; } sv; 1264 % with ( sv ) { §\C{// implicit reference}§1264 % with ( sv ) { §\C{// implicit reference}§ 1265 1265 % S & sr = sv; 1266 % with ( sr ) { §\C{// explicit reference}§1266 % with ( sr ) { §\C{// explicit reference}§ 1267 1267 % S * sp = &sv; 1268 % with ( *sp ) { §\C{// computed reference}§1269 % i = 3; j = 4; §\C{\color{red}// sp--{\textgreater}i, sp--{\textgreater}j}§1268 % with ( *sp ) { §\C{// computed reference}§ 1269 % i = 3; j = 4; §\C{\color{red}// sp--{\textgreater}i, sp--{\textgreater}j}§ 1270 1270 % } 1271 % i = 2; j = 3; §\C{\color{red}// sr.i, sr.j}§1271 % i = 2; j = 3; §\C{\color{red}// sr.i, sr.j}§ 1272 1272 % } 1273 % i = 1; j = 2; §\C{\color{red}// sv.i, sv.j}§1273 % i = 1; j = 2; §\C{\color{red}// sv.i, sv.j}§ 1274 1274 % } 1275 1275 % \end{cfa} … … 1279 1279 class C { 1280 1280 int i, j; 1281 int mem() { §\C{\color{red}// implicit "this" parameter}§1282 i = 1; §\C{\color{red}// this->i}§1283 j = 2; §\C{\color{red}// this->j}§1281 int mem() { §\C{\color{red}// implicit "this" parameter}§ 1282 i = 1; §\C{\color{red}// this->i}§ 1283 j = 2; §\C{\color{red}// this->j}§ 1284 1284 } 1285 1285 } … … 1288 1288 \begin{cfa} 1289 1289 struct S { int i, j; }; 1290 int mem( S & ®this® ) { §\C{// explicit "this" parameter}§1291 ®this.®i = 1; §\C{// "this" is not elided}§1290 int mem( S & ®this® ) { §\C{// explicit "this" parameter}§ 1291 ®this.®i = 1; §\C{// "this" is not elided}§ 1292 1292 ®this.®j = 2; 1293 1293 } … … 1297 1297 \CFA provides a ©with© clause/statement (see Pascal~\cite[\S~4.F]{Pascal}) to elided the "©this.©" by opening a scope containing field identifiers, changing the qualified fields into variables and giving an opportunity for optimizing qualified references. 1298 1298 \begin{cfa} 1299 int mem( S & this ) ®with( this )® { §\C{// with clause}§1300 i = 1; §\C{\color{red}// this.i}§1301 j = 2; §\C{\color{red}// this.j}§1299 int mem( S & this ) ®with( this )® { §\C{// with clause}§ 1300 i = 1; §\C{\color{red}// this.i}§ 1301 j = 2; §\C{\color{red}// this.j}§ 1302 1302 } 1303 1303 \end{cfa} … … 1316 1316 struct S1 { ... } s1; 1317 1317 struct S2 { ... } s2; 1318 ®with( s1 )® { §\C{// with statement}§1318 ®with( s1 )® { §\C{// with statement}§ 1319 1319 // access fields of s1 without qualification 1320 ®with s2® { §\C{// nesting}§1320 ®with s2® { §\C{// nesting}§ 1321 1321 // access fields of s1 and s2 without qualification 1322 1322 } … … 1373 1373 Non-local transfer can cause stack unwinding, \ie non-local routine termination, depending on the kind of raise. 1374 1374 \begin{cfa} 1375 exception_t E {}; §\C{// exception type}§1375 exception_t E {}; §\C{// exception type}§ 1376 1376 void f(...) { 1377 ... throw E{}; ... §\C{// termination}§1378 ... throwResume E{}; ... §\C{// resumption}§1377 ... throw E{}; ... §\C{// termination}§ 1378 ... throwResume E{}; ... §\C{// resumption}§ 1379 1379 } 1380 1380 try { … … 1442 1442 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 1443 1443 \begin{cfa} 1444 int ®(*®f®())[®5®]® {...}; §\C{// definition}§1445 ... ®(*®f®())[®3®]® += 1; §\C{// usage}§1444 int ®(*®f®())[®5®]® {...}; §\C{// definition}§ 1445 ... ®(*®f®())[®3®]® += 1; §\C{// usage}§ 1446 1446 \end{cfa} 1447 1447 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). … … 1635 1635 *x = 3; // implicit dereference 1636 1636 int * ®const® y = (int *)104; 1637 *y = *x; // implicit dereference1637 *y = *x; // implicit dereference 1638 1638 \end{cfa} 1639 1639 \end{tabular} … … 1649 1649 \hline 1650 1650 \begin{cfa} 1651 lda r1,100 // load address of x1652 ld r2,(r1) // load value of x1653 lda r3,104 // load address of y1654 st r2,(r3) // store x into y1651 lda r1,100 // load address of x 1652 ld r2,(r1) // load value of x 1653 lda r3,104 // load address of y 1654 st r2,(r3) // store x into y 1655 1655 \end{cfa} 1656 1656 & 1657 1657 \begin{cfa} 1658 1658 1659 ld r2,(100) // load value of x1660 1661 st r2,(104) // store x into y1659 ld r2,(100) // load value of x 1660 1661 st r2,(104) // store x into y 1662 1662 \end{cfa} 1663 1663 \end{tabular} … … 1673 1673 \begin{cfa} 1674 1674 int x, y, ®*® p1, ®*® p2, ®**® p3; 1675 p1 = ®&®x; // p1 points to x1676 p2 = p1; // p2 points to x1677 p1 = ®&®y; // p1 points to y1678 p3 = &p2; // p3 points to p21675 p1 = ®&®x; // p1 points to x 1676 p2 = p1; // p2 points to x 1677 p1 = ®&®y; // p1 points to y 1678 p3 = &p2; // p3 points to p2 1679 1679 \end{cfa} 1680 1680 & … … 1687 1687 For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage 1688 1688 \begin{cfa} 1689 p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§1689 p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§ 1690 1690 \end{cfa} 1691 1691 Algol68 infers the following dereferencing ©*p2 = *p1 + x©, because adding the arbitrary integer value in ©x© to the address of ©p1© and storing the resulting address into ©p2© is an unlikely operation. … … 1695 1695 In C, objects of pointer type always manipulate the pointer object's address: 1696 1696 \begin{cfa} 1697 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§1698 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§1697 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§ 1698 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§ 1699 1699 \end{cfa} 1700 1700 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant: 1701 1701 \begin{cfa} 1702 p1 = p2; §\C{// pointer address assignment}§1703 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§1702 p1 = p2; §\C{// pointer address assignment}§ 1703 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§ 1704 1704 \end{cfa} 1705 1705 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). … … 1718 1718 \begin{cfa} 1719 1719 int x, y, ®&® r1, ®&® r2, ®&&® r3; 1720 ®&®r1 = &x; §\C{// r1 points to x}§1721 ®&®r2 = &r1; §\C{// r2 points to x}§1722 ®&®r1 = &y; §\C{// r1 points to y}§1723 ®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§1720 ®&®r1 = &x; §\C{// r1 points to x}§ 1721 ®&®r2 = &r1; §\C{// r2 points to x}§ 1722 ®&®r1 = &y; §\C{// r1 points to y}§ 1723 ®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§ 1724 1724 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§ 1725 1725 \end{cfa} … … 1737 1737 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 1738 1738 \begin{cfa} 1739 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§1739 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§ 1740 1740 \end{cfa} 1741 1741 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 1742 1742 \begin{cfa} 1743 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§1743 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§ 1744 1744 \end{cfa} 1745 1745 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. … … 1749 1749 int x, *p1 = &x, **p2 = &p1, ***p3 = &p2, 1750 1750 &r1 = x, &&r2 = r1, &&&r3 = r2; 1751 ***p3 = 3; §\C{// change x}§1752 r3 = 3; §\C{// change x, ***r3}§1753 **p3 = ...; §\C{// change p1}§1754 &r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§1755 *p3 = ...; §\C{// change p2}§1756 &&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§1757 &&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§1751 ***p3 = 3; §\C{// change x}§ 1752 r3 = 3; §\C{// change x, ***r3}§ 1753 **p3 = ...; §\C{// change p1}§ 1754 &r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§ 1755 *p3 = ...; §\C{// change p2}§ 1756 &&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§ 1757 &&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§ 1758 1758 \end{cfa} 1759 1759 Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types. … … 1762 1762 As for a pointer type, a reference type may have qualifiers: 1763 1763 \begin{cfa} 1764 const int cx = 5; §\C{// cannot change cx;}§1765 const int & cr = cx; §\C{// cannot change what cr points to}§1766 ®&®cr = &cx; §\C{// can change cr}§1767 cr = 7; §\C{// error, cannot change cx}§1768 int & const rc = x; §\C{// must be initialized}§1769 ®&®rc = &x; §\C{// error, cannot change rc}§1770 const int & const crc = cx; §\C{// must be initialized}§1771 crc = 7; §\C{// error, cannot change cx}§1772 ®&®crc = &cx; §\C{// error, cannot change crc}§1764 const int cx = 5; §\C{// cannot change cx;}§ 1765 const int & cr = cx; §\C{// cannot change what cr points to}§ 1766 ®&®cr = &cx; §\C{// can change cr}§ 1767 cr = 7; §\C{// error, cannot change cx}§ 1768 int & const rc = x; §\C{// must be initialized}§ 1769 ®&®rc = &x; §\C{// error, cannot change rc}§ 1770 const int & const crc = cx; §\C{// must be initialized}§ 1771 crc = 7; §\C{// error, cannot change cx}§ 1772 ®&®crc = &cx; §\C{// error, cannot change crc}§ 1773 1773 \end{cfa} 1774 1774 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: 1775 1775 \begin{cfa} 1776 int & const cr = *0; §\C{// where 0 is the int * zero}§1776 int & const cr = *0; §\C{// where 0 is the int * zero}§ 1777 1777 \end{cfa} 1778 1778 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management: … … 1781 1781 cr = 5; 1782 1782 free( &cr ); 1783 cr = 7; §\C{// unsound pointer dereference}§1783 cr = 7; §\C{// unsound pointer dereference}§ 1784 1784 \end{cfa} 1785 1785 … … 1806 1806 \begin{cfa} 1807 1807 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§ 1808 &ar[1] = &w; §\C{// change reference array element}§1809 typeof( ar[1] ) p; §\C{// (gcc) is int, \ie the type of referenced object}§1810 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, \ie the type of reference}§1811 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, \ie the size of referenced object}§1812 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, \ie the size of a reference}§1808 &ar[1] = &w; §\C{// change reference array element}§ 1809 typeof( ar[1] ) p; §\C{// (gcc) is int, \ie the type of referenced object}§ 1810 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, \ie the type of reference}§ 1811 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, \ie the size of referenced object}§ 1812 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, \ie the size of a reference}§ 1813 1813 \end{cfa} 1814 1814 … … 1827 1827 Therefore, for pointer/reference initialization, the initializing value must be an address not a value. 1828 1828 \begin{cfa} 1829 int * p = &x; §\C{// assign address of x}§1830 ®int * p = x;® §\C{// assign value of x}§1831 int & r = x; §\C{// must have address of x}§1829 int * p = &x; §\C{// assign address of x}§ 1830 ®int * p = x;® §\C{// assign value of x}§ 1831 int & r = x; §\C{// must have address of x}§ 1832 1832 \end{cfa} 1833 1833 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given). … … 1838 1838 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason. 1839 1839 \begin{cfa} 1840 int & f( int & r ); §\C{// reference parameter and return}§1841 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§1840 int & f( int & r ); §\C{// reference parameter and return}§ 1841 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§ 1842 1842 \end{cfa} 1843 1843 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©. … … 1866 1866 void f( int & r ); 1867 1867 void g( int * p ); 1868 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§1869 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§1868 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§ 1869 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§ 1870 1870 \end{cfa} 1871 1871 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ … … 1878 1878 \begin{cfa} 1879 1879 void f( int i ); 1880 void (* fp)( int ); §\C{// routine pointer}§1881 fp = f; §\C{// reference initialization}§1882 fp = &f; §\C{// pointer initialization}§1883 fp = *f; §\C{// reference initialization}§1884 fp(3); §\C{// reference invocation}§1885 (*fp)(3); §\C{// pointer invocation}§1880 void (* fp)( int ); §\C{// routine pointer}§ 1881 fp = f; §\C{// reference initialization}§ 1882 fp = &f; §\C{// pointer initialization}§ 1883 fp = *f; §\C{// reference initialization}§ 1884 fp(3); §\C{// reference invocation}§ 1885 (*fp)(3); §\C{// pointer invocation}§ 1886 1886 \end{cfa} 1887 1887 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type. 1888 1888 Instead, a routine object should be referenced by a ©const© reference: 1889 1889 \begin{cfa} 1890 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§1891 fr = ... §\C{// error, cannot change code}§1892 &fr = ...; §\C{// changing routine reference}§1893 fr( 3 ); §\C{// reference call to f}§1894 (*fr)(3); §\C{// error, incorrect type}§1890 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§ 1891 fr = ... §\C{// error, cannot change code}§ 1892 &fr = ...; §\C{// changing routine reference}§ 1893 fr( 3 ); §\C{// reference call to f}§ 1894 (*fr)(3); §\C{// error, incorrect type}§ 1895 1895 \end{cfa} 1896 1896 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{ … … 1914 1914 int x, * px, ** ppx, *** pppx, **** ppppx; 1915 1915 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 1916 x = rrrx; // rrrx is an lvalue with type int &&& (equivalent to x)1917 px = &rrrx; // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x)1918 ppx = &&rrrx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx)1919 pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx)1920 ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx)1916 x = rrrx; §\C[2.0in]{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§ 1917 px = &rrrx; §\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}§ 1918 ppx = &&rrrx; §\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}§ 1919 pppx = &&&rrrx; §\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}§ 1920 ppppx = &&&&rrrx; §\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}§ 1921 1921 \end{cfa} 1922 1922 The following example shows the second rule applied to different \Index{lvalue} contexts: … … 1924 1924 int x, * px, ** ppx, *** pppx; 1925 1925 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 1926 rrrx = 2; // rrrx is an lvalue with type int &&& (equivalent to x)1927 &rrrx = px; // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx)1928 &&rrrx = ppx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx)1929 &&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx)1926 rrrx = 2; §\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§ 1927 &rrrx = px; §\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (rx)}§ 1928 &&rrrx = ppx; §\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (rrx)}§ 1929 &&&rrrx = pppx; §\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (rrrx)}\CRT§ 1930 1930 \end{cfa} 1931 1931 … … 1940 1940 \begin{cfa} 1941 1941 int x; 1942 x + 1; // lvalue variable (int) converts to rvalue for expression1942 x + 1; §\C[2.0in]{// lvalue variable (int) converts to rvalue for expression}§ 1943 1943 \end{cfa} 1944 1944 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped. … … 1950 1950 \begin{cfa} 1951 1951 int x, &r = x, f( int p ); 1952 x = ®r® + f( ®r® ); // lvalue reference converts to rvalue1952 x = ®r® + f( ®r® ); §\C{// lvalue reference converts to rvalue}§ 1953 1953 \end{cfa} 1954 1954 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. … … 1957 1957 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references. 1958 1958 \begin{cfa} 1959 int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &)1960 f( ®x® ); // lvalue variable (int) convert to reference (int &)1959 int x, &r = ®x®, f( int & p ); §\C{// lvalue variable (int) convert to reference (int \&)}§ 1960 f( ®x® ); §\C{// lvalue variable (int) convert to reference (int \&)}§ 1961 1961 \end{cfa} 1962 1962 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. … … 1968 1968 \begin{cfa} 1969 1969 int x, & f( int & p ); 1970 f( ®x + 3® ); // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &)1971 ®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &)1970 f( ®x + 3® ); §\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}§ 1971 ®&f®(...) = &x; §\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT§ 1972 1972 \end{cfa} 1973 1973 In both case, modifications to the temporary are inaccessible (\Index{warning}). … … 2158 2158 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in: 2159 2159 \begin{cfa} 2160 [§\,§] g(); §\C{// no input or output parameters}§2161 [ void ] g( void ); §\C{// no input or output parameters}§2160 [§\,§] g(); §\C{// no input or output parameters}§ 2161 [ void ] g( void ); §\C{// no input or output parameters}§ 2162 2162 \end{cfa} 2163 2163 … … 2177 2177 \begin{cfa} 2178 2178 typedef int foo; 2179 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§2179 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§ 2180 2180 \end{cfa} 2181 2181 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo. … … 2185 2185 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg: 2186 2186 \begin{cfa} 2187 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§2188 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§2187 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§ 2188 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§ 2189 2189 \end{cfa} 2190 2190 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in: 2191 2191 \begin{cfa} 2192 2192 #define ptoa( n, d ) int (*n)[ d ] 2193 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§2194 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§2193 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§ 2194 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§ 2195 2195 \end{cfa} 2196 2196 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms. … … 2214 2214 int z; 2215 2215 ... x = 0; ... y = z; ... 2216 ®return;® §\C{// implicitly return x, y}§2216 ®return;® §\C{// implicitly return x, y}§ 2217 2217 } 2218 2218 \end{cfa} … … 2224 2224 [ int x, int y ] f() { 2225 2225 ... 2226 } §\C{// implicitly return x, y}§2226 } §\C{// implicitly return x, y}§ 2227 2227 \end{cfa} 2228 2228 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered. … … 2233 2233 [ int x, int y ] f( int, x, int y ) { 2234 2234 ... 2235 } §\C{// implicitly return x, y}§2235 } §\C{// implicitly return x, y}§ 2236 2236 \end{cfa} 2237 2237 This notation allows the compiler to eliminate temporary variables in nested routine calls. 2238 2238 \begin{cfa} 2239 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§2239 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§ 2240 2240 int a, b; 2241 2241 [a, b] = f( f( f( a, b ) ) ); … … 2251 2251 as well, parameter names are optional, \eg: 2252 2252 \begin{cfa} 2253 [ int x ] f (); §\C{// returning int with no parameters}§2254 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§2255 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§2256 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§2253 [ int x ] f (); §\C{// returning int with no parameters}§ 2254 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§ 2255 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§ 2256 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§ 2257 2257 \end{cfa} 2258 2258 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa). … … 2275 2275 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg: 2276 2276 \begin{cfa} 2277 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§2278 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§2279 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§2280 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}§2277 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§ 2278 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§ 2279 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§ 2280 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}§ 2281 2281 \end{cfa} 2282 2282 While parameter names are optional, \emph{a routine name cannot be specified}; 2283 2283 for example, the following is incorrect: 2284 2284 \begin{cfa} 2285 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§2285 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§ 2286 2286 \end{cfa} 2287 2287 … … 2306 2306 whereas a named (keyword) call may be: 2307 2307 \begin{cfa} 2308 p( z : 3, x : 4, y : 7 ); §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§2308 p( z : 3, x : 4, y : 7 ); §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§ 2309 2309 \end{cfa} 2310 2310 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters. … … 2323 2323 For example, the following routine prototypes and definition are all valid. 2324 2324 \begin{cfa} 2325 void p( int, int, int ); §\C{// equivalent prototypes}§2325 void p( int, int, int ); §\C{// equivalent prototypes}§ 2326 2326 void p( int x, int y, int z ); 2327 2327 void p( int y, int x, int z ); 2328 2328 void p( int z, int y, int x ); 2329 void p( int q, int r, int s ) {} §\C{// match with this definition}§2329 void p( int q, int r, int s ) {} §\C{// match with this definition}§ 2330 2330 \end{cfa} 2331 2331 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming. … … 2339 2339 int f( int x, double y ); 2340 2340 2341 f( j : 3, i : 4 ); §\C{// 1st f}§2342 f( x : 7, y : 8.1 ); §\C{// 2nd f}§2343 f( 4, 5 ); §\C{// ambiguous call}§2341 f( j : 3, i : 4 ); §\C{// 1st f}§ 2342 f( x : 7, y : 8.1 ); §\C{// 2nd f}§ 2343 f( 4, 5 ); §\C{// ambiguous call}§ 2344 2344 \end{cfa} 2345 2345 However, named arguments compound routine resolution in conjunction with conversions: 2346 2346 \begin{cfa} 2347 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§2347 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§ 2348 2348 \end{cfa} 2349 2349 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous. … … 2359 2359 the allowable positional calls are: 2360 2360 \begin{cfa} 2361 p(); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§2362 p( 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§2363 p( 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§2364 p( 4, 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 4 )}§2361 p(); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§ 2362 p( 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§ 2363 p( 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§ 2364 p( 4, 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 4 )}§ 2365 2365 // empty arguments 2366 p( , 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 4 )}§2367 p( 4, , 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 4 )}§2368 p( 4, 4, ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§2369 p( 4, , ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§2370 p( , 4, ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 3 )}§2371 p( , , 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 4 )}§2372 p( , , ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§2366 p( , 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 4 )}§ 2367 p( 4, , 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 4 )}§ 2368 p( 4, 4, ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§ 2369 p( 4, , ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§ 2370 p( , 4, ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 3 )}§ 2371 p( , , 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 4 )}§ 2372 p( , , ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§ 2373 2373 \end{cfa} 2374 2374 Here the missing arguments are inserted from the default values in the parameter list. … … 2394 2394 Default values may only appear in a prototype versus definition context: 2395 2395 \begin{cfa} 2396 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§2397 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§2398 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§2396 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§ 2397 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§ 2398 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§ 2399 2399 \end{cfa} 2400 2400 The reason for this restriction is to allow separate compilation. … … 2421 2421 \begin{cfa} 2422 2422 void p( int x, int y = 2, int z = 3... ); 2423 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§2424 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§2423 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§ 2424 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§ 2425 2425 \end{cfa} 2426 2426 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments; … … 2452 2452 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as: 2453 2453 \begin{cfa} 2454 p( 1, /* default */, 5 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§2454 p( 1, /* default */, 5 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§ 2455 2455 \end{cfa} 2456 2456 … … 2465 2465 \begin{cfa} 2466 2466 struct { 2467 int f1; §\C{// named field}§2468 int f2 : 4; §\C{// named field with bit field size}§2469 int : 3; §\C{// unnamed field for basic type with bit field size}§2470 int ; §\C{// disallowed, unnamed field}§2471 int *; §\C{// disallowed, unnamed field}§2472 int (*)( int ); §\C{// disallowed, unnamed field}§2467 int f1; §\C{// named field}§ 2468 int f2 : 4; §\C{// named field with bit field size}§ 2469 int : 3; §\C{// unnamed field for basic type with bit field size}§ 2470 int ; §\C{// disallowed, unnamed field}§ 2471 int *; §\C{// disallowed, unnamed field}§ 2472 int (*)( int ); §\C{// disallowed, unnamed field}§ 2473 2473 }; 2474 2474 \end{cfa} … … 2478 2478 \begin{cfa} 2479 2479 struct { 2480 int , , ; §\C{// 3 unnamed fields}§2480 int , , ; §\C{// 3 unnamed fields}§ 2481 2481 } 2482 2482 \end{cfa} … … 2572 2572 const unsigned int size = 5; 2573 2573 int ia[size]; 2574 ... §\C{// assign values to array ia}§2575 qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§2574 ... §\C{// assign values to array ia}§ 2575 qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§ 2576 2576 { 2577 2577 ®int ?<?( int x, int y ) { return x > y; }® §\C{// nested routine}§ 2578 qsort( ia, size ); §\C{// sort descending order by local redefinition}§2578 qsort( ia, size ); §\C{// sort descending order by local redefinition}§ 2579 2579 } 2580 2580 \end{cfa} … … 2584 2584 The following program in undefined in \CFA (and Indexc{gcc}) 2585 2585 \begin{cfa} 2586 [* [int]( int )] foo() { §\C{// int (* foo())( int )}§2586 [* [int]( int )] foo() { §\C{// int (* foo())( int )}§ 2587 2587 int ®i® = 7; 2588 2588 int bar( int p ) { 2589 ®i® += 1; §\C{// dependent on local variable}§2589 ®i® += 1; §\C{// dependent on local variable}§ 2590 2590 sout | ®i®; 2591 2591 } 2592 return bar; §\C{// undefined because of local dependence}§2592 return bar; §\C{// undefined because of local dependence}§ 2593 2593 } 2594 2594 int main() { 2595 * [int]( int ) fp = foo(); §\C{// int (* fp)( int )}§2595 * [int]( int ) fp = foo(); §\C{// int (* fp)( int )}§ 2596 2596 sout | fp( 3 ); 2597 2597 } … … 2606 2606 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call. 2607 2607 \begin{cfa} 2608 f( ®2, x, 3 + i® ); §\C{// element list}§2608 f( ®2, x, 3 + i® ); §\C{// element list}§ 2609 2609 \end{cfa} 2610 2610 A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}. … … 2623 2623 typedef struct { int quot, rem; } div_t; §\C[7cm]{// from include stdlib.h}§ 2624 2624 div_t div( int num, int den ); 2625 div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§2626 printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§2625 div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§ 2626 printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§ 2627 2627 \end{cfa} 2628 2628 This approach requires a name for the return type and fields, where \Index{naming} is a common programming-language issue. … … 2634 2634 For example, consider C's \Indexc{modf} function, which returns the integral and fractional part of a floating value. 2635 2635 \begin{cfa} 2636 double modf( double x, double * i ); §\C{// from include math.h}§2637 double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§2638 printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§2636 double modf( double x, double * i ); §\C{// from include math.h}§ 2637 double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§ 2638 printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§ 2639 2639 \end{cfa} 2640 2640 This approach requires allocating storage for the return values, which complicates the call site with a sequence of variable declarations leading to the call. … … 2663 2663 When a function call is passed as an argument to another call, the best match of actual arguments to formal parameters is evaluated given all possible expression interpretations in the current scope. 2664 2664 \begin{cfa} 2665 void g( int, int ); §\C{// 1}§2666 void g( double, double ); §\C{// 2}§2667 g( div( 13, 5 ) ); §\C{// select 1}§2668 g( modf( 13.5 ) ); §\C{// select 2}§2665 void g( int, int ); §\C{// 1}§ 2666 void g( double, double ); §\C{// 2}§ 2667 g( div( 13, 5 ) ); §\C{// select 1}§ 2668 g( modf( 13.5 ) ); §\C{// select 2}§ 2669 2669 \end{cfa} 2670 2670 In this case, there are two overloaded ©g© routines. … … 2675 2675 The previous examples can be rewritten passing the multiple returned-values directly to the ©printf© function call. 2676 2676 \begin{cfa} 2677 [ int, int ] div( int x, int y ); §\C{// from include stdlib}§2678 printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§2679 2680 [ double, double ] modf( double x ); §\C{// from include math}§2681 printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§2677 [ int, int ] div( int x, int y ); §\C{// from include stdlib}§ 2678 printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§ 2679 2680 [ double, double ] modf( double x ); §\C{// from include math}§ 2681 printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§ 2682 2682 \end{cfa} 2683 2683 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type. … … 2689 2689 \begin{cfa} 2690 2690 int quot, rem; 2691 [ quot, rem ] = div( 13, 5 ); §\C{// assign multiple variables}§2692 printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§2691 [ quot, rem ] = div( 13, 5 ); §\C{// assign multiple variables}§ 2692 printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§ 2693 2693 \end{cfa} 2694 2694 Here, the multiple return-values are matched in much the same way as passing multiple return-values to multiple parameters in a call. … … 2716 2716 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}. 2717 2717 \begin{cfa} 2718 [int, int] ®qr® = div( 13, 5 ); §\C{// initialize tuple variable}§2719 printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§2718 [int, int] ®qr® = div( 13, 5 ); §\C{// initialize tuple variable}§ 2719 printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§ 2720 2720 \end{cfa} 2721 2721 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}. … … 2723 2723 One way to access the individual components of a tuple variable is with assignment. 2724 2724 \begin{cfa} 2725 [ quot, rem ] = qr; §\C{// assign multiple variables}§2725 [ quot, rem ] = qr; §\C{// assign multiple variables}§ 2726 2726 \end{cfa} 2727 2727 … … 2746 2746 [int, double] * p; 2747 2747 2748 int y = x.0; §\C{// access int component of x}§2749 y = f().1; §\C{// access int component of f}§2750 p->0 = 5; §\C{// access int component of tuple pointed-to by p}§2751 g( x.1, x.0 ); §\C{// rearrange x to pass to g}§2752 double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§2748 int y = x.0; §\C{// access int component of x}§ 2749 y = f().1; §\C{// access int component of f}§ 2750 p->0 = 5; §\C{// access int component of tuple pointed-to by p}§ 2751 g( x.1, x.0 ); §\C{// rearrange x to pass to g}§ 2752 double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§ 2753 2753 \end{cfa} 2754 2754 Tuple-index expressions can occur on any tuple-typed expression, including tuple-returning functions, square-bracketed tuple expressions, and other tuple-index expressions, provided the retrieved component is also a tuple. … … 2817 2817 double y; 2818 2818 [int, double] z; 2819 [y, x] = 3.14; §\C{// mass assignment}§2819 [y, x] = 3.14; §\C{// mass assignment}§ 2820 2820 [x, y] = z; §\C{// multiple assignment}§ 2821 2821 z = 10; §\C{// mass assignment}§ 2822 z = [x, y]; §\C{// multiple assignment}§2822 z = [x, y]; §\C{// multiple assignment}§ 2823 2823 \end{cfa} 2824 2824 Let $L_i$ for $i$ in $[0, n)$ represent each component of the flattened left side, $R_i$ represent each component of the flattened right side of a multiple assignment, and $R$ represent the right side of a mass assignment. … … 2864 2864 double c, d; 2865 2865 [ void ] f( [ int, int ] ); 2866 f( [ c, a ] = [ b, d ] = 1.5 ); // assignments in parameter list2866 f( [ c, a ] = [ b, d ] = 1.5 ); §\C{// assignments in parameter list}§ 2867 2867 \end{cfa} 2868 2868 The tuple expression begins with a mass assignment of ©1.5© into ©[b, d]©, which assigns ©1.5© into ©b©, which is truncated to ©1©, and ©1.5© into ©d©, producing the tuple ©[1, 1.5]© as a result. … … 2877 2877 \begin{cfa} 2878 2878 struct S; 2879 void ?{}(S *); // (1)2880 void ?{}(S *, int); // (2)2881 void ?{}(S * double); // (3)2882 void ?{}(S *, S); // (4)2883 2884 [S, S] x = [3, 6.28]; // uses (2), (3), specialized constructors2885 [S, S] y; // uses (1), (1), default constructor2886 [S, S] z = x.0; // uses (4), (4), copy constructor2879 void ?{}(S *); §\C{// (1)}§ 2880 void ?{}(S *, int); §\C{// (2)}§ 2881 void ?{}(S * double); §\C{// (3)}§ 2882 void ?{}(S *, S); §\C{// (4)}§ 2883 2884 [S, S] x = [3, 6.28]; §\C{// uses (2), (3), specialized constructors}§ 2885 [S, S] y; §\C{// uses (1), (1), default constructor}§ 2886 [S, S] z = x.0; §\C{// uses (4), (4), copy constructor}§ 2887 2887 \end{cfa} 2888 2888 In this example, ©x© is initialized by the multiple constructor calls ©?{}(&x.0, 3)© and ©?{}(&x.1, 6.28)©, while ©y© is initialized by two default constructor calls ©?{}(&y.0)© and ©?{}(&y.1)©. … … 2925 2925 A member-access tuple may be used anywhere a tuple can be used, \eg: 2926 2926 \begin{cfa} 2927 s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§2928 f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§2927 s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§ 2928 f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§ 2929 2929 \end{cfa} 2930 2930 Note, the fields appearing in a record-field tuple may be specified in any order; … … 2936 2936 void f( double, long ); 2937 2937 2938 f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§2939 x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§2938 f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§ 2939 x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§ 2940 2940 [ long, int, long ] y = x.[ 2, 0, 2 ]; 2941 2941 \end{cfa} … … 2954 2954 \begin{cfa} 2955 2955 [ int, float, double ] f(); 2956 [ double, float ] x = f().[ 2, 1 ]; §\C{// f() called once}§2956 [ double, float ] x = f().[ 2, 1 ]; §\C{// f() called once}§ 2957 2957 \end{cfa} 2958 2958 … … 2967 2967 That is, a cast can be used to select the type of an expression when it is ambiguous, as in the call to an overloaded function. 2968 2968 \begin{cfa} 2969 int f(); // (1)2970 double f(); // (2)2971 2972 f(); // ambiguous - (1),(2) both equally viable2973 (int)f(); // choose (2)2969 int f(); §\C{// (1)}§ 2970 double f(); §\C{// (2)}§ 2971 2972 f(); §\C{// ambiguous - (1),(2) both equally viable}§ 2973 (int)f(); §\C{// choose (2)}§ 2974 2974 \end{cfa} 2975 2975 Since casting is a fundamental operation in \CFA, casts need to be given a meaningful interpretation in the context of tuples. … … 2979 2979 void g(); 2980 2980 2981 (void)f(); // valid, ignore results2982 (int)g(); // invalid, void cannot be converted to int2981 (void)f(); §\C{// valid, ignore results}§ 2982 (int)g(); §\C{// invalid, void cannot be converted to int}§ 2983 2983 2984 2984 struct A { int x; }; 2985 (struct A)f(); // invalid, int cannot be converted to A2985 (struct A)f(); §\C{// invalid, int cannot be converted to A}§ 2986 2986 \end{cfa} 2987 2987 In C, line 4 is a valid cast, which calls ©f© and discards its result. … … 2999 2999 [int, [int, int], int] g(); 3000 3000 3001 ([int, double])f(); // (1) valid3002 ([int, int, int])g(); // (2) valid3003 ([void, [int, int]])g(); // (3) valid3004 ([int, int, int, int])g(); // (4) invalid3005 ([int, [int, int, int]])g(); // (5) invalid3001 ([int, double])f(); §\C{// (1) valid}§ 3002 ([int, int, int])g(); §\C{// (2) valid}§ 3003 ([void, [int, int]])g(); §\C{// (3) valid}§ 3004 ([int, int, int, int])g(); §\C{// (4) invalid}§ 3005 ([int, [int, int, int]])g(); §\C{// (5) invalid}§ 3006 3006 \end{cfa} 3007 3007 … … 3063 3063 void f([int, int], int, int); 3064 3064 3065 f([0, 0], 0, 0); // no cost3066 f(0, 0, 0, 0); // cost for structuring3067 f([0, 0,], [0, 0]); // cost for flattening3068 f([0, 0, 0], 0); // cost for flattening and structuring3065 f([0, 0], 0, 0); §\C{// no cost}§ 3066 f(0, 0, 0, 0); §\C{// cost for structuring}§ 3067 f([0, 0,], [0, 0]); §\C{// cost for flattening}§ 3068 f([0, 0, 0], 0); §\C{// cost for flattening and structuring}§ 3069 3069 \end{cfa} 3070 3070 … … 3129 3129 [ unsigned int, char ] 3130 3130 [ double, double, double ] 3131 [ * int, int * ] §\C{// mix of CFA and ANSI}§3131 [ * int, int * ] §\C{// mix of CFA and ANSI}§ 3132 3132 [ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ] 3133 3133 \end{cfa} … … 3136 3136 Examples of declarations using tuple types are: 3137 3137 \begin{cfa} 3138 [ int, int ] x; §\C{// 2 element tuple, each element of type int}§3139 * [ char, char ] y; §\C{// pointer to a 2 element tuple}§3138 [ int, int ] x; §\C{// 2 element tuple, each element of type int}§ 3139 * [ char, char ] y; §\C{// pointer to a 2 element tuple}§ 3140 3140 [ [ int, int ] ] z ([ int, int ]); 3141 3141 \end{cfa} … … 3154 3154 [ int, int ] w1; 3155 3155 [ int, int, int ] w2; 3156 [ void ] f (int, int, int); /* three input parameters of type int */3157 [ void ] g ([ int, int, int ]); /* 3 element tuple as input */3156 [ void ] f (int, int, int); §\C{// three input parameters of type int}§ 3157 [ void ] g ([ int, int, int ]); §\C{3 element tuple as input}§ 3158 3158 f( [ 1, 2, 3 ] ); 3159 3159 f( w1, 3 ); … … 3235 3235 [ int, int, int, int ] w = [ 1, 2, 3, 4 ]; 3236 3236 int x = 5; 3237 [ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§3237 [ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§ 3238 3238 \end{cfa} 3239 3239 Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values; … … 3323 3323 both these examples produce indeterminate results: 3324 3324 \begin{cfa} 3325 f( x++, x++ ); §\C{// C routine call with side effects in arguments}§3326 [ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in righthand side of multiple assignment}§3325 f( x++, x++ ); §\C{// C routine call with side effects in arguments}§ 3326 [ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in righthand side of multiple assignment}§ 3327 3327 \end{cfa} 3328 3328 … … 3346 3346 3347 3347 3348 \section{I/O Library} 3349 \label{s:IOLibrary} 3350 \index{input/output library} 3351 3352 The goal of \CFA I/O is to simplify the common cases\index{I/O!common case}, while fully supporting polymorphism and user defined types in a consistent way. 3353 The approach combines ideas from \CC and Python. 3354 The \CFA header file for the I/O library is \Indexc{fstream}. 3355 3356 The common case is printing out a sequence of variables separated by whitespace. 3348 \section{I/O Stream Library} 3349 \label{s:IOStreamLibrary} 3350 \index{input/output stream library} 3351 \index{stream library} 3352 3353 The goal of \CFA input/output (I/O) is to simplify the common cases\index{I/O!common case}, while fully supporting polymorphism and user defined types in a consistent way. 3354 \CFA I/O combines ideas from C ©printf©, \CC, and Python. 3355 I/O can be unformatted or formatted. 3356 Unformatted means \CFA selects the output or input format for values that match with the type of a variable. 3357 Formatted means additional information is specified to augment how an output or input of value is interpreted. 3358 \CFA formatting is a cross between C ©printf© and \CC ©cout© manipulators. 3359 \begin{itemize} 3360 \item 3361 ©printf© format codes are dense, making them difficult to read and remember. 3362 \CFA/\CC format manipulators are named, making them easier to read and remember. 3363 \item 3364 ©printf© separates format codes from associated variables, making it difficult to match codes with variables. 3365 \CFA/\CC co-locate codes with associated variables, where \CFA has the tighter binding. 3366 \item 3367 Format manipulators in \CC have global rather than local effect, except ©setw©. 3368 Hence, it is common programming practice to toggle manipulators on and then back to the default to prevent downstream side-effects. 3369 Without this programming style, errors occur when moving prints, as manipulator effects incorrectly flow into the new location. 3370 (To guarantee no side-effects, manipulator values must be saved and restored across function calls.) 3371 \end{itemize} 3372 The \CFA header file for the I/O library is \Indexc{fstream.hfa}. 3373 3374 For unformatted output, the common case is printing a sequence of variables separated by whitespace. 3357 3375 \begin{cquote} 3358 3376 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} … … 3373 3391 & 3374 3392 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3375 1 233393 1® ®2® ®3 3376 3394 \end{cfa} 3377 3395 \end{tabular} 3378 3396 \end{cquote} 3379 The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators .3380 Similar simplification occurs for \Index{tuple} I/O, which prints all tuple valuesseparated by ``\lstinline[showspaces=true]@, @''.3397 The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators and newline. 3398 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]@, @''. 3381 3399 \begin{cfa} 3382 3400 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ]; 3383 sout | t1 | t2; §\C{// print tuples}§3401 sout | t1 | t2; §\C{// print tuples}§ 3384 3402 \end{cfa} 3385 3403 \begin{cfa}[showspaces=true,aboveskip=0pt] 3386 3404 1®, ®2®, ®3 4®, ®5®, ®6 3387 3405 \end{cfa} 3388 Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority overloadableoperator, other than assignment.3406 Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment. 3389 3407 Therefore, fewer output expressions require parenthesis. 3390 3408 \begin{cquote} … … 3393 3411 & 3394 3412 \begin{cfa} 3395 sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2);3413 sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®; 3396 3414 \end{cfa} 3397 3415 \\ … … 3399 3417 & 3400 3418 \begin{cfa} 3401 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << (x | y) << (x || y) << (x > z ? 1 : 2)<< endl;3419 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)® << endl; 3402 3420 \end{cfa} 3403 3421 \\ … … 3408 3426 \end{tabular} 3409 3427 \end{cquote} 3410 There is a weak similarity between the \CFA logical-or operator and the Shell pipe-operator for moving data, where data flows in the correct direction for input but the opposite direction for output. 3428 Input and output use a uniform operator, ©|©, rather than separate operators, as in ©>>© and ©<<© for \CC. 3429 There is a weak similarity between the \CFA logical-or operator and the \Index{Shell pipe-operator} for moving data, where data flows in the correct direction for input but the opposite direction for output. 3430 3431 For unformatter input, the common case is reading a sequence of values separated by whitespace, where the type of an input constant must match with the type of the input variable. 3432 \begin{cquote} 3433 \begin{lrbox}{\LstBox} 3434 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 3435 int x; double y char z; 3436 \end{cfa} 3437 \end{lrbox} 3438 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 3439 \multicolumn{1}{@{}l@{}}{\usebox\LstBox} \\ 3440 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\ 3441 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 3442 sin | x | y | z; 3443 \end{cfa} 3444 & 3445 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 3446 cin >> x >> y >> z; 3447 \end{cfa} 3448 \\ 3449 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3450 ®1® ®2.5® ®A® 3451 \end{cfa} 3452 & 3453 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3454 ®1® ®2.5® ®A® 3455 \end{cfa} 3456 \end{tabular} 3457 \end{cquote} 3458 3411 3459 3412 3460 3413 3461 \subsection{Implicit Separator} 3414 3462 3415 The \Index{implicit separator}\index{I/O!separator} character (space/blank) is a separator not a terminator .3463 The \Index{implicit separator}\index{I/O!separator} character (space/blank) is a separator not a terminator for output. 3416 3464 The rules for implicitly adding the separator are: 3417 3465 \begin{enumerate} … … 3441 3489 3442 3490 \item 3443 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \lstinline[mathescape=off,basicstyle=\tt]@([{=$£¥¡¿«@ 3491 {\lstset{language=CFA,deletedelim=**[is][]{¢}{¢}} 3492 A seperator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \lstinline[basicstyle=\tt]@,.;!?)]}%¢»@ 3493 \begin{cfa}[belowskip=0pt] 3494 sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x" 3495 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x"; 3496 \end{cfa} 3497 \begin{cfa}[basicstyle=\tt,showspaces=true,aboveskip=0pt,belowskip=0pt] 3498 1®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7§\color{red}\textcent§ x 8®»® x 9®)® x 10®]® x 11®}® x 3499 \end{cfa}}% 3500 where \lstinline[basicstyle=\tt]@»@ is a closing citation mark. 3501 3502 \item 3503 A separator does not appear after a C string ending with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \lstinline[mathescape=off,basicstyle=\tt]@([{=$£¥¡¿«@ 3444 3504 %$ 3445 3505 \begin{cfa}[mathescape=off] … … 3455 3515 3456 3516 \item 3457 {\lstset{language=CFA,deletedelim=**[is][]{¢}{¢}} 3458 A seperator does not appear after a C string ending with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \lstinline[basicstyle=\tt]@,.;!?)]}%¢»@ 3459 \begin{cfa}[belowskip=0pt] 3460 sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x" 3461 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x"; 3462 \end{cfa} 3463 \begin{cfa}[basicstyle=\tt,showspaces=true,aboveskip=0pt,belowskip=0pt] 3464 1®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7§\color{red}\textcent§ x 8®»® x 9®)® x 10®]® x 11®}® x 3465 \end{cfa}}% 3466 where \lstinline[basicstyle=\tt]@»@ is a closing citation mark. 3467 3468 \item 3469 A seperator does not appear before or after a C string begining/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]@`'": \t\v\f\r\n@ 3517 A seperator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]@`'": \t\v\f\r\n@ 3470 3518 \begin{cfa}[belowskip=0pt] 3471 3519 sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx"; … … 3486 3534 3487 3535 3488 \subsection{Manipulator} 3489 3490 The following \CC-style \Index{manipulator}s and routines control implicit seperation. 3536 \subsection{Separation Manipulators} 3537 3538 The following \Index{manipulator}s control \Index{implicit output separation}. 3539 The effect of these manipulators is global for an output stream (except ©sepOn© and ©sepOff©). 3491 3540 \begin{enumerate} 3492 3541 \item 3493 Routines\Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string.3542 \Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string. 3494 3543 The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 3495 3544 \begin{cfa}[mathescape=off,belowskip=0pt] 3496 sepSet( sout, ", $" ); §\C{// set separator from " " to ", \$"}§3545 sepSet( sout, ", $" ); §\C{// set separator from " " to ", \$"}§ 3497 3546 sout | 1 | 2 | 3 | " \"" | ®sep® | "\""; 3498 3547 \end{cfa} … … 3503 3552 %$ 3504 3553 \begin{cfa}[belowskip=0pt] 3505 sepSet( sout, " " ); §\C{// reset separator to " "}§3554 sepSet( sout, " " ); §\C{// reset separator to " "}§ 3506 3555 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\""; 3507 3556 \end{cfa} … … 3511 3560 ©sepGet© can be used to store a separator and then restore it: 3512 3561 \begin{cfa}[belowskip=0pt] 3513 char store[®sepSize®]; §\C{// sepSize is the maximum separator size}§3514 strcpy( store, sepGet( sout ) ); §\C{// copy current separator}§3515 sepSet( sout, "_" ); §\C{// change separator to underscore}§3562 char store[®sepSize®]; §\C{// sepSize is the maximum separator size}§ 3563 strcpy( store, sepGet( sout ) ); §\C{// copy current separator}§ 3564 sepSet( sout, "_" ); §\C{// change separator to underscore}§ 3516 3565 sout | 1 | 2 | 3; 3517 3566 \end{cfa} … … 3520 3569 \end{cfa} 3521 3570 \begin{cfa}[belowskip=0pt] 3522 sepSet( sout, store ); §\C{// change separator back to original}§3571 sepSet( sout, store ); §\C{// change separator back to original}§ 3523 3572 sout | 1 | 2 | 3; 3524 3573 \end{cfa} … … 3528 3577 3529 3578 \item 3530 Routine\Indexc{sepSetTuple}\index{manipulator!sepSetTuple@©sepSetTuple©} and \Indexc{sepTuple}\index{manipulator!sepTuple@©sepTuple©}/\Indexc{sepGetTuple}\index{manipulator!sepGetTuple@©sepGetTuple©} get and set the tuple separator-string.3579 \Indexc{sepSetTuple}\index{manipulator!sepSetTuple@©sepSetTuple©} and \Indexc{sepTuple}\index{manipulator!sepTuple@©sepTuple©}/\Indexc{sepGetTuple}\index{manipulator!sepGetTuple@©sepGetTuple©} get and set the tuple separator-string. 3531 3580 The tuple separator-string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 3532 3581 \begin{cfa}[belowskip=0pt] 3533 sepSetTuple( sout, " " ); §\C{// set tuple separator from ", " to " "}§3582 sepSetTuple( sout, " " ); §\C{// set tuple separator from ", " to " "}§ 3534 3583 sout | t1 | t2 | " \"" | ®sepTuple® | "\""; 3535 3584 \end{cfa} … … 3538 3587 \end{cfa} 3539 3588 \begin{cfa}[belowskip=0pt] 3540 sepSetTuple( sout, ", " ); §\C{// reset tuple separator to ", "}§3589 sepSetTuple( sout, ", " ); §\C{// reset tuple separator to ", "}§ 3541 3590 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\""; 3542 3591 \end{cfa} … … 3547 3596 3548 3597 \item 3549 Manipulators \Indexc{sepDisable}\index{manipulator!sepDisable@©sepDisable©} and \Indexc{sepEnable}\index{manipulator!sepEnable@©sepEnable©} \emph{globally} toggle printing the separator, \ie the seperator is adjusted with respect to all subsequent printed items.3598 \Indexc{sepDisable}\index{manipulator!sepDisable@©sepDisable©} and \Indexc{sepEnable}\index{manipulator!sepEnable@©sepEnable©} toggle printing the separator. 3550 3599 \begin{cfa}[belowskip=0pt] 3551 sout | sepDisable | 1 | 2 | 3; §\C{// globallyturn off implicit separator}§3600 sout | sepDisable | 1 | 2 | 3; §\C{// turn off implicit separator}§ 3552 3601 \end{cfa} 3553 3602 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3555 3604 \end{cfa} 3556 3605 \begin{cfa}[belowskip=0pt] 3557 sout | sepEnable | 1 | 2 | 3; §\C{// globallyturn on implicit separator}§3606 sout | sepEnable | 1 | 2 | 3; §\C{// turn on implicit separator}§ 3558 3607 \end{cfa} 3559 3608 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3562 3611 3563 3612 \item 3564 Manipulators \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} \emph{locally} toggle printing the separator, \ie the seperator is adjusted only with respect to the next printed item.3613 \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} toggle printing the separator with respect to the next printed item, and then return to the global seperator setting. 3565 3614 \begin{cfa}[belowskip=0pt] 3566 sout | 1 | sepOff | 2 | 3; §\C{// locally turn off implicit separator}§3615 sout | 1 | sepOff | 2 | 3; §\C{// turn off implicit separator for the next item}§ 3567 3616 \end{cfa} 3568 3617 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3570 3619 \end{cfa} 3571 3620 \begin{cfa}[belowskip=0pt] 3572 sout | sepDisable | 1 | sepOn | 2 | 3; §\C{// locally turn on implicit separator}§3621 sout | sepDisable | 1 | sepOn | 2 | 3; §\C{// turn on implicit separator for the next item}§ 3573 3622 \end{cfa} 3574 3623 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3577 3626 The tuple separator also responses to being turned on and off. 3578 3627 \begin{cfa}[belowskip=0pt] 3579 sout | t1 | sepOff | t2; §\C{// locally turn on/off implicit separator}§3628 sout | t1 | sepOff | t2; §\C{// locally turn on/off implicit separator}§ 3580 3629 \end{cfa} 3581 3630 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3585 3634 use ©sep© to accomplish this functionality. 3586 3635 \begin{cfa}[belowskip=0pt] 3587 sout | sepOn | 1 | 2 | 3 | sepOn; §\C{// sepOn does nothing at start/end of line}§3636 sout | sepOn | 1 | 2 | 3 | sepOn; §\C{// sepOn does nothing at start/end of line}§ 3588 3637 \end{cfa} 3589 3638 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 3591 3640 \end{cfa} 3592 3641 \begin{cfa}[belowskip=0pt] 3593 sout | sep | 1 | 2 | 3 | sep ; §\C{// use sep to print separator at start/end of line}§3642 sout | sep | 1 | 2 | 3 | sep ; §\C{// use sep to print separator at start/end of line}§ 3594 3643 \end{cfa} 3595 3644 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3596 3645 ® ®1 2 3® ® 3646 \end{cfa} 3647 \end{enumerate} 3648 3649 3650 \subsection{Newline Manipulators} 3651 3652 The following \Index{manipulator} controls \Index{newline separation} for input and output. 3653 3654 For input: 3655 \begin{enumerate}[parsep=0pt] 3656 \item 3657 \Indexc{nl}\index{manipulator!nl@©nl©} scans characters until the next newline character, i.e., ignore the remaining characters in the line. 3658 \item 3659 \Indexc{nlOn}\index{manipulator!nlOn@©nlOn©} reads the newline character, when reading single characters. 3660 \item 3661 \Indexc{nlOff}\index{manipulator!nlOff@©nlOff©} does \emph{not} read the newline character, when reading single characters. 3662 \end{enumerate} 3663 For example, in: 3664 \begin{cfa} 3665 sin | i | ®nl® | j; 3666 1 ®2® 3667 3 3668 \end{cfa} 3669 variable ©i© is assigned 1, the 2 is skipped, and variable ©j© is assigned 3. 3670 3671 For output: 3672 \begin{enumerate}[parsep=0pt] 3673 \item 3674 \Indexc{nl}\index{manipulator!nl@©nl©} inserts a newline. 3675 \begin{cfa} 3676 sout | nl; §\C{// only print newline}§ 3677 sout | 2; §\C{// implicit newline}§ 3678 sout | 3 | nl | 4 | nl; §\C{// terminating nl merged with implicit newline}§ 3679 sout | 5 | nl | nl; §\C{// again terminating nl merged with implicit newline}§ 3680 sout | 6; §\C{// implicit newline}§ 3681 3682 2 3683 3 3684 4 3685 5 3686 3687 6 3688 \end{cfa} 3689 Note, a terminating ©nl© is merged (overrides) with the implicit newline at the end of the ©sout© expression, otherwise it is impossible to to print a single newline 3690 \item 3691 \Indexc{nlOn}\index{manipulator!nlOn@©nlOn©} implicitly prints a newline at the end of each output expression. 3692 \item 3693 \Indexc{nlOff}\index{manipulator!nlOff@©nlOff©} does \emph{not} implicitly print a newline at the end of each output expression. 3694 \end{enumerate} 3695 3696 3697 \subsection{Output Value Manipulators} 3698 3699 The following \Index{manipulator}s control formatting of output values (printing), and only affect the format of the argument. 3700 \begin{enumerate} 3701 \item 3702 \Indexc{bin}( integer )\index{manipulator!bin@©bin©} print value in base 2 preceded by ©0b©/©0B©. 3703 \begin{cfa}[belowskip=0pt] 3704 sout | bin( 0 ) | bin( 27HH ) | bin( 27H ) | bin( 27 ) | bin( 27L ); 3705 0b0 0b11011 0b11011 0b11011 0b11011 3706 sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L ); 3707 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b(58 1s)100101 3708 \end{cfa} 3709 3710 \item 3711 \Indexc{oct}( integer )\index{manipulator!oct@©oct©} print value in base 8 preceded by ©0©. 3712 \begin{cfa}[belowskip=0pt] 3713 sout | oct( 0 ) | oct( 27HH ) | oct( 27H ) | oct( 27 ) | oct( 27L ); 3714 0 033 033 033 033 3715 sout | oct( -27HH ) | oct( -27H ) | oct( -27 ) | oct( -27L ); 3716 0345 0177745 037777777745 01777777777777777777745 3717 \end{cfa} 3718 Note, octal 0 is \emph{not} preceded by ©0© to prevent confusion. 3719 3720 \item 3721 \Indexc{hex}( integer / floating-point )\index{manipulator!hex@©hex©} print value in base 16 preceded by ©0x©/©0X©. 3722 \begin{cfa}[belowskip=0pt] 3723 sout | hex( 0 ) | hex( 27HH ) | hex( 27H ) | hex( 27 ) | hex( 27L ); 3724 0 0x1b 0x1b 0x1b 0x1b 3725 sout | hex( -27HH ) | hex( -27H ) | hex( -27 ) | hex( -27L ); 3726 0xe5 0xffe5 0xffffffe5 0xffffffffffffffe5 3727 3728 sout | hex( 0.0 ) | hex( 27.5F ) | hex( 27.5 ) | hex( 27.5L ); 3729 0x0.p+0 0x1.b8p+4 0x1.b8p+4 0xd.cp+1 3730 sout | hex( -27.5F ) | hex( -27.5 ) | hex( -27.5L ); 3731 -0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1 3732 \end{cfa} 3733 3734 \item 3735 \Indexc{sci}( floating-point )\index{manipulator!sci@©sci©} print value in scientific notation with exponent. 3736 Default is 6 digits of precision. 3737 \begin{cfa}[belowskip=0pt] 3738 sout | sci( 0.0 ) | sci( 27.5 ) | sci( -27.5 ); 3739 0.000000e+00 2.750000e+01 -2.750000e+01 3740 \end{cfa} 3741 3742 \item 3743 \Indexc{upcase}( bin / hex / floating-point )\index{manipulator!upcase@©upcase©} print letters in a value in upper case. Lower case is the default. 3744 \begin{cfa}[belowskip=0pt] 3745 sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) ); 3746 0®B®11011 0®X®1®B® 2.75®E®-09 0®X®1.®B®8®P®+4 3747 \end{cfa} 3748 3749 \item 3750 \Indexc{nobase}( integer )\index{manipulator!nobase@©nobase©} do not precede ©bin©, ©oct©, ©hex© with ©0b©/©0B©, ©0©, or ©0x©/©0X©. Printing the base is the default. 3751 \begin{cfa}[belowskip=0pt] 3752 sout | nobase( bin( 27 ) ) | nobase( oct( 27 ) ) | nobase( hex( 27 ) ); 3753 11011 33 1b 3754 \end{cfa} 3755 3756 \item 3757 \Indexc{nodp}( floating-point )\index{manipulator!nodp@©nodp©} do not print a decimal point if there are no fractional digits. 3758 Printing a decimal point is the default, if there are no fractional digits. 3759 \begin{cfa}[belowskip=0pt] 3760 sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 ); 3761 0.0 ®0® 27.0 ®27® 27.5 3762 \end{cfa} 3763 3764 \item 3765 \Indexc{sign}( integer / floating-point )\index{manipulator!sign@©sign©} prefix with plus or minus sign (©+© or ©-©). Only printing the minus sign is the default. 3766 \begin{cfa}[belowskip=0pt] 3767 sout | sign( 27 ) | sign( -27 ) | sign( 27. ) | sign( -27. ) | sign( 27.5 ) | sign( -27.5 ); 3768 ®+®27 -27 ®+®27.0 -27.0 ®+®27.5 -27.5 3769 \end{cfa} 3770 3771 \item 3772 \Indexc{wd}©( unsigned char minimum, T val )©\index{manipulator!wd@©wd©}, ©wd( unsigned char minimum, unsigned char precision, T val )© 3773 For all types, ©minimum© is the minimum number of printed characters. 3774 If the value is shorter than the minimum, it is padded on the right with spaces. 3775 \begin{cfa}[belowskip=0pt] 3776 sout | wd( 4, 34) | wd( 3, 34 ) | wd( 2, 34 ); 3777 sout | wd( 10, 4.) | wd( 9, 4. ) | wd( 8, 4. ); 3778 sout | wd( 4, "ab" ) | wd( 3, "ab" ) | wd( 2, "ab" ); 3779 \end{cfa} 3780 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3781 ® ®34 ® ®34 34 3782 ® ®4.000000 ® ®4.000000 4.000000 3783 ® ®ab ® ®ab ab 3784 ab ab ab 3785 \end{cfa} 3786 If the value is larger, it is printed without truncation, ignoring the ©minimum©. 3787 \begin{cfa}[belowskip=0pt] 3788 sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 ); 3789 sout | wd( 4, 3456. ) | wd( 3, 3456. ) | wd( 2, 3456. ); 3790 sout | wd( 4, "abcde" ) | wd( 3, "abcde" ) | wd( 2,"abcde" ); 3791 \end{cfa} 3792 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3793 3456®7® 345®67® 34®567® 3794 3456®.® 345®6.® 34®56.® 3795 abcd®e® abc®de® ab®cde® 3796 \end{cfa} 3797 3798 For integer types, ©precision© is the minimum number of printed digits. 3799 If the value is shorter, it is padded on the left with leading zeros. 3800 \begin{cfa}[belowskip=0pt] 3801 sout | wd( 4,3, 34 ) | wd( 8,4, 34 ) | wd( 10,10, 34 ); 3802 \end{cfa} 3803 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3804 ®0®34 ®00®34 ®00000000®34 3805 \end{cfa} 3806 If the value is larger, it is printed without truncation, ignoring the ©precision©. 3807 \begin{cfa}[belowskip=0pt] 3808 sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 ); 3809 \end{cfa} 3810 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3811 3456 3456 3456 3812 \end{cfa} 3813 If ©precision© is 0, nothing is printed for zero. 3814 If ©precision© is greater than the minimum, it becomes the minimum. 3815 \begin{cfa}[belowskip=0pt] 3816 sout | wd( 4,0, 0 ) | wd( 3,10, 34 ); 3817 \end{cfa} 3818 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3819 ® ® ®00000000®34 3820 \end{cfa} 3821 For floating-point types, ©precision© is the minimum number of digits after the decimal point. 3822 \begin{cfa}[belowskip=0pt] 3823 sout | wd( 6,3, 27.5 ) | wd( 8,1, 27.5 ) | wd( 8,0, 27.5 ) | wd( 3,8, 27.5 ); 3824 \end{cfa} 3825 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3826 27.®500® 27.®5® 28. 27.®50000000® 3827 \end{cfa} 3828 For the C-string type, ©precision© is the maximum number of printed characters, so the string is truncared if it exceeds the maximum. 3829 \begin{cfa}[belowskip=0pt] 3830 sout | wd( 6,8, "abcd" ) | wd( 6,8, "abcdefghijk" ) | wd( 6,3, "abcd" ); 3831 \end{cfa} 3832 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3833 abcd abcdefgh abc 3834 \end{cfa} 3835 3836 \item 3837 \Indexc{ws( unsigned char minimum, unsigned char significant, floating-point )}\index{manipulator!ws@©ws©} 3838 For floating-point type, ©minimum© is the same as for manipulator ©wd©, but ©significant© is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©). 3839 If a value's significant digits is greater than ©significant©, the last significant digit is rounded up. 3840 \begin{cfa}[belowskip=0pt] 3841 sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567); 3842 \end{cfa} 3843 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3844 234.567 234.5®7® 234.®6® 23®5® 3845 \end{cfa} 3846 If a value's magnitude is greater than ©significant©, the value is printed in scientific notation with the specified number of significant digits. 3847 \begin{cfa}[belowskip=0pt] 3848 sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.); 3849 \end{cfa} 3850 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3851 234567. 2.3457®e+05® 2.346®e+05® 2.35®e+05® 3852 \end{cfa} 3853 If ©significant© is greater than ©minimum©, it defines the number of printed characters. 3854 \begin{cfa}[belowskip=0pt] 3855 sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.); 3856 \end{cfa} 3857 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3858 234567. 234567. 234567. 234567. 3859 \end{cfa} 3860 3861 \item 3862 \Indexc{left}( field-width )\index{manipulator!left@©left©} left justify within the given field. 3863 \begin{cfa}[belowskip=0pt] 3864 sout | left(wd(4, 27)) | left(wd(10, 27.)) | left(wd(10, 27.5)) | left(wd(4,3, 27)) | left(wd(10,3, 27.5)); 3865 \end{cfa} 3866 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3867 27® ® 27.000000 27.500000 027 27.500® ® 3868 \end{cfa} 3869 3870 \item 3871 \Indexc{pad0}( field-width )\index{manipulator!pad0@©pad0©} left pad with zeroes (0). 3872 \begin{cfa}[belowskip=0pt] 3873 sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) ); 3874 ®00®27 ®0®27 ®00®27.500 3597 3875 \end{cfa} 3598 3876 \end{enumerate} … … 3655 3933 3656 3934 3935 \subsection{Input Value Manipulators} 3936 3937 The format of numeric input values in the same as C constants without a trailing type suffix, as the input value-type is denoted by the input variable. 3938 For ©_Bool© type, the constants are ©true© and ©false©. 3939 For integral types, any number of digits, optionally preceded by a sign (©+© or ©-©), where a 3940 \begin{itemize} 3941 \item 3942 ©1©-©9© prefix introduces a decimal value (©0©-©9©), 3943 \item 3944 ©0© prefix introduces an octal value (©0©-©7©), and 3945 \item 3946 ©0x© or ©0X© prefix introduces a hexadecimal value (©0©-©f©) with lower or upper case letters. 3947 \end{itemize} 3948 For floating-point types, any number of decimal digits, optionally preceded by a sign (©+© or ©-©), optionally containing a decimal point, and optionally followed by an exponent, ©e© or ©E©, with signed (optional) decimal digits. 3949 Floating-point values can also be written in hexadecimal format preceded by ©0x© or ©0X© with hexadecimal digits and exponent denoted by ©p© or ©P©. 3950 3951 For the C-string type, the input values are \emph{not} the same as C-string constants, \ie double quotes bracketing arbitrary text with escape sequences. 3952 Instead, the next sequence of non-whitespace characters are read, and the input sequence is terminated with delimiter ©'\0'©. 3953 The string variable \emph{must} be large enough to contain the input sequence. 3954 3955 The following \Index{manipulator}s control formatting of input values (reading), and only affect the format of the argument. 3956 3957 \begin{enumerate} 3958 \item 3959 \Indexc{skip( const char * pattern )}\index{manipulator!skip@©skip©} / ©skip( unsigned int length )© / ©const char * pattern© 3960 The argument defines a ©pattern© or ©length©. 3961 The ©pattern© is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character. 3962 The ©length© is composed of the next $N$ characters, including the newline character. 3963 If the match successes, the input characters are discarded, and input continues with the next character. 3964 If the match fails, the input characters are left unread. 3965 \begin{cfa}[belowskip=0pt] 3966 char sk[$\,$] = "abc"; 3967 sin | "abc " | skip( sk ) | skip( 5 ); // match input sequence 3968 \end{cfa} 3969 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3970 ®abc ® 3971 ®abc ® 3972 ®xx® 3973 \end{cfa} 3974 3975 \item 3976 \Indexc{wdi}©( unsigned int maximum, T & val )©\index{manipulator!wdi@©wdi©} 3977 For all types except ©char©, ©maximum© is the maximum number of characters read for the current operation. 3978 \begin{cfa}[belowskip=0pt] 3979 char s[10]; int i; double d; 3980 sin | wdi( 4, s ) | wdi( 3, i ) | wdi( 8, d ); // c == "abcd", i == 123, d == 3.456E+2 3981 \end{cfa} 3982 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3983 ®abcd1233.456E+2® 3984 \end{cfa} 3985 Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types. 3986 Currently, \CFA cannot distinguish between these two manipulators in the middle of an ©sout©/©sin© expression based on return type. 3987 3988 \item 3989 \Indexc{ignore( T & val )}\index{manipulator!ignore@©ignore©} 3990 For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument. 3991 \begin{cfa}[belowskip=0pt] 3992 double d; 3993 sin | ignore( d ); // d is unchanged 3994 \end{cfa} 3995 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3996 ® -75.35e-4® 25 3997 \end{cfa} 3998 3999 \item 4000 \Indexc{incl( const char * scanset, char * s )}\index{manipulator!incl@©incl©} 4001 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set. 4002 Matching characters are read into the C string and null terminated. 4003 \begin{cfa}[belowskip=0pt] 4004 char s[10]; 4005 sin | incl( "abc", s ); 4006 \end{cfa} 4007 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4008 ®bca®xyz 4009 \end{cfa} 4010 4011 \item 4012 \Indexc{excl( const char * scanset, char * s )}\index{manipulator!excl@©excl©} 4013 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set. 4014 Non-matching characters are read into the C string and null terminated. 4015 \begin{cfa}[belowskip=0pt] 4016 char s[10]; 4017 sin | excl( "abc", s ); 4018 \end{cfa} 4019 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4020 ®xyz®bca 4021 \end{cfa} 4022 \end{enumerate} 4023 4024 3657 4025 \section{Types} 3658 4026 … … 4022 4390 \begin{itemize} 4023 4391 \item 4024 preventing having to determine or writelong generic types,4025 \item 4026 ensur esecondary variables, related to a primary variable, always have the same type.4392 not determining or writing long generic types, 4393 \item 4394 ensuring secondary variables, related to a primary variable, always have the same type. 4027 4395 \end{itemize} 4028 4396 … … 4046 4414 There is also the conundrum in type inferencing of when to \emph{\Index{brand}} a type. 4047 4415 That is, when is the type of the variable more important than the type of its initialization expression. 4048 For example, if a change is made in an initialization expression, it can cause significantcascading type changes and/or errors.4416 For example, if a change is made in an initialization expression, it can cause cascading type changes and/or errors. 4049 4417 At some point, a variable type needs to remain constant and the expression to be in error when it changes. 4050 4418 … … 4279 4647 4280 4648 coroutine Fibonacci { 4281 int fn; §\C{// used for communication}§4649 int fn; §\C{// used for communication}§ 4282 4650 }; 4283 4651 void ?{}( Fibonacci * this ) { … … 4285 4653 } 4286 4654 void main( Fibonacci * this ) { 4287 int fn1, fn2; §\C{// retained between resumes}§4288 this->fn = 0; §\C{// case 0}§4655 int fn1, fn2; §\C{// retained between resumes}§ 4656 this->fn = 0; §\C{// case 0}§ 4289 4657 fn1 = this->fn; 4290 suspend(); §\C{// return to last resume}§4291 4292 this->fn = 1; §\C{// case 1}§4658 suspend(); §\C{// return to last resume}§ 4659 4660 this->fn = 1; §\C{// case 1}§ 4293 4661 fn2 = fn1; 4294 4662 fn1 = this->fn; 4295 suspend(); §\C{// return to last resume}§4296 4297 for ( ;; ) { §\C{// general case}§4663 suspend(); §\C{// return to last resume}§ 4664 4665 for ( ;; ) { §\C{// general case}§ 4298 4666 this->fn = fn1 + fn2; 4299 4667 fn2 = fn1; 4300 4668 fn1 = this->fn; 4301 suspend(); §\C{// return to last resume}§4669 suspend(); §\C{// return to last resume}§ 4302 4670 } // for 4303 4671 } 4304 4672 int next( Fibonacci * this ) { 4305 resume( this ); §\C{// transfer to last suspend}§4673 resume( this ); §\C{// transfer to last suspend}§ 4306 4674 return this->fn; 4307 4675 } … … 5848 6216 In \CFA, there are ambiguous cases with dereference and operator identifiers, \eg ©int *?*?()©, where the string ©*?*?© can be interpreted as: 5849 6217 \begin{cfa} 5850 *?§\color{red}\textvisiblespace§*? §\C{// dereference operator, dereference operator}§5851 *§\color{red}\textvisiblespace§?*? §\C{// dereference, multiplication operator}§6218 *?§\color{red}\textvisiblespace§*? §\C{// dereference operator, dereference operator}§ 6219 *§\color{red}\textvisiblespace§?*? §\C{// dereference, multiplication operator}§ 5852 6220 \end{cfa} 5853 6221 By default, the first interpretation is selected, which does not yield a meaningful parse. … … 5901 6269 \eg: 5902 6270 \begin{cfa} 5903 x; §\C{// int x}§5904 *y; §\C{// int *y}§5905 f( p1, p2 ); §\C{// int f( int p1, int p2 );}§5906 g( p1, p2 ) int p1, p2; §\C{// int g( int p1, int p2 );}§6271 x; §\C{// int x}§ 6272 *y; §\C{// int *y}§ 6273 f( p1, p2 ); §\C{// int f( int p1, int p2 );}§ 6274 g( p1, p2 ) int p1, p2; §\C{// int g( int p1, int p2 );}§ 5907 6275 \end{cfa} 5908 6276 \CFA continues to support K\&R routine definitions: 5909 6277 \begin{cfa} 5910 f( a, b, c ) §\C{// default int return}§5911 int a, b; char c §\C{// K\&R parameter declarations}§6278 f( a, b, c ) §\C{// default int return}§ 6279 int a, b; char c §\C{// K\&R parameter declarations}§ 5912 6280 { 5913 6281 ... … … 5928 6296 int rtn( int i ); 5929 6297 int rtn( char c ); 5930 rtn( 'x' ); §\C{// programmer expects 2nd rtn to be called}§6298 rtn( 'x' ); §\C{// programmer expects 2nd rtn to be called}§ 5931 6299 \end{cfa} 5932 6300 \item[Rationale:] it is more intuitive for the call to ©rtn© to match the second version of definition of ©rtn© rather than the first. … … 5950 6318 \item[Change:] make string literals ©const©: 5951 6319 \begin{cfa} 5952 char * p = "abc"; §\C{// valid in C, deprecated in \CFA}§5953 char * q = expr ? "abc" : "de"; §\C{// valid in C, invalid in \CFA}§6320 char * p = "abc"; §\C{// valid in C, deprecated in \CFA}§ 6321 char * q = expr ? "abc" : "de"; §\C{// valid in C, invalid in \CFA}§ 5954 6322 \end{cfa} 5955 6323 The type of a string literal is changed from ©[] char© to ©const [] char©. … … 5958 6326 \begin{cfa} 5959 6327 char * p = "abc"; 5960 p[0] = 'w'; §\C{// segment fault or change constant literal}§6328 p[0] = 'w'; §\C{// segment fault or change constant literal}§ 5961 6329 \end{cfa} 5962 6330 The same problem occurs when passing a string literal to a routine that changes its argument. … … 5970 6338 \item[Change:] remove \newterm{tentative definitions}, which only occurs at file scope: 5971 6339 \begin{cfa} 5972 int i; §\C{// forward definition}§5973 int *j = ®&i®; §\C{// forward reference, valid in C, invalid in \CFA}§5974 int i = 0; §\C{// definition}§6340 int i; §\C{// forward definition}§ 6341 int *j = ®&i®; §\C{// forward reference, valid in C, invalid in \CFA}§ 6342 int i = 0; §\C{// definition}§ 5975 6343 \end{cfa} 5976 6344 is valid in C, and invalid in \CFA because duplicate overloaded object definitions at the same scope level are disallowed. … … 5978 6346 \begin{cfa} 5979 6347 struct X { int i; struct X *next; }; 5980 static struct X a; §\C{// forward definition}§6348 static struct X a; §\C{// forward definition}§ 5981 6349 static struct X b = { 0, ®&a® };§\C{// forward reference, valid in C, invalid in \CFA}§ 5982 static struct X a = { 1, &b }; §\C{// definition}§6350 static struct X a = { 1, &b }; §\C{// definition}§ 5983 6351 \end{cfa} 5984 6352 \item[Rationale:] avoids having different initialization rules for builtin types and user-defined types. … … 5995 6363 struct Person { 5996 6364 enum ®Colour® { R, G, B }; §\C[7cm]{// nested type}§ 5997 struct Face { §\C{// nested type}§5998 ®Colour® Eyes, Hair; §\C{// type defined outside (1 level)}§6365 struct Face { §\C{// nested type}§ 6366 ®Colour® Eyes, Hair; §\C{// type defined outside (1 level)}§ 5999 6367 }; 6000 ®.Colour® shirt; §\C{// type defined outside (top level)}§6001 ®Colour® pants; §\C{// type defined same level}§6002 Face looks[10]; §\C{// type defined same level}§6368 ®.Colour® shirt; §\C{// type defined outside (top level)}§ 6369 ®Colour® pants; §\C{// type defined same level}§ 6370 Face looks[10]; §\C{// type defined same level}§ 6003 6371 }; 6004 ®Colour® c = R; §\C{// type/enum defined same level}§6372 ®Colour® c = R; §\C{// type/enum defined same level}§ 6005 6373 Person®.Colour® pc = Person®.®R;§\C{// type/enum defined inside}§ 6006 Person®.®Face pretty; §\C{// type defined inside}\CRT§6374 Person®.®Face pretty; §\C{// type defined inside}\CRT§ 6007 6375 \end{cfa} 6008 6376 In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing. … … 6021 6389 \item[Difficulty of converting:] Semantic transformation. To make the struct type name visible in the scope of the enclosing struct, the struct tag could be declared in the scope of the enclosing struct, before the enclosing struct is defined. Example: 6022 6390 \begin{cfa} 6023 struct Y; §\C{// struct Y and struct X are at the same scope}§6391 struct Y; §\C{// struct Y and struct X are at the same scope}§ 6024 6392 struct X { 6025 6393 struct Y { /* ... */ } y; … … 6036 6404 \begin{cfa} 6037 6405 void foo() { 6038 int * b = malloc( sizeof(int) ); §\C{// implicitly convert void * to int *}§6039 char * c = b; §\C{// implicitly convert int * to void *, and then void * to char *}§6406 int * b = malloc( sizeof(int) ); §\C{// implicitly convert void * to int *}§ 6407 char * c = b; §\C{// implicitly convert int * to void *, and then void * to char *}§ 6040 6408 } 6041 6409 \end{cfa} … … 6298 6666 \leavevmode 6299 6667 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 6300 forall( otype T | { int ?<?( T, T ); } ) §\C{// location}§6668 forall( otype T | { int ?<?( T, T ); } ) §\C{// location}§ 6301 6669 T * bsearch( T key, const T * arr, size_t dim );§\indexc{bsearch}§ 6302 6670 6303 forall( otype T | { int ?<?( T, T ); } ) §\C{// position}§6671 forall( otype T | { int ?<?( T, T ); } ) §\C{// position}§ 6304 6672 unsigned int bsearch( T key, const T * arr, size_t dim ); 6305 6673 … … 6308 6676 6309 6677 forall( otype E | { int ?<?( E, E ); } ) { 6310 E * bsearch( E key, const E * vals, size_t dim );§\indexc{bsearch}§ §\C{// location}§6678 E * bsearch( E key, const E * vals, size_t dim );§\indexc{bsearch}§ §\C{// location}§ 6311 6679 size_t bsearch( E key, const E * vals, size_t dim );§\C{// position}§ 6312 6680 E * bsearchl( E key, const E * vals, size_t dim );§\indexc{bsearchl}§ … … 6356 6724 void srandom( unsigned int seed );§\indexc{srandom}§ 6357 6725 char random( void );§\indexc{random}§ 6358 char random( char u ); §\C{// [0,u)}§6359 char random( char l, char u ); §\C{// [l,u)}§6726 char random( char u ); §\C{// [0,u)}§ 6727 char random( char l, char u ); §\C{// [l,u)}§ 6360 6728 int random( void ); 6361 int random( int u ); §\C{// [0,u)}§6362 int random( int l, int u ); §\C{// [l,u)}§6729 int random( int u ); §\C{// [0,u)}§ 6730 int random( int l, int u ); §\C{// [l,u)}§ 6363 6731 unsigned int random( void ); 6364 unsigned int random( unsigned int u ); §\C{// [0,u)}§6732 unsigned int random( unsigned int u ); §\C{// [0,u)}§ 6365 6733 unsigned int random( unsigned int l, unsigned int u ); §\C{// [l,u)}§ 6366 6734 long int random( void ); 6367 long int random( long int u ); §\C{// [0,u)}§6368 long int random( long int l, long int u ); §\C{// [l,u)}§6735 long int random( long int u ); §\C{// [0,u)}§ 6736 long int random( long int l, long int u ); §\C{// [l,u)}§ 6369 6737 unsigned long int random( void ); 6370 6738 unsigned long int random( unsigned long int u ); §\C{// [0,u)}§ … … 6417 6785 [ int, long double ] remquo( long double, long double ); 6418 6786 6419 float div( float, float, int * );§\indexc{div}§ §\C{// alternative name for remquo}§6787 float div( float, float, int * );§\indexc{div}§ §\C{// alternative name for remquo}§ 6420 6788 double div( double, double, int * ); 6421 6789 long double div( long double, long double, int * ); … … 6573 6941 long double atan2( long double, long double ); 6574 6942 6575 float atan( float, float ); §\C{// alternative name for atan2}§6943 float atan( float, float ); §\C{// alternative name for atan2}§ 6576 6944 double atan( double, double );§\indexc{atan}§ 6577 6945 long double atan( long double, long double ); … … 6764 7132 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 6765 7133 struct Duration { 6766 int64_t tv; §\C{// nanoseconds}§7134 int64_t tv; §\C{// nanoseconds}§ 6767 7135 }; 6768 7136 … … 6894 7262 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 6895 7263 struct Time { 6896 uint64_t tv; §\C{// nanoseconds since UNIX epoch}§7264 uint64_t tv; §\C{// nanoseconds since UNIX epoch}§ 6897 7265 }; 6898 7266 … … 6965 7333 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 6966 7334 struct Clock { 6967 Duration offset; §\C{// for virtual clock: contains offset from real-time}§6968 int clocktype; §\C{// implementation only -1 (virtual), CLOCK\_REALTIME}§7335 Duration offset; §\C{// for virtual clock: contains offset from real-time}§ 7336 int clocktype; §\C{// implementation only -1 (virtual), CLOCK\_REALTIME}§ 6969 7337 }; 6970 7338 … … 6974 7342 void ?{}( Clock & clk, Duration adj ); 6975 7343 6976 Duration getResNsec(); §\C{// with nanoseconds}§6977 Duration getRes(); §\C{// without nanoseconds}§6978 6979 Time getTimeNsec(); §\C{// with nanoseconds}§6980 Time getTime(); §\C{// without nanoseconds}§7344 Duration getResNsec(); §\C{// with nanoseconds}§ 7345 Duration getRes(); §\C{// without nanoseconds}§ 7346 7347 Time getTimeNsec(); §\C{// with nanoseconds}§ 7348 Time getTime(); §\C{// without nanoseconds}§ 6981 7349 Time getTime( Clock & clk ); 6982 7350 Time ?()( Clock & clk ); … … 6994 7362 6995 7363 \begin{cfa} 6996 void ?{}( Int * this ); §\C{// constructor/destructor}§7364 void ?{}( Int * this ); §\C{// constructor/destructor}§ 6997 7365 void ?{}( Int * this, Int init ); 6998 7366 void ?{}( Int * this, zero_t ); … … 7003 7371 void ^?{}( Int * this ); 7004 7372 7005 Int ?=?( Int * lhs, Int rhs ); §\C{// assignment}§7373 Int ?=?( Int * lhs, Int rhs ); §\C{// assignment}§ 7006 7374 Int ?=?( Int * lhs, long int rhs ); 7007 7375 Int ?=?( Int * lhs, unsigned long int rhs ); … … 7020 7388 unsigned long int narrow( Int val ); 7021 7389 7022 int ?==?( Int oper1, Int oper2 ); §\C{// comparison}§7390 int ?==?( Int oper1, Int oper2 ); §\C{// comparison}§ 7023 7391 int ?==?( Int oper1, long int oper2 ); 7024 7392 int ?==?( long int oper2, Int oper1 ); … … 7056 7424 int ?>=?( unsigned long int oper1, Int oper2 ); 7057 7425 7058 Int +?( Int oper ); §\C{// arithmetic}§7426 Int +?( Int oper ); §\C{// arithmetic}§ 7059 7427 Int -?( Int oper ); 7060 7428 Int ~?( Int oper ); … … 7138 7506 Int ?>>=?( Int * lhs, mp_bitcnt_t shift ); 7139 7507 7140 Int abs( Int oper ); §\C{// number functions}§7508 Int abs( Int oper ); §\C{// number functions}§ 7141 7509 Int fact( unsigned long int N ); 7142 7510 Int gcd( Int oper1, Int oper2 ); … … 7249 7617 // implementation 7250 7618 struct Rational {§\indexc{Rational}§ 7251 long int numerator, denominator; §\C{// invariant: denominator > 0}§7619 long int numerator, denominator; §\C{// invariant: denominator > 0}§ 7252 7620 }; // Rational 7253 7621 7254 Rational rational(); §\C{// constructors}§7622 Rational rational(); §\C{// constructors}§ 7255 7623 Rational rational( long int n ); 7256 7624 Rational rational( long int n, long int d ); … … 7258 7626 void ?{}( Rational * r, one_t ); 7259 7627 7260 long int numerator( Rational r ); §\C{// numerator/denominator getter/setter}§7628 long int numerator( Rational r ); §\C{// numerator/denominator getter/setter}§ 7261 7629 long int numerator( Rational r, long int n ); 7262 7630 long int denominator( Rational r ); 7263 7631 long int denominator( Rational r, long int d ); 7264 7632 7265 int ?==?( Rational l, Rational r ); §\C{// comparison}§7633 int ?==?( Rational l, Rational r ); §\C{// comparison}§ 7266 7634 int ?!=?( Rational l, Rational r ); 7267 7635 int ?<?( Rational l, Rational r ); … … 7270 7638 int ?>=?( Rational l, Rational r ); 7271 7639 7272 Rational -?( Rational r ); §\C{// arithmetic}§7640 Rational -?( Rational r ); §\C{// arithmetic}§ 7273 7641 Rational ?+?( Rational l, Rational r ); 7274 7642 Rational ?-?( Rational l, Rational r ); … … 7276 7644 Rational ?/?( Rational l, Rational r ); 7277 7645 7278 double widen( Rational r ); §\C{// conversion}§7646 double widen( Rational r ); §\C{// conversion}§ 7279 7647 Rational narrow( double f, long int md ); 7280 7648 -
libcfa/src/concurrency/coroutine.hfa
r3c6e417 r54dd994 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 30 18:23:45 201813 // Update Count : 812 // Last Modified On : Fri Jun 21 17:49:39 2019 13 // Update Count : 9 14 14 // 15 15 … … 53 53 forall(dtype T | is_coroutine(T)) 54 54 void prime(T & cor); 55 56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 55 57 56 58 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/invoke.h
r3c6e417 r54dd994 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 19 08:23:21 201813 // Update Count : 3112 // Last Modified On : Sat Jun 22 18:19:13 2019 13 // Update Count : 40 14 14 // 15 15 … … 46 46 #ifdef __cforall 47 47 extern "Cforall" { 48 static inline struct thread_desc * & get_next( struct thread_desc & this );49 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this );48 static inline struct thread_desc *& get_next( struct thread_desc & this ); 49 static inline struct __condition_criterion_t *& get_next( struct __condition_criterion_t & this ); 50 50 51 51 extern thread_local struct KernelThreadData { … … 199 199 #ifdef __cforall 200 200 extern "Cforall" { 201 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 202 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 203 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 204 205 static inline thread_desc * & get_next( thread_desc & this ) { 201 static inline thread_desc *& get_next( thread_desc & this ) { 206 202 return this.next; 207 203 } … … 210 206 return this.node.[next, prev]; 211 207 } 212 213 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this );214 208 215 209 static inline void ?{}(__monitor_group_t & this) { -
libcfa/src/concurrency/kernel.cfa
r3c6e417 r54dd994 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 9 16:11:46 201813 // Update Count : 2 412 // Last Modified On : Thu Jun 20 17:21:23 2019 13 // Update Count : 25 14 14 // 15 15 … … 907 907 void doregister( cluster * cltr, thread_desc & thrd ) { 908 908 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 909 cltr->nthreads += 1; 909 910 push_front(cltr->threads, thrd); 910 911 unlock (cltr->thread_list_lock); … … 914 915 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 915 916 remove(cltr->threads, thrd ); 917 cltr->nthreads -= 1; 916 918 unlock(cltr->thread_list_lock); 917 919 } … … 919 921 void doregister( cluster * cltr, processor * proc ) { 920 922 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 923 cltr->nprocessors += 1; 921 924 push_front(cltr->procs, *proc); 922 925 unlock (cltr->proc_list_lock); … … 926 929 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 927 930 remove(cltr->procs, *proc ); 931 cltr->nprocessors -= 1; 928 932 unlock(cltr->proc_list_lock); 929 933 } -
libcfa/src/concurrency/kernel.hfa
r3c6e417 r54dd994 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 10 14:46:49 201813 // Update Count : 1 012 // Last Modified On : Sat Jun 22 11:39:17 2019 13 // Update Count : 16 14 14 // 15 15 … … 91 91 this.lock = NULL; 92 92 } 93 static inline void ^?{}(FinishAction & this) {}93 static inline void ^?{}(FinishAction &) {} 94 94 95 95 // Processor … … 176 176 __dllist_t(struct processor) procs; 177 177 __dllist_t(struct processor) idles; 178 179 // List of processors 178 unsigned int nprocessors; 179 180 // List of threads 180 181 __spinlock_t thread_list_lock; 181 182 __dllist_t(struct thread_desc) threads; 183 unsigned int nthreads; 182 184 183 185 // Link lists fields … … 200 202 } 201 203 204 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 205 static inline struct cluster * active_cluster () { return TL_GET( this_processor )->cltr; } 206 202 207 // Local Variables: // 203 208 // mode: c // -
libcfa/src/concurrency/thread.hfa
r3c6e417 r54dd994 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 29 14:07:11 201813 // Update Count : 412 // Last Modified On : Fri Jun 21 17:51:33 2019 13 // Update Count : 5 14 14 // 15 15 … … 91 91 void yield( unsigned times ); 92 92 93 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 94 93 95 // Local Variables: // 94 96 // mode: c // -
src/AST/Expr.hpp
r3c6e417 r54dd994 248 248 AddressExpr( const CodeLocation & loc, const Expr * a ); 249 249 250 /// Generate AddressExpr wrapping given expression at same location 251 AddressExpr( const Expr * a ) : AddressExpr( a->location, a ) {} 252 250 253 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 251 254 private: … … 281 284 /// Cast-to-void 282 285 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast ); 286 287 /// Wrap a cast expression around an existing expression (always generated) 288 CastExpr( const Expr * a, const Type * to ) : CastExpr( a->location, a, to, GeneratedCast ) {} 289 290 /// Wrap a cast-to-void expression around an existing expression (always generated) 291 CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {} 283 292 284 293 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Init.hpp
r3c6e417 r54dd994 55 55 ConstructFlag maybeConstructed; 56 56 57 Init( const CodeLocation & loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}57 Init( const CodeLocation & loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {} 58 58 59 const Init * accept( Visitor & v ) const override = 0;59 const Init * accept( Visitor & v ) const override = 0; 60 60 private: 61 61 Init * clone() const override = 0; … … 69 69 ptr<Expr> value; 70 70 71 SingleInit( const CodeLocation & loc, Expr* val, ConstructFlag mc = DoConstruct )71 SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct ) 72 72 : Init( loc, mc ), value( val ) {} 73 73 … … 87 87 std::vector<ptr<Designation>> designations; 88 88 89 ListInit( const CodeLocation & loc, std::vector<ptr<Init>>&& is,90 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );89 ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is, 90 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct ); 91 91 92 92 using iterator = std::vector<ptr<Init>>::iterator; … … 114 114 ptr<Init> init; 115 115 116 ConstructorInit( const CodeLocation& loc, Stmt* ctor, Stmt* dtor, Init* init ) 116 ConstructorInit( 117 const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init ) 117 118 : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {} 118 119 -
src/AST/Node.hpp
r3c6e417 r54dd994 17 17 18 18 #include <cassert> 19 #include <cstddef> // for nullptr_t 19 20 #include <iosfwd> 20 21 #include <type_traits> // for remove_reference … … 181 182 } 182 183 184 ptr_base & operator=( std::nullptr_t ) { 185 if ( node ) _dec(node); 186 node = nullptr; 187 return *this; 188 } 189 183 190 ptr_base & operator=( const ptr_base & o ) { 184 191 assign(o.node); -
src/AST/Stmt.hpp
r3c6e417 r54dd994 61 61 CompoundStmt( CompoundStmt&& o ) = default; 62 62 63 void push_back( Stmt * s ) { kids.emplace_back( s ); }64 void push_front( Stmt * s ) { kids.emplace_front( s ); }63 void push_back( const Stmt * s ) { kids.emplace_back( s ); } 64 void push_front( const Stmt * s ) { kids.emplace_front( s ); } 65 65 66 66 const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 143 143 144 144 IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * thenPart, 145 Stmt * const elsePart, std::vector<ptr<Stmt>> && inits,145 const Stmt * elsePart = nullptr, std::vector<ptr<Stmt>> && inits = {}, 146 146 std::vector<Label> && labels = {} ) 147 147 : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart), -
src/Common/utility.h
r3c6e417 r54dd994 16 16 #pragma once 17 17 18 #include <cassert> 18 19 #include <cctype> 19 20 #include <algorithm> … … 27 28 #include <type_traits> 28 29 #include <utility> 29 30 #include <cassert> 30 #include <vector> 31 31 32 32 #include "Common/Indenter.h" 33 33 34 34 class Expression; 35 36 /// bring std::move into global scope 37 using std::move; 38 39 /// partner to move that copies any copyable type 40 template<typename T> 41 T copy( const T & x ) { return x; } 35 42 36 43 template< typename T > … … 145 152 return ret; 146 153 } // switch 154 } 155 156 /// Splice src onto the end of dst, clearing src 157 template< typename T > 158 void splice( std::vector< T > & dst, std::vector< T > & src ) { 159 dst.reserve( dst.size() + src.size() ); 160 for ( T & x : src ) { dst.emplace_back( std::move( x ) ); } 161 src.clear(); 162 } 163 164 /// Splice src onto the begining of dst, clearing src 165 template< typename T > 166 void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) { 167 splice( src, dst ); 168 dst.swap( src ); 147 169 } 148 170 -
src/InitTweak/FixInit.cc
r3c6e417 r54dd994 1111 1111 arg2 = new MemberExpr( field, new VariableExpr( params.back() ) ); 1112 1112 } 1113 InitExpander srcParam( arg2 );1113 InitExpander_old srcParam( arg2 ); 1114 1114 // cast away reference type and construct field. 1115 1115 Expression * thisExpr = new CastExpr( new VariableExpr( thisParam ), thisParam->get_type()->stripReferences()->clone() ); -
src/InitTweak/GenInit.cc
r3c6e417 r54dd994 18 18 #include <algorithm> // for any_of 19 19 #include <cassert> // for assert, strict_dynamic_cast, assertf 20 #include <deque> 20 21 #include <iterator> // for back_inserter, inserter, back_inse... 21 22 #include <list> // for _List_iterator, list 22 23 24 #include "AST/Decl.hpp" 25 #include "AST/Init.hpp" 26 #include "AST/Node.hpp" 27 #include "AST/Stmt.hpp" 23 28 #include "CodeGen/OperatorTable.h" 24 29 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort... … … 274 279 assertf( objDecl, "genCtorDtor passed null objDecl" ); 275 280 std::list< Statement * > stmts; 276 InitExpander srcParam( maybeClone( arg ) );281 InitExpander_old srcParam( maybeClone( arg ) ); 277 282 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl ); 278 283 assert( stmts.size() <= 1 ); … … 286 291 std::list< Statement * > dtor; 287 292 288 InitExpander srcParam( objDecl->get_init() );289 InitExpander nullParam( (Initializer *)NULL );293 InitExpander_old srcParam( objDecl->get_init() ); 294 InitExpander_old nullParam( (Initializer *)NULL ); 290 295 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 291 296 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); … … 353 358 GuardScope( managedTypes ); 354 359 } 360 361 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) { 362 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each 363 // constructable object 364 InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr }; 365 366 ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall( 367 srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl ); 368 ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall( 369 nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl, 370 SymTab::LoopBackward ); 371 372 // check that either both ctor and dtor are present, or neither 373 assert( (bool)ctor == (bool)dtor ); 374 375 if ( ctor ) { 376 // need to remember init expression, in case no ctors exist. If ctor does exist, want to 377 // use ctor expression instead of init. 378 ctor.strict_as< ast::ImplicitCtorDtorStmt >(); 379 dtor.strict_as< ast::ImplicitCtorDtorStmt >(); 380 381 return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init }; 382 } 383 384 return nullptr; 385 } 386 355 387 } // namespace InitTweak 356 388 -
src/InitTweak/GenInit.h
r3c6e417 r54dd994 19 19 #include <string> // for string 20 20 21 #include "AST/Fwd.hpp" 22 #include "Common/CodeLocation.h" 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 21 24 #include "SynTree/SynTree.h" // for Visitor Nodes 22 23 #include "GenPoly/ScopedSet.h" // for ScopedSet24 25 25 26 namespace InitTweak { … … 35 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 36 37 ConstructorInit * genCtorInit( ObjectDecl * objDecl ); 38 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 37 39 38 40 class ManagedTypes { -
src/InitTweak/InitTweak.cc
r3c6e417 r54dd994 22 22 23 23 #include "AST/Expr.hpp" 24 #include "AST/Init.hpp" 25 #include "AST/Node.hpp" 26 #include "AST/Pass.hpp" 24 27 #include "AST/Stmt.hpp" 25 28 #include "AST/Type.hpp" … … 84 87 }; 85 88 86 struct InitFlattener : public WithShortCircuiting {89 struct InitFlattener_old : public WithShortCircuiting { 87 90 void previsit( SingleInit * singleInit ) { 88 91 visit_children = false; … … 92 95 }; 93 96 94 } 97 struct InitFlattener_new : public ast::WithShortCircuiting { 98 std::vector< ast::ptr< ast::Expr > > argList; 99 100 void previsit( const ast::SingleInit * singleInit ) { 101 visit_children = false; 102 argList.emplace_back( singleInit->value ); 103 } 104 }; 105 106 } // anonymous namespace 95 107 96 108 std::list< Expression * > makeInitList( Initializer * init ) { 97 PassVisitor<InitFlattener > flattener;109 PassVisitor<InitFlattener_old> flattener; 98 110 maybeAccept( init, flattener ); 99 111 return flattener.pass.argList; … … 112 124 } 113 125 114 class InitExpander::ExpanderImpl { 126 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 127 ast::Pass< InitFlattener_new > flattener; 128 maybe_accept( init, flattener ); 129 return std::move( flattener.pass.argList ); 130 } 131 132 class InitExpander_old::ExpanderImpl { 115 133 public: 116 134 virtual ~ExpanderImpl() = default; … … 119 137 }; 120 138 121 class InitImpl : public InitExpander::ExpanderImpl {139 class InitImpl_old : public InitExpander_old::ExpanderImpl { 122 140 public: 123 InitImpl ( Initializer * init ) : init( init ) {}124 virtual ~InitImpl () = default;141 InitImpl_old( Initializer * init ) : init( init ) {} 142 virtual ~InitImpl_old() = default; 125 143 126 144 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) { … … 136 154 }; 137 155 138 class ExprImpl : public InitExpander::ExpanderImpl {156 class ExprImpl_old : public InitExpander_old::ExpanderImpl { 139 157 public: 140 ExprImpl ( Expression * expr ) : arg( expr ) {}141 virtual ~ExprImpl () { delete arg; }158 ExprImpl_old( Expression * expr ) : arg( expr ) {} 159 virtual ~ExprImpl_old() { delete arg; } 142 160 143 161 virtual std::list< Expression * > next( std::list< Expression * > & indices ) { … … 163 181 }; 164 182 165 InitExpander ::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {}166 167 InitExpander ::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {}168 169 std::list< Expression * > InitExpander ::operator*() {183 InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {} 184 185 InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {} 186 187 std::list< Expression * > InitExpander_old::operator*() { 170 188 return cur; 171 189 } 172 190 173 InitExpander & InitExpander::operator++() {191 InitExpander_old & InitExpander_old::operator++() { 174 192 cur = expander->next( indices ); 175 193 return *this; … … 177 195 178 196 // use array indices list to build switch statement 179 void InitExpander ::addArrayIndex( Expression * index, Expression * dimension ) {197 void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) { 180 198 indices.push_back( index ); 181 199 indices.push_back( dimension ); 182 200 } 183 201 184 void InitExpander ::clearArrayIndices() {202 void InitExpander_old::clearArrayIndices() { 185 203 deleteAll( indices ); 186 204 indices.clear(); 187 205 } 188 206 189 bool InitExpander ::addReference() {207 bool InitExpander_old::addReference() { 190 208 bool added = false; 191 209 for ( Expression *& expr : cur ) { … … 218 236 219 237 template< typename OutIterator > 220 void build( UntypedExpr * callExpr, InitExpander ::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {238 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) { 221 239 if ( idx == idxEnd ) return; 222 240 Expression * index = *idx++; … … 275 293 // remaining elements. 276 294 // To accomplish this, generate switch statement, consuming all of expander's elements 277 Statement * InitImpl ::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {295 Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) { 278 296 if ( ! init ) return nullptr; 279 297 CompoundStmt * block = new CompoundStmt(); … … 288 306 } 289 307 290 Statement * ExprImpl ::buildListInit( UntypedExpr *, std::list< Expression * > & ) {308 Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) { 291 309 return nullptr; 292 310 } 293 311 294 Statement * InitExpander ::buildListInit( UntypedExpr * dst ) {312 Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) { 295 313 return expander->buildListInit( dst, indices ); 296 314 } 315 316 class InitExpander_new::ExpanderImpl { 317 public: 318 virtual ~ExpanderImpl() = default; 319 virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0; 320 virtual ast::ptr< ast::Stmt > buildListInit( 321 ast::UntypedExpr * callExpr, IndexList & indices ) = 0; 322 }; 323 324 namespace { 325 template< typename Out > 326 void buildCallExpr( 327 ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension, 328 const ast::Init * init, Out & out 329 ) { 330 const CodeLocation & loc = init->location; 331 332 auto cond = new ast::UntypedExpr{ 333 loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } }; 334 335 std::vector< ast::ptr< ast::Expr > > args = makeInitList( init ); 336 splice( callExpr->args, args ); 337 338 out.emplace_back( new ast::IfStmt{ loc, cond, new ast::ExprStmt{ loc, callExpr } } ); 339 340 out.emplace_back( new ast::ExprStmt{ 341 loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } ); 342 } 343 344 template< typename Out > 345 void build( 346 ast::UntypedExpr * callExpr, const InitExpander_new::IndexList & indices, 347 const ast::Init * init, Out & out 348 ) { 349 if ( indices.empty() ) return; 350 351 unsigned idx = 0; 352 353 const ast::Expr * index = indices[idx++]; 354 assert( idx != indices.size() ); 355 const ast::Expr * dimension = indices[idx++]; 356 357 if ( idx == indices.size() ) { 358 if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) { 359 for ( const ast::Init * init : *listInit ) { 360 buildCallExpr( callExpr, index, dimension, init, out ); 361 } 362 } else { 363 buildCallExpr( callExpr, index, dimension, init, out ); 364 } 365 } else { 366 const CodeLocation & loc = init->location; 367 368 unsigned long cond = 0; 369 auto listInit = dynamic_cast< const ast::ListInit * >( init ); 370 if ( ! listInit ) { SemanticError( loc, "unbalanced list initializers" ); } 371 372 static UniqueName targetLabel( "L__autogen__" ); 373 ast::Label switchLabel{ 374 loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } }; 375 376 std::vector< ast::ptr< ast::Stmt > > branches; 377 for ( const ast::Init * init : *listInit ) { 378 auto condition = ast::ConstantExpr::from_ulong( loc, cond ); 379 ++cond; 380 381 std::vector< ast::ptr< ast::Stmt > > stmts; 382 build( callExpr, indices, init, stmts ); 383 stmts.emplace_back( 384 new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } ); 385 branches.emplace_back( new ast::CaseStmt{ loc, condition, std::move( stmts ) } ); 386 } 387 out.emplace_back( new ast::SwitchStmt{ loc, index, std::move( branches ) } ); 388 out.emplace_back( new ast::NullStmt{ loc, { switchLabel } } ); 389 } 390 } 391 392 class InitImpl_new final : public InitExpander_new::ExpanderImpl { 393 ast::ptr< ast::Init > init; 394 public: 395 InitImpl_new( const ast::Init * i ) : init( i ) {} 396 397 std::vector< ast::ptr< ast::Expr > > next( InitExpander_new::IndexList & ) override { 398 return makeInitList( init ); 399 } 400 401 ast::ptr< ast::Stmt > buildListInit( 402 ast::UntypedExpr * callExpr, InitExpander_new::IndexList & indices 403 ) override { 404 // If array came with an initializer list, initialize each element. We may have more 405 // initializers than elements of the array; need to check at each index that we have 406 // not exceeded size. We may have fewer initializers than elements in the array; need 407 // to default-construct remaining elements. To accomplish this, generate switch 408 // statement consuming all of expander's elements 409 410 if ( ! init ) return {}; 411 412 std::list< ast::ptr< ast::Stmt > > stmts; 413 build( callExpr, indices, init, stmts ); 414 if ( stmts.empty() ) { 415 return {}; 416 } else { 417 auto block = new ast::CompoundStmt{ init->location, std::move( stmts ) }; 418 init = nullptr; // consumed in creating the list init 419 return block; 420 } 421 } 422 }; 423 424 class ExprImpl_new final : public InitExpander_new::ExpanderImpl { 425 ast::ptr< ast::Expr > arg; 426 public: 427 ExprImpl_new( const ast::Expr * a ) : arg( a ) {} 428 429 std::vector< ast::ptr< ast::Expr > > next( 430 InitExpander_new::IndexList & indices 431 ) override { 432 if ( ! arg ) return {}; 433 434 const CodeLocation & loc = arg->location; 435 const ast::Expr * expr = arg; 436 for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) { 437 // go through indices and layer on subscript exprs ?[?] 438 ++it; 439 expr = new ast::UntypedExpr{ 440 loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } }; 441 } 442 return { expr }; 443 } 444 445 ast::ptr< ast::Stmt > buildListInit( 446 ast::UntypedExpr *, InitExpander_new::IndexList & 447 ) override { 448 return {}; 449 } 450 }; 451 } // anonymous namespace 452 453 InitExpander_new::InitExpander_new( const ast::Init * init ) 454 : expander( new InitImpl_new{ init } ), crnt(), indices() {} 455 456 InitExpander_new::InitExpander_new( const ast::Expr * expr ) 457 : expander( new ExprImpl_new{ expr } ), crnt(), indices() {} 458 459 std::vector< ast::ptr< ast::Expr > > InitExpander_new::operator* () { return crnt; } 460 461 InitExpander_new & InitExpander_new::operator++ () { 462 crnt = expander->next( indices ); 463 return *this; 464 } 465 466 /// builds statement which has the same semantics as a C-style list initializer (for array 467 /// initializers) using callExpr as the base expression to perform initialization 468 ast::ptr< ast::Stmt > InitExpander_new::buildListInit( ast::UntypedExpr * callExpr ) { 469 return expander->buildListInit( callExpr, indices ); 470 } 471 472 void InitExpander_new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) { 473 indices.emplace_back( index ); 474 indices.emplace_back( dimension ); 475 } 476 477 void InitExpander_new::clearArrayIndices() { indices.clear(); } 478 479 bool InitExpander_new::addReference() { 480 for ( ast::ptr< ast::Expr > & expr : crnt ) { 481 expr = new ast::AddressExpr{ expr }; 482 } 483 return ! crnt.empty(); 484 } 297 485 298 486 Type * getTypeofThis( FunctionType * ftype ) { -
src/InitTweak/InitTweak.h
r3c6e417 r54dd994 44 44 /// transform Initializer into an argument list that can be passed to a call expression 45 45 std::list< Expression * > makeInitList( Initializer * init ); 46 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 46 47 47 48 /// True if the resolver should try to construct dwt … … 101 102 bool isConstExpr( Initializer * init ); 102 103 103 class InitExpander {104 class InitExpander_old { 104 105 public: 105 106 // expand by stepping through init to get each list of arguments 106 InitExpander ( Initializer * init );107 InitExpander_old( Initializer * init ); 107 108 108 109 // always expand to expr 109 InitExpander ( Expression * expr );110 InitExpander_old( Expression * expr ); 110 111 111 112 // iterator-like interface 112 113 std::list< Expression * > operator*(); 113 InitExpander & operator++();114 InitExpander_old & operator++(); 114 115 115 116 // builds statement which has the same semantics as a C-style list initializer … … 130 131 IndexList indices; 131 132 }; 133 134 class InitExpander_new { 135 public: 136 using IndexList = std::vector< ast::ptr< ast::Expr > >; 137 class ExpanderImpl; 138 139 private: 140 std::shared_ptr< ExpanderImpl > expander; 141 std::vector< ast::ptr< ast::Expr > > crnt; 142 // invariant: list of size 2N (elements come in pairs [index, dimension]) 143 IndexList indices; 144 145 public: 146 /// Expand by stepping through init to get each list of arguments 147 InitExpander_new( const ast::Init * init ); 148 149 /// Always expand to expression 150 InitExpander_new( const ast::Expr * expr ); 151 152 std::vector< ast::ptr< ast::Expr > > operator* (); 153 InitExpander_new & operator++ (); 154 155 /// builds statement which has the same semantics as a C-style list initializer (for array 156 /// initializers) using callExpr as the base expression to perform initialization. 157 /// Mutates callExpr 158 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr ); 159 160 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ); 161 162 void clearArrayIndices(); 163 164 bool addReference(); 165 }; 132 166 } // namespace 133 167 -
src/ResolvExpr/Alternative.cc
r3c6e417 r54dd994 125 125 } 126 126 127 void splice( AltList& dst, AltList& src ) {128 dst.reserve( dst.size() + src.size() );129 for ( Alternative& alt : src ) {130 dst.push_back( std::move(alt) );131 }132 src.clear();133 }134 135 void spliceBegin( AltList& dst, AltList& src ) {136 splice( src, dst );137 dst.swap( src );138 }139 140 127 } // namespace ResolvExpr 141 128 -
src/ResolvExpr/Alternative.h
r3c6e417 r54dd994 112 112 typedef std::vector< Alternative > AltList; 113 113 114 /// Moves all elements from src to the end of dst115 void splice( AltList& dst, AltList& src );116 117 /// Moves all elements from src to the beginning of dst118 void spliceBegin( AltList& dst, AltList& src );119 120 114 static inline std::ostream & operator<<(std::ostream & os, const ResolvExpr::Alternative & alt) { 121 115 alt.print( os ); -
src/ResolvExpr/AlternativeFinder.cc
r3c6e417 r54dd994 56 56 #define PRINT( text ) if ( resolvep ) { text } 57 57 //#define DEBUG_COST 58 59 using std::move;60 61 /// copies any copyable type62 template<typename T>63 T copy(const T& x) { return x; }64 58 65 59 namespace ResolvExpr { -
src/ResolvExpr/Candidate.hpp
r3c6e417 r54dd994 75 75 using CandidateList = std::vector< CandidateRef >; 76 76 77 /// Splice src after dst, clearing src78 static inline void splice( CandidateList & dst, CandidateList & src ) {79 dst.reserve( dst.size() + src.size() );80 for ( CandidateRef & r : src ) { dst.emplace_back( std::move( r ) ); }81 src.clear();82 }83 84 /// Splice src before dst85 static inline void spliceBegin( CandidateList & dst, CandidateList & src ) {86 splice( src, dst );87 dst.swap( src );88 }89 90 77 /// Sum the cost of a list of candidates 91 78 static inline Cost sumCost( const CandidateList & candidates ) { -
src/ResolvExpr/CandidateFinder.cpp
r3c6e417 r54dd994 39 39 #include "AST/SymbolTable.hpp" 40 40 #include "AST/Type.hpp" 41 #include "Common/utility.h" // for move, copy 41 42 #include "SymTab/Mangler.h" 42 43 #include "SymTab/Validate.h" // for validateType … … 46 47 47 48 namespace ResolvExpr { 48 49 using std::move;50 51 /// partner to move that copies any copyable type52 template<typename T>53 T copy( const T & x ) { return x; }54 49 55 50 const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) { … … 57 52 // cast away reference from expr 58 53 cost.incReference(); 59 return new ast::CastExpr{ expr ->location, expr, expr->result->stripReferences() };54 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 60 55 } 61 56 … … 126 121 ast::ptr< ast::Type > newType = paramType; 127 122 env.apply( newType ); 128 return new ast::CastExpr{ arg ->location, arg, newType };123 return new ast::CastExpr{ arg, newType }; 129 124 130 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not … … 793 788 794 789 if ( aggrType.as< ast::ReferenceType >() ) { 795 aggrExpr = 796 new ast::CastExpr{ aggrExpr->location, aggrExpr, aggrType->stripReferences() }; 790 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; 797 791 } 798 792 -
src/ResolvExpr/Cost.h
r3c6e417 r54dd994 10 10 // Created On : Sun May 17 09:39:50 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 29 18:33:44201913 // Update Count : 4912 // Last Modified On : Fri Jun 21 11:39:13 2019 13 // Update Count : 63 14 14 // 15 15 … … 21 21 22 22 namespace ResolvExpr { 23 #if 024 25 //*************************** OLD ***************************26 27 class Cost {28 private:29 Cost( int unsafeCost, int polyCost, int safeCost, int signCost,30 int varCost, int specCost, int referenceCost );31 public:32 Cost & incUnsafe( int inc = 1 );33 Cost & incPoly( int inc = 1 );34 Cost & incSafe( int inc = 1 );35 Cost & incSign( int inc = 1 );36 Cost & incVar( int inc = 1 );37 Cost & decSpec( int inc = 1 );38 Cost & incReference( int inc = 1 );39 40 int get_unsafeCost() const { return unsafeCost; }41 int get_polyCost() const { return polyCost; }42 int get_safeCost() const { return safeCost; }43 int get_signCost() const { return signCost; }44 int get_varCost() const { return varCost; }45 int get_specCost() const { return specCost; }46 int get_referenceCost() const { return referenceCost; }47 48 Cost operator+( const Cost &other ) const;49 Cost &operator+=( const Cost &other );50 bool operator<( const Cost &other ) const;51 bool operator==( const Cost &other ) const;52 bool operator!=( const Cost &other ) const;53 friend std::ostream &operator<<( std::ostream &os, const Cost &cost );54 // returns negative for *this < other, 0 for *this == other, positive for *this > other55 int compare( const Cost &other ) const;56 57 static const Cost zero;58 static const Cost infinity;59 60 static const Cost unsafe;61 static const Cost poly;62 static const Cost safe;63 static const Cost sign;64 static const Cost var;65 static const Cost spec;66 static const Cost reference;67 68 private:69 int unsafeCost; ///< Unsafe (narrowing) conversions70 int polyCost; ///< Count of parameters and return values bound to some poly type71 int safeCost; ///< Safe (widening) conversions72 int signCost; ///< Count of safe sign conversions73 int varCost; ///< Count of polymorphic type variables74 int specCost; ///< Polymorphic type specializations (type assertions), negative cost75 int referenceCost; ///< reference conversions76 };77 78 inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int signCost,79 int varCost, int specCost, int referenceCost )80 : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), signCost( signCost ),81 varCost( varCost ), specCost( specCost ), referenceCost( referenceCost ) {}82 83 inline Cost & Cost::incUnsafe( int inc ) {84 if ( *this == infinity ) return *this;85 unsafeCost += inc;86 return *this;87 }88 89 inline Cost & Cost::incPoly( int inc ) {90 if ( *this == infinity ) return *this;91 polyCost += inc;92 return *this;93 }94 95 inline Cost & Cost::incSafe( int inc ) {96 if ( *this == infinity ) return *this;97 safeCost += inc;98 return *this;99 }100 101 inline Cost & Cost::incSign( int inc ) {102 if ( *this == infinity ) return *this;103 signCost += inc;104 return *this;105 }106 107 inline Cost & Cost::incVar( int inc ) {108 if ( *this == infinity ) return *this;109 varCost += inc;110 return *this;111 }112 113 inline Cost& Cost::decSpec( int dec ) {114 if ( *this == infinity ) return *this;115 specCost -= dec;116 return *this;117 }118 119 inline Cost & Cost::incReference( int inc ) {120 if ( *this == infinity ) return *this;121 referenceCost += inc;122 return *this;123 }124 125 inline Cost Cost::operator+( const Cost &other ) const {126 if ( *this == infinity || other == infinity ) return infinity;127 return Cost{128 unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost,129 signCost + other.signCost, varCost + other.varCost, specCost + other.specCost,130 referenceCost + other.referenceCost };131 }132 133 inline Cost &Cost::operator+=( const Cost &other ) {134 if ( *this == infinity ) return *this;135 if ( other == infinity ) {136 *this = infinity;137 return *this;138 }139 unsafeCost += other.unsafeCost;140 polyCost += other.polyCost;141 safeCost += other.safeCost;142 signCost += other.signCost;143 varCost += other.varCost;144 specCost += other.specCost;145 referenceCost += other.referenceCost;146 return *this;147 }148 149 inline bool Cost::operator<( const Cost &other ) const {150 if ( *this == infinity ) return false;151 if ( other == infinity ) return true;152 153 if ( unsafeCost > other.unsafeCost ) {154 return false;155 } else if ( unsafeCost < other.unsafeCost ) {156 return true;157 } else if ( polyCost > other.polyCost ) {158 return false;159 } else if ( polyCost < other.polyCost ) {160 return true;161 } else if ( safeCost > other.safeCost ) {162 return false;163 } else if ( safeCost < other.safeCost ) {164 return true;165 } else if ( signCost > other.signCost ) {166 return false;167 } else if ( signCost < other.signCost ) {168 return true;169 } else if ( varCost > other.varCost ) {170 return false;171 } else if ( varCost < other.varCost ) {172 return true;173 } else if ( specCost > other.specCost ) {174 return false;175 } else if ( specCost > other.specCost ) {176 return true;177 } else if ( referenceCost > other.referenceCost ) {178 return false;179 } else if ( referenceCost < other.referenceCost ) {180 return true;181 } else {182 return false;183 } // if184 }185 186 inline int Cost::compare( const Cost &other ) const {187 if ( *this == infinity ) return +1;188 if ( other == infinity ) return -1;189 190 int c = unsafeCost - other.unsafeCost; if ( c ) return c;191 c = polyCost - other.polyCost; if ( c ) return c;192 c = safeCost - other.safeCost; if ( c ) return c;193 c = signCost - other.signCost; if ( c ) return c;194 c = varCost - other.varCost; if ( c ) return c;195 c = specCost - other.specCost; if ( c ) return c;196 return referenceCost - other.referenceCost;197 }198 199 inline bool Cost::operator==( const Cost &other ) const {200 return unsafeCost == other.unsafeCost201 && polyCost == other.polyCost202 && safeCost == other.safeCost203 && signCost == other.signCost204 && varCost == other.varCost205 && specCost == other.specCost206 && referenceCost == other.referenceCost;207 }208 209 inline bool Cost::operator!=( const Cost &other ) const {210 return !( *this == other );211 }212 213 inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {214 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "215 << cost.safeCost << ", " << cost.signCost << ", "216 << cost.varCost << ", " << cost.specCost << ", "217 << cost.referenceCost << " )";218 }219 220 #else221 222 //*************************** NEW ***************************223 224 23 // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the 225 24 // specialization cost is a negative value so a correction is needed is a few places. … … 371 170 << ", " << cost.get_referenceCost() << " )"; 372 171 } 373 #endif // 0374 172 } // namespace ResolvExpr 375 173 -
src/ResolvExpr/RenameVars.cc
r3c6e417 r54dd994 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:05:18 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T ue Apr 30 17:07:57201913 // Update Count : 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Jun 20 17:39:00 2019 13 // Update Count : 8 14 14 // 15 15 … … 19 19 #include <utility> // for pair 20 20 21 #include "AST/Pass.hpp" 22 #include "AST/Type.hpp" 21 23 #include "Common/PassVisitor.h" 24 #include "Common/ScopedMap.h" 22 25 #include "Common/SemanticError.h" // for SemanticError 23 26 #include "RenameVars.h" … … 28 31 29 32 namespace ResolvExpr { 30 namespace {31 struct RenameVars {32 RenameVars();33 void reset();34 33 35 void previsit( TypeInstType * instType ); 36 void previsit( Type * ); 37 void postvisit( Type * ); 34 namespace { 35 class RenamingData { 36 int level = 0; 37 int resetCount = 0; 38 ScopedMap< std::string, std::string > nameMap; 38 39 39 private: 40 int level, resetCount; 41 std::list< std::unordered_map< std::string, std::string > > mapStack; 42 }; 43 44 PassVisitor<RenameVars> global_renamer; 45 } // namespace 46 47 void renameTyVars( Type * t ) { 48 t->accept( global_renamer ); 49 } 50 51 void resetTyVarRenaming() { 52 global_renamer.pass.reset(); 53 } 54 55 namespace { 56 RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) { 57 mapStack.push_front( std::unordered_map< std::string, std::string >() ); 40 public: 41 void reset() { 42 level = 0; 43 ++resetCount; 58 44 } 59 45 60 void RenameVars::reset() { 61 level = 0; 62 resetCount++; 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator; 47 48 void rename( TypeInstType * type ) { 49 mapConstIterator it = nameMap.find( type->name ); 50 if ( it != nameMap.end() ) { 51 type->name = it->second; 52 } 63 53 } 64 54 65 void RenameVars::previsit( TypeInstType * instType ) { 66 previsit( (Type *)instType ); 67 std::unordered_map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name ); 68 if ( i != mapStack.front().end() ) { 69 instType->name = i->second; 70 } // if 71 } 72 73 void RenameVars::previsit( Type * type ) { 55 void openLevel( Type * type ) { 74 56 if ( ! type->forall.empty() ) { 75 // copies current name mapping into new mapping 76 mapStack.push_front( mapStack.front() ); 57 nameMap.beginScope(); 77 58 // renames all "forall" type names to `_${level}_${name}' 78 59 for ( auto td : type->forall ) { … … 80 61 output << "_" << resetCount << "_" << level << "_" << td->name; 81 62 std::string newname( output.str() ); 82 mapStack.front()[ td->get_name() ] = newname;63 nameMap[ td->get_name() ] = newname; 83 64 td->name = newname; 84 65 // ditto for assertion names, the next level in … … 89 70 } 90 71 91 void RenameVars::postvisit( Type * type ) { 92 // clears name mapping added by typeBefore() 93 if ( ! type->forall.empty() ) { 94 mapStack.pop_front(); 95 } // if 72 void closeLevel( Type * type ) { 73 if ( !type->forall.empty() ) { 74 nameMap.endScope(); 75 } 96 76 } 97 } // namespace98 77 99 const ast::Type * renameTyVars( const ast::Type * t ) { 100 #warning unimplemented; make sure resetTyVarRenaming() updated when implemented 101 (void)t; 102 assert(false); 103 return t; 104 } 78 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 84 } 85 return type; 86 } 87 88 template<typename NodeT> 89 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 100 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 105 } 106 return type; 107 } 108 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 115 } 116 }; 117 118 // Global State: 119 RenamingData renaming; 120 121 struct RenameVars { 122 void previsit( TypeInstType * instType ) { 123 renaming.openLevel( (Type*)instType ); 124 renaming.rename( instType ); 125 } 126 void previsit( Type * type ) { 127 renaming.openLevel( type ); 128 } 129 void postvisit( Type * type ) { 130 renaming.closeLevel( type ); 131 } 132 133 const ast::FunctionType * previsit( const ast::FunctionType * type ) { 134 return renaming.openLevel( type ); 135 } 136 const ast::StructInstType * previsit( const ast::StructInstType * type ) { 137 return renaming.openLevel( type ); 138 } 139 const ast::UnionInstType * previsit( const ast::UnionInstType * type ) { 140 return renaming.openLevel( type ); 141 } 142 const ast::TraitInstType * previsit( const ast::TraitInstType * type ) { 143 return renaming.openLevel( type ); 144 } 145 const ast::TypeInstType * previsit( const ast::TypeInstType * type ) { 146 return renaming.rename( renaming.openLevel( type ) ); 147 } 148 const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) { 149 return renaming.closeLevel( type ); 150 } 151 }; 152 153 } // namespace 154 155 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars> renamer; 157 t->accept( renamer ); 158 } 159 160 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 162 return t->accept( renamer ); 163 } 164 165 void resetTyVarRenaming() { 166 renaming.reset(); 167 } 168 105 169 } // namespace ResolvExpr 106 170 -
src/ResolvExpr/Resolver.cc
r3c6e417 r54dd994 1109 1109 1110 1110 // set up and resolve expression cast to void 1111 ast::CastExpr * untyped = new ast::CastExpr{ expr ->location, expr};1111 ast::CastExpr * untyped = new ast::CastExpr{ expr }; 1112 1112 CandidateRef choice = findUnfinishedKindExpression( 1113 1113 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1161 1161 ) { 1162 1162 assert( untyped && type ); 1163 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped ->location, untyped, type };1163 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type }; 1164 1164 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab ); 1165 1165 removeExtraneousCast( newExpr, symtab ); … … 1251 1251 ast::Pass< Resolver_new > resolver; 1252 1252 accept_all( translationUnit, resolver ); 1253 } 1254 1255 ast::ptr< ast::Init > resolveCtorInit( 1256 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab 1257 ) { 1258 assert( ctorInit ); 1259 ast::Pass< Resolver_new > resolver{ symtab }; 1260 return ctorInit->accept( resolver ); 1253 1261 } 1254 1262 -
src/ResolvExpr/Resolver.h
r3c6e417 r54dd994 29 29 30 30 namespace ast { 31 class ConstructorInit; 31 32 class Decl; 32 33 class DeletedExpr; 34 class Init; 33 35 class StmtExpr; 34 36 class SymbolTable; … … 59 61 ast::ptr< ast::Expr > resolveInVoidContext( 60 62 const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env ); 63 /// Resolves a constructor init expression 64 ast::ptr< ast::Init > resolveCtorInit( 65 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab ); 61 66 /// Resolves a statement expression 62 67 ast::ptr< ast::Expr > resolveStmtExpr( -
src/SymTab/Autogen.cc
r3c6e417 r54dd994 24 24 #include <vector> // for vector 25 25 26 #include "AST/Decl.hpp" 26 27 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 27 28 #include "Common/PassVisitor.h" // for PassVisitor … … 209 210 } 210 211 212 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) { 213 return obj && obj->name.empty() && obj->bitfieldWidth; 214 } 215 211 216 /// inserts a forward declaration for functionDecl into declsToAdd 212 217 void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) { … … 388 393 389 394 void StructFuncGenerator::makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward ) { 390 InitTweak::InitExpander srcParam( src );395 InitTweak::InitExpander_old srcParam( src ); 391 396 392 397 // assign to destination -
src/SymTab/Autogen.h
r3c6e417 r54dd994 17 17 18 18 #include <cassert> // for assert 19 #include <iterator> // for back_inserter 19 20 #include <string> // for string 20 21 22 #include "AST/Decl.hpp" 23 #include "AST/Expr.hpp" 24 #include "AST/Init.hpp" 25 #include "AST/Node.hpp" 26 #include "AST/Stmt.hpp" 27 #include "AST/Type.hpp" 21 28 #include "CodeGen/OperatorTable.h" 22 29 #include "Common/UniqueName.h" // for UniqueName 30 #include "Common/utility.h" // for splice 23 31 #include "InitTweak/InitTweak.h" // for InitExpander 24 32 #include "SynTree/Constant.h" // for Constant … … 36 44 /// returns true if obj's name is the empty string and it has a bitfield width 37 45 bool isUnnamedBitfield( ObjectDecl * obj ); 46 bool isUnnamedBitfield( const ast::ObjectDecl * obj ); 38 47 39 48 /// generate the type of an assignment function for paramType. … … 49 58 FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true ); 50 59 60 /// Enum for loop direction 61 enum LoopDirection { LoopBackward, LoopForward }; 62 51 63 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. 52 64 template< typename OutputIterator > 53 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true ); 65 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true ); 66 67 template< typename OutIter > 68 ast::ptr< ast::Stmt > genCall( 69 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 70 const CodeLocation & loc, const std::string & fname, OutIter && out, 71 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward ); 54 72 55 73 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types. 56 74 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one 57 75 template< typename OutputIterator > 58 Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {76 Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) { 59 77 bool isReferenceCtorDtor = false; 60 78 if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) { … … 106 124 } 107 125 126 /// inserts into out a generated call expression to function fname with arguments dstParam and 127 /// srcParam. Should only be called with non-array types. 128 /// optionally returns a statement which must be inserted prior to the containing loop, if 129 /// there is one 130 template< typename OutIter > 131 ast::ptr< ast::Stmt > genScalarCall( 132 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 133 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 134 const ast::Type * addCast = nullptr 135 ) { 136 bool isReferenceCtorDtor = false; 137 if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) { 138 // reference constructors are essentially application of the rebind operator. 139 // apply & to both arguments, do not need a cast 140 fname = "?=?"; 141 dstParam = new ast::AddressExpr{ dstParam }; 142 addCast = nullptr; 143 isReferenceCtorDtor = true; 144 } 145 146 // want to be able to generate assignment, ctor, and dtor generically, so fname is one of 147 // "?=?", "?{}", or "^?{}" 148 ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } }; 149 150 if ( addCast ) { 151 // cast to T& with qualifiers removed, so that qualified objects can be constructed and 152 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue 153 // is considered a qualifier - for AddressExpr to resolve, its argument must have an 154 // lvalue-qualified type, so remove all qualifiers except lvalue. 155 // xxx -- old code actually removed lvalue too... 156 ast::ptr< ast::Type > guard = addCast; // prevent castType from mutating addCast 157 ast::ptr< ast::Type > castType = addCast; 158 ast::remove_qualifiers( 159 castType, 160 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic ); 161 dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } }; 162 } 163 fExpr->args.emplace_back( dstParam ); 164 165 const ast::Stmt * listInit = srcParam.buildListInit( fExpr ); 166 167 // fetch next set of arguments 168 ++srcParam; 169 170 // return if adding reference fails -- will happen on default ctor and dtor 171 if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit; 172 173 std::vector< ast::ptr< ast::Expr > > args = *srcParam; 174 splice( fExpr->args, args ); 175 176 *out++ = new ast::ExprStmt{ loc, fExpr }; 177 178 srcParam.clearArrayIndices(); 179 180 return listInit; 181 } 182 108 183 /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments. 109 184 /// If forward is true, loop goes from 0 to N-1, else N-1 to 0 110 185 template< typename OutputIterator > 111 void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {186 void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) { 112 187 static UniqueName indexName( "_index" ); 113 188 … … 170 245 } 171 246 247 /// Store in out a loop which calls fname on each element of the array with srcParam and 248 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0 249 template< typename OutIter > 250 void genArrayCall( 251 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 252 const CodeLocation & loc, const std::string & fname, OutIter && out, 253 const ast::ArrayType * array, const ast::Type * addCast = nullptr, 254 LoopDirection forward = LoopForward 255 ) { 256 static UniqueName indexName( "_index" ); 257 258 // for a flexible array member nothing is done -- user must define own assignment 259 if ( ! array->dimension ) return; 260 261 if ( addCast ) { 262 // peel off array layer from cast 263 addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base; 264 } 265 266 ast::ptr< ast::Expr > begin, end, cmp, update; 267 268 if ( forward ) { 269 // generate: for ( int i = 0; i < N; ++i ) 270 begin = ast::ConstantExpr::from_int( loc, 0 ); 271 end = array->dimension; 272 cmp = new ast::NameExpr{ loc, "?<?" }; 273 update = new ast::NameExpr{ loc, "++?" }; 274 } else { 275 // generate: for ( int i = N-1; i >= 0; --i ) 276 begin = new ast::UntypedExpr{ 277 loc, new ast::NameExpr{ loc, "?-?" }, 278 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } }; 279 end = ast::ConstantExpr::from_int( loc, 0 ); 280 cmp = new ast::NameExpr{ loc, "?>=?" }; 281 update = new ast::NameExpr{ loc, "--?" }; 282 } 283 284 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 285 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 286 new ast::SingleInit{ loc, begin } }; 287 288 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{ 289 loc, cmp, { new ast::VariableExpr{ loc, index }, end } }; 290 291 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{ 292 loc, update, { new ast::VariableExpr{ loc, index } } }; 293 294 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{ 295 loc, new ast::NameExpr{ loc, "?[?]" }, 296 { dstParam, new ast::VariableExpr{ loc, index } } }; 297 298 // srcParam must keep track of the array indices to build the source parameter and/or 299 // array list initializer 300 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension ); 301 302 // for stmt's body, eventually containing call 303 ast::CompoundStmt * body = new ast::CompoundStmt{ loc }; 304 ast::ptr< ast::Stmt > listInit = genCall( 305 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 306 forward ); 307 308 // block containing the stmt and index variable 309 ast::CompoundStmt * block = new ast::CompoundStmt{ loc }; 310 block->push_back( new ast::DeclStmt{ loc, index } ); 311 if ( listInit ) { block->push_back( listInit ); } 312 block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } ); 313 314 *out++ = block; 315 } 316 172 317 template< typename OutputIterator > 173 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {318 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) { 174 319 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 175 320 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward ); … … 180 325 } 181 326 327 template< typename OutIter > 328 ast::ptr< ast::Stmt > genCall( 329 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 330 const CodeLocation & loc, const std::string & fname, OutIter && out, 331 const ast::Type * type, const ast::Type * addCast, LoopDirection forward 332 ) { 333 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 334 genArrayCall( 335 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 336 forward ); 337 return {}; 338 } else { 339 return genScalarCall( 340 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast ); 341 } 342 } 343 182 344 /// inserts into out a generated call expression to function fname with arguments dstParam 183 345 /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the … … 185 347 /// ImplicitCtorDtorStmt node. 186 348 template< typename OutputIterator > 187 void genImplicitCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {349 void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) { 188 350 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl ); 189 351 assert( obj ); … … 213 375 } 214 376 } 377 378 static inline ast::ptr< ast::Stmt > genImplicitCall( 379 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 380 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 381 LoopDirection forward = LoopForward 382 ) { 383 // unnamed bit fields are not copied as they cannot be accessed 384 if ( isUnnamedBitfield( obj ) ) return {}; 385 386 ast::ptr< ast::Type > addCast = nullptr; 387 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) { 388 assert( dstParam->result ); 389 addCast = dstParam->result; 390 } 391 392 std::vector< ast::ptr< ast::Stmt > > stmts; 393 genCall( 394 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward ); 395 396 if ( stmts.empty() ) { 397 return {}; 398 } else if ( stmts.size() == 1 ) { 399 const ast::Stmt * callStmt = stmts.front(); 400 if ( addCast ) { 401 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 402 // aware they were generated. 403 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt }; 404 } 405 return callStmt; 406 } else { 407 assert( false ); 408 return {}; 409 } 410 } 215 411 } // namespace SymTab 216 412 -
src/SymTab/FixFunction.cc
r3c6e417 r54dd994 18 18 #include <list> // for list 19 19 20 #include "Common/utility.h" // for maybeClone 20 #include "AST/Decl.hpp" 21 #include "AST/Pass.hpp" 22 #include "AST/Type.hpp" 23 #include "Common/utility.h" // for maybeClone, copy 21 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati... 22 25 #include "SynTree/Expression.h" // for Expression … … 24 27 25 28 namespace SymTab { 26 FixFunction::FixFunction() : isVoid( false ) {} 29 class FixFunction_old : public WithShortCircuiting { 30 typedef Mutator Parent; 31 public: 32 FixFunction_old() : isVoid( false ) {} 27 33 34 void premutate(FunctionDecl *functionDecl); 35 DeclarationWithType* postmutate(FunctionDecl *functionDecl); 28 36 29 DeclarationWithType * FixFunction::postmutate(FunctionDecl *functionDecl) { 37 Type * postmutate(ArrayType * arrayType); 38 39 void premutate(ArrayType * arrayType); 40 void premutate(VoidType * voidType); 41 void premutate(BasicType * basicType); 42 void premutate(PointerType * pointerType); 43 void premutate(StructInstType * aggregateUseType); 44 void premutate(UnionInstType * aggregateUseType); 45 void premutate(EnumInstType * aggregateUseType); 46 void premutate(TraitInstType * aggregateUseType); 47 void premutate(TypeInstType * aggregateUseType); 48 void premutate(TupleType * tupleType); 49 void premutate(VarArgsType * varArgsType); 50 void premutate(ZeroType * zeroType); 51 void premutate(OneType * oneType); 52 53 bool isVoid; 54 }; 55 56 DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) { 30 57 // can't delete function type because it may contain assertions, so transfer ownership to new object 31 58 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes ); … … 41 68 // does not cause an error 42 69 43 Type * FixFunction ::postmutate(ArrayType *arrayType) {70 Type * FixFunction_old::postmutate(ArrayType *arrayType) { 44 71 // need to recursively mutate the base type in order for multi-dimensional arrays to work. 45 72 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic ); … … 51 78 } 52 79 53 void FixFunction ::premutate(VoidType *) {80 void FixFunction_old::premutate(VoidType *) { 54 81 isVoid = true; 55 82 } 56 83 57 void FixFunction ::premutate(FunctionDecl *) { visit_children = false; }58 void FixFunction ::premutate(ArrayType *) { visit_children = false; }59 void FixFunction ::premutate(BasicType *) { visit_children = false; }60 void FixFunction ::premutate(PointerType *) { visit_children = false; }61 void FixFunction ::premutate(StructInstType *) { visit_children = false; }62 void FixFunction ::premutate(UnionInstType *) { visit_children = false; }63 void FixFunction ::premutate(EnumInstType *) { visit_children = false; }64 void FixFunction ::premutate(TraitInstType *) { visit_children = false; }65 void FixFunction ::premutate(TypeInstType *) { visit_children = false; }66 void FixFunction ::premutate(TupleType *) { visit_children = false; }67 void FixFunction ::premutate(VarArgsType *) { visit_children = false; }68 void FixFunction ::premutate(ZeroType *) { visit_children = false; }69 void FixFunction ::premutate(OneType *) { visit_children = false; }84 void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; } 85 void FixFunction_old::premutate(ArrayType *) { visit_children = false; } 86 void FixFunction_old::premutate(BasicType *) { visit_children = false; } 87 void FixFunction_old::premutate(PointerType *) { visit_children = false; } 88 void FixFunction_old::premutate(StructInstType *) { visit_children = false; } 89 void FixFunction_old::premutate(UnionInstType *) { visit_children = false; } 90 void FixFunction_old::premutate(EnumInstType *) { visit_children = false; } 91 void FixFunction_old::premutate(TraitInstType *) { visit_children = false; } 92 void FixFunction_old::premutate(TypeInstType *) { visit_children = false; } 93 void FixFunction_old::premutate(TupleType *) { visit_children = false; } 94 void FixFunction_old::premutate(VarArgsType *) { visit_children = false; } 95 void FixFunction_old::premutate(ZeroType *) { visit_children = false; } 96 void FixFunction_old::premutate(OneType *) { visit_children = false; } 70 97 71 98 bool fixFunction( DeclarationWithType *& dwt ) { 72 PassVisitor<FixFunction > fixer;99 PassVisitor<FixFunction_old> fixer; 73 100 dwt = dwt->acceptMutator( fixer ); 74 101 return fixer.pass.isVoid; 75 102 } 103 104 namespace { 105 struct FixFunction_new final : public ast::WithShortCircuiting { 106 bool isVoid = false; 107 108 void premutate( const ast::FunctionDecl * ) { visit_children = false; } 109 110 const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) { 111 return new ast::ObjectDecl{ 112 func->location, func->name, new ast::PointerType{ func->type }, nullptr, 113 func->storage, func->linkage, nullptr, copy( func->attributes ) }; 114 } 115 116 void premutate( const ast::ArrayType * ) { visit_children = false; } 117 118 const ast::Type * postmutate( const ast::ArrayType * array ) { 119 return new ast::PointerType{ 120 array->base, array->dimension, array->isVarLen, array->isStatic, 121 array->qualifiers }; 122 } 123 124 void premutate( const ast::VoidType * ) { isVoid = true; } 125 126 void premutate( const ast::BasicType * ) { visit_children = false; } 127 void premutate( const ast::PointerType * ) { visit_children = false; } 128 void premutate( const ast::StructInstType * ) { visit_children = false; } 129 void premutate( const ast::UnionInstType * ) { visit_children = false; } 130 void premutate( const ast::EnumInstType * ) { visit_children = false; } 131 void premutate( const ast::TraitInstType * ) { visit_children = false; } 132 void premutate( const ast::TypeInstType * ) { visit_children = false; } 133 void premutate( const ast::TupleType * ) { visit_children = false; } 134 void premutate( const ast::VarArgsType * ) { visit_children = false; } 135 void premutate( const ast::ZeroType * ) { visit_children = false; } 136 void premutate( const ast::OneType * ) { visit_children = false; } 137 }; 138 } // anonymous namespace 139 140 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) { 141 ast::Pass< FixFunction_new > fixer; 142 dwt = dwt->accept( fixer ); 143 isVoid |= fixer.pass.isVoid; 144 return dwt; 145 } 146 76 147 } // namespace SymTab 77 148 -
src/SymTab/FixFunction.h
r3c6e417 r54dd994 19 19 #include "SynTree/SynTree.h" // for Types 20 20 21 namespace ast { 22 class DeclWithType; 23 } 24 21 25 namespace SymTab { 22 /// Replaces function and array types by equivalent pointer types. 23 class FixFunction : public WithShortCircuiting { 24 typedef Mutator Parent; 25 public: 26 FixFunction(); 26 /// Replaces function and array types by equivalent pointer types. Returns true if type is 27 /// void 28 bool fixFunction( DeclarationWithType *& ); 27 29 28 void premutate(FunctionDecl *functionDecl); 29 DeclarationWithType* postmutate(FunctionDecl *functionDecl); 30 31 Type * postmutate(ArrayType * arrayType); 32 33 void premutate(ArrayType * arrayType); 34 void premutate(VoidType * voidType); 35 void premutate(BasicType * basicType); 36 void premutate(PointerType * pointerType); 37 void premutate(StructInstType * aggregateUseType); 38 void premutate(UnionInstType * aggregateUseType); 39 void premutate(EnumInstType * aggregateUseType); 40 void premutate(TraitInstType * aggregateUseType); 41 void premutate(TypeInstType * aggregateUseType); 42 void premutate(TupleType * tupleType); 43 void premutate(VarArgsType * varArgsType); 44 void premutate(ZeroType * zeroType); 45 void premutate(OneType * oneType); 46 47 bool isVoid; 48 }; 49 50 bool fixFunction( DeclarationWithType *& ); 30 /// Returns declaration with function and array types replaced by equivalent pointer types. 31 /// Sets isVoid to true if type is void 32 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ); 51 33 } // namespace SymTab 52 34 -
src/SymTab/Validate.cc
r3c6e417 r54dd994 46 46 #include <utility> // for pair 47 47 48 #include "AST/Decl.hpp" 49 #include "AST/Node.hpp" 50 #include "AST/Pass.hpp" 51 #include "AST/SymbolTable.hpp" 52 #include "AST/Type.hpp" 48 53 #include "CodeGen/CodeGenerator.h" // for genName 49 54 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign … … 124 129 125 130 /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers. 126 struct EnumAndPointerDecay {131 struct EnumAndPointerDecay_old { 127 132 void previsit( EnumDecl *aggregateDecl ); 128 133 void previsit( FunctionType *func ); … … 130 135 131 136 /// Associates forward declarations of aggregates with their definitions 132 struct LinkReferenceToTypes final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes>, public WithShortCircuiting {133 LinkReferenceToTypes ( const Indexer *indexer );137 struct LinkReferenceToTypes_old final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes_old>, public WithShortCircuiting { 138 LinkReferenceToTypes_old( const Indexer *indexer ); 134 139 void postvisit( TypeInstType *typeInst ); 135 140 … … 165 170 166 171 /// Replaces array and function types in forall lists by appropriate pointer type and assigns each Object and Function declaration a unique ID. 167 struct ForallPointerDecay final {172 struct ForallPointerDecay_old final { 168 173 void previsit( ObjectDecl * object ); 169 174 void previsit( FunctionDecl * func ); … … 290 295 291 296 void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) { 292 PassVisitor<EnumAndPointerDecay > epc;293 PassVisitor<LinkReferenceToTypes > lrt( nullptr );294 PassVisitor<ForallPointerDecay > fpd;297 PassVisitor<EnumAndPointerDecay_old> epc; 298 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr ); 299 PassVisitor<ForallPointerDecay_old> fpd; 295 300 PassVisitor<CompoundLiteral> compoundliteral; 296 301 PassVisitor<ValidateGenericParameters> genericParams; … … 305 310 ReplaceTypedef::replaceTypedef( translationUnit ); 306 311 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 307 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling312 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling 308 313 } 309 314 { … … 314 319 }); 315 320 Stats::Time::TimeBlock("Fix Qualified Types", [&]() { 316 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes , because aggregate members are accessed321 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed 317 322 }); 318 323 Stats::Time::TimeBlock("Hoist Structs", [&]() { … … 326 331 Stats::Heap::newPass("validate-C"); 327 332 Stats::Time::BlockGuard guard("validate-C"); 328 acceptAll( translationUnit, genericParams ); // check as early as possible - can't happen before LinkReferenceToTypes 333 acceptAll( translationUnit, genericParams ); // check as early as possible - can't happen before LinkReferenceToTypes_old 329 334 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors 330 335 ReturnChecker::checkFunctionReturns( translationUnit ); … … 344 349 }); 345 350 Stats::Time::TimeBlock("Generate Autogen routines", [&]() { 346 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 351 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay_old 347 352 }); 348 353 } … … 385 390 386 391 void validateType( Type *type, const Indexer *indexer ) { 387 PassVisitor<EnumAndPointerDecay > epc;388 PassVisitor<LinkReferenceToTypes > lrt( indexer );389 PassVisitor<ForallPointerDecay > fpd;392 PassVisitor<EnumAndPointerDecay_old> epc; 393 PassVisitor<LinkReferenceToTypes_old> lrt( indexer ); 394 PassVisitor<ForallPointerDecay_old> fpd; 390 395 type->accept( epc ); 391 396 type->accept( lrt ); … … 586 591 } 587 592 588 void EnumAndPointerDecay ::previsit( EnumDecl *enumDecl ) {593 void EnumAndPointerDecay_old::previsit( EnumDecl *enumDecl ) { 589 594 // Set the type of each member of the enumeration to be EnumConstant 590 595 for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) { … … 618 623 } 619 624 620 void EnumAndPointerDecay ::previsit( FunctionType *func ) {625 void EnumAndPointerDecay_old::previsit( FunctionType *func ) { 621 626 // Fix up parameters and return types 622 627 fixFunctionList( func->parameters, func->isVarArgs, func ); … … 624 629 } 625 630 626 LinkReferenceToTypes ::LinkReferenceToTypes( const Indexer *other_indexer ) {631 LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer *other_indexer ) { 627 632 if ( other_indexer ) { 628 633 local_indexer = other_indexer; … … 632 637 } 633 638 634 void LinkReferenceToTypes ::postvisit( EnumInstType *enumInst ) {639 void LinkReferenceToTypes_old::postvisit( EnumInstType *enumInst ) { 635 640 EnumDecl *st = local_indexer->lookupEnum( enumInst->name ); 636 641 // it's not a semantic error if the enum is not found, just an implicit forward declaration … … 652 657 } 653 658 654 void LinkReferenceToTypes ::postvisit( StructInstType *structInst ) {659 void LinkReferenceToTypes_old::postvisit( StructInstType *structInst ) { 655 660 StructDecl *st = local_indexer->lookupStruct( structInst->name ); 656 661 // it's not a semantic error if the struct is not found, just an implicit forward declaration … … 665 670 } 666 671 667 void LinkReferenceToTypes ::postvisit( UnionInstType *unionInst ) {672 void LinkReferenceToTypes_old::postvisit( UnionInstType *unionInst ) { 668 673 UnionDecl *un = local_indexer->lookupUnion( unionInst->name ); 669 674 // it's not a semantic error if the union is not found, just an implicit forward declaration … … 678 683 } 679 684 680 void LinkReferenceToTypes ::previsit( QualifiedType * ) {685 void LinkReferenceToTypes_old::previsit( QualifiedType * ) { 681 686 visit_children = false; 682 687 } 683 688 684 void LinkReferenceToTypes ::postvisit( QualifiedType * qualType ) {689 void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) { 685 690 // linking only makes sense for the 'oldest ancestor' of the qualified type 686 691 qualType->parent->accept( *visitor ); … … 729 734 } 730 735 731 void LinkReferenceToTypes ::postvisit( TraitDecl * traitDecl ) {736 void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) { 732 737 if ( traitDecl->name == "sized" ) { 733 738 // "sized" is a special trait - flick the sized status on for the type variable … … 751 756 } 752 757 753 void LinkReferenceToTypes ::postvisit( TraitInstType * traitInst ) {758 void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) { 754 759 // handle other traits 755 760 TraitDecl *traitDecl = local_indexer->lookupTrait( traitInst->name ); … … 777 782 } 778 783 779 void LinkReferenceToTypes ::postvisit( EnumDecl *enumDecl ) {784 void LinkReferenceToTypes_old::postvisit( EnumDecl *enumDecl ) { 780 785 // visit enum members first so that the types of self-referencing members are updated properly 781 786 if ( enumDecl->body ) { … … 799 804 } 800 805 801 void LinkReferenceToTypes ::renameGenericParams( std::list< TypeDecl * > & params ) {806 void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) { 802 807 // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g. 803 808 // forall(otype T) … … 817 822 } 818 823 819 void LinkReferenceToTypes ::previsit( StructDecl * structDecl ) {824 void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) { 820 825 renameGenericParams( structDecl->parameters ); 821 826 } 822 827 823 void LinkReferenceToTypes ::previsit( UnionDecl * unionDecl ) {828 void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) { 824 829 renameGenericParams( unionDecl->parameters ); 825 830 } 826 831 827 void LinkReferenceToTypes ::postvisit( StructDecl *structDecl ) {832 void LinkReferenceToTypes_old::postvisit( StructDecl *structDecl ) { 828 833 // visit struct members first so that the types of self-referencing members are updated properly 829 834 // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults) … … 839 844 } 840 845 841 void LinkReferenceToTypes ::postvisit( UnionDecl *unionDecl ) {846 void LinkReferenceToTypes_old::postvisit( UnionDecl *unionDecl ) { 842 847 if ( unionDecl->body ) { 843 848 ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name ); … … 851 856 } 852 857 853 void LinkReferenceToTypes ::postvisit( TypeInstType *typeInst ) {858 void LinkReferenceToTypes_old::postvisit( TypeInstType *typeInst ) { 854 859 // ensure generic parameter instances are renamed like the base type 855 860 if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name; … … 888 893 } 889 894 890 void ForallPointerDecay ::previsit( ObjectDecl *object ) {895 void ForallPointerDecay_old::previsit( ObjectDecl *object ) { 891 896 // ensure that operator names only apply to functions or function pointers 892 897 if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) { … … 896 901 } 897 902 898 void ForallPointerDecay ::previsit( FunctionDecl *func ) {903 void ForallPointerDecay_old::previsit( FunctionDecl *func ) { 899 904 func->fixUniqueId(); 900 905 } 901 906 902 void ForallPointerDecay ::previsit( FunctionType * ftype ) {907 void ForallPointerDecay_old::previsit( FunctionType * ftype ) { 903 908 forallFixer( ftype->forall, ftype ); 904 909 } 905 910 906 void ForallPointerDecay ::previsit( StructDecl * aggrDecl ) {911 void ForallPointerDecay_old::previsit( StructDecl * aggrDecl ) { 907 912 forallFixer( aggrDecl->parameters, aggrDecl ); 908 913 } 909 914 910 void ForallPointerDecay ::previsit( UnionDecl * aggrDecl ) {915 void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) { 911 916 forallFixer( aggrDecl->parameters, aggrDecl ); 912 917 } … … 1368 1373 } 1369 1374 1370 const ast::Type * validateType( const ast::Type * type, const ast::SymbolTable & symtab ) { 1371 #warning unimplemented 1372 (void)type; (void)symtab; 1373 assert(false); 1374 return nullptr; 1375 } 1375 namespace { 1376 /// Replaces enum types by int, and function/array types in function parameter and return 1377 /// lists by appropriate pointers 1378 struct EnumAndPointerDecay_new { 1379 const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) { 1380 // set the type of each member of the enumeration to be EnumConstant 1381 for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) { 1382 // build new version of object with EnumConstant 1383 ast::ptr< ast::ObjectDecl > obj = 1384 enumDecl->members[i].strict_as< ast::ObjectDecl >(); 1385 obj.get_and_mutate()->type = 1386 new ast::EnumInstType{ enumDecl->name, ast::CV::Const }; 1387 1388 // set into decl 1389 ast::EnumDecl * mut = mutate( enumDecl ); 1390 mut->members[i] = obj.get(); 1391 enumDecl = mut; 1392 } 1393 return enumDecl; 1394 } 1395 1396 static const ast::FunctionType * fixFunctionList( 1397 const ast::FunctionType * func, 1398 std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field, 1399 ast::ArgumentFlag isVarArgs = ast::FixedArgs 1400 ) { 1401 const auto & dwts = func->*field; 1402 unsigned nvals = dwts.size(); 1403 bool hasVoid = false; 1404 for ( unsigned i = 0; i < nvals; ++i ) { 1405 func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) ); 1406 } 1407 1408 // the only case in which "void" is valid is where it is the only one in the list 1409 if ( hasVoid && ( nvals > 1 || isVarArgs ) ) { 1410 SemanticError( 1411 dwts.front()->location, func, "invalid type void in function type" ); 1412 } 1413 1414 // one void is the only thing in the list, remove it 1415 if ( hasVoid ) { 1416 func = ast::mutate_field( 1417 func, field, std::vector< ast::ptr< ast::DeclWithType > >{} ); 1418 } 1419 1420 return func; 1421 } 1422 1423 const ast::FunctionType * previsit( const ast::FunctionType * func ) { 1424 func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs ); 1425 return fixFunctionList( func, &ast::FunctionType::returns ); 1426 } 1427 }; 1428 1429 /// Associates forward declarations of aggregates with their definitions 1430 struct LinkReferenceToTypes_new final 1431 : public ast::WithSymbolTable, public ast::WithGuards, public 1432 ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting { 1433 1434 const ast::SymbolTable * localSyms; 1435 1436 LinkReferenceToTypes_new( const ast::SymbolTable & syms ) : localSyms( &syms ) {} 1437 1438 #warning incomplete 1439 }; 1440 1441 /// Replaces array and function types in forall lists by appropriate pointer type and assigns 1442 /// each object and function declaration a unique ID 1443 struct ForallPointerDecay_new { 1444 #warning incomplete 1445 }; 1446 } // anonymous namespace 1447 1448 const ast::Type * validateType( const ast::Type * type, const ast::SymbolTable & symtab ) { 1449 ast::Pass< EnumAndPointerDecay_new > epc; 1450 ast::Pass< LinkReferenceToTypes_new > lrt{ symtab }; 1451 ast::Pass< ForallPointerDecay_new > fpd; 1452 1453 return type->accept( epc )->accept( lrt )->accept( fpd ); 1454 } 1455 1376 1456 } // namespace SymTab 1377 1457 -
src/Tuples/Explode.cc
r3c6e417 r54dd994 133 133 if ( first ) { 134 134 castAdded = true; 135 const ast::Expr * tuple = new ast::TupleExpr( 136 tupleExpr->location, std::move( exprs ) ); 137 return new ast::CastExpr( tuple->location, 138 tuple, new ast::ReferenceType( tuple->result.get(), ast::CV::Qualifiers() ) ); 135 const ast::Expr * tuple = new ast::TupleExpr{ 136 tupleExpr->location, std::move( exprs ) }; 137 return new ast::CastExpr{ tuple, new ast::ReferenceType{ tuple->result } }; 139 138 } else { 140 139 return new ast::TupleExpr( tupleExpr->location, std::move( exprs ) ); … … 145 144 } else { 146 145 castAdded = true; 147 return new ast::CastExpr( expr->location, expr, 148 new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) ); 146 return new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } }; 149 147 } 150 148 } … … 164 162 castAdded = false; 165 163 const ast::Type * newType = getReferenceBase( newNode->result ); 166 return new ast::CastExpr ( newNode->location, node, newType );164 return new ast::CastExpr{ newNode->location, node, newType }; 167 165 } 168 166 return newNode; … … 183 181 expr = expr->accept( exploder ); 184 182 if ( ! exploder.pass.foundUniqueExpr ) { 185 expr = new ast::CastExpr( expr->location, expr, 186 new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) ); 183 expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } }; 187 184 } 188 185 return expr; -
src/Tuples/Explode.h
r3c6e417 r54dd994 211 211 // Cast a reference away to a value-type to allow further explosion. 212 212 if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) { 213 local = new ast::CastExpr ( local->location, local, tupleType );213 local = new ast::CastExpr{ local, tupleType }; 214 214 } 215 215 // Now we have to go across the tuple via indexing. … … 238 238 } 239 239 240 /// explode list of candidates into flattened list of candidates 241 template< typename Output > 242 void explode( 243 const ResolvExpr::CandidateList & cands, const ast::SymbolTable & symtab, Output && out, 244 bool isTupleAssign = false 245 ) { 246 for ( const ResolvExpr::CandidateRef & cand : cands ) { 247 explode( *cand, symtab, std::forward< Output >( out ), isTupleAssign ); 248 } 249 } 250 240 251 } // namespace Tuples 241 252 -
src/Tuples/TupleAssignment.cc
r3c6e417 r54dd994 22 22 #include <vector> 23 23 24 #include "AST/Decl.hpp" 25 #include "AST/Init.hpp" 26 #include "AST/Pass.hpp" 27 #include "AST/Stmt.hpp" 28 #include "AST/TypeEnvironment.hpp" 24 29 #include "CodeGen/OperatorTable.h" 25 30 #include "Common/PassVisitor.h" 26 31 #include "Common/UniqueName.h" // for UniqueName 27 #include "Common/utility.h" // for zipWith32 #include "Common/utility.h" // for splice, zipWith 28 33 #include "Explode.h" // for explode 29 34 #include "InitTweak/GenInit.h" // for genCtorInit … … 51 56 52 57 namespace Tuples { 53 class TupleAssignSpotter {58 class TupleAssignSpotter_old { 54 59 public: 55 60 // dispatcher for Tuple (multiple and mass) assignment operations 56 TupleAssignSpotter ( ResolvExpr::AlternativeFinder & );61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & ); 57 62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ); 58 63 … … 62 67 struct Matcher { 63 68 public: 64 Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 65 70 const ResolvExpr::AltList& rhs ); 66 71 virtual ~Matcher() {} … … 80 85 81 86 ResolvExpr::AltList lhs, rhs; 82 TupleAssignSpotter &spotter;87 TupleAssignSpotter_old &spotter; 83 88 ResolvExpr::Cost baseCost; 84 89 std::list< ObjectDecl * > tmpDecls; … … 90 95 struct MassAssignMatcher : public Matcher { 91 96 public: 92 MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 93 98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 94 99 virtual void match( std::list< Expression * > &out ); … … 97 102 struct MultipleAssignMatcher : public Matcher { 98 103 public: 99 MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 100 105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 101 106 virtual void match( std::list< Expression * > &out ); … … 136 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 137 142 std::vector<ResolvExpr::AlternativeFinder> &args ) { 138 TupleAssignSpotter spotter( currentFinder );143 TupleAssignSpotter_old spotter( currentFinder ); 139 144 spotter.spot( expr, args ); 140 145 } 141 146 142 TupleAssignSpotter ::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f ) 143 148 : currentFinder(f) {} 144 149 145 void TupleAssignSpotter ::spot( UntypedExpr * expr,150 void TupleAssignSpotter_old::spot( UntypedExpr * expr, 146 151 std::vector<ResolvExpr::AlternativeFinder> &args ) { 147 152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) { … … 224 229 } 225 230 226 void TupleAssignSpotter ::match() {231 void TupleAssignSpotter_old::match() { 227 232 assert ( matcher != 0 ); 228 233 … … 275 280 } 276 281 277 TupleAssignSpotter ::Matcher::Matcher( TupleAssignSpotter&spotter,282 TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter, 278 283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs ) 279 284 : lhs(lhs), rhs(rhs), spotter(spotter), … … 313 318 }; 314 319 315 ObjectDecl * TupleAssignSpotter ::Matcher::newObject( UniqueName & namer, Expression * expr ) {320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) { 316 321 assert( expr->result && ! expr->get_result()->isVoid() ); 317 322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) ); … … 329 334 } 330 335 331 void TupleAssignSpotter ::MassAssignMatcher::match( std::list< Expression * > &out ) {336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) { 332 337 static UniqueName lhsNamer( "__massassign_L" ); 333 338 static UniqueName rhsNamer( "__massassign_R" ); … … 347 352 } 348 353 349 void TupleAssignSpotter ::MultipleAssignMatcher::match( std::list< Expression * > &out ) {354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) { 350 355 static UniqueName lhsNamer( "__multassign_L" ); 351 356 static UniqueName rhsNamer( "__multassign_R" ); … … 378 383 } 379 384 380 void handleTupleAssignment( 381 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 382 std::vector< ResolvExpr::CandidateFinder > & args 383 ) { 384 #warning unimplmented 385 (void)finder; (void)assign; (void)args; 386 assert(false); 387 } 385 namespace { 386 /// true if `expr` is of tuple type 387 bool isTuple( const ast::Expr * expr ) { 388 if ( ! expr ) return false; 389 assert( expr->result ); 390 return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() ); 391 } 392 393 /// true if `expr` is of tuple type or a reference to one 394 bool refToTuple( const ast::Expr * expr ) { 395 assert( expr->result ); 396 // check for function returning tuple of reference types 397 if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) { 398 return refToTuple( castExpr->arg ); 399 } else { 400 return isTuple( expr ); 401 } 402 } 403 404 /// Dispatcher for tuple (multiple and mass) assignment operations 405 class TupleAssignSpotter_new final { 406 /// Actually finds tuple assignment operations, by subclass 407 struct Matcher { 408 ResolvExpr::CandidateList lhs, rhs; 409 TupleAssignSpotter_new & spotter; 410 CodeLocation location; 411 ResolvExpr::Cost baseCost; 412 std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls; 413 ast::TypeEnvironment env; 414 ast::OpenVarSet open; 415 ast::AssertionSet need; 416 417 void combineState( const ResolvExpr::Candidate & cand ) { 418 env.simpleCombine( cand.env ); 419 ast::mergeOpenVars( open, cand.open ); 420 need.insert( cand.need.begin(), cand.need.end() ); 421 } 422 423 Matcher( 424 TupleAssignSpotter_new & s, const CodeLocation & loc, 425 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 426 : lhs( l ), rhs( r ), spotter( s ), location( loc ), 427 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(), 428 env(), open(), need() { 429 for ( auto & cand : lhs ) combineState( *cand ); 430 for ( auto & cand : rhs ) combineState( *cand ); 431 } 432 433 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 434 435 /// removes environments from subexpressions within statement expressions, which could 436 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 437 /// bindings to the env 438 struct EnvRemover { 439 /// environment to hoist ExprStmt environments to 440 ast::TypeEnvironment & tenv; 441 442 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 443 444 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 445 if ( stmt->expr->env ) { 446 tenv.add( *stmt->expr->env ); 447 ast::ExprStmt * mut = mutate( stmt ); 448 mut->expr.get_and_mutate()->env = nullptr; 449 return mut; 450 } 451 return stmt; 452 } 453 }; 454 455 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 456 assert( expr->result && ! expr->result->isVoid() ); 457 458 ast::ObjectDecl * ret = new ast::ObjectDecl{ 459 location, namer.newName(), expr->result, new ast::SingleInit{ location, expr }, 460 ast::Storage::Classes{}, ast::Linkage::Cforall }; 461 462 // if expression type is a reference, just need an initializer, otherwise construct 463 if ( ! expr->result.as< ast::ReferenceType >() ) { 464 // resolve ctor/dtor for the new object 465 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 466 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab ); 467 // remove environments from subexpressions of stmtExpr 468 ast::Pass< EnvRemover > rm{ env }; 469 ret->init = ctorInit->accept( rm ); 470 } 471 472 PRINT( std::cerr << "new object: " << ret << std::endl; ) 473 return ret; 474 } 475 476 ast::UntypedExpr * createFunc( 477 const std::string & fname, const ast::ObjectDecl * left, 478 const ast::ObjectDecl * right 479 ) { 480 assert( left ); 481 std::vector< ast::ptr< ast::Expr > > args; 482 args.emplace_back( new ast::VariableExpr{ location, left } ); 483 if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); } 484 485 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 486 args.front() = new ast::AddressExpr{ location, args.front() }; 487 if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; } 488 return new ast::UntypedExpr{ 489 location, new ast::NameExpr{ location, "?=?" }, std::move(args) }; 490 } else { 491 return new ast::UntypedExpr{ 492 location, new ast::NameExpr{ location, fname }, std::move(args) }; 493 } 494 } 495 }; 496 497 /// Finds mass-assignment operations 498 struct MassAssignMatcher final : public Matcher { 499 MassAssignMatcher( 500 TupleAssignSpotter_new & s, const CodeLocation & loc, 501 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 502 : Matcher( s, loc, l, r ) {} 503 504 std::vector< ast::ptr< ast::Expr > > match() override { 505 static UniqueName lhsNamer( "__massassign_L" ); 506 static UniqueName rhsNamer( "__massassign_R" ); 507 // empty tuple case falls into this matcher 508 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); 509 510 ast::ptr< ast::ObjectDecl > rtmp = 511 rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr; 512 513 std::vector< ast::ptr< ast::Expr > > out; 514 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) { 515 // create a temporary object for each value in the LHS and create a call 516 // involving the RHS 517 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr ); 518 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) ); 519 tmpDecls.emplace_back( std::move( ltmp ) ); 520 } 521 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) ); 522 523 return out; 524 } 525 }; 526 527 /// Finds multiple-assignment operations 528 struct MultipleAssignMatcher final : public Matcher { 529 MultipleAssignMatcher( 530 TupleAssignSpotter_new & s, const CodeLocation & loc, 531 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 532 : Matcher( s, loc, l, r ) {} 533 534 std::vector< ast::ptr< ast::Expr > > match() override { 535 static UniqueName lhsNamer( "__multassign_L" ); 536 static UniqueName rhsNamer( "__multassign_R" ); 537 538 if ( lhs.size() != rhs.size() ) return {}; 539 540 // produce a new temporary object for each value in the LHS and RHS and pairwise 541 // create the calls 542 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp; 543 544 std::vector< ast::ptr< ast::Expr > > out; 545 for ( unsigned i = 0; i < lhs.size(); ++i ) { 546 ResolvExpr::CandidateRef & lhsCand = lhs[i]; 547 ResolvExpr::CandidateRef & rhsCand = rhs[i]; 548 549 // convert RHS to LHS type minus one reference -- important for case where LHS 550 // is && and RHS is lvalue 551 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >(); 552 rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base }; 553 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr ); 554 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr ); 555 out.emplace_back( createFunc( spotter.fname, lobj, robj ) ); 556 ltmp.emplace_back( std::move( lobj ) ); 557 rtmp.emplace_back( std::move( robj ) ); 558 559 // resolve the cast expression so that rhsCand return type is bound by the cast 560 // type as needed, and transfer the resulting environment 561 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env }; 562 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 563 assert( finder.candidates.size() == 1 ); 564 env = std::move( finder.candidates.front()->env ); 565 } 566 567 splice( tmpDecls, ltmp ); 568 splice( tmpDecls, rtmp ); 569 570 return out; 571 } 572 }; 573 574 ResolvExpr::CandidateFinder & crntFinder; 575 std::string fname; 576 std::unique_ptr< Matcher > matcher; 577 578 public: 579 TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f ) 580 : crntFinder( f ), fname(), matcher() {} 581 582 // find left- and right-hand-sides for mass or multiple assignment 583 void spot( 584 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 585 ) { 586 if ( auto op = expr->func.as< ast::NameExpr >() ) { 587 // skip non-assignment functions 588 if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return; 589 fname = op->name; 590 591 // handled by CandidateFinder if applicable (both odd cases) 592 if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) { 593 return; 594 } 595 596 // look over all possible left-hand-side 597 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 598 // skip non-tuple LHS 599 if ( ! refToTuple( lhsCand->expr ) ) continue; 600 601 // explode is aware of casts - ensure every LHS is sent into explode with a 602 // reference cast 603 if ( ! lhsCand->expr.as< ast::CastExpr >() ) { 604 lhsCand->expr = new ast::CastExpr{ 605 lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } }; 606 } 607 608 // explode the LHS so that each field of a tuple-valued expr is assigned 609 ResolvExpr::CandidateList lhs; 610 explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true ); 611 for ( ResolvExpr::CandidateRef & cand : lhs ) { 612 // each LHS value must be a reference - some come in with a cast, if not 613 // just cast to reference here 614 if ( ! cand->expr->result.as< ast::ReferenceType >() ) { 615 cand->expr = new ast::CastExpr{ 616 cand->expr, new ast::ReferenceType{ cand->expr->result } }; 617 } 618 } 619 620 if ( args.size() == 1 ) { 621 // mass default-initialization/destruction 622 ResolvExpr::CandidateList rhs{}; 623 matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 624 match(); 625 } else if ( args.size() == 2 ) { 626 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 627 ResolvExpr::CandidateList rhs; 628 if ( isTuple( rhsCand->expr ) ) { 629 // multiple assignment 630 explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true ); 631 matcher.reset( 632 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 633 } else { 634 // mass assignment 635 rhs.emplace_back( rhsCand ); 636 matcher.reset( 637 new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 638 } 639 match(); 640 } 641 } else { 642 // expand all possible RHS possibilities 643 std::vector< ResolvExpr::CandidateList > rhsCands; 644 combos( 645 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 646 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 647 // multiple assignment 648 ResolvExpr::CandidateList rhs; 649 explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true ); 650 matcher.reset( 651 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 652 match(); 653 } 654 } 655 } 656 } 657 } 658 659 void match() { 660 assert( matcher ); 661 662 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 663 664 if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 665 // if both LHS and RHS are empty than this is the empty tuple case, wherein it's 666 // okay for newAssigns to be empty. Otherwise, return early so that no new 667 // candidates are generated 668 if ( newAssigns.empty() ) return; 669 } 670 671 ResolvExpr::CandidateList crnt; 672 // now resolve new assignments 673 for ( const ast::Expr * expr : newAssigns ) { 674 PRINT( 675 std::cerr << "== resolving tuple assign ==" << std::endl; 676 std::cerr << expr << std::endl; 677 ) 678 679 ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env }; 680 681 try { 682 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() ); 683 } catch (...) { 684 // no match is not failure, just that this tuple assignment is invalid 685 return; 686 } 687 688 ResolvExpr::CandidateList & cands = finder.candidates; 689 assert( cands.size() == 1 ); 690 assert( cands.front()->expr ); 691 crnt.emplace_back( std::move( cands.front() ) ); 692 } 693 694 // extract expressions from the assignment candidates to produce a list of assignments 695 // that together form a sigle candidate 696 std::vector< ast::ptr< ast::Expr > > solved; 697 for ( ResolvExpr::CandidateRef & cand : crnt ) { 698 solved.emplace_back( cand->expr ); 699 matcher->combineState( *cand ); 700 } 701 702 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 703 new ast::TupleAssignExpr{ 704 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) }, 705 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 706 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 707 } 708 }; 709 } // anonymous namespace 710 711 void handleTupleAssignment( 712 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 713 std::vector< ResolvExpr::CandidateFinder > & args 714 ) { 715 TupleAssignSpotter_new spotter{ finder }; 716 spotter.spot( assign, args ); 717 } 718 388 719 } // namespace Tuples 389 720 -
tests/concurrent/examples/boundedBufferEXT.cfa
r3c6e417 r54dd994 10 10 // Created On : Wed Apr 18 22:52:12 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:33201913 // Update Count : 1 212 // Last Modified On : Fri Jun 21 08:19:20 2019 13 // Update Count : 14 14 14 // 15 15 … … 52 52 } 53 53 54 const int Sentinel = -1;54 enum { Sentinel = -1 }; 55 55 56 56 thread Producer { … … 59 59 }; 60 60 void main( Producer & prod ) with( prod ) { 61 for ( i nt i = 1; i <= N; i += 1) {61 for ( i; 1 ~= N ) { 62 62 yield( random( 5 ) ); 63 63 insert( buffer, 1 ); … … 99 99 srandom( 1003 ); 100 100 101 for ( i = 0; i < Cons; i += 1 ) {// create consumers101 for ( i; Cons ) { // create consumers 102 102 cons[i] = new( &buffer, sums[i] ); 103 103 } // for 104 for ( i = 0; i < Prods; i += 1 ) {// create producers104 for ( i; Prods ) { // create producers 105 105 prods[i] = new( &buffer, 100000 ); 106 106 } // for 107 107 108 for ( i = 0; i < Prods; i += 1 ) {// wait for producers to finish108 for ( i; Prods ) { // wait for producers to finish 109 109 delete( prods[i] ); 110 110 } // for 111 for ( i = 0; i < Cons; i += 1 ) {// generate sentinal values to stop consumers111 for ( i; Cons ) { // generate sentinal values to stop consumers 112 112 insert( buffer, Sentinel ); 113 113 } // for 114 114 int sum = 0; 115 for ( i = 0; i < Cons; i += 1 ) {// wait for consumers to finish115 for ( i; Cons ) { // wait for consumers to finish 116 116 delete( cons[i] ); 117 117 sum += sums[i]; -
tests/concurrent/examples/boundedBufferINT.cfa
r3c6e417 r54dd994 10 10 // Created On : Mon Oct 30 12:45:13 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:52201913 // Update Count : 8812 // Last Modified On : Fri Jun 21 08:20:46 2019 13 // Update Count : 90 14 14 // 15 15 … … 53 53 } 54 54 55 const int Sentinel = -1;55 enum { Sentinel = -1 }; 56 56 57 57 thread Producer { … … 60 60 }; 61 61 void main( Producer & prod ) with( prod ) { 62 for ( i nt i = 1; i <= N; i += 1) {62 for ( i; 1 ~= N ) { 63 63 yield( random( 5 ) ); 64 64 insert( buffer, 1 ); … … 100 100 srandom( 1003 ); 101 101 102 for ( i = 0; i < Cons; i += 1 ) {// create consumers102 for ( i; Cons ) { // create consumers 103 103 cons[i] = new( &buffer, sums[i] ); 104 104 } // for 105 for ( i = 0; i < Prods; i += 1 ) {// create producers105 for ( i; Prods ) { // create producers 106 106 prods[i] = new( &buffer, 100000 ); 107 107 } // for 108 108 109 for ( i = 0; i < Prods; i += 1 ) {// wait for producers to finish109 for ( i; Prods ) { // wait for producers to finish 110 110 delete( prods[i] ); 111 111 } // for 112 for ( i = 0; i < Cons; i += 1 ) {// generate sentinal values to stop consumers112 for ( i; Cons ) { // generate sentinal values to stop consumers 113 113 insert( buffer, Sentinel ); 114 114 } // for 115 115 int sum = 0; 116 for ( i = 0; i < Cons; i += 1 ) {// wait for consumers to finish116 for ( i; Cons ) { // wait for consumers to finish 117 117 delete( cons[i] ); 118 118 sum += sums[i]; -
tests/concurrent/examples/datingService.cfa
r3c6e417 r54dd994 10 10 // Created On : Mon Oct 30 12:56:20 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:39201913 // Update Count : 3 112 // Last Modified On : Fri Jun 21 11:32:34 2019 13 // Update Count : 38 14 14 // 15 15 … … 95 95 srandom( /*getpid()*/ 103 ); 96 96 97 for ( unsigned int i = 0; i < CompCodes; i += 1) {98 girls[i] = new( &TheExchange, i, i ); 97 for ( i; (unsigned int)CompCodes ) { 98 girls[i] = new( &TheExchange, i, i ); // TheExchange constructor needs unsigned int 99 99 boys[i] = new( &TheExchange, i, CompCodes - ( i + 1 ) ); 100 100 } // for 101 101 102 for ( unsigned int i = 0; i < CompCodes; i += 1) {102 for ( i; CompCodes ) { 103 103 delete( boys[i] ); 104 104 delete( girls[i] ); 105 105 } // for 106 106 107 for ( unsigned int i = 0; i < CompCodes; i += 1) {107 for ( i; CompCodes ) { 108 108 if ( girlck[ boyck[i] ] != boyck[ girlck[i] ] ) abort(); 109 109 } // for -
tests/concurrent/examples/gortn.cfa
r3c6e417 r54dd994 10 10 // Created On : Wed Feb 20 08:02:37 2019 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 20 08:35:55201913 // Update Count : 312 // Last Modified On : Fri Jun 21 08:25:03 2019 13 // Update Count : 4 14 14 // 15 15 … … 18 18 19 19 struct Msg { int i, j; }; 20 thread Go rtn { int i; float f; Msg m; };21 void ^?{}( Go rtn & mutex ) {}22 void mem1( Go rtn & mutex gortn, int i ) { gortn.i = i; }23 void mem2( Go rtn & mutex gortn, float f ) { gortn.f = f; }24 void mem3( Go rtn & mutex gortn, Msg m ) { gortn.m = m; }20 thread GoRtn { int i; float f; Msg m; }; 21 void ^?{}( GoRtn & mutex ) {} 22 void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; } 23 void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; } 24 void mem3( GoRtn & mutex gortn, Msg m ) { gortn.m = m; } 25 25 26 void main( Go rtn & gortn ) with( gortn ) {27 for ( ;;) {26 void main( GoRtn & gortn ) with( gortn ) { 27 for () { 28 28 waitfor( mem1, gortn ) sout | i; 29 29 or waitfor( mem2, gortn ) sout | f; … … 33 33 } 34 34 int main() { 35 Go rtn gortn; // start thread35 GoRtn gortn; // start thread 36 36 mem1( gortn, 0 ); 37 37 mem2( gortn, 2.5 ); -
tests/concurrent/examples/quickSort.cfa
r3c6e417 r54dd994 11 11 // Created On : Wed Dec 6 12:15:52 2017 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Mar 22 13:42:01201914 // Update Count : 17 013 // Last Modified On : Fri Jun 21 08:27:45 2019 14 // Update Count : 172 15 15 // 16 16 … … 138 138 if ( eof( unsortedfile ) ) break; 139 139 int * values = alloc( size ); // values to be sorted, too large to put on stack 140 for ( int counter = 0; counter < size; counter += 1 ) {// read unsorted numbers140 for ( counter; size ) { // read unsorted numbers 141 141 unsortedfile | values[counter]; 142 142 if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | " "; … … 148 148 Quicksort QS = { values, size - 1, 0 }; // sort values 149 149 } // wait until sort tasks terminate 150 for ( int counter = 0; counter < size; counter += 1 ) {// print sorted list150 for ( counter; size ) { // print sorted list 151 151 if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | " "; 152 152 sortedfile | values[counter]; … … 163 163 164 164 int * values = alloc( size ); // values to be sorted, too large to put on stack 165 for ( int counter = 0; counter < size; counter += 1 ) {// generate unsorted numbers165 for ( counter; size ) { // generate unsorted numbers 166 166 values[counter] = size - counter; // descending values 167 167 } // for … … 170 170 } // wait until sort tasks terminate 171 171 172 // for ( int counter = 0; counter < size - 1; counter += 1 ) {// check sorting172 // for ( counter; size - 1 ) { // check sorting 173 173 // if ( values[counter] > values[counter + 1] ) abort(); 174 174 // } // for -
tests/concurrent/examples/quickSort.generic.cfa
r3c6e417 r54dd994 11 11 // Created On : Wed Dec 6 12:15:52 2017 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Mar 15 14:52:41201914 // Update Count : 14 713 // Last Modified On : Fri Jun 21 08:28:20 2019 14 // Update Count : 149 15 15 // 16 16 … … 141 141 if ( eof( unsortedfile ) ) break; 142 142 ELEMTYPE * values = alloc( size ); // values to be sorted, too large to put on stack 143 for ( int counter = 0; counter < size; counter += 1 ) {// read unsorted numbers143 for ( counter; size ) { // read unsorted numbers 144 144 unsortedfile | values[counter]; 145 145 if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | " "; … … 151 151 Quicksort(ELEMTYPE) QS = { values, size - 1, 0 }; // sort values 152 152 } // wait until sort tasks terminate 153 for ( int counter = 0; counter < size; counter += 1 ) {// print sorted list153 for ( counter; size ) { // print sorted list 154 154 if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | " "; 155 155 sortedfile | values[counter]; … … 166 166 167 167 ELEMTYPE * values = alloc( size ); // values to be sorted, too large to put on stack 168 for ( int counter = 0; counter < size; counter += 1 ) {// generate unsorted numbers168 for ( counter; size ) { // generate unsorted numbers 169 169 values[counter] = size - counter; // descending values 170 170 } // for … … 173 173 } // wait until sort tasks terminate 174 174 175 // for ( int counter = 0; counter < size - 1; counter += 1 ) {// check sorting175 // for ( counter; size - 1 ) { // check sorting 176 176 // if ( values[counter] > values[counter + 1] ) abort(); 177 177 // } // for -
tools/stat.py
r3c6e417 r54dd994 11 11 content = f.readlines() 12 12 content = [x.strip() for x in content] 13 content = [ int(x) for x in content]14 content.remove(max(content)) 15 content.remove(min(content)) 16 med = numpy. around( numpy.median(content), decimals=1)17 avg = numpy. around( numpy.mean (content), decimals=2)18 std = numpy. around( numpy.std (content), decimals=2)19 print "median {0 } avg {1} stddev {2}".format( med, avg, std )13 content = [float(x) for x in content] # expect floating-point strings 14 content.remove(max(content)) # need at least 4 data values because 15 content.remove(min(content)) # the max and min values are removed 16 med = numpy.median(content) 17 avg = numpy.mean (content) 18 std = numpy.std (content) 19 print "median {0:.1f} avg {1:.1f} stddev {2:.2f}".format( med, avg, std ) 20 20 21 21
Note:
See TracChangeset
for help on using the changeset viewer.