Changeset 54dd994


Ignore:
Timestamp:
Jun 24, 2019, 10:30:47 AM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
5 added
80 edited

Legend:

Unmodified
Added
Removed
  • benchmark/Makefile.am

    r3c6e417 r54dd994  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Nov  6 09:01:23 2018
    14 ## Update Count     : 26
     13## Last Modified On : Sun Jun 23 12:34:29 2019
     14## Update Count     : 52
    1515###############################################################################
    1616
     
    2121include $(top_srcdir)/src/cfa.make
    2222
    23 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     23AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror
    2424AM_CFAFLAGS = -quiet -nodebug -in-tree
    2525AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
     
    3131BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    3232BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
     33BENCH_V_QTHREAD = $(__bench_v_QTHREAD_$(__quiet))
    3334
    3435__quiet = verbose
     
    4546__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    4647__bench_v_UPP_verbose = $(AM_V_UPP)
    47 
     48__bench_v_QTHREAD_verbose = $(AM_V_CC)
    4849
    4950
     
    5152REPEAT   = ${abs_top_builddir}/tools/repeat
    5253STATS    = ${abs_top_srcdir}/tools/stat.py
    53 repeats  = 30
     54repeats  = 3 # 30
    5455skipcompile = no
    5556TIME_FORMAT = "%E"
     
    124125
    125126ctxswitch.csv:
    126         @echo "coroutine,thread" > $@
     127        @echo "generator,coroutine,thread" > $@
     128        @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
    127129        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    128130        @+make ctxswitch-cfa_thread.runquiet >> $@
     
    153155        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    154156
     157ttst_lock$(EXEEXT):
     158        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
     159
    155160tls-fetch_add$(EXEEXT):
    156161        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     
    161166        function.run                    \
    162167        fetch_add.run                   \
     168        ttst_lock.run                   \
    163169        tls-fetch_add.run                       \
    164170        ctxswitch-pthread.run           \
     171        ctxswitch-cfa_generator.run     \
    165172        ctxswitch-cfa_coroutine.run     \
    166173        ctxswitch-cfa_thread.run        \
     
    169176        ctxswitch-upp_thread.run        \
    170177        ctxswitch-goroutine.run         \
    171         ctxswitch-java_thread.run
     178        ctxswitch-java_thread.run       \
     179        ctxswitch-qthreads.run
     180
    172181
    173182if WITH_LIBFIBRE
     
    188197ctxswitch-pthread$(EXEEXT):
    189198        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     199
     200ctxswitch-cfa_generator$(EXEEXT):
     201        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
    190202
    191203ctxswitch-cfa_coroutine$(EXEEXT):
     
    212224        @echo "java JavaThread" >> a.out
    213225        @chmod a+x a.out
     226
     227ctxswitch-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
    214229
    215230## =========================================================================================================
     
    305320        creation-upp_thread.run                 \
    306321        creation-goroutine.run                  \
    307         creation-java_thread.run
     322        creation-java_thread.run                \
     323        creation-qthreads.run
    308324
    309325creation-cfa_coroutine$(EXEEXT):
     
    333349        @echo "java JavaThread" >> a.out
    334350        @chmod a+x a.out
     351
     352creation-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
    335354
    336355## =========================================================================================================
     
    375394compile-typeof$(EXEEXT):
    376395        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    377 
  • benchmark/Makefile.in

    r3c6e417 r54dd994  
    371371
    372372# applies to both programs
    373 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     373AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror
    374374AM_CFAFLAGS = -quiet -nodebug -in-tree
    375375AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
     
    380380BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    381381BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
     382BENCH_V_QTHREAD = $(__bench_v_QTHREAD_$(__quiet))
    382383__quiet = verbose
    383384__bench_v_CC_quiet = @
     
    393394__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    394395__bench_v_UPP_verbose = $(AM_V_UPP)
     396__bench_v_QTHREAD_verbose = $(AM_V_CC)
    395397TOOLSDIR = ${abs_top_builddir}/tools/
    396398REPEAT = ${abs_top_builddir}/tools/repeat
    397399STATS = ${abs_top_srcdir}/tools/stat.py
    398 repeats = 30
     400repeats = 3 # 30
    399401skipcompile = no
    400402TIME_FORMAT = "%E"
     
    402404dummy_SOURCES = dummyC.c dummyCXX.cpp
    403405FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    404 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \
     406CTXSWITCH_DEPEND = loop.run function.run fetch_add.run ttst_lock.run \
    405407        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)
    410413testdir = $(top_srcdir)/tests
    411414all: all-am
     
    784787
    785788ctxswitch.csv:
    786         @echo "coroutine,thread" > $@
     789        @echo "generator,coroutine,thread" > $@
     790        @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
    787791        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    788792        @+make ctxswitch-cfa_thread.runquiet >> $@
     
    812816        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    813817
     818ttst_lock$(EXEEXT):
     819        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
     820
    814821tls-fetch_add$(EXEEXT):
    815822        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     
    825832ctxswitch-pthread$(EXEEXT):
    826833        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     834
     835ctxswitch-cfa_generator$(EXEEXT):
     836        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
    827837
    828838ctxswitch-cfa_coroutine$(EXEEXT):
     
    849859        @echo "java JavaThread" >> a.out
    850860        @chmod a+x a.out
     861
     862ctxswitch-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
    851864
    852865mutex$(EXEEXT) :\
     
    937950        creation-upp_thread.run                 \
    938951        creation-goroutine.run                  \
    939         creation-java_thread.run
     952        creation-java_thread.run                \
     953        creation-qthreads.run
    940954
    941955creation-cfa_coroutine$(EXEEXT):
     
    965979        @echo "java JavaThread" >> a.out
    966980        @chmod a+x a.out
     981
     982creation-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
    967984
    968985compile$(EXEEXT) :\
  • benchmark/bench.h

    r3c6e417 r54dd994  
    4545        statement;                                      \
    4646        EndTime = bench_time();                 \
    47         unsigned long long int output =         \
    48         ( EndTime - StartTime ) / n;
     47        double output =         \
     48            (double)( EndTime - StartTime ) / n;
    4949
    5050#if defined(__cforall)
  • benchmark/creation/cfa_cor.cfa

    r3c6e417 r54dd994  
    1010#endif
    1111}
    12 void main(MyCoroutine & this) {}
     12void main(MyCoroutine &) {}
    1313
    1414int main(int argc, char* argv[]) {
    1515        BENCH(
    16                 for (size_t i = 0; i < n; i++) {
     16                for ( i; n ) {
    1717                        MyCoroutine m;
    1818                },
     
    2020        )
    2121
    22         printf("%llu\n", result);
     22        printf("%g\n", result);
    2323}
  • benchmark/creation/cfa_thrd.cfa

    r3c6e417 r54dd994  
    55
    66thread MyThread {};
    7 void main(MyThread & this) {}
     7void main(MyThread &) {}
    88
    99int main(int argc, char* argv[]) {
    1010        BENCH(
    11                 for (size_t i = 0; i < n; i++) {
     11                for ( i; n ) {
    1212                        MyThread m;
    1313                },
     
    1515        )
    1616
    17         printf("%llu\n", result);
     17        printf("%g\n", result);
    1818}
  • benchmark/creation/pthreads.c

    r3c6e417 r54dd994  
    2525        )
    2626
    27         printf("%llu\n", result);
     27        printf("%g\n", result);
    2828}
  • benchmark/creation/upp_cor.cc

    r3c6e417 r54dd994  
    1515        )
    1616
    17         printf("%llu\n", result);
     17        printf("%g\n", result);
    1818}
  • benchmark/creation/upp_thrd.cc

    r3c6e417 r54dd994  
    1515        )
    1616
    17         printf("%llu\n", result);
     17        printf("%g\n", result);
    1818}
  • benchmark/ctxswitch/cfa_cor.cfa

    r3c6e417 r54dd994  
    1 #include <stdio.h>
    21#include <kernel.hfa>
    32#include <thread.hfa>
     
    2120
    2221        BENCH(
    23                 for (size_t i = 0; i < n; i++) {
     22                for ( i; n ) {
    2423                        resume( s );
    2524                },
     
    2726        )
    2827
    29         printf("%llu\n", result);
     28        printf("%g\n", result);
    3029}
  • benchmark/ctxswitch/cfa_cor_then.cfa

    r3c6e417 r54dd994  
    1 #include <stdio.h>
    21#include <kernel.hfa>
    32#include <thread.hfa>
     
    2322
    2423        BENCH(
    25                 for (size_t i = 0; i < n; i++) {
     24                for ( i; n ) {
    2625                        resume( s );
    2726                },
     
    2928        )
    3029
    31         printf("%llu\n", result);
     30        printf("%g\n", result);
    3231}
  • benchmark/ctxswitch/cfa_thrd.cfa

    r3c6e417 r54dd994  
    1 #include <stdio.h>
    21#include <thread.hfa>
    32
     
    65int main(int argc, char* argv[]) {
    76        BENCH(
    8                 for (size_t i = 0; i < n; i++) {
     7                for ( i; n ) {
    98                        yield();
    109                },
     
    1211        )
    1312
    14         printf("%llu\n", result);
     13        printf("%g\n", result);
    1514}
  • benchmark/ctxswitch/cfa_thrd2.cfa

    r3c6e417 r54dd994  
    1 #include <stdio.h>
    21#include <thread.hfa>
    32
     
    1716        Fibre f1;
    1817        BENCH(
    19                 for (size_t i = 0; i < n; i++) {
     18                for ( i; n ) {
    2019                        yield();
    2120                },
     
    2322        )
    2423
    25         printf("%llu\n", result);
     24        printf("%g\n", result);
    2625        done = true;
    2726        return 0;
  • benchmark/ctxswitch/kos_fibre.cpp

    r3c6e417 r54dd994  
    1010                result
    1111        )
    12         printf("%llu\n", result);
     12        printf("%g\n", result);
    1313        return 0;
    1414}
  • benchmark/ctxswitch/kos_fibre2.cpp

    r3c6e417 r54dd994  
    1919                result
    2020        )
    21         printf("%llu\n", result);
     21        printf("%g\n", result);
    2222        done = true;
    2323        Fibre::yield();
  • benchmark/ctxswitch/pthreads.c

    r3c6e417 r54dd994  
    1414        )
    1515
    16         printf("%llu\n", result);
     16        printf("%g\n", result);
    1717}
  • benchmark/ctxswitch/upp_cor.cc

    r3c6e417 r54dd994  
    3030        )
    3131
    32         printf("%llu\n", result);
     32        printf("%g\n", result);
    3333}
  • benchmark/ctxswitch/upp_thrd.cc

    r3c6e417 r54dd994  
    1111        )
    1212
    13         printf("%llu\n", result);
     13        printf("%g\n", result);
    1414}
  • benchmark/fetch_add.c

    r3c6e417 r54dd994  
    1919        )
    2020
    21         printf("%llu\n", result);
     21        printf("%g\n", result);
    2222}
  • benchmark/function.c

    r3c6e417 r54dd994  
    1515        )
    1616
    17         printf("%llu\n", result);
     17        printf("%g\n", result);
    1818}
  • benchmark/loop.c

    r3c6e417 r54dd994  
    1111        )
    1212
    13         printf("%llu\n", result);
     13        printf("%g\n", result);
    1414}
  • benchmark/mutex/cfa1.cfa

    r3c6e417 r54dd994  
    1010        M m;
    1111        BENCH(
    12                 for (size_t i = 0; i < n; i++) {
     12                for ( i; n ) {
    1313                        call(m);
    1414                },
     
    1616        )
    1717
    18         printf("%llu\n", result);
     18        printf("%g\n", result);
    1919}
  • benchmark/mutex/cfa2.cfa

    r3c6e417 r54dd994  
    1010        M m1, m2;
    1111        BENCH(
    12                 for (size_t i = 0; i < n; i++) {
     12                for ( i; n ) {
    1313                        call(m1, m2);
    1414                },
     
    1616        )
    1717
    18         printf("%llu\n", result);
     18        printf("%g\n", result);
    1919}
  • benchmark/mutex/cfa4.cfa

    r3c6e417 r54dd994  
    1111        M m1, m2, m3, m4;
    1212        BENCH(
    13                 for (size_t i = 0; i < n; i++) {
     13                for ( i; n ) {
    1414                        call(m1, m2, m3, m4);
    1515                },
     
    1717        )
    1818
    19         printf("%llu\n", result);
     19        printf("%g\n", result);
    2020}
  • benchmark/mutex/pthreads.c

    r3c6e417 r54dd994  
    1919        )
    2020
    21         printf("%llu\n", result);
     21        printf("%g\n", result);
    2222}
  • benchmark/mutex/upp.cc

    r3c6e417 r54dd994  
    1717        )
    1818
    19         printf("%llu\n", result);
     19        printf("%g\n", result);
    2020}
  • benchmark/schedext/cfa1.cfa

    r3c6e417 r54dd994  
    1818        go = 1;
    1919        BENCH(
    20                 for (size_t i = 0; i < n; i++) {
     20                for ( i; n ) {
    2121                        waitfor(call, a1);
    2222                },
     
    2424        )
    2525
    26         printf("%llu\n", result);
     26        printf("%g\n", result);
    2727        go = 0;
    2828        return 0;
     
    3131thread T {};
    3232void ^?{}( T & mutex this ) {}
    33 void main( T & this ) {
     33void main( T & ) {
    3434        while(go == 0) { yield(); }
    3535        while(go == 1) { call(m1); }
     
    3737}
    3838
    39 int main(int margc, char* margv[]) {
    40         argc = margc;
    41         argv = margv;
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4240        T t;
    4341        return wait(m1);
  • benchmark/schedext/cfa2.cfa

    r3c6e417 r54dd994  
    1818        go = 1;
    1919        BENCH(
    20                 for (size_t i = 0; i < n; i++) {
     20                for ( i; n ) {
    2121                        waitfor(call, a1, a2);
    2222                },
     
    2424        )
    2525
    26         printf("%llu\n", result);
     26        printf("%g\n", result);
    2727        go = 0;
    2828        return 0;
     
    3131thread T {};
    3232void ^?{}( T & mutex this ) {}
    33 void main( T & this ) {
     33void main( T & ) {
    3434        while(go == 0) { yield(); }
    3535        while(go == 1) { call(m1, m2); }
     
    3737}
    3838
    39 int main(int margc, char* margv[]) {
    40         argc = margc;
    41         argv = margv;
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4240        T t;
    4341        return wait(m1, m2);
  • benchmark/schedext/cfa4.cfa

    r3c6e417 r54dd994  
    1818        go = 1;
    1919        BENCH(
    20                 for (size_t i = 0; i < n; i++) {
     20                for ( i; n ) {
    2121                        waitfor(call, a1, a2, a3, a4);
    2222                },
     
    2424        )
    2525
    26         printf("%llu\n", result);
     26        printf("%g\n", result);
    2727        go = 0;
    2828        return 0;
     
    3131thread T {};
    3232void ^?{}( T & mutex this ) {}
    33 void main( T & this ) {
     33void main( T & ) {
    3434        while(go == 0) { yield(); }
    3535        while(go == 1) { call(m1, m2, m3, m4); }
     
    3737}
    3838
    39 int main(int margc, char* margv[]) {
    40         argc = margc;
    41         argv = margv;
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4240        T t;
    4341        return wait(m1, m2, m3, m4);
  • benchmark/schedext/upp.cc

    r3c6e417 r54dd994  
    2020                )
    2121
    22                 printf("%llu\n", result);
     22                printf("%g\n", result);
    2323                go = 0;
    2424                return 0;
  • benchmark/schedint/cfa1.cfa

    r3c6e417 r54dd994  
    2121        go = 1;
    2222        BENCH(
    23                 for (size_t i = 0; i < n; i++) {
     23                for ( i; n ) {
    2424                        wait(c);
    2525                },
     
    2727        )
    2828
    29         printf("%llu\n", result);
     29        printf("%g\n", result);
    3030        go = 0;
    3131        return 0;
     
    3333
    3434thread T {};
    35 void ^?{}( T & mutex this ) {}
    36 void main( T & this ) {
     35void ^?{}( T & mutex ) {}
     36void main( T & ) {
    3737        while(go == 0) { yield(); }
    3838        while(go == 1) { call(m1); }
     
    4040}
    4141
    42 int main(int margc, char* margv[]) {
    43         argc = margc;
    44         argv = margv;
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4543        T t;
    4644        return wait(m1);
  • benchmark/schedint/cfa2.cfa

    r3c6e417 r54dd994  
    2121        go = 1;
    2222        BENCH(
    23                 for (size_t i = 0; i < n; i++) {
     23                for ( i; n ) {
    2424                        wait(c);
    2525                },
     
    2727        )
    2828
    29         printf("%llu\n", result);
     29        printf("%g\n", result);
    3030        go = 0;
    3131        return 0;
     
    3434thread T {};
    3535void ^?{}( T & mutex this ) {}
    36 void main( T & this ) {
     36void main( T & ) {
    3737        while(go == 0) { yield(); }
    3838        while(go == 1) { call(m1, m2); }
     
    4040}
    4141
    42 int main(int margc, char* margv[]) {
    43         argc = margc;
    44         argv = margv;
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4543        T t;
    4644        return wait(m1, m2);
  • benchmark/schedint/cfa4.cfa

    r3c6e417 r54dd994  
    2121        go = 1;
    2222        BENCH(
    23                 for (size_t i = 0; i < n; i++) {
     23                for ( i; n ) {
    2424                        wait(c);
    2525                },
     
    2727        )
    2828
    29         printf("%llu\n", result);
     29        printf("%g\n", result);
    3030        go = 0;
    3131        return 0;
     
    3434thread T {};
    3535void ^?{}( T & mutex this ) {}
    36 void main( T & this ) {
     36void main( T & ) {
    3737        while(go == 0) { yield(); }
    3838        while(go == 1) { call(m1, m2, m3, m4); }
     
    4040}
    4141
    42 int main(int margc, char* margv[]) {
    43         argc = margc;
    44         argv = margv;
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4543        T t;
    4644        return wait(m1, m2, m3, m4);
  • benchmark/schedint/pthreads.c

    r3c6e417 r54dd994  
    2727        )
    2828
    29         printf("%llu\n", result);
     29        printf("%g\n", result);
    3030        go = 0;
    3131        pthread_mutex_unlock(&m);
     
    3333}
    3434
    35 void* thread_main(void * a) {
     35void* thread_main(__attribute__((unused)) void * arg ) {
    3636        while(go == 0) { sched_yield(); }
    3737        while(go == 1) { call(); }
     
    3939}
    4040
    41 int main(int margc, char* margv[]) {
    42         argc = margc;
    43         argv = margv;
     41int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4442        pthread_t thread;
    4543        if (pthread_create(&thread, NULL, thread_main, NULL) < 0) {
  • benchmark/schedint/upp.cc

    r3c6e417 r54dd994  
    2323                )
    2424
    25                 printf("%llu\n", result);
     25                printf("%g\n", result);
    2626                go = 0;
    2727                return 0;
     
    3939};
    4040
    41 int main(int margc, char* margv[]) {
    42         argc = margc;
    43         argv = margv;
     41int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4442        T t;
    4543        return m.wait();
  • benchmark/tls-fetch_add.c

    r3c6e417 r54dd994  
    2424        )
    2525
    26         printf("%llu\n", result);
     26        printf("%g\n", result);
    2727}
  • doc/bibliography/pl.bib

    r3c6e417 r54dd994  
    948948    author      = {{\textsf{C}{$\mathbf{\forall}$} Features}},
    949949    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}},
    950957}
    951958
     
    19191926    year        = 1965,
    19201927    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}},
    19211951}
    19221952
     
    43594389}
    43604390
     4391
    43614392@article{Liskov86,
    43624393    keywords    = {synchronous communication, concurrency},
     
    43714402    year        = {},
    43724403    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}},
    43734414}
    43744415
     
    44934534    year        = 2016,
    44944535    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}},
    44984537    optnote     = {Accessed: 2016-09},
    44994538}
     
    45174556        trivial changes to the source code of the library.
    45184557    }
     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}},
    45194568}
    45204569
  • doc/papers/AMA/AMA-stix/ama/WileyNJD-v2.cls

    r3c6e417 r54dd994  
    24442444     \@afterheading}
    24452445
    2446 \renewcommand\section{\@startsection{section}{1}{\z@}{-27pt \@plus -2pt \@minus -2pt}{12\p@}{\sectionfont}}%
    2447 \renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-23pt \@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}}%
    24482448\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-20pt \@plus -2pt \@minus -2pt}{2\p@}{\subsubsectionfont}}%
    24492449%
  • doc/papers/concurrency/Paper.tex

    r3c6e417 r54dd994  
    157157                __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    158158                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,
    160160                _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    161161                virtual, __volatile, __volatile__, waitfor, when, with, zero_t},
     
    303303However, \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;
    304304no high-level language concurrency features are defined.
    305 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach.
     305Interestingly, 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.
    306306Finally, 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}.
    307307
     
    313313From 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}.
    314314The 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}.
     315As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{Adya02,vonBehren03}.
    316316Finally, 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.
    317317
     
    613613Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types.
    614614\begin{cfa}
    615 int ?()( Fib & fib ) with( fib ) { return `resume( fib )`.fn; }   // function-call interface
    616 int ?()( Fib & fib, int N ) with( fib ) { for ( N - 1 ) `fib()`; return `fib()`; }   // use simple interface
    617 double ?()( Fib & fib ) with( fib ) { return (int)`fib()` / 3.14159; } // cast prevents recursive call
    618 sout | (int)f1() | (double)f1() | f2( 2 );   // simple interface, cast selects call based on return type, step 2 values
     615int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$
     616int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// use function-call interface to skip N values}$
     617double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}\CRT$
     618sout | (int)f1() | (double)f1() | f2( 2 ); // alternative interface, cast selects call based on return type, step 2 values
    619619\end{cfa}
    620620Now, the generator can be a separately-compiled opaque-type only accessed through its interface functions.
     
    628628With 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.
    629629Finally, 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 with this kind of semantic programming requirement, if it results in very small, fast generators.
     630As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small, fast generators.
    631631
    632632Figure~\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.
     
    796796This semantics is basically a tail-call optimization, which compilers already perform.
    797797The 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.
     798This assembly code depends on what entry code is generated, specifically if there are local variables, and the level of optimization.
    799799To provide this new calling convention requires a mechanism built into the compiler, which is beyond the scope of \CFA at this time.
    800800Nevertheless, 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.
     801A 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@.
    802802
    803803\begin{figure}
     
    12131213Hence, a compromise solution is necessary that works for asymmetric (acyclic) and symmetric (cyclic) coroutines.
    12141214
    1215 Our solution for coroutine termination works well for the most common asymmetric and symmetric coroutine usage-patterns.
     1215Our solution is to context switch back to the first resumer (starter) once the coroutine ends.
     1216This semantics works well for the most common asymmetric and symmetric coroutine usage-patterns.
    12161217For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer.
    12171218All previous generators converted to coroutines have this property.
     
    12451246
    12461247
    1247 \subsection{(Generator) Coroutine Implementation}
     1248\subsection{Generator / Coroutine Implementation}
    12481249
    12491250A 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.
     
    12541255class myCoroutine inherits baseCoroutine { ... }
    12551256\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.
     1258The 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.
    12581259Alternatives, such as explicitly starting threads as in Java, are repetitive and forgetting to call start is a common source of errors.
    12591260An alternative is composition:
     
    12671268However, there is nothing preventing wrong placement or multiple declarations.
    12681269
    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,
     1272and IDEs using simple parsing can find and manipulate types with special properties.
    12701273The downside of this approach is that it makes custom types a special case in the language.
    12711274Users wanting to extend custom types or build their own can only do so in ways offered by the language.
     
    12821285\end{cfa}
    12831286Note, 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.
     1287For example, both the resumer and suspender descriptors can have bi-directional pointers;
     1288copying these coroutines does not update the internal pointers so behaviour of both copies would be difficult to understand.
    12861289Furthermore, two coroutines cannot logically execute on the same stack.
    12871290A 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.
    12881291The \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 currently executing coroutine handle.
     1292The 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.
    12901293The @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.
    12911294The 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@.
     
    14931496\end{tabular}
    14941497\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 thread handle, and a special destructor to prevent deallocation while the thread is executing.
     1498Like 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).
     1499Similarly, 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.
    14971500(The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitor}.)
    14981501The 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;
     
    16171620% 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.
    16181621% 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 monitor handle, and a special destructor to prevent deallocation if a thread using the shared data.
     1622Similarly, 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.
    16201623The custom monitor type also inserts any locks needed to implement the mutual exclusion semantics.
    16211624
     
    16561659called \newterm{bulk acquire}.
    16571660\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.
     1661Figure~\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.
    16591662A \CFA programmer only has to manage when to acquire mutual exclusion;
    16601663a \CC programmer must select the correct lock and acquisition mechanism from a panoply of locking options.
     
    18001803Figure~\ref{f:MonitorScheduling} shows general internal/external scheduling (for the bounded-buffer example in Figure~\ref{f:InternalExternalScheduling}).
    18011804External 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.
     1805Internal threads block on condition queues via @wait@ and reenter from the condition in FIFO order.
     1806Alternatively, 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.
    18031807
    18041808There 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.
     1809Note, 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.
    18061810For internal scheduling, threads are unblocked from condition queues using @signal@, where the signallee is moved to urgent and the signaller continues (solid line).
    18071811Multiple signals move multiple signallees to urgent, until the condition is empty.
     
    18431847It 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.
    18441848In \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.
    18461850
    18471851% Signalling semantics cannot have the signaller and signalled thread in the monitor simultaneously, which means:
     
    18521856% The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
    18531857% \item
    1854 % The signalling thread blocks but is marked for urgrent 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.
    18551859% \end{enumerate}
    18561860% The first approach is too restrictive, as it precludes solving a reasonable class of problems, \eg dating service (see Figure~\ref{f:DatingService}).
     
    19611965External 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.
    19621966If 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 excluded block outside of (external to) the monitor on the calling queue, versus blocking on condition queues inside of (internal to) the monitor.
     1967Threads 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.
    19641968Figure~\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@.
    19651969The writer does a similar action for each reader or writer using the resource.
     
    20762080For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex parameters, \ie @wait( e, m1, m2 )@.
    20772081To 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.
     2082Wait cannot statically verifies the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
    20792083While \CC supports bulk locking, @wait@ only accepts a single lock for a condition variable, so bulk locking with condition variables is asymmetric.
    20802084Finally, a signaller,
     
    20882092Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn, m1, m2 )@.
    20892093To 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.
    20922095% When an overloaded function appears in an @waitfor@ statement, calls to any function with that name are accepted.
    20932096% The rationale is that members with the same name should perform a similar function, and therefore, all should be eligible to accept a call.
     
    21482151The right example accepts either @mem1@ or @mem2@ if @C1@ and @C2@ are true.
    21492152
    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.
     2153An 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}
     2155void 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}
     2164When the program main deallocates the buffer, it first calls the buffer's destructor, which is accepted, the destructor runs, and the buffer is deallocated.
     2165However, the buffer thread cannot continue after the destructor call because the object is gone;
     2166hence, clean up in @main@ cannot occur, which means destructors for local objects are not run.
     2167To 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.
     2168Then, the destructor caller unblocks from urgent to deallocate the object.
     2169Accepting the destructor is the idiomatic way in \CFA to terminate a thread performing direct communication.
    21632170
    21642171
     
    23572364
    23582365struct Msg { int i, j; };
    2359 thread Gortn { int i;  float f;  Msg m; };
    2360 void mem1( Gortn & mutex gortn, int i ) { gortn.i = i; }
    2361 void mem2( Gortn & mutex gortn, float f ) { gortn.f = f; }
    2362 void mem3( Gortn & mutex gortn, Msg m ) { gortn.m = m; }
    2363 void ^?{}( Gortn & mutex ) {}
    2364 
    2365 void main( Gortn & gortn ) with( gortn ) {  // thread starts
     2366thread GoRtn { int i;  float f;  Msg m; };
     2367void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; }
     2368void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; }
     2369void mem3( GoRtn & mutex gortn, Msg m ) { gortn.m = m; }
     2370void ^?{}( GoRtn & mutex ) {}
     2371
     2372void main( GoRtn & gortn ) with( gortn ) {  // thread starts
    23662373
    23672374        for () {
     
    23762383}
    23772384int main() {
    2378         Gortn gortn; $\C[2.0in]{// start thread}$
     2385        GoRtn gortn; $\C[2.0in]{// start thread}$
    23792386        `mem1( gortn, 0 );` $\C{// different calls}\CRT$
    23802387        `mem2( gortn, 2.5 );`
     
    25342541% However, preemption is necessary for fairness and to reduce tail-latency.
    25352542% 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
     2548In 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.
     2549If the jobs are dependent, \ie interact, there is an implicit/explicit dependency graph that ties them together.
     2550While removing direct concurrency, and hence the amount of context switching, thread pools significantly limit the interaction that can occur among jobs.
     2551Indeed, jobs should not block because that also blocks the underlying thread, which effectively means the CPU utilization, and therefore throughput, suffers.
     2552While 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.
     2553As 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}
     2559struct Adder {
     2560    int * row, cols;
     2561};
     2562int operator()() {
     2563        subtotal = 0;
     2564        for ( int c = 0; c < cols; c += 1 )
     2565                subtotal += row[c];
     2566        return subtotal;
     2567}
     2568void ?{}( 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}
     2578int 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}
    25462599
    25472600
     
    25672620The purpose of a cluster is to control the amount of parallelism that is possible among threads, plus scheduling and other execution defaults.
    25682621The 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.
     2622However, the design allows changing the scheduler, \eg multi-queue multi-server with work-stealing/sharing across the virtual processors.
    25702623If several clusters exist, both threads and virtual processors, can be explicitly migrated from one cluster to another.
    25712624No automatic load balancing among clusters is performed by \CFA.
     
    25742627The user cluster is created to contain the application user-threads.
    25752628Having 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.
     2629However, because of limitations of scheduling requirements (real-time), NUMA architecture, heterogeneous hardware, or issues with the underlying operating system, multiple clusters are sometimes necessary.
    25772630
    25782631
     
    26182671\subsection{Preemption}
    26192672
    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.
     2673Nondeterministic 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.
     2674This atomic reliance can fail on multi-core machines, because execution across cores is nondeterministic.
     2675A 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).
    26222676Preemption is normally handled by setting a count-down timer on each virtual processor.
    26232677When 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.
     
    26282682Because preemption frequency is usually long (1 millisecond) performance cost is negligible.
    26292683
    2630 However, on current Linux systems:
     2684Linux switched a decade ago from specific to arbitrary process signal-delivery for applications with multiple kernel threads.
    26312685\begin{cquote}
    26322686A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked.
     
    26342688SIGNAL(7) - Linux Programmer's Manual
    26352689\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.
     2690Hence, 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).
     2691To 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.
    26382692Virtual processors register an expiration time with the discrete-event simulator, which is inserted in sorted order.
    26392693The 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.
     
    26522706
    26532707To 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.
     2708The 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.
    26552709
    26562710\begin{comment}
     
    27072761\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    27082762\begin{cfa}
    2709 thread MyThread {};
    2710 void main( MyThread & ) {}
     2763@thread@ MyThread {};
     2764void @main@( MyThread & ) {}
    27112765int main() {
    27122766        BENCH( for ( N ) { @MyThread m;@ } )
     
    27502804\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    27512805\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2752 coroutine C {} c;
     2806@coroutine@ C {} c;
    27532807void main( C & ) { for ( ;; ) { @suspend;@ } }
    27542808int main() { // coroutine test
     
    27712825\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    27722826\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   \\
     2827C function              & 2                     & 2             & 0             \\
     2828\CFA generator  & 2                     & 2             & 0             \\
    27742829\CFA Coroutine  & 49    & 48.68         & 0.47  \\
    27752830\CFA Thread             & 105   & 105.57        & 1.37  \\
     
    27772832\uC Thread              & 100   & 99.29         & 0.96  \\
    27782833Goroutine               & 145   & 147.25        & 4.15  \\
    2779 Java Thread             & 373.5 & 375.14        & 8.72
     2834Java Thread             & 373.5 & 375.14        & 8.72  \\
     2835Pthreads Thread & 333.5 & 332.96        & 4.1
    27802836\end{tabular}
    27812837\end{multicols}
     
    27932849\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    27942850\begin{cfa}
    2795 monitor M {} m1/*, m2, m3, m4*/;
     2851@monitor@ M {} m1/*, m2, m3, m4*/;
    27962852void __attribute__((noinline))
    2797 do_call( M & mutex m/*, m2, m3, m4*/ ) {}
     2853do_call( M & @mutex m/*, m2, m3, m4*/@ ) {}
    27982854int main() {
    27992855        BENCH(
    2800                 for( N ) @do_call( m1/*, m2, m3, m4*/ );@
     2856                for( N ) do_call( m1/*, m2, m3, m4*/ );
    28012857        )
    28022858        sout | result`ns;
     
    28132869\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    28142870\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             \\
     2871test and test-and-test lock             & 26            & 26    & 0             \\
    28172872Pthreads Mutex Lock                             & 31            & 31.71 & 0.97  \\
    28182873\uC @monitor@ member rtn.               & 31            & 31    & 0             \\
     
    28202875\CFA @mutex@ function, 2 arg.   & 84            & 85.36 & 1.99  \\
    28212876\CFA @mutex@ function, 4 arg.   & 158           & 161   & 4.22  \\
    2822 Java synchronized function              & 27.5          & 29.79 & 2.93
     2877Java synchronized method                & 27.5          & 29.79 & 2.93
    28232878\end{tabular}
    28242879\end{multicols}
     
    28362891\begin{cfa}
    28372892volatile int go = 0;
    2838 monitor M { condition c; } m;
     2893@monitor@ M { @condition c;@ } m;
    28392894void __attribute__((noinline))
    2840 do_call( M & mutex a1 ) { @signal( c );@ }
     2895do_call( M & @mutex@ a1 ) { @signal( c );@ }
    28412896thread T {};
    28422897void main( T & this ) {
     
    28692924\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    28702925Pthreads Cond. Variable         & 6005          & 5681.43       & 835.45        \\
    2871 \uC @signal@                            & 324           & 325.54        & 3,02          \\
     2926\uC @signal@                            & 324           & 325.54        & 3.02          \\
    28722927\CFA @signal@, 1 @monitor@      & 368.5         & 370.61        & 4.77          \\
    28732928\CFA @signal@, 2 @monitor@      & 467           & 470.5         & 6.79          \\
     
    28892944\begin{cfa}
    28902945volatile int go = 0;
    2891 monitor M {} m;
     2946@monitor@ M {} m;
    28922947thread T {};
    28932948void __attribute__((noinline))
    2894 do_call( M & mutex ) {}
     2949do_call( M & @mutex@ ) {}
    28952950void main( T & ) {
    28962951        while ( go == 0 ) { yield(); }
    2897         while ( go == 1 ) { @do_call( m );@ }
     2952        while ( go == 1 ) { do_call( m ); }
    28982953}
    28992954int __attribute__((noinline))
    2900 do_wait( M & mutex m ) {
     2955do_wait( M & @mutex@ m ) {
    29012956        go = 1; // continue other thread
    29022957        BENCH( for ( N ) { @waitfor( do_call, m );@ } )
  • doc/papers/concurrency/annex/local.bib

    r3c6e417 r54dd994  
    6666}
    6767
    68 @article{BankTransfer,
     68@misc{BankTransfer,
    6969        key     = {Bank Transfer},
    7070        keywords        = {Bank Transfer},
    7171        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}},
    7473        year            = 2010
    7574}
  • doc/papers/concurrency/examples/Fib.cfa

    r3c6e417 r54dd994  
    1313}
    1414
    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 }
     16typedef struct { int fn1, fn; } Fib;
     17int fib_state( Fib & f ) with(f) {
     18        int ret = fn; fn = fn1; fn1 = fn + ret;
     19        return ret;
    2020}
    2121
     
    3232coroutine Fib2 { int fn; };                                             // used for communication
    3333void 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];
    3536        for () {
    36                 fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;  // general case
    3737                suspend();                                                              // restart last resume
     38                [fn1, fn] = [fn, fn + fn1];
    3839        }
    3940}
    40 int ?()( Fib2 & fib ) with( fib ) {
     41int ?()( Fib2 & fib ) {                                                 // function-call interface
    4142        return resume( fib ).fn;                                        // restart last suspend
    4243}
    43 int ?()( Fib2 & fib, int N ) with( fib ) {
    44         for ( N - 1 ) fib();
     44int ?()( Fib2 & fib, int N ) {                                  // skip N values
     45        for ( N - 1 ) fib();                                            // use function-call interface
    4546        return fib();
    4647}
    47 double ?()( Fib2 & fib ) with( fib ) {
    48         return (int)(fib()) / 3.14159;                                          // restart last suspend
     48double ?()( Fib2 & fib ) {                                              // different return type
     49        return (int)(fib()) / 3.14159;                          // cast prevents recursive call
    4950}
    5051
  • doc/user/user.tex

    r3c6e417 r54dd994  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun May  5 18:24:50 2019
    14 %% Update Count     : 3489
     13%% Last Modified On : Sat Jun 15 16:29:45 2019
     14%% Update Count     : 3847
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    254254\begin{lstlisting}
    255255®forall( otype T )® T identity( T val ) { return val; }
    256 int forty_two = identity( 42 );                         §\C{// T is bound to int, forty\_two == 42}§
     256int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§
    257257\end{lstlisting}
    258258% extending the C type system with parametric polymorphism and overloading, as opposed to the \Index*[C++]{\CC{}} approach of object-oriented extensions.
     
    282282
    283283double 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}§
     284double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§
    285285\end{lstlisting}
    286286which can be augmented simply with a polymorphic, type-safe, \CFA-overloaded wrappers:
     
    291291
    292292forall( 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
     296double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§
    297297int posn = bsearch( 5.0, vals, 10 );
    298298\end{lstlisting}
     
    306306\begin{lstlisting}
    307307forall( 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}§
     308int * ip = malloc(); §\C{// select type and size from left-hand side}§
    309309double * dp = malloc();
    310310struct S {...} * sp = malloc();
     
    318318\begin{cfa}
    319319char ®abs®( char );
    320 extern "C" { int ®abs®( int ); }                        §\C{// use default C routine for int}§
     320extern "C" { int ®abs®( int ); } §\C{// use default C routine for int}§
    321321long int ®abs®( long int );
    322322long long int ®abs®( long long int );
     
    426426\begin{cfa}
    427427#ifndef __CFORALL__
    428 #include <stdio.h>§\indexc{stdio.h}§            §\C{// C header file}§
     428#include <stdio.h>§\indexc{stdio.h}§ §\C{// C header file}§
    429429#else
    430 #include <fstream>§\indexc{fstream}§            §\C{// \CFA header file}§
     430#include <fstream>§\indexc{fstream}§ §\C{// \CFA header file}§
    431431#endif
    432432\end{cfa}
     
    512512Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    513513\begin{cfa}
    514 int ®`®otype®`® = 3;                                            §\C{// make keyword an identifier}§
     514int ®`®otype®`® = 3; §\C{// make keyword an identifier}§
    515515double ®`®forall®`® = 3.5;
    516516\end{cfa}
     
    523523\begin{cfa}
    524524// 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}§
    527527#define __CFA_BFD_H__
    528528#endif
    529529
    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}§
    531531®
    532532#if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§
     
    544544Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore}, \eg:
    545545\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}§
     5462®_®147®_®483®_®648; §\C{// decimal constant}§
     54756®_®ul; §\C{// decimal unsigned long constant}§
     5480®_®377; §\C{// octal constant}§
     5490x®_®ff®_®ff; §\C{// hexadecimal constant}§
     5500x®_®ef3d®_®aa5c; §\C{// hexadecimal constant}§
     5513.141®_®592®_®654; §\C{// floating constant}§
     55210®_®e®_®+1®_®00; §\C{// floating constant}§
     5530x®_®ff®_®ff®_®p®_®3; §\C{// hexadecimal floating}§
     5540x®_®1.ffff®_®ffff®_®p®_®128®_®l; §\C{// hexadecimal floating long constant}§
     555L®_®§"\texttt{\textbackslash{x}}§®_®§\texttt{ff}§®_®§\texttt{ee}"§; §\C{// wide character constant}§
    556556\end{cfa}
    557557The rules for placement of underscores are:
     
    612612(Does not make sense for ©do©-©while©.)
    613613\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}§
     614if ( ®int x = f()® ) ... §\C{// x != 0}§
     615if ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§
     616if ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§
    617617if ( ®struct S { int i; } x = { f() }; x.i < 4® ) §\C{// relational expression}§
    618618
    619 while ( ®int x = f()® ) ...                                     §\C{// x != 0}§
    620 while ( ®int x = f(), y = g()® ) ...            §\C{// x != 0 \&\& y != 0}§
     619while ( ®int x = f()® ) ... §\C{// x != 0}§
     620while ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§
    621621while ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§
    622622while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... §\C{// relational expression}§
     
    892892\begin{cfa}
    893893switch ( 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}§
    896896  case 0: ...
    897897        ...
    898         ®int z = 0;®                                                    §\C{// unreachable initialization, cannot appear after case}§
     898        ®int z = 0;® §\C{// unreachable initialization, cannot appear after case}§
    899899        z = 2;
    900900  case 1:
    901         ®x = z;®                                                                §\C{// without fall through, z is uninitialized}§
     901        ®x = z;® §\C{// without fall through, z is uninitialized}§
    902902}
    903903\end{cfa}
     
    937937  ®case 5:
    938938        ...
    939         ®fallthru®;                                                             §\C{// explicit fall through}§
     939        ®fallthru®; §\C{// explicit fall through}§
    940940  case 7:
    941941        ...
    942         ®break®                                                                 §\C{// explicit end of switch (redundant)}§
     942        ®break® §\C{// explicit end of switch (redundant)}§
    943943  default:
    944944        j = 3;
     
    961961\begin{cfa}
    962962switch ( x ) {
    963         ®int i = 0;®                                                    §\C{// allowed only at start}§
     963        ®int i = 0;® §\C{// allowed only at start}§
    964964  case 0:
    965965        ...
    966         ®int j = 0;®                                                    §\C{// disallowed}§
     966        ®int j = 0;® §\C{// disallowed}§
    967967  case 1:
    968968        {
    969                 ®int k = 0;®                                            §\C{// allowed at different nesting levels}§
     969                ®int k = 0;® §\C{// allowed at different nesting levels}§
    970970                ...
    971           ®case 2:®                                                             §\C{// disallow case in nested statements}§
     971          ®case 2:® §\C{// disallow case in nested statements}§
    972972        }
    973973  ...
     
    10191019\begin{cfa}
    10201020switch ( i ) {
    1021   case ®1~5:®                                   §\C{// 1, 2, 3, 4, 5}§
     1021  case ®1~5:® §\C{// 1, 2, 3, 4, 5}§
    10221022        ...
    1023   case ®10~15:®                                 §\C{// 10, 11, 12, 13, 14, 15}§
     1023  case ®10~15:® §\C{// 10, 11, 12, 13, 14, 15}§
    10241024        ...
    10251025}
     
    11521152Grouping 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:
    11531153\begin{cfa}
    1154 struct S {                                                                      §\C{// aggregate}§
    1155         char c;                                                                 §\C{// fields}§
     1154struct S { §\C{// aggregate}§
     1155        char c; §\C{// fields}§
    11561156        int i;
    11571157        double d;
     
    11621162\begin{cfa}
    11631163void 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}§
    11651165}
    11661166\end{cfa}
     
    11691169\begin{C++}
    11701170struct S {
    1171         char c;                                                                 §\C{// fields}§
     1171        char c; §\C{// fields}§
    11721172        int i;
    11731173        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}§
    11761176        }
    11771177}
     
    11811181\begin{cfa}
    11821182struct 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}§
     1183int 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}§
    11861186}
    11871187\end{cfa}
     
    11901190Hence, the qualified fields become variables with the side-effect that it is easier to optimizing field references in a block.
    11911191\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}§
     1192void f( S & this ) ®with ( this )® { §\C{// with statement}§
     1193        c; i; d; §\C{\color{red}// this.c, this.i, this.d}§
    11941194}
    11951195\end{cfa}
    11961196with the generality of opening multiple aggregate-parameters:
    11971197\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}§
     1198void 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}§
    12011201}
    12021202\end{cfa}
     
    12201220struct T { int ®i®; int k; int m; } t, w;
    12211221with ( 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}§
    12291229}
    12301230\end{cfa}
     
    12361236There is an interesting problem between parameters and the function-body ©with©, \eg:
    12371237\begin{cfa}
    1238 void ?{}( S & s, int i ) with ( s ) {           §\C{// constructor}§
    1239         ®s.i = i;®  j = 3;  m = 5.5;                    §\C{// initialize fields}§
     1238void ?{}( S & s, int i ) with ( s ) { §\C{// constructor}§
     1239        ®s.i = i;®  j = 3;  m = 5.5; §\C{// initialize fields}§
    12401240}
    12411241\end{cfa}
     
    12561256Finally, a cast may be used to disambiguate among overload variables in a ©with© expression:
    12571257\begin{cfa}
    1258 with ( w ) { ... }                                                      §\C{// ambiguous, same name and no context}§
    1259 with ( (S)w ) { ... }                                           §\C{// unambiguous, cast}§
     1258with ( w ) { ... } §\C{// ambiguous, same name and no context}§
     1259with ( (S)w ) { ... } §\C{// unambiguous, cast}§
    12601260\end{cfa}
    12611261and ©with© expressions may be complex expressions with type reference (see Section~\ref{s:References}) to aggregate:
    12621262% \begin{cfa}
    12631263% struct S { int i, j; } sv;
    1264 % with ( sv ) {                                                         §\C{// implicit reference}§
     1264% with ( sv ) { §\C{// implicit reference}§
    12651265%       S & sr = sv;
    1266 %       with ( sr ) {                                                   §\C{// explicit reference}§
     1266%       with ( sr ) { §\C{// explicit reference}§
    12671267%               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}§
    12701270%               }
    1271 %               i = 2; j = 3;                                           §\C{\color{red}// sr.i, sr.j}§
     1271%               i = 2; j = 3; §\C{\color{red}// sr.i, sr.j}§
    12721272%       }
    1273 %       i = 1; j = 2;                                                   §\C{\color{red}// sv.i, sv.j}§
     1273%       i = 1; j = 2; §\C{\color{red}// sv.i, sv.j}§
    12741274% }
    12751275% \end{cfa}
     
    12791279class C {
    12801280        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}§
    12841284        }
    12851285}
     
    12881288\begin{cfa}
    12891289struct S { int i, j; };
    1290 int mem( S & ®this® ) {                                         §\C{// explicit "this" parameter}§
    1291         ®this.®i = 1;                                                   §\C{// "this" is not elided}§
     1290int mem( S & ®this® ) { §\C{// explicit "this" parameter}§
     1291        ®this.®i = 1; §\C{// "this" is not elided}§
    12921292        ®this.®j = 2;
    12931293}
     
    12971297\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.
    12981298\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}§
     1299int mem( S & this ) ®with( this )® { §\C{// with clause}§
     1300        i = 1; §\C{\color{red}// this.i}§
     1301        j = 2; §\C{\color{red}// this.j}§
    13021302}
    13031303\end{cfa}
     
    13161316        struct S1 { ... } s1;
    13171317        struct S2 { ... } s2;
    1318         ®with( s1 )® {                                                  §\C{// with statement}§
     1318        ®with( s1 )® { §\C{// with statement}§
    13191319                // access fields of s1 without qualification
    1320                 ®with s2® {                                                     §\C{// nesting}§
     1320                ®with s2® { §\C{// nesting}§
    13211321                        // access fields of s1 and s2 without qualification
    13221322                }
     
    13731373Non-local transfer can cause stack unwinding, \ie non-local routine termination, depending on the kind of raise.
    13741374\begin{cfa}
    1375 exception_t E {};                                                       §\C{// exception type}§
     1375exception_t E {}; §\C{// exception type}§
    13761376void f(...) {
    1377         ... throw E{}; ...                                              §\C{// termination}§
    1378         ... throwResume E{}; ...                                §\C{// resumption}§
     1377        ... throw E{}; ... §\C{// termination}§
     1378        ... throwResume E{}; ... §\C{// resumption}§
    13791379}
    13801380try {
     
    14421442For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
    14431443\begin{cfa}
    1444 int ®(*®f®())[®5®]® {...};                              §\C{// definition}§
    1445  ... ®(*®f®())[®3®]® += 1;                              §\C{// usage}§
     1444int ®(*®f®())[®5®]® {...}; §\C{// definition}§
     1445 ... ®(*®f®())[®3®]® += 1; §\C{// usage}§
    14461446\end{cfa}
    14471447Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
     
    16351635*x = 3;                 // implicit dereference
    16361636int * ®const® y = (int *)104;
    1637 *y = *x;                // implicit dereference
     1637*y = *x;                        // implicit dereference
    16381638\end{cfa}
    16391639\end{tabular}
     
    16491649\hline
    16501650\begin{cfa}
    1651 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
     1651lda             r1,100   // load address of x
     1652ld               r2,(r1)   // load value of x
     1653lda             r3,104   // load address of y
     1654st               r2,(r3)   // store x into y
    16551655\end{cfa}
    16561656&
    16571657\begin{cfa}
    16581658
    1659 ld              r2,(100)        // load value of x
    1660 
    1661 st              r2,(104)        // store x into y
     1659ld              r2,(100)   // load value of x
     1660
     1661st              r2,(104)   // store x into y
    16621662\end{cfa}
    16631663\end{tabular}
     
    16731673\begin{cfa}
    16741674int x, y, ®*® p1, ®*® p2, ®**® p3;
    1675 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
     1675p1 = ®&®x;    // p1 points to x
     1676p2 = p1;    // p2 points to x
     1677p1 = ®&®y;    // p1 points to y
     1678p3 = &p2;  // p3 points to p2
    16791679\end{cfa}
    16801680&
     
    16871687For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage
    16881688\begin{cfa}
    1689 p2 = p1 + x;                                    §\C{// compiler infers *p2 = *p1 + x;}§
     1689p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§
    16901690\end{cfa}
    16911691Algol68 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.
     
    16951695In C, objects of pointer type always manipulate the pointer object's address:
    16961696\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}§
     1697p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§
     1698p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§
    16991699\end{cfa}
    17001700even though the assignment to ©p2© is likely incorrect, and the programmer probably meant:
    17011701\begin{cfa}
    1702 p1 = p2;                                                §\C{// pointer address assignment}§
    1703 ®*®p2 = ®*®p1 + x;                              §\C{// pointed-to value assignment / operation}§
     1702p1 = p2; §\C{// pointer address assignment}§
     1703®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§
    17041704\end{cfa}
    17051705The 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©).
     
    17181718\begin{cfa}
    17191719int 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}§
    17241724r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§
    17251725\end{cfa}
     
    17371737For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
    17381738\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}§
    17401740\end{cfa}
    17411741Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
    17421742\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}§
    17441744\end{cfa}
    17451745Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
     
    17491749int x, *p1 = &x, **p2 = &p1, ***p3 = &p2,
    17501750                 &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}§
     1752r3 = 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}§
    17581758\end{cfa}
    17591759Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types.
     
    17621762As for a pointer type, a reference type may have qualifiers:
    17631763\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}§
     1764const int cx = 5; §\C{// cannot change cx;}§
     1765const int & cr = cx; §\C{// cannot change what cr points to}§
     1766®&®cr = &cx; §\C{// can change cr}§
     1767cr = 7; §\C{// error, cannot change cx}§
     1768int & const rc = x; §\C{// must be initialized}§
     1769®&®rc = &x; §\C{// error, cannot change rc}§
     1770const int & const crc = cx; §\C{// must be initialized}§
     1771crc = 7; §\C{// error, cannot change cx}§
     1772®&®crc = &cx; §\C{// error, cannot change crc}§
    17731773\end{cfa}
    17741774Hence, 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}:
    17751775\begin{cfa}
    1776 int & const cr = *0;                            §\C{// where 0 is the int * zero}§
     1776int & const cr = *0; §\C{// where 0 is the int * zero}§
    17771777\end{cfa}
    17781778Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management:
     
    17811781cr = 5;
    17821782free( &cr );
    1783 cr = 7;                                                         §\C{// unsound pointer dereference}§
     1783cr = 7; §\C{// unsound pointer dereference}§
    17841784\end{cfa}
    17851785
     
    18061806\begin{cfa}
    18071807int 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}§
     1809typeof( ar[1] ) p; §\C{// (gcc) is int, \ie the type of referenced object}§
     1810typeof( &ar[1] ) q; §\C{// (gcc) is int \&, \ie the type of reference}§
     1811sizeof( ar[1] ) == sizeof( int ); §\C{// is true, \ie the size of referenced object}§
     1812sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, \ie the size of a reference}§
    18131813\end{cfa}
    18141814
     
    18271827Therefore, for pointer/reference initialization, the initializing value must be an address not a value.
    18281828\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}§
     1829int * p = &x; §\C{// assign address of x}§
     1830®int * p = x;® §\C{// assign value of x}§
     1831int & r = x; §\C{// must have address of x}§
    18321832\end{cfa}
    18331833Like 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).
     
    18381838Similarly, 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.
    18391839\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}§
     1840int & f( int & r ); §\C{// reference parameter and return}§
     1841z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§
    18421842\end{cfa}
    18431843Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©.
     
    18661866void f( int & r );
    18671867void 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}§
     1868f( 3 );                   g( ®&®3 ); §\C{// compiler implicit generates temporaries}§
     1869f( x + y );             g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§
    18701870\end{cfa}
    18711871Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
     
    18781878\begin{cfa}
    18791879void 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}§
     1880void (* fp)( int ); §\C{// routine pointer}§
     1881fp = f; §\C{// reference initialization}§
     1882fp = &f; §\C{// pointer initialization}§
     1883fp = *f; §\C{// reference initialization}§
     1884fp(3); §\C{// reference invocation}§
     1885(*fp)(3); §\C{// pointer invocation}§
    18861886\end{cfa}
    18871887While 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.
    18881888Instead, a routine object should be referenced by a ©const© reference:
    18891889\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}§
     1891fr = ... §\C{// error, cannot change code}§
     1892&fr = ...; §\C{// changing routine reference}§
     1893fr( 3 ); §\C{// reference call to f}§
     1894(*fr)(3); §\C{// error, incorrect type}§
    18951895\end{cfa}
    18961896because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{
     
    19141914int x, * px, ** ppx, *** pppx, **** ppppx;
    19151915int & 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)
     1916x = rrrx; §\C[2.0in]{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§
     1917px = &rrrx; §\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}§
     1918ppx = &&rrrx; §\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}§
     1919pppx = &&&rrrx; §\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}§
     1920ppppx = &&&&rrrx; §\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}§
    19211921\end{cfa}
    19221922The following example shows the second rule applied to different \Index{lvalue} contexts:
     
    19241924int x, * px, ** ppx, *** pppx;
    19251925int & 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)
     1926rrrx = 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§
    19301930\end{cfa}
    19311931
     
    19401940\begin{cfa}
    19411941int x;
    1942 x + 1;                  // lvalue variable (int) converts to rvalue for expression
     1942x + 1; §\C[2.0in]{// lvalue variable (int) converts to rvalue for expression}§
    19431943\end{cfa}
    19441944An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped.
     
    19501950\begin{cfa}
    19511951int x, &r = x, f( int p );
    1952 x = ®r® + f( ®r® );  // lvalue reference converts to rvalue
     1952x = ®r® + f( ®r® ); §\C{// lvalue reference converts to rvalue}§
    19531953\end{cfa}
    19541954An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
     
    19571957lvalue to reference conversion: \lstinline[deletekeywords=lvalue]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.
    19581958\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 &)
     1959int x, &r = ®x®, f( int & p ); §\C{// lvalue variable (int) convert to reference (int \&)}§
     1960f( ®x® ); §\C{// lvalue variable (int) convert to reference (int \&)}§
    19611961\end{cfa}
    19621962Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
     
    19681968\begin{cfa}
    19691969int 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 &)
     1970f( ®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§
    19721972\end{cfa}
    19731973In both case, modifications to the temporary are inaccessible (\Index{warning}).
     
    21582158in 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:
    21592159\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}§
    21622162\end{cfa}
    21632163
     
    21772177\begin{cfa}
    21782178typedef int foo;
    2179 int f( int (* foo) );                           §\C{// foo is redefined as a parameter name}§
     2179int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§
    21802180\end{cfa}
    21812181The 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.
     
    21852185C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
    21862186\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}§
    21892189\end{cfa}
    21902190The 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:
    21912191\begin{cfa}
    21922192#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 ] )}§
     2193int 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 ] )}§
    21952195\end{cfa}
    21962196Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms.
     
    22142214        int z;
    22152215        ... x = 0; ... y = z; ...
    2216         ®return;®                                                       §\C{// implicitly return x, y}§
     2216        ®return;® §\C{// implicitly return x, y}§
    22172217}
    22182218\end{cfa}
     
    22242224[ int x, int y ] f() {
    22252225        ...
    2226 }                                                                               §\C{// implicitly return x, y}§
     2226} §\C{// implicitly return x, y}§
    22272227\end{cfa}
    22282228In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered.
     
    22332233[ int x, int y ] f( int, x, int y ) {
    22342234        ...
    2235 }                                                                               §\C{// implicitly return x, y}§
     2235} §\C{// implicitly return x, y}§
    22362236\end{cfa}
    22372237This notation allows the compiler to eliminate temporary variables in nested routine calls.
    22382238\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}§
    22402240int a, b;
    22412241[a, b] = f( f( f( a, b ) ) );
     
    22512251as well, parameter names are optional, \eg:
    22522252\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}§
    22572257\end{cfa}
    22582258This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa).
     
    22752275The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:
    22762276\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}§
    22812281\end{cfa}
    22822282While parameter names are optional, \emph{a routine name cannot be specified};
    22832283for example, the following is incorrect:
    22842284\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}§
    22862286\end{cfa}
    22872287
     
    23062306whereas a named (keyword) call may be:
    23072307\begin{cfa}
    2308 p( z : 3, x : 4, y : 7 );       §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§
     2308p( z : 3, x : 4, y : 7 );  §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§
    23092309\end{cfa}
    23102310Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
     
    23232323For example, the following routine prototypes and definition are all valid.
    23242324\begin{cfa}
    2325 void p( int, int, int );                        §\C{// equivalent prototypes}§
     2325void p( int, int, int ); §\C{// equivalent prototypes}§
    23262326void p( int x, int y, int z );
    23272327void p( int y, int x, int z );
    23282328void p( int z, int y, int x );
    2329 void p( int q, int r, int s ) {}        §\C{// match with this definition}§
     2329void p( int q, int r, int s ) {} §\C{// match with this definition}§
    23302330\end{cfa}
    23312331Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming.
     
    23392339int f( int x, double y );
    23402340
    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}§
     2341f( j : 3, i : 4 ); §\C{// 1st f}§
     2342f( x : 7, y : 8.1 ); §\C{// 2nd f}§
     2343f( 4, 5 );  §\C{// ambiguous call}§
    23442344\end{cfa}
    23452345However, named arguments compound routine resolution in conjunction with conversions:
    23462346\begin{cfa}
    2347 f( i : 3, 5.7 );                                §\C{// ambiguous call ?}§
     2347f( i : 3, 5.7 ); §\C{// ambiguous call ?}§
    23482348\end{cfa}
    23492349Depending on the cost associated with named arguments, this call could be resolvable or ambiguous.
     
    23592359the allowable positional calls are:
    23602360\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 )}§
     2361p(); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§
     2362p( 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§
     2363p( 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§
     2364p( 4, 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 4 )}§
    23652365// 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 )}§
     2366p(  , 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 4 )}§
     2367p( 4,  , 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 4 )}§
     2368p( 4, 4,   ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§
     2369p( 4,  ,   ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§
     2370p(  , 4,   ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 3 )}§
     2371p(  ,  , 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 4 )}§
     2372p(  ,  ,   ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§
    23732373\end{cfa}
    23742374Here the missing arguments are inserted from the default values in the parameter list.
     
    23942394Default values may only appear in a prototype versus definition context:
    23952395\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}§
     2396void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§
     2397void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§
     2398void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§
    23992399\end{cfa}
    24002400The reason for this restriction is to allow separate compilation.
     
    24212421\begin{cfa}
    24222422void 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 */, ... );}§
     2423p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
     2424p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
    24252425\end{cfa}
    24262426The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments;
     
    24522452Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as:
    24532453\begin{cfa}
    2454 p( 1, /* default */, 5 );               §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§
     2454p( 1, /* default */, 5 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§
    24552455\end{cfa}
    24562456
     
    24652465\begin{cfa}
    24662466struct {
    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}§
    24732473};
    24742474\end{cfa}
     
    24782478\begin{cfa}
    24792479struct {
    2480         int , , ;                               §\C{// 3 unnamed fields}§
     2480        int , , ; §\C{// 3 unnamed fields}§
    24812481}
    24822482\end{cfa}
     
    25722572const unsigned int size = 5;
    25732573int 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}§
     2575qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§
    25762576{
    25772577        ®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}§
    25792579}
    25802580\end{cfa}
     
    25842584The following program in undefined in \CFA (and Indexc{gcc})
    25852585\begin{cfa}
    2586 [* [int]( int )] foo() {                §\C{// int (* foo())( int )}§
     2586[* [int]( int )] foo() { §\C{// int (* foo())( int )}§
    25872587        int ®i® = 7;
    25882588        int bar( int p ) {
    2589                 ®i® += 1;                               §\C{// dependent on local variable}§
     2589                ®i® += 1; §\C{// dependent on local variable}§
    25902590                sout | ®i®;
    25912591        }
    2592         return bar;                                     §\C{// undefined because of local dependence}§
     2592        return bar; §\C{// undefined because of local dependence}§
    25932593}
    25942594int main() {
    2595         * [int]( int ) fp = foo();      §\C{// int (* fp)( int )}§
     2595        * [int]( int ) fp = foo(); §\C{// int (* fp)( int )}§
    25962596        sout | fp( 3 );
    25972597}
     
    26062606In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
    26072607\begin{cfa}
    2608 f( ®2, x, 3 + i® );                             §\C{// element list}§
     2608f( ®2, x, 3 + i® ); §\C{// element list}§
    26092609\end{cfa}
    26102610A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}.
     
    26232623typedef struct { int quot, rem; } div_t;        §\C[7cm]{// from include stdlib.h}§
    26242624div_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}§
     2625div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§
     2626printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§
    26272627\end{cfa}
    26282628This approach requires a name for the return type and fields, where \Index{naming} is a common programming-language issue.
     
    26342634For example, consider C's \Indexc{modf} function, which returns the integral and fractional part of a floating value.
    26352635\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}§
     2636double modf( double x, double * i ); §\C{// from include math.h}§
     2637double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§
     2638printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§
    26392639\end{cfa}
    26402640This approach requires allocating storage for the return values, which complicates the call site with a sequence of variable declarations leading to the call.
     
    26632663When 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.
    26642664\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}§
     2665void g( int, int ); §\C{// 1}§
     2666void g( double, double ); §\C{// 2}§
     2667g( div( 13, 5 ) ); §\C{// select 1}§
     2668g( modf( 13.5 ) ); §\C{// select 2}§
    26692669\end{cfa}
    26702670In this case, there are two overloaded ©g© routines.
     
    26752675The previous examples can be rewritten passing the multiple returned-values directly to the ©printf© function call.
    26762676\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}§
     2678printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§
     2679
     2680[ double, double ] modf( double x ); §\C{// from include math}§
     2681printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§
    26822682\end{cfa}
    26832683This 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.
     
    26892689\begin{cfa}
    26902690int 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}§
     2692printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§
    26932693\end{cfa}
    26942694Here, the multiple return-values are matched in much the same way as passing multiple return-values to multiple parameters in a call.
     
    27162716In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}.
    27172717\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}§
     2719printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§
    27202720\end{cfa}
    27212721It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}.
     
    27232723One way to access the individual components of a tuple variable is with assignment.
    27242724\begin{cfa}
    2725 [ quot, rem ] = qr;                                             §\C{// assign multiple variables}§
     2725[ quot, rem ] = qr; §\C{// assign multiple variables}§
    27262726\end{cfa}
    27272727
     
    27462746[int, double] * p;
    27472747
    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}§
     2748int y = x.0; §\C{// access int component of x}§
     2749y = f().1; §\C{// access int component of f}§
     2750p->0 = 5; §\C{// access int component of tuple pointed-to by p}§
     2751g( x.1, x.0 ); §\C{// rearrange x to pass to g}§
     2752double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§
    27532753\end{cfa}
    27542754Tuple-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.
     
    28172817double y;
    28182818[int, double] z;
    2819 [y, x] = 3.14;                                                  §\C{// mass assignment}§
     2819[y, x] = 3.14; §\C{// mass assignment}§
    28202820[x, y] = z;                                                         §\C{// multiple assignment}§
    28212821z = 10;                                                         §\C{// mass assignment}§
    2822 z = [x, y];                                                             §\C{// multiple assignment}§
     2822z = [x, y]; §\C{// multiple assignment}§
    28232823\end{cfa}
    28242824Let $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.
     
    28642864        double c, d;
    28652865        [ void ] f( [ int, int ] );
    2866         f( [ c, a ] = [ b, d ] = 1.5 );  // assignments in parameter list
     2866        f( [ c, a ] = [ b, d ] = 1.5 ); §\C{// assignments in parameter list}§
    28672867\end{cfa}
    28682868The 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.
     
    28772877\begin{cfa}
    28782878struct 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 constructors
    2885 [S, S] y;              // uses (1), (1), default constructor
    2886 [S, S] z = x.0;        // uses (4), (4), copy constructor
     2879void ?{}(S *); §\C{// (1)}§
     2880void ?{}(S *, int); §\C{// (2)}§
     2881void ?{}(S * double); §\C{// (3)}§
     2882void ?{}(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}§
    28872887\end{cfa}
    28882888In 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)©.
     
    29252925A member-access tuple may be used anywhere a tuple can be used, \eg:
    29262926\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 )}§
     2927s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§
     2928f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§
    29292929\end{cfa}
    29302930Note, the fields appearing in a record-field tuple may be specified in any order;
     
    29362936void f( double, long );
    29372937
    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 ]}§
     2938f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§
     2939x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§
    29402940[ long, int, long ] y = x.[ 2, 0, 2 ];
    29412941\end{cfa}
     
    29542954\begin{cfa}
    29552955[ 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}§
    29572957\end{cfa}
    29582958
     
    29672967That 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.
    29682968\begin{cfa}
    2969 int f();     // (1)
    2970 double f();  // (2)
    2971 
    2972 f();       // ambiguous - (1),(2) both equally viable
    2973 (int)f();  // choose (2)
     2969int f(); §\C{// (1)}§
     2970double f(); §\C{// (2)}§
     2971
     2972f(); §\C{// ambiguous - (1),(2) both equally viable}§
     2973(int)f(); §\C{// choose (2)}§
    29742974\end{cfa}
    29752975Since casting is a fundamental operation in \CFA, casts need to be given a meaningful interpretation in the context of tuples.
     
    29792979void g();
    29802980
    2981 (void)f();  // valid, ignore results
    2982 (int)g();   // invalid, void cannot be converted to int
     2981(void)f(); §\C{// valid, ignore results}§
     2982(int)g(); §\C{// invalid, void cannot be converted to int}§
    29832983
    29842984struct A { int x; };
    2985 (struct A)f();  // invalid, int cannot be converted to A
     2985(struct A)f(); §\C{// invalid, int cannot be converted to A}§
    29862986\end{cfa}
    29872987In C, line 4 is a valid cast, which calls ©f© and discards its result.
     
    29992999        [int, [int, int], int] g();
    30003000
    3001         ([int, double])f();           // (1) valid
    3002         ([int, int, int])g();         // (2) valid
    3003         ([void, [int, int]])g();      // (3) valid
    3004         ([int, int, int, int])g();    // (4) invalid
    3005         ([int, [int, int, int]])g();  // (5) invalid
     3001        ([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}§
    30063006\end{cfa}
    30073007
     
    30633063void f([int, int], int, int);
    30643064
    3065 f([0, 0], 0, 0);    // no cost
    3066 f(0, 0, 0, 0);      // cost for structuring
    3067 f([0, 0,], [0, 0]); // cost for flattening
    3068 f([0, 0, 0], 0);    // cost for flattening and structuring
     3065f([0, 0], 0, 0); §\C{// no cost}§
     3066f(0, 0, 0, 0); §\C{// cost for structuring}§
     3067f([0, 0,], [0, 0]); §\C{// cost for flattening}§
     3068f([0, 0, 0], 0); §\C{// cost for flattening and structuring}§
    30693069\end{cfa}
    30703070
     
    31293129[ unsigned int, char ]
    31303130[ double, double, double ]
    3131 [ * int, int * ]                §\C{// mix of CFA and ANSI}§
     3131[ * int, int * ] §\C{// mix of CFA and ANSI}§
    31323132[ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ]
    31333133\end{cfa}
     
    31363136Examples of declarations using tuple types are:
    31373137\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}§
    31403140[ [ int, int ] ] z ([ int, int ]);
    31413141\end{cfa}
     
    31543154[ int, int ] w1;
    31553155[ 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}§
    31583158f( [ 1, 2, 3 ] );
    31593159f( w1, 3 );
     
    32353235[ int, int, int, int ] w = [ 1, 2, 3, 4 ];
    32363236int x = 5;
    3237 [ x, w ] = [ w, x ];            §\C{// all four tuple coercions}§
     3237[ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§
    32383238\end{cfa}
    32393239Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values;
     
    33233323both these examples produce indeterminate results:
    33243324\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}§
     3325f( 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}§
    33273327\end{cfa}
    33283328
     
    33463346
    33473347
    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
     3353The 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.
     3355I/O can be unformatted or formatted.
     3356Unformatted means \CFA selects the output or input format for values that match with the type of a variable.
     3357Formatted 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
     3367Format manipulators in \CC have global rather than local effect, except ©setw©.
     3368Hence, it is common programming practice to toggle manipulators on and then back to the default to prevent downstream side-effects.
     3369Without 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}
     3372The \CFA header file for the I/O library is \Indexc{fstream.hfa}.
     3373
     3374For unformatted output, the common case is printing a sequence of variables separated by whitespace.
    33573375\begin{cquote}
    33583376\begin{tabular}{@{}l@{\hspace{3em}}l@{}}
     
    33733391&
    33743392\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3375 1 2 3
     33931® ®2® ®3
    33763394\end{cfa}
    33773395\end{tabular}
    33783396\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 values separated by ``\lstinline[showspaces=true]@, @''.
     3397The \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.
     3398Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]@, @''.
    33813399\begin{cfa}
    33823400[int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ];
    3383 sout | t1 | t2;                                         §\C{// print tuples}§
     3401sout | t1 | t2; §\C{// print tuples}§
    33843402\end{cfa}
    33853403\begin{cfa}[showspaces=true,aboveskip=0pt]
    338634041®, ®2®, ®3 4®, ®5®, ®6
    33873405\end{cfa}
    3388 Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority overloadable operator, other than assignment.
     3406Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment.
    33893407Therefore, fewer output expressions require parenthesis.
    33903408\begin{cquote}
     
    33933411&
    33943412\begin{cfa}
    3395 sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2);
     3413sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®;
    33963414\end{cfa}
    33973415\\
     
    33993417&
    34003418\begin{cfa}
    3401 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << (x | y) << (x || y) << (x > z ? 1 : 2) << endl;
     3419cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)® << endl;
    34023420\end{cfa}
    34033421\\
     
    34083426\end{tabular}
    34093427\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.
     3428Input and output use a uniform operator, ©|©, rather than separate operators, as in ©>>© and ©<<© for \CC.
     3429There 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
     3431For 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]
     3435int 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]
     3442sin | x | y | z;
     3443\end{cfa}
     3444&
     3445\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     3446cin >> 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
    34113459
    34123460
    34133461\subsection{Implicit Separator}
    34143462
    3415 The \Index{implicit separator}\index{I/O!separator} character (space/blank) is a separator not a terminator.
     3463The \Index{implicit separator}\index{I/O!separator} character (space/blank) is a separator not a terminator for output.
    34163464The rules for implicitly adding the separator are:
    34173465\begin{enumerate}
     
    34413489
    34423490\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][]{¢}{¢}}
     3492A 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]
     3494sout | 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]
     34981®,® 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}}%
     3500where \lstinline[basicstyle=\tt]@»@ is a closing citation mark.
     3501
     3502\item
     3503A separator does not appear after a C string ending with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \lstinline[mathescape=off,basicstyle=\tt]@([{=$£¥¡¿«@
    34443504%$
    34453505\begin{cfa}[mathescape=off]
     
    34553515
    34563516\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@
     3517A 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@
    34703518\begin{cfa}[belowskip=0pt]
    34713519sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
     
    34863534
    34873535
    3488 \subsection{Manipulator}
    3489 
    3490 The following \CC-style \Index{manipulator}s and routines control implicit seperation.
     3536\subsection{Separation Manipulators}
     3537
     3538The following \Index{manipulator}s control \Index{implicit output separation}.
     3539The effect of these manipulators is global for an output stream (except ©sepOn© and ©sepOff©).
    34913540\begin{enumerate}
    34923541\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.
    34943543The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
    34953544\begin{cfa}[mathescape=off,belowskip=0pt]
    3496 sepSet( sout, ", $" );                                          §\C{// set separator from " " to ", \$"}§
     3545sepSet( sout, ", $" ); §\C{// set separator from " " to ", \$"}§
    34973546sout | 1 | 2 | 3 | " \"" | ®sep® | "\"";
    34983547\end{cfa}
     
    35033552%$
    35043553\begin{cfa}[belowskip=0pt]
    3505 sepSet( sout, " " );                                            §\C{// reset separator to " "}§
     3554sepSet( sout, " " ); §\C{// reset separator to " "}§
    35063555sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\"";
    35073556\end{cfa}
     
    35113560©sepGet© can be used to store a separator and then restore it:
    35123561\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}§
     3562char store[®sepSize®]; §\C{// sepSize is the maximum separator size}§
     3563strcpy( store, sepGet( sout ) ); §\C{// copy current separator}§
     3564sepSet( sout, "_" ); §\C{// change separator to underscore}§
    35163565sout | 1 | 2 | 3;
    35173566\end{cfa}
     
    35203569\end{cfa}
    35213570\begin{cfa}[belowskip=0pt]
    3522 sepSet( sout, store );                                          §\C{// change separator back to original}§
     3571sepSet( sout, store ); §\C{// change separator back to original}§
    35233572sout | 1 | 2 | 3;
    35243573\end{cfa}
     
    35283577
    35293578\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.
    35313580The tuple separator-string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
    35323581\begin{cfa}[belowskip=0pt]
    3533 sepSetTuple( sout, " " );                                       §\C{// set tuple separator from ", " to " "}§
     3582sepSetTuple( sout, " " ); §\C{// set tuple separator from ", " to " "}§
    35343583sout | t1 | t2 | " \"" | ®sepTuple® | "\"";
    35353584\end{cfa}
     
    35383587\end{cfa}
    35393588\begin{cfa}[belowskip=0pt]
    3540 sepSetTuple( sout, ", " );                                      §\C{// reset tuple separator to ", "}§
     3589sepSetTuple( sout, ", " ); §\C{// reset tuple separator to ", "}§
    35413590sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\"";
    35423591\end{cfa}
     
    35473596
    35483597\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.
    35503599\begin{cfa}[belowskip=0pt]
    3551 sout | sepDisable | 1 | 2 | 3;                  §\C{// globally turn off implicit separator}§
     3600sout | sepDisable | 1 | 2 | 3; §\C{// turn off implicit separator}§
    35523601\end{cfa}
    35533602\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35553604\end{cfa}
    35563605\begin{cfa}[belowskip=0pt]
    3557 sout | sepEnable | 1 | 2 | 3;           §\C{// globally turn on implicit separator}§
     3606sout | sepEnable | 1 | 2 | 3; §\C{// turn on implicit separator}§
    35583607\end{cfa}
    35593608\begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35623611
    35633612\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.
    35653614\begin{cfa}[belowskip=0pt]
    3566 sout | 1 | sepOff | 2 | 3;                      §\C{// locally turn off implicit separator
     3615sout | 1 | sepOff | 2 | 3; §\C{// turn off implicit separator for the next item
    35673616\end{cfa}
    35683617\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35703619\end{cfa}
    35713620\begin{cfa}[belowskip=0pt]
    3572 sout | sepDisable | 1 | sepOn | 2 | 3; §\C{// locally turn on implicit separator
     3621sout | sepDisable | 1 | sepOn | 2 | 3; §\C{// turn on implicit separator for the next item
    35733622\end{cfa}
    35743623\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35773626The tuple separator also responses to being turned on and off.
    35783627\begin{cfa}[belowskip=0pt]
    3579 sout | t1 | sepOff | t2;                                §\C{// locally turn on/off implicit separator}§
     3628sout | t1 | sepOff | t2; §\C{// locally turn on/off implicit separator}§
    35803629\end{cfa}
    35813630\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35853634use ©sep© to accomplish this functionality.
    35863635\begin{cfa}[belowskip=0pt]
    3587 sout | sepOn | 1 | 2 | 3 | sepOn;       §\C{// sepOn does nothing at start/end of line}§
     3636sout | sepOn | 1 | 2 | 3 | sepOn; §\C{// sepOn does nothing at start/end of line}§
    35883637\end{cfa}
    35893638\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     
    35913640\end{cfa}
    35923641\begin{cfa}[belowskip=0pt]
    3593 sout | sep | 1 | 2 | 3 | sep ;          §\C{// use sep to print separator at start/end of line}§
     3642sout | sep | 1 | 2 | 3 | sep ; §\C{// use sep to print separator at start/end of line}§
    35943643\end{cfa}
    35953644\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    35963645® ®1 2 3® ®
     3646\end{cfa}
     3647\end{enumerate}
     3648
     3649
     3650\subsection{Newline Manipulators}
     3651
     3652The following \Index{manipulator} controls \Index{newline separation} for input and output.
     3653
     3654For 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}
     3663For example, in:
     3664\begin{cfa}
     3665sin | i | ®nl® | j;
     36661 ®2®
     36673
     3668\end{cfa}
     3669variable ©i© is assigned 1, the 2 is skipped, and variable ©j© is assigned 3.
     3670
     3671For output:
     3672\begin{enumerate}[parsep=0pt]
     3673\item
     3674\Indexc{nl}\index{manipulator!nl@©nl©} inserts a newline.
     3675\begin{cfa}
     3676sout | nl; §\C{// only print newline}§
     3677sout | 2; §\C{// implicit newline}§
     3678sout | 3 | nl | 4 | nl; §\C{// terminating nl merged with implicit newline}§
     3679sout | 5 | nl | nl; §\C{// again terminating nl merged with implicit newline}§
     3680sout | 6; §\C{// implicit newline}§
     3681
     36822
     36833
     36844
     36855
     3686
     36876
     3688\end{cfa}
     3689Note, 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
     3699The 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]
     3704sout | bin( 0 ) | bin( 27HH ) | bin( 27H ) | bin( 27 ) | bin( 27L );
     37050b0 0b11011 0b11011 0b11011 0b11011
     3706sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L );
     37070b11100101 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]
     3713sout | oct( 0 ) | oct( 27HH ) | oct( 27H ) | oct( 27 ) | oct( 27L );
     37140 033 033 033 033
     3715sout | oct( -27HH ) | oct( -27H ) | oct( -27 ) | oct( -27L );
     37160345 0177745 037777777745 01777777777777777777745
     3717\end{cfa}
     3718Note, 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]
     3723sout | hex( 0 ) | hex( 27HH ) | hex( 27H ) | hex( 27 ) | hex( 27L );
     37240 0x1b 0x1b 0x1b 0x1b
     3725sout | hex( -27HH ) | hex( -27H ) | hex( -27 ) | hex( -27L );
     37260xe5 0xffe5 0xffffffe5 0xffffffffffffffe5
     3727
     3728sout | hex( 0.0 ) | hex( 27.5F ) | hex( 27.5 ) | hex( 27.5L );
     37290x0.p+0 0x1.b8p+4 0x1.b8p+4 0xd.cp+1
     3730sout | 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.
     3736Default is 6 digits of precision.
     3737\begin{cfa}[belowskip=0pt]
     3738sout | sci( 0.0 ) | sci( 27.5 ) | sci( -27.5 );
     37390.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]
     3745sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) );
     37460®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]
     3752sout | nobase( bin( 27 ) ) | nobase( oct( 27 ) ) | nobase( hex( 27 ) );
     375311011 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.
     3758Printing a decimal point is the default, if there are no fractional digits.
     3759\begin{cfa}[belowskip=0pt]
     3760sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 );
     37610.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]
     3767sout | 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 )©
     3773For all types, ©minimum© is the minimum number of printed characters.
     3774If the value is shorter than the minimum, it is padded on the right with spaces.
     3775\begin{cfa}[belowskip=0pt]
     3776sout | wd( 4, 34) | wd( 3, 34 ) | wd( 2, 34 );
     3777sout | wd( 10, 4.) | wd( 9, 4. ) | wd( 8, 4. );
     3778sout | 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}
     3786If the value is larger, it is printed without truncation, ignoring the ©minimum©.
     3787\begin{cfa}[belowskip=0pt]
     3788sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 );
     3789sout | wd( 4, 3456. ) | wd( 3, 3456. ) | wd( 2, 3456. );
     3790sout | wd( 4, "abcde" ) | wd( 3, "abcde" ) | wd( 2,"abcde" );
     3791\end{cfa}
     3792\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     37933456®7® 345®67® 34®567®
     37943456®.® 345®6.® 34®56.®
     3795abcd®e® abc®de® ab®cde®
     3796\end{cfa}
     3797
     3798For integer types, ©precision© is the minimum number of printed digits.
     3799If the value is shorter, it is padded on the left with leading zeros.
     3800\begin{cfa}[belowskip=0pt]
     3801sout | 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}
     3806If the value is larger, it is printed without truncation, ignoring the ©precision©.
     3807\begin{cfa}[belowskip=0pt]
     3808sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 );
     3809\end{cfa}
     3810\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     38113456     3456       3456
     3812\end{cfa}
     3813If ©precision© is 0, nothing is printed for zero.
     3814If ©precision© is greater than the minimum, it becomes the minimum.
     3815\begin{cfa}[belowskip=0pt]
     3816sout | 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}
     3821For floating-point types, ©precision© is the minimum number of digits after the decimal point.
     3822\begin{cfa}[belowskip=0pt]
     3823sout | 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]
     382627.®500®     27.®5®      28. 27.®50000000®
     3827\end{cfa}
     3828For 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]
     3830sout | 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©}
     3838For 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©).
     3839If a value's significant digits is greater than ©significant©, the last significant digit is rounded up.
     3840\begin{cfa}[belowskip=0pt]
     3841sout | 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]
     3844234.567 234.5®7®  234.®6®    23®5®
     3845\end{cfa}
     3846If 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]
     3848sout | 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]
     3851234567. 2.3457®e+05® 2.346®e+05® 2.35®e+05®
     3852\end{cfa}
     3853If ©significant© is greater than ©minimum©, it defines the number of printed characters.
     3854\begin{cfa}[belowskip=0pt]
     3855sout | 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]
     3858234567. 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]
     3864sout | 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]
     386727®  ® 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]
     3873sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) );
     3874®00®27  ®0®27 ®00®27.500
    35973875\end{cfa}
    35983876\end{enumerate}
     
    36553933
    36563934
     3935\subsection{Input Value Manipulators}
     3936
     3937The 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.
     3938For ©_Bool© type, the constants are ©true© and ©false©.
     3939For 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}
     3948For 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.
     3949Floating-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
     3951For 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.
     3952Instead, the next sequence of non-whitespace characters are read, and the input sequence is terminated with delimiter ©'\0'©.
     3953The string variable \emph{must} be large enough to contain the input sequence.
     3954
     3955The 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©
     3960The argument defines a ©pattern© or ©length©.
     3961The ©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.
     3962The ©length© is composed of the next $N$ characters, including the newline character.
     3963If the match successes, the input characters are discarded, and input continues with the next character.
     3964If the match fails, the input characters are left unread.
     3965\begin{cfa}[belowskip=0pt]
     3966char sk[$\,$] = "abc";
     3967sin | "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©}
     3977For all types except ©char©, ©maximum© is the maximum number of characters read for the current operation.
     3978\begin{cfa}[belowskip=0pt]
     3979char s[10];   int i;   double d;   
     3980sin | 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}
     3985Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types.
     3986Currently, \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©}
     3990For 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]
     3992double d;
     3993sin | 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©}
     4001For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set.
     4002Matching characters are read into the C string and null terminated.
     4003\begin{cfa}[belowskip=0pt]
     4004char s[10];
     4005sin | 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©}
     4013For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set.
     4014Non-matching characters are read into the C string and null terminated.
     4015\begin{cfa}[belowskip=0pt]
     4016char s[10];
     4017sin | 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
    36574025\section{Types}
    36584026
     
    40224390\begin{itemize}
    40234391\item
    4024 preventing having to determine or write long generic types,
    4025 \item
    4026 ensure secondary variables, related to a primary variable, always have the same type.
     4392not determining or writing long generic types,
     4393\item
     4394ensuring secondary variables, related to a primary variable, always have the same type.
    40274395\end{itemize}
    40284396
     
    40464414There is also the conundrum in type inferencing of when to \emph{\Index{brand}} a type.
    40474415That 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 significant cascading type changes and/or errors.
     4416For example, if a change is made in an initialization expression, it can cause cascading type changes and/or errors.
    40494417At some point, a variable type needs to remain constant and the expression to be in error when it changes.
    40504418
     
    42794647
    42804648coroutine Fibonacci {
    4281         int fn;                                                         §\C{// used for communication}§
     4649        int fn; §\C{// used for communication}§
    42824650};
    42834651void ?{}( Fibonacci * this ) {
     
    42854653}
    42864654void 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}§
    42894657        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}§
    42934661        fn2 = fn1;
    42944662        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}§
    42984666                this->fn = fn1 + fn2;
    42994667                fn2 = fn1;
    43004668                fn1 = this->fn;
    4301                 suspend();                                              §\C{// return to last resume}§
     4669                suspend(); §\C{// return to last resume}§
    43024670        } // for
    43034671}
    43044672int next( Fibonacci * this ) {
    4305         resume( this );                                         §\C{// transfer to last suspend}§
     4673        resume( this ); §\C{// transfer to last suspend}§
    43064674        return this->fn;
    43074675}
     
    58486216In \CFA, there are ambiguous cases with dereference and operator identifiers, \eg ©int *?*?()©, where the string ©*?*?© can be interpreted as:
    58496217\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}§
    58526220\end{cfa}
    58536221By default, the first interpretation is selected, which does not yield a meaningful parse.
     
    59016269\eg:
    59026270\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 );}§
     6271x; §\C{// int x}§
     6272*y; §\C{// int *y}§
     6273f( p1, p2 ); §\C{// int f( int p1, int p2 );}§
     6274g( p1, p2 ) int p1, p2; §\C{// int g( int p1, int p2 );}§
    59076275\end{cfa}
    59086276\CFA continues to support K\&R routine definitions:
    59096277\begin{cfa}
    5910 f( a, b, c )                                    §\C{// default int return}§
    5911         int a, b; char c                        §\C{// K\&R parameter declarations}§
     6278f( a, b, c ) §\C{// default int return}§
     6279        int a, b; char c §\C{// K\&R parameter declarations}§
    59126280{
    59136281        ...
     
    59286296int rtn( int i );
    59296297int rtn( char c );
    5930 rtn( 'x' );                                             §\C{// programmer expects 2nd rtn to be called}§
     6298rtn( 'x' ); §\C{// programmer expects 2nd rtn to be called}§
    59316299\end{cfa}
    59326300\item[Rationale:] it is more intuitive for the call to ©rtn© to match the second version of definition of ©rtn© rather than the first.
     
    59506318\item[Change:] make string literals ©const©:
    59516319\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}§
     6320char * p = "abc"; §\C{// valid in C, deprecated in \CFA}§
     6321char * q = expr ? "abc" : "de"; §\C{// valid in C, invalid in \CFA}§
    59546322\end{cfa}
    59556323The type of a string literal is changed from ©[] char© to ©const [] char©.
     
    59586326\begin{cfa}
    59596327char * p = "abc";
    5960 p[0] = 'w';                                             §\C{// segment fault or change constant literal}§
     6328p[0] = 'w'; §\C{// segment fault or change constant literal}§
    59616329\end{cfa}
    59626330The same problem occurs when passing a string literal to a routine that changes its argument.
     
    59706338\item[Change:] remove \newterm{tentative definitions}, which only occurs at file scope:
    59716339\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}§
     6340int i; §\C{// forward definition}§
     6341int *j = ®&i®; §\C{// forward reference, valid in C, invalid in \CFA}§
     6342int i = 0; §\C{// definition}§
    59756343\end{cfa}
    59766344is valid in C, and invalid in \CFA because duplicate overloaded object definitions at the same scope level are disallowed.
     
    59786346\begin{cfa}
    59796347struct X { int i; struct X *next; };
    5980 static struct X a;                              §\C{// forward definition}§
     6348static struct X a; §\C{// forward definition}§
    59816349static struct X b = { 0, ®&a® };§\C{// forward reference, valid in C, invalid in \CFA}§
    5982 static struct X a = { 1, &b };  §\C{// definition}§
     6350static struct X a = { 1, &b }; §\C{// definition}§
    59836351\end{cfa}
    59846352\item[Rationale:] avoids having different initialization rules for builtin types and user-defined types.
     
    59956363struct Person {
    59966364        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)}§
    59996367        };
    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}§
    60036371};
    6004 ®Colour® c = R;                                 §\C{// type/enum defined same level}§
     6372®Colour® c = R; §\C{// type/enum defined same level}§
    60056373Person®.Colour® pc = Person®.®R;§\C{// type/enum defined inside}§
    6006 Person®.®Face pretty;                   §\C{// type defined inside}\CRT§
     6374Person®.®Face pretty; §\C{// type defined inside}\CRT§
    60076375\end{cfa}
    60086376In 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.
     
    60216389\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:
    60226390\begin{cfa}
    6023 struct Y;                                               §\C{// struct Y and struct X are at the same scope}§
     6391struct Y; §\C{// struct Y and struct X are at the same scope}§
    60246392struct X {
    60256393        struct Y { /* ... */ } y;
     
    60366404\begin{cfa}
    60376405void 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 *}§
    60406408}
    60416409\end{cfa}
     
    62986666\leavevmode
    62996667\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    6300 forall( otype T | { int ?<?( T, T ); } )        §\C{// location}§
     6668forall( otype T | { int ?<?( T, T ); } ) §\C{// location}§
    63016669T * bsearch( T key, const T * arr, size_t dim );§\indexc{bsearch}§
    63026670
    6303 forall( otype T | { int ?<?( T, T ); } )        §\C{// position}§
     6671forall( otype T | { int ?<?( T, T ); } ) §\C{// position}§
    63046672unsigned int bsearch( T key, const T * arr, size_t dim );
    63056673
     
    63086676
    63096677forall( 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}§
    63116679        size_t bsearch( E key, const E * vals, size_t dim );§\C{// position}§
    63126680        E * bsearchl( E key, const E * vals, size_t dim );§\indexc{bsearchl}§
     
    63566724void srandom( unsigned int seed );§\indexc{srandom}§
    63576725char random( void );§\indexc{random}§
    6358 char random( char u );                                          §\C{// [0,u)}§
    6359 char random( char l, char u );                          §\C{// [l,u)}§
     6726char random( char u ); §\C{// [0,u)}§
     6727char random( char l, char u ); §\C{// [l,u)}§
    63606728int random( void );
    6361 int random( int u );                                            §\C{// [0,u)}§
    6362 int random( int l, int u );                                     §\C{// [l,u)}§
     6729int random( int u ); §\C{// [0,u)}§
     6730int random( int l, int u ); §\C{// [l,u)}§
    63636731unsigned int random( void );
    6364 unsigned int random( unsigned int u );          §\C{// [0,u)}§
     6732unsigned int random( unsigned int u ); §\C{// [0,u)}§
    63656733unsigned int random( unsigned int l, unsigned int u ); §\C{// [l,u)}§
    63666734long 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)}§
     6735long int random( long int u ); §\C{// [0,u)}§
     6736long int random( long int l, long int u ); §\C{// [l,u)}§
    63696737unsigned long int random( void );
    63706738unsigned long int random( unsigned long int u ); §\C{// [0,u)}§
     
    64176785[ int, long double ] remquo( long double, long double );
    64186786
    6419 float div( float, float, int * );§\indexc{div}§ §\C{// alternative name for remquo}§
     6787float div( float, float, int * );§\indexc{div}§ §\C{// alternative name for remquo}§
    64206788double div( double, double, int * );
    64216789long double div( long double, long double, int * );
     
    65736941long double atan2( long double, long double );
    65746942
    6575 float atan( float, float );                                     §\C{// alternative name for atan2}§
     6943float atan( float, float ); §\C{// alternative name for atan2}§
    65766944double atan( double, double );§\indexc{atan}§
    65776945long double atan( long double, long double );
     
    67647132\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    67657133struct Duration {
    6766         int64_t tv;                                                     §\C{// nanoseconds}§
     7134        int64_t tv; §\C{// nanoseconds}§
    67677135};
    67687136
     
    68947262\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    68957263struct Time {
    6896         uint64_t tv;                                            §\C{// nanoseconds since UNIX epoch}§
     7264        uint64_t tv; §\C{// nanoseconds since UNIX epoch}§
    68977265};
    68987266
     
    69657333\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    69667334struct 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}§
    69697337};
    69707338
     
    69747342void ?{}( Clock & clk, Duration adj );
    69757343
    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}§
     7344Duration getResNsec(); §\C{// with nanoseconds}§
     7345Duration getRes(); §\C{// without nanoseconds}§
     7346
     7347Time getTimeNsec(); §\C{// with nanoseconds}§
     7348Time getTime(); §\C{// without nanoseconds}§
    69817349Time getTime( Clock & clk );
    69827350Time ?()( Clock & clk );
     
    69947362
    69957363\begin{cfa}
    6996 void ?{}( Int * this );                                 §\C{// constructor/destructor}§
     7364void ?{}( Int * this ); §\C{// constructor/destructor}§
    69977365void ?{}( Int * this, Int init );
    69987366void ?{}( Int * this, zero_t );
     
    70037371void ^?{}( Int * this );
    70047372
    7005 Int ?=?( Int * lhs, Int rhs );                  §\C{// assignment}§
     7373Int ?=?( Int * lhs, Int rhs ); §\C{// assignment}§
    70067374Int ?=?( Int * lhs, long int rhs );
    70077375Int ?=?( Int * lhs, unsigned long int rhs );
     
    70207388unsigned long int narrow( Int val );
    70217389
    7022 int ?==?( Int oper1, Int oper2 );               §\C{// comparison}§
     7390int ?==?( Int oper1, Int oper2 ); §\C{// comparison}§
    70237391int ?==?( Int oper1, long int oper2 );
    70247392int ?==?( long int oper2, Int oper1 );
     
    70567424int ?>=?( unsigned long int oper1, Int oper2 );
    70577425
    7058 Int +?( Int oper );                                             §\C{// arithmetic}§
     7426Int +?( Int oper ); §\C{// arithmetic}§
    70597427Int -?( Int oper );
    70607428Int ~?( Int oper );
     
    71387506Int ?>>=?( Int * lhs, mp_bitcnt_t shift );
    71397507
    7140 Int abs( Int oper );                                    §\C{// number functions}§
     7508Int abs( Int oper ); §\C{// number functions}§
    71417509Int fact( unsigned long int N );
    71427510Int gcd( Int oper1, Int oper2 );
     
    72497617// implementation
    72507618struct Rational {§\indexc{Rational}§
    7251         long int numerator, denominator;        §\C{// invariant: denominator > 0}§
     7619        long int numerator, denominator; §\C{// invariant: denominator > 0}§
    72527620}; // Rational
    72537621
    7254 Rational rational();                                    §\C{// constructors}§
     7622Rational rational(); §\C{// constructors}§
    72557623Rational rational( long int n );
    72567624Rational rational( long int n, long int d );
     
    72587626void ?{}( Rational * r, one_t );
    72597627
    7260 long int numerator( Rational r );               §\C{// numerator/denominator getter/setter}§
     7628long int numerator( Rational r ); §\C{// numerator/denominator getter/setter}§
    72617629long int numerator( Rational r, long int n );
    72627630long int denominator( Rational r );
    72637631long int denominator( Rational r, long int d );
    72647632
    7265 int ?==?( Rational l, Rational r );             §\C{// comparison}§
     7633int ?==?( Rational l, Rational r ); §\C{// comparison}§
    72667634int ?!=?( Rational l, Rational r );
    72677635int ?<?( Rational l, Rational r );
     
    72707638int ?>=?( Rational l, Rational r );
    72717639
    7272 Rational -?( Rational r );                              §\C{// arithmetic}§
     7640Rational -?( Rational r ); §\C{// arithmetic}§
    72737641Rational ?+?( Rational l, Rational r );
    72747642Rational ?-?( Rational l, Rational r );
     
    72767644Rational ?/?( Rational l, Rational r );
    72777645
    7278 double widen( Rational r );                             §\C{// conversion}§
     7646double widen( Rational r ); §\C{// conversion}§
    72797647Rational narrow( double f, long int md );
    72807648
  • libcfa/src/concurrency/coroutine.hfa

    r3c6e417 r54dd994  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 30 18:23:45 2018
    13 // Update Count     : 8
     12// Last Modified On : Fri Jun 21 17:49:39 2019
     13// Update Count     : 9
    1414//
    1515
     
    5353forall(dtype T | is_coroutine(T))
    5454void prime(T & cor);
     55
     56static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    5557
    5658//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/invoke.h

    r3c6e417 r54dd994  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 19 08:23:21 2018
    13 // Update Count     : 31
     12// Last Modified On : Sat Jun 22 18:19:13 2019
     13// Update Count     : 40
    1414//
    1515
     
    4646        #ifdef __cforall
    4747        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 );
    5050
    5151                extern thread_local struct KernelThreadData {
     
    199199        #ifdef __cforall
    200200        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 ) {
    206202                        return this.next;
    207203                }
     
    210206                        return this.node.[next, prev];
    211207                }
    212 
    213                 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this );
    214208
    215209                static inline void ?{}(__monitor_group_t & this) {
  • libcfa/src/concurrency/kernel.cfa

    r3c6e417 r54dd994  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr  9 16:11:46 2018
    13 // Update Count     : 24
     12// Last Modified On : Thu Jun 20 17:21:23 2019
     13// Update Count     : 25
    1414//
    1515
     
    907907void doregister( cluster * cltr, thread_desc & thrd ) {
    908908        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     909        cltr->nthreads += 1;
    909910        push_front(cltr->threads, thrd);
    910911        unlock    (cltr->thread_list_lock);
     
    914915        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    915916        remove(cltr->threads, thrd );
     917        cltr->nthreads -= 1;
    916918        unlock(cltr->thread_list_lock);
    917919}
     
    919921void doregister( cluster * cltr, processor * proc ) {
    920922        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     923        cltr->nprocessors += 1;
    921924        push_front(cltr->procs, *proc);
    922925        unlock    (cltr->proc_list_lock);
     
    926929        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    927930        remove(cltr->procs, *proc );
     931        cltr->nprocessors -= 1;
    928932        unlock(cltr->proc_list_lock);
    929933}
  • libcfa/src/concurrency/kernel.hfa

    r3c6e417 r54dd994  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 10 14:46:49 2018
    13 // Update Count     : 10
     12// Last Modified On : Sat Jun 22 11:39:17 2019
     13// Update Count     : 16
    1414//
    1515
     
    9191        this.lock = NULL;
    9292}
    93 static inline void ^?{}(FinishAction & this) {}
     93static inline void ^?{}(FinishAction &) {}
    9494
    9595// Processor
     
    176176        __dllist_t(struct processor) procs;
    177177        __dllist_t(struct processor) idles;
    178 
    179         // List of processors
     178        unsigned int nprocessors;
     179
     180        // List of threads
    180181        __spinlock_t thread_list_lock;
    181182        __dllist_t(struct thread_desc) threads;
     183        unsigned int nthreads;
    182184
    183185        // Link lists fields
     
    200202}
    201203
     204static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
     205static inline struct cluster   * active_cluster  () { return TL_GET( this_processor )->cltr; }
     206
    202207// Local Variables: //
    203208// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r3c6e417 r54dd994  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 29 14:07:11 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Jun 21 17:51:33 2019
     13// Update Count     : 5
    1414//
    1515
     
    9191void yield( unsigned times );
    9292
     93static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); }
     94
    9395// Local Variables: //
    9496// mode: c //
  • src/AST/Expr.hpp

    r3c6e417 r54dd994  
    248248        AddressExpr( const CodeLocation & loc, const Expr * a );
    249249
     250        /// Generate AddressExpr wrapping given expression at same location
     251        AddressExpr( const Expr * a ) : AddressExpr( a->location, a ) {}
     252
    250253        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    251254private:
     
    281284        /// Cast-to-void
    282285        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 ) {}
    283292
    284293        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Init.hpp

    r3c6e417 r54dd994  
    5555        ConstructFlag maybeConstructed;
    5656
    57         Init( const CodeLocation& loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
     57        Init( const CodeLocation & loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
    5858
    59         const Init * accept( Visitor& v ) const override = 0;
     59        const Init * accept( Visitor & v ) const override = 0;
    6060private:
    6161        Init * clone() const override = 0;
     
    6969        ptr<Expr> value;
    7070
    71         SingleInit( const CodeLocation& loc, Expr* val, ConstructFlag mc = DoConstruct )
     71        SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )
    7272        : Init( loc, mc ), value( val ) {}
    7373
     
    8787        std::vector<ptr<Designation>> designations;
    8888
    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 );
    9191
    9292        using iterator = std::vector<ptr<Init>>::iterator;
     
    114114        ptr<Init> init;
    115115
    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 )
    117118        : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
    118119
  • src/AST/Node.hpp

    r3c6e417 r54dd994  
    1717
    1818#include <cassert>
     19#include <cstddef>     // for nullptr_t
    1920#include <iosfwd>
    2021#include <type_traits> // for remove_reference
     
    181182        }
    182183
     184        ptr_base & operator=( std::nullptr_t ) {
     185                if ( node ) _dec(node);
     186                node = nullptr;
     187                return *this;
     188        }
     189
    183190        ptr_base & operator=( const ptr_base & o ) {
    184191                assign(o.node);
  • src/AST/Stmt.hpp

    r3c6e417 r54dd994  
    6161        CompoundStmt( CompoundStmt&& o ) = default;
    6262
    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 ); }
    6565
    6666        const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    143143
    144144        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 = {},
    146146                std::vector<Label> && labels = {} )
    147147        : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart),
  • src/Common/utility.h

    r3c6e417 r54dd994  
    1616#pragma once
    1717
     18#include <cassert>
    1819#include <cctype>
    1920#include <algorithm>
     
    2728#include <type_traits>
    2829#include <utility>
    29 
    30 #include <cassert>
     30#include <vector>
    3131
    3232#include "Common/Indenter.h"
    3333
    3434class Expression;
     35
     36/// bring std::move into global scope
     37using std::move;
     38
     39/// partner to move that copies any copyable type
     40template<typename T>
     41T copy( const T & x ) { return x; }
    3542
    3643template< typename T >
     
    145152                return ret;
    146153        } // switch
     154}
     155
     156/// Splice src onto the end of dst, clearing src
     157template< typename T >
     158void 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
     165template< typename T >
     166void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) {
     167        splice( src, dst );
     168        dst.swap( src );
    147169}
    148170
  • src/InitTweak/FixInit.cc

    r3c6e417 r54dd994  
    11111111                                                arg2 = new MemberExpr( field, new VariableExpr( params.back() ) );
    11121112                                        }
    1113                                         InitExpander srcParam( arg2 );
     1113                                        InitExpander_old srcParam( arg2 );
    11141114                                        // cast away reference type and construct field.
    11151115                                        Expression * thisExpr = new CastExpr( new VariableExpr( thisParam ), thisParam->get_type()->stripReferences()->clone() );
  • src/InitTweak/GenInit.cc

    r3c6e417 r54dd994  
    1818#include <algorithm>                   // for any_of
    1919#include <cassert>                     // for assert, strict_dynamic_cast, assertf
     20#include <deque>
    2021#include <iterator>                    // for back_inserter, inserter, back_inse...
    2122#include <list>                        // for _List_iterator, list
    2223
     24#include "AST/Decl.hpp"
     25#include "AST/Init.hpp"
     26#include "AST/Node.hpp"
     27#include "AST/Stmt.hpp"
    2328#include "CodeGen/OperatorTable.h"
    2429#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
     
    274279                assertf( objDecl, "genCtorDtor passed null objDecl" );
    275280                std::list< Statement * > stmts;
    276                 InitExpander srcParam( maybeClone( arg ) );
     281                InitExpander_old srcParam( maybeClone( arg ) );
    277282                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
    278283                assert( stmts.size() <= 1 );
     
    286291                std::list< Statement * > dtor;
    287292
    288                 InitExpander srcParam( objDecl->get_init() );
    289                 InitExpander nullParam( (Initializer *)NULL );
     293                InitExpander_old srcParam( objDecl->get_init() );
     294                InitExpander_old nullParam( (Initializer *)NULL );
    290295                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    291296                SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     
    353358                GuardScope( managedTypes );
    354359        }
     360
     361ast::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
    355387} // namespace InitTweak
    356388
  • src/InitTweak/GenInit.h

    r3c6e417 r54dd994  
    1919#include <string>              // for string
    2020
     21#include "AST/Fwd.hpp"
     22#include "Common/CodeLocation.h"
     23#include "GenPoly/ScopedSet.h" // for ScopedSet
    2124#include "SynTree/SynTree.h"   // for Visitor Nodes
    22 
    23 #include "GenPoly/ScopedSet.h" // for ScopedSet
    2425
    2526namespace InitTweak {
     
    3536        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    3637        ConstructorInit * genCtorInit( ObjectDecl * objDecl );
     38        ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    3739
    3840        class ManagedTypes {
  • src/InitTweak/InitTweak.cc

    r3c6e417 r54dd994  
    2222
    2323#include "AST/Expr.hpp"
     24#include "AST/Init.hpp"
     25#include "AST/Node.hpp"
     26#include "AST/Pass.hpp"
    2427#include "AST/Stmt.hpp"
    2528#include "AST/Type.hpp"
     
    8487                };
    8588
    86                 struct InitFlattener : public WithShortCircuiting {
     89                struct InitFlattener_old : public WithShortCircuiting {
    8790                        void previsit( SingleInit * singleInit ) {
    8891                                visit_children = false;
     
    9295                };
    9396
    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
    95107
    96108        std::list< Expression * > makeInitList( Initializer * init ) {
    97                 PassVisitor<InitFlattener> flattener;
     109                PassVisitor<InitFlattener_old> flattener;
    98110                maybeAccept( init, flattener );
    99111                return flattener.pass.argList;
     
    112124        }
    113125
    114         class InitExpander::ExpanderImpl {
     126std::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 {
    115133        public:
    116134                virtual ~ExpanderImpl() = default;
     
    119137        };
    120138
    121         class InitImpl : public InitExpander::ExpanderImpl {
     139        class InitImpl_old : public InitExpander_old::ExpanderImpl {
    122140        public:
    123                 InitImpl( Initializer * init ) : init( init ) {}
    124                 virtual ~InitImpl() = default;
     141                InitImpl_old( Initializer * init ) : init( init ) {}
     142                virtual ~InitImpl_old() = default;
    125143
    126144                virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
     
    136154        };
    137155
    138         class ExprImpl : public InitExpander::ExpanderImpl {
     156        class ExprImpl_old : public InitExpander_old::ExpanderImpl {
    139157        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; }
    142160
    143161                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     
    163181        };
    164182
    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*() {
    170188                return cur;
    171189        }
    172190
    173         InitExpander & InitExpander::operator++() {
     191        InitExpander_old & InitExpander_old::operator++() {
    174192                cur = expander->next( indices );
    175193                return *this;
     
    177195
    178196        // 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 ) {
    180198                indices.push_back( index );
    181199                indices.push_back( dimension );
    182200        }
    183201
    184         void InitExpander::clearArrayIndices() {
     202        void InitExpander_old::clearArrayIndices() {
    185203                deleteAll( indices );
    186204                indices.clear();
    187205        }
    188206
    189         bool InitExpander::addReference() {
     207        bool InitExpander_old::addReference() {
    190208                bool added = false;
    191209                for ( Expression *& expr : cur ) {
     
    218236
    219237                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 ) {
    221239                        if ( idx == idxEnd ) return;
    222240                        Expression * index = *idx++;
     
    275293        // remaining elements.
    276294        // 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 ) {
    278296                if ( ! init ) return nullptr;
    279297                CompoundStmt * block = new CompoundStmt();
     
    288306        }
    289307
    290         Statement * ExprImpl::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
     308        Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
    291309                return nullptr;
    292310        }
    293311
    294         Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
     312        Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {
    295313                return expander->buildListInit( dst, indices );
    296314        }
     315
     316class InitExpander_new::ExpanderImpl {
     317public:
     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
     324namespace {
     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
     453InitExpander_new::InitExpander_new( const ast::Init * init )
     454: expander( new InitImpl_new{ init } ), crnt(), indices() {}
     455
     456InitExpander_new::InitExpander_new( const ast::Expr * expr )
     457: expander( new ExprImpl_new{ expr } ), crnt(), indices() {}
     458
     459std::vector< ast::ptr< ast::Expr > > InitExpander_new::operator* () { return crnt; }
     460
     461InitExpander_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
     468ast::ptr< ast::Stmt > InitExpander_new::buildListInit( ast::UntypedExpr * callExpr ) {
     469        return expander->buildListInit( callExpr, indices );
     470}
     471
     472void InitExpander_new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
     473        indices.emplace_back( index );
     474        indices.emplace_back( dimension );
     475}
     476
     477void InitExpander_new::clearArrayIndices() { indices.clear(); }
     478
     479bool InitExpander_new::addReference() {
     480        for ( ast::ptr< ast::Expr > & expr : crnt ) {
     481                expr = new ast::AddressExpr{ expr };
     482        }
     483        return ! crnt.empty();
     484}
    297485
    298486        Type * getTypeofThis( FunctionType * ftype ) {
  • src/InitTweak/InitTweak.h

    r3c6e417 r54dd994  
    4444        /// transform Initializer into an argument list that can be passed to a call expression
    4545        std::list< Expression * > makeInitList( Initializer * init );
     46        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    4647
    4748        /// True if the resolver should try to construct dwt
     
    101102        bool isConstExpr( Initializer * init );
    102103
    103         class InitExpander {
     104        class InitExpander_old {
    104105        public:
    105106                // expand by stepping through init to get each list of arguments
    106                 InitExpander( Initializer * init );
     107                InitExpander_old( Initializer * init );
    107108
    108109                // always expand to expr
    109                 InitExpander( Expression * expr );
     110                InitExpander_old( Expression * expr );
    110111
    111112                // iterator-like interface
    112113                std::list< Expression * > operator*();
    113                 InitExpander & operator++();
     114                InitExpander_old & operator++();
    114115
    115116                // builds statement which has the same semantics as a C-style list initializer
     
    130131                IndexList indices;
    131132        };
     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        };
    132166} // namespace
    133167
  • src/ResolvExpr/Alternative.cc

    r3c6e417 r54dd994  
    125125        }
    126126
    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 
    140127} // namespace ResolvExpr
    141128
  • src/ResolvExpr/Alternative.h

    r3c6e417 r54dd994  
    112112        typedef std::vector< Alternative > AltList;
    113113
    114         /// Moves all elements from src to the end of dst
    115         void splice( AltList& dst, AltList& src );
    116 
    117         /// Moves all elements from src to the beginning of dst
    118         void spliceBegin( AltList& dst, AltList& src );
    119 
    120114        static inline std::ostream & operator<<(std::ostream & os, const ResolvExpr::Alternative & alt) {
    121115                alt.print( os );
  • src/ResolvExpr/AlternativeFinder.cc

    r3c6e417 r54dd994  
    5656#define PRINT( text ) if ( resolvep ) { text }
    5757//#define DEBUG_COST
    58 
    59 using std::move;
    60 
    61 /// copies any copyable type
    62 template<typename T>
    63 T copy(const T& x) { return x; }
    6458
    6559namespace ResolvExpr {
  • src/ResolvExpr/Candidate.hpp

    r3c6e417 r54dd994  
    7575using CandidateList = std::vector< CandidateRef >;
    7676
    77 /// Splice src after dst, clearing src
    78 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 dst
    85 static inline void spliceBegin( CandidateList & dst, CandidateList & src ) {
    86         splice( src, dst );
    87         dst.swap( src );
    88 }
    89 
    9077/// Sum the cost of a list of candidates
    9178static inline Cost sumCost( const CandidateList & candidates ) {
  • src/ResolvExpr/CandidateFinder.cpp

    r3c6e417 r54dd994  
    3939#include "AST/SymbolTable.hpp"
    4040#include "AST/Type.hpp"
     41#include "Common/utility.h"       // for move, copy
    4142#include "SymTab/Mangler.h"
    4243#include "SymTab/Validate.h"      // for validateType
     
    4647
    4748namespace ResolvExpr {
    48 
    49 using std::move;
    50 
    51 /// partner to move that copies any copyable type
    52 template<typename T>
    53 T copy( const T & x ) { return x; }
    5449
    5550const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
     
    5752                // cast away reference from expr
    5853                cost.incReference();
    59                 return new ast::CastExpr{ expr->location, expr, expr->result->stripReferences() };
     54                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    6055        }
    6156       
     
    126121                        ast::ptr< ast::Type > newType = paramType;
    127122                        env.apply( newType );
    128                         return new ast::CastExpr{ arg->location, arg, newType };
     123                        return new ast::CastExpr{ arg, newType };
    129124
    130125                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     
    793788                       
    794789                        if ( aggrType.as< ast::ReferenceType >() ) {
    795                                 aggrExpr =
    796                                         new ast::CastExpr{ aggrExpr->location, aggrExpr, aggrType->stripReferences() };
     790                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    797791                        }
    798792
  • src/ResolvExpr/Cost.h

    r3c6e417 r54dd994  
    1010// Created On       : Sun May 17 09:39:50 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 29 18:33:44 2019
    13 // Update Count     : 49
     12// Last Modified On : Fri Jun 21 11:39:13 2019
     13// Update Count     : 63
    1414//
    1515
     
    2121
    2222namespace ResolvExpr {
    23 #if 0
    24 
    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 > other
    55                 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) conversions
    70                 int polyCost;       ///< Count of parameters and return values bound to some poly type
    71                 int safeCost;       ///< Safe (widening) conversions
    72                 int signCost;       ///< Count of safe sign conversions
    73                 int varCost;        ///< Count of polymorphic type variables
    74                 int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
    75                 int referenceCost;  ///< reference conversions
    76         };
    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                 } // if
    184         }
    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.unsafeCost
    201                         && polyCost == other.polyCost
    202                         && safeCost == other.safeCost
    203                         && signCost == other.signCost
    204                         && varCost == other.varCost
    205                         && specCost == other.specCost
    206                         && 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 #else
    221 
    222         //*************************** NEW ***************************
    223 
    22423        // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
    22524        // specialization cost is a negative value so a correction is needed is a few places.
     
    371170                                  << ", " << cost.get_referenceCost() << " )";
    372171        }
    373 #endif // 0
    374172} // namespace ResolvExpr
    375173
  • src/ResolvExpr/RenameVars.cc

    r3c6e417 r54dd994  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:05:18 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 17:07:57 2019
    13 // Update Count     : 7
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Jun 20 17:39:00 2019
     13// Update Count     : 8
    1414//
    1515
     
    1919#include <utility>                 // for pair
    2020
     21#include "AST/Pass.hpp"
     22#include "AST/Type.hpp"
    2123#include "Common/PassVisitor.h"
     24#include "Common/ScopedMap.h"
    2225#include "Common/SemanticError.h"  // for SemanticError
    2326#include "RenameVars.h"
     
    2831
    2932namespace ResolvExpr {
    30         namespace {
    31                 struct RenameVars {
    32                         RenameVars();
    33                         void reset();
    3433
    35                         void previsit( TypeInstType * instType );
    36                         void previsit( Type * );
    37                         void postvisit( Type * );
     34namespace {
     35        class RenamingData {
     36                int level = 0;
     37                int resetCount = 0;
     38                ScopedMap< std::string, std::string > nameMap;
    3839
    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;
    5844                }
    5945
    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                        }
    6353                }
    6454
    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 ) {
    7456                        if ( ! type->forall.empty() ) {
    75                                 // copies current name mapping into new mapping
    76                                 mapStack.push_front( mapStack.front() );
     57                                nameMap.beginScope();
    7758                                // renames all "forall" type names to `_${level}_${name}'
    7859                                for ( auto td : type->forall ) {
     
    8061                                        output << "_" << resetCount << "_" << level << "_" << td->name;
    8162                                        std::string newname( output.str() );
    82                                         mapStack.front()[ td->get_name() ] = newname;
     63                                        nameMap[ td->get_name() ] = newname;
    8364                                        td->name = newname;
    8465                                        // ditto for assertion names, the next level in
     
    8970                }
    9071
    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                        }
    9676                }
    97         } // namespace
    9877
    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
     155void renameTyVars( Type * t ) {
     156        PassVisitor<RenameVars> renamer;
     157        t->accept( renamer );
     158}
     159
     160const ast::Type * renameTyVars( const ast::Type * t ) {
     161        ast::Pass<RenameVars> renamer;
     162        return t->accept( renamer );
     163}
     164
     165void resetTyVarRenaming() {
     166        renaming.reset();
     167}
     168
    105169} // namespace ResolvExpr
    106170
  • src/ResolvExpr/Resolver.cc

    r3c6e417 r54dd994  
    11091109               
    11101110                // 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 };
    11121112                CandidateRef choice = findUnfinishedKindExpression(
    11131113                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    11611161                ) {
    11621162                        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 };
    11641164                        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
    11651165                        removeExtraneousCast( newExpr, symtab );
     
    12511251                ast::Pass< Resolver_new > resolver;
    12521252                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 );
    12531261        }
    12541262
  • src/ResolvExpr/Resolver.h

    r3c6e417 r54dd994  
    2929
    3030namespace ast {
     31        class ConstructorInit;
    3132        class Decl;
    3233        class DeletedExpr;
     34        class Init;
    3335        class StmtExpr;
    3436        class SymbolTable;
     
    5961        ast::ptr< ast::Expr > resolveInVoidContext(
    6062                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 );
    6166        /// Resolves a statement expression
    6267        ast::ptr< ast::Expr > resolveStmtExpr(
  • src/SymTab/Autogen.cc

    r3c6e417 r54dd994  
    2424#include <vector>                  // for vector
    2525
     26#include "AST/Decl.hpp"
    2627#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2728#include "Common/PassVisitor.h"    // for PassVisitor
     
    209210        }
    210211
     212        bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     213                return obj && obj->name.empty() && obj->bitfieldWidth;
     214        }
     215
    211216        /// inserts a forward declaration for functionDecl into declsToAdd
    212217        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    388393
    389394        void StructFuncGenerator::makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward ) {
    390                 InitTweak::InitExpander srcParam( src );
     395                InitTweak::InitExpander_old srcParam( src );
    391396
    392397                // assign to destination
  • src/SymTab/Autogen.h

    r3c6e417 r54dd994  
    1717
    1818#include <cassert>                // for assert
     19#include <iterator>               // for back_inserter
    1920#include <string>                 // for string
    2021
     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"
    2128#include "CodeGen/OperatorTable.h"
    2229#include "Common/UniqueName.h"    // for UniqueName
     30#include "Common/utility.h"       // for splice
    2331#include "InitTweak/InitTweak.h"  // for InitExpander
    2432#include "SynTree/Constant.h"     // for Constant
     
    3644        /// returns true if obj's name is the empty string and it has a bitfield width
    3745        bool isUnnamedBitfield( ObjectDecl * obj );
     46        bool isUnnamedBitfield( const ast::ObjectDecl * obj );
    3847
    3948        /// generate the type of an assignment function for paramType.
     
    4958        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true );
    5059
     60        /// Enum for loop direction
     61        enum LoopDirection { LoopBackward, LoopForward };
     62
    5163        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
    5264        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 );
    5472
    5573        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
    5674        /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
    5775        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 ) {
    5977                bool isReferenceCtorDtor = false;
    6078                if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
     
    106124        }
    107125
     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
    108183        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
    109184        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
    110185        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 ) {
    112187                static UniqueName indexName( "_index" );
    113188
     
    170245        }
    171246
     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
    172317        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 ) {
    174319                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    175320                        genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
     
    180325        }
    181326
     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
    182344        /// inserts into out a generated call expression to function fname with arguments dstParam
    183345        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
     
    185347        /// ImplicitCtorDtorStmt node.
    186348        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 ) {
    188350                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
    189351                assert( obj );
     
    213375                }
    214376        }
     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        }
    215411} // namespace SymTab
    216412
  • src/SymTab/FixFunction.cc

    r3c6e417 r54dd994  
    1818#include <list>                   // for list
    1919
    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
    2124#include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    2225#include "SynTree/Expression.h"   // for Expression
     
    2427
    2528namespace SymTab {
    26         FixFunction::FixFunction() : isVoid( false ) {}
     29        class FixFunction_old : public WithShortCircuiting {
     30                typedef Mutator Parent;
     31          public:
     32                FixFunction_old() : isVoid( false ) {}
    2733
     34                void premutate(FunctionDecl *functionDecl);
     35                DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    2836
    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) {
    3057                // can't delete function type because it may contain assertions, so transfer ownership to new object
    3158                ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );
     
    4168        // does not cause an error
    4269
    43         Type * FixFunction::postmutate(ArrayType *arrayType) {
     70        Type * FixFunction_old::postmutate(ArrayType *arrayType) {
    4471                // need to recursively mutate the base type in order for multi-dimensional arrays to work.
    4572                PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );
     
    5178        }
    5279
    53         void FixFunction::premutate(VoidType *) {
     80        void FixFunction_old::premutate(VoidType *) {
    5481                isVoid = true;
    5582        }
    5683
    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; }
    7097
    7198        bool fixFunction( DeclarationWithType *& dwt ) {
    72                 PassVisitor<FixFunction> fixer;
     99                PassVisitor<FixFunction_old> fixer;
    73100                dwt = dwt->acceptMutator( fixer );
    74101                return fixer.pass.isVoid;
    75102        }
     103
     104namespace {
     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
     140const 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
    76147} // namespace SymTab
    77148
  • src/SymTab/FixFunction.h

    r3c6e417 r54dd994  
    1919#include "SynTree/SynTree.h"    // for Types
    2020
     21namespace ast {
     22        class DeclWithType;
     23}
     24
    2125namespace 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 *& );
    2729
    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 );
    5133} // namespace SymTab
    5234
  • src/SymTab/Validate.cc

    r3c6e417 r54dd994  
    4646#include <utility>                     // for pair
    4747
     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"
    4853#include "CodeGen/CodeGenerator.h"     // for genName
    4954#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
     
    124129
    125130        /// 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 {
    127132                void previsit( EnumDecl *aggregateDecl );
    128133                void previsit( FunctionType *func );
     
    130135
    131136        /// 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 );
    134139                void postvisit( TypeInstType *typeInst );
    135140
     
    165170
    166171        /// 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 {
    168173                void previsit( ObjectDecl * object );
    169174                void previsit( FunctionDecl * func );
     
    290295
    291296        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;
    295300                PassVisitor<CompoundLiteral> compoundliteral;
    296301                PassVisitor<ValidateGenericParameters> genericParams;
     
    305310                        ReplaceTypedef::replaceTypedef( translationUnit );
    306311                        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 mangling
     312                        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
    308313                }
    309314                {
     
    314319                        });
    315320                        Stats::Time::TimeBlock("Fix Qualified Types", [&]() {
    316                                 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed
     321                                mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed
    317322                        });
    318323                        Stats::Time::TimeBlock("Hoist Structs", [&]() {
     
    326331                        Stats::Heap::newPass("validate-C");
    327332                        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
    329334                        VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    330335                        ReturnChecker::checkFunctionReturns( translationUnit );
     
    344349                        });
    345350                        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
    347352                        });
    348353                }
     
    385390
    386391        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;
    390395                type->accept( epc );
    391396                type->accept( lrt );
     
    586591        }
    587592
    588         void EnumAndPointerDecay::previsit( EnumDecl *enumDecl ) {
     593        void EnumAndPointerDecay_old::previsit( EnumDecl *enumDecl ) {
    589594                // Set the type of each member of the enumeration to be EnumConstant
    590595                for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) {
     
    618623        }
    619624
    620         void EnumAndPointerDecay::previsit( FunctionType *func ) {
     625        void EnumAndPointerDecay_old::previsit( FunctionType *func ) {
    621626                // Fix up parameters and return types
    622627                fixFunctionList( func->parameters, func->isVarArgs, func );
     
    624629        }
    625630
    626         LinkReferenceToTypes::LinkReferenceToTypes( const Indexer *other_indexer ) {
     631        LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer *other_indexer ) {
    627632                if ( other_indexer ) {
    628633                        local_indexer = other_indexer;
     
    632637        }
    633638
    634         void LinkReferenceToTypes::postvisit( EnumInstType *enumInst ) {
     639        void LinkReferenceToTypes_old::postvisit( EnumInstType *enumInst ) {
    635640                EnumDecl *st = local_indexer->lookupEnum( enumInst->name );
    636641                // it's not a semantic error if the enum is not found, just an implicit forward declaration
     
    652657        }
    653658
    654         void LinkReferenceToTypes::postvisit( StructInstType *structInst ) {
     659        void LinkReferenceToTypes_old::postvisit( StructInstType *structInst ) {
    655660                StructDecl *st = local_indexer->lookupStruct( structInst->name );
    656661                // it's not a semantic error if the struct is not found, just an implicit forward declaration
     
    665670        }
    666671
    667         void LinkReferenceToTypes::postvisit( UnionInstType *unionInst ) {
     672        void LinkReferenceToTypes_old::postvisit( UnionInstType *unionInst ) {
    668673                UnionDecl *un = local_indexer->lookupUnion( unionInst->name );
    669674                // it's not a semantic error if the union is not found, just an implicit forward declaration
     
    678683        }
    679684
    680         void LinkReferenceToTypes::previsit( QualifiedType * ) {
     685        void LinkReferenceToTypes_old::previsit( QualifiedType * ) {
    681686                visit_children = false;
    682687        }
    683688
    684         void LinkReferenceToTypes::postvisit( QualifiedType * qualType ) {
     689        void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) {
    685690                // linking only makes sense for the 'oldest ancestor' of the qualified type
    686691                qualType->parent->accept( *visitor );
     
    729734        }
    730735
    731         void LinkReferenceToTypes::postvisit( TraitDecl * traitDecl ) {
     736        void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) {
    732737                if ( traitDecl->name == "sized" ) {
    733738                        // "sized" is a special trait - flick the sized status on for the type variable
     
    751756        }
    752757
    753         void LinkReferenceToTypes::postvisit( TraitInstType * traitInst ) {
     758        void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) {
    754759                // handle other traits
    755760                TraitDecl *traitDecl = local_indexer->lookupTrait( traitInst->name );
     
    777782        }
    778783
    779         void LinkReferenceToTypes::postvisit( EnumDecl *enumDecl ) {
     784        void LinkReferenceToTypes_old::postvisit( EnumDecl *enumDecl ) {
    780785                // visit enum members first so that the types of self-referencing members are updated properly
    781786                if ( enumDecl->body ) {
     
    799804        }
    800805
    801         void LinkReferenceToTypes::renameGenericParams( std::list< TypeDecl * > & params ) {
     806        void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) {
    802807                // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g.
    803808                //   forall(otype T)
     
    817822        }
    818823
    819         void LinkReferenceToTypes::previsit( StructDecl * structDecl ) {
     824        void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) {
    820825                renameGenericParams( structDecl->parameters );
    821826        }
    822827
    823         void LinkReferenceToTypes::previsit( UnionDecl * unionDecl ) {
     828        void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) {
    824829                renameGenericParams( unionDecl->parameters );
    825830        }
    826831
    827         void LinkReferenceToTypes::postvisit( StructDecl *structDecl ) {
     832        void LinkReferenceToTypes_old::postvisit( StructDecl *structDecl ) {
    828833                // visit struct members first so that the types of self-referencing members are updated properly
    829834                // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults)
     
    839844        }
    840845
    841         void LinkReferenceToTypes::postvisit( UnionDecl *unionDecl ) {
     846        void LinkReferenceToTypes_old::postvisit( UnionDecl *unionDecl ) {
    842847                if ( unionDecl->body ) {
    843848                        ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name );
     
    851856        }
    852857
    853         void LinkReferenceToTypes::postvisit( TypeInstType *typeInst ) {
     858        void LinkReferenceToTypes_old::postvisit( TypeInstType *typeInst ) {
    854859                // ensure generic parameter instances are renamed like the base type
    855860                if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name;
     
    888893        }
    889894
    890         void ForallPointerDecay::previsit( ObjectDecl *object ) {
     895        void ForallPointerDecay_old::previsit( ObjectDecl *object ) {
    891896                // ensure that operator names only apply to functions or function pointers
    892897                if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) {
     
    896901        }
    897902
    898         void ForallPointerDecay::previsit( FunctionDecl *func ) {
     903        void ForallPointerDecay_old::previsit( FunctionDecl *func ) {
    899904                func->fixUniqueId();
    900905        }
    901906
    902         void ForallPointerDecay::previsit( FunctionType * ftype ) {
     907        void ForallPointerDecay_old::previsit( FunctionType * ftype ) {
    903908                forallFixer( ftype->forall, ftype );
    904909        }
    905910
    906         void ForallPointerDecay::previsit( StructDecl * aggrDecl ) {
     911        void ForallPointerDecay_old::previsit( StructDecl * aggrDecl ) {
    907912                forallFixer( aggrDecl->parameters, aggrDecl );
    908913        }
    909914
    910         void ForallPointerDecay::previsit( UnionDecl * aggrDecl ) {
     915        void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) {
    911916                forallFixer( aggrDecl->parameters, aggrDecl );
    912917        }
     
    13681373        }
    13691374
    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         }
     1375namespace {
     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
     1448const 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
    13761456} // namespace SymTab
    13771457
  • src/Tuples/Explode.cc

    r3c6e417 r54dd994  
    133133                        if ( first ) {
    134134                                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 } };
    139138                        } else {
    140139                                return new ast::TupleExpr( tupleExpr->location, std::move( exprs ) );
     
    145144                } else {
    146145                        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 } };
    149147                }
    150148        }
     
    164162                        castAdded = false;
    165163                        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 };
    167165                }
    168166                return newNode;
     
    183181        expr = expr->accept( exploder );
    184182        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 } };
    187184        }
    188185        return expr;
  • src/Tuples/Explode.h

    r3c6e417 r54dd994  
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212212                        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 };
    214214                        }
    215215                        // Now we have to go across the tuple via indexing.
     
    238238}
    239239
     240/// explode list of candidates into flattened list of candidates
     241template< typename Output >
     242void 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
    240251} // namespace Tuples
    241252
  • src/Tuples/TupleAssignment.cc

    r3c6e417 r54dd994  
    2222#include <vector>
    2323
     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"
    2429#include "CodeGen/OperatorTable.h"
    2530#include "Common/PassVisitor.h"
    2631#include "Common/UniqueName.h"             // for UniqueName
    27 #include "Common/utility.h"                // for zipWith
     32#include "Common/utility.h"                // for splice, zipWith
    2833#include "Explode.h"                       // for explode
    2934#include "InitTweak/GenInit.h"             // for genCtorInit
     
    5156
    5257namespace Tuples {
    53         class TupleAssignSpotter {
     58        class TupleAssignSpotter_old {
    5459          public:
    5560                // dispatcher for Tuple (multiple and mass) assignment operations
    56                 TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
     61                TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    5762                void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    5863
     
    6267                struct Matcher {
    6368                  public:
    64                         Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     69                        Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    6570                                const ResolvExpr::AltList& rhs );
    6671                        virtual ~Matcher() {}
     
    8085                       
    8186                        ResolvExpr::AltList lhs, rhs;
    82                         TupleAssignSpotter &spotter;
     87                        TupleAssignSpotter_old &spotter;
    8388                        ResolvExpr::Cost baseCost;
    8489                        std::list< ObjectDecl * > tmpDecls;
     
    9095                struct MassAssignMatcher : public Matcher {
    9196                  public:
    92                         MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     97                        MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    9398                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    9499                        virtual void match( std::list< Expression * > &out );
     
    97102                struct MultipleAssignMatcher : public Matcher {
    98103                  public:
    99                         MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     104                        MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    100105                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    101106                        virtual void match( std::list< Expression * > &out );
     
    136141        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    137142                                std::vector<ResolvExpr::AlternativeFinder> &args ) {
    138                 TupleAssignSpotter spotter( currentFinder );
     143                TupleAssignSpotter_old spotter( currentFinder );
    139144                spotter.spot( expr, args );
    140145        }
    141146
    142         TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
     147        TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    143148                : currentFinder(f) {}
    144149
    145         void TupleAssignSpotter::spot( UntypedExpr * expr,
     150        void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    146151                        std::vector<ResolvExpr::AlternativeFinder> &args ) {
    147152                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     
    224229        }
    225230
    226         void TupleAssignSpotter::match() {
     231        void TupleAssignSpotter_old::match() {
    227232                assert ( matcher != 0 );
    228233
     
    275280        }
    276281
    277         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter,
     282        TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    278283                const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    279284        : lhs(lhs), rhs(rhs), spotter(spotter),
     
    313318        };
    314319
    315         ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
     320        ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    316321                assert( expr->result && ! expr->get_result()->isVoid() );
    317322                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
     
    329334        }
    330335
    331         void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
     336        void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    332337                static UniqueName lhsNamer( "__massassign_L" );
    333338                static UniqueName rhsNamer( "__massassign_R" );
     
    347352        }
    348353
    349         void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
     354        void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    350355                static UniqueName lhsNamer( "__multassign_L" );
    351356                static UniqueName rhsNamer( "__multassign_R" );
     
    378383        }
    379384
    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         }
     385namespace {
     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
     711void 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
    388719} // namespace Tuples
    389720
  • tests/concurrent/examples/boundedBufferEXT.cfa

    r3c6e417 r54dd994  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:33 2019
    13 // Update Count     : 12
     12// Last Modified On : Fri Jun 21 08:19:20 2019
     13// Update Count     : 14
    1414//
    1515
     
    5252}
    5353
    54 const int Sentinel = -1;
     54enum { Sentinel = -1 };
    5555
    5656thread Producer {
     
    5959};
    6060void main( Producer & prod ) with( prod ) {
    61         for ( int i = 1; i <= N; i += 1 ) {
     61        for ( i; 1 ~= N ) {
    6262                yield( random( 5 ) );
    6363                insert( buffer, 1 );
     
    9999        srandom( 1003 );
    100100
    101         for ( i = 0; i < Cons; i += 1 ) {                                       // create consumers
     101        for ( i; Cons ) {                                                                       // create consumers
    102102                cons[i] = new( &buffer, sums[i] );
    103103        } // for
    104         for ( i = 0; i < Prods; i += 1 ) {                                      // create producers
     104        for ( i; Prods ) {                                                                      // create producers
    105105                prods[i] = new( &buffer, 100000 );
    106106        } // for
    107107
    108         for ( i = 0; i < Prods; i += 1 ) {                                      // wait for producers to finish
     108        for ( i; Prods ) {                                                                      // wait for producers to finish
    109109                delete( prods[i] );
    110110        } // for
    111         for ( i = 0; i < Cons; i += 1 ) {                                       // generate sentinal values to stop consumers
     111        for ( i; Cons ) {                                                                       // generate sentinal values to stop consumers
    112112                insert( buffer, Sentinel );
    113113        } // for
    114114        int sum = 0;
    115         for ( i = 0; i < Cons; i += 1 ) {                                       // wait for consumers to finish
     115        for ( i; Cons ) {                                                                       // wait for consumers to finish
    116116                delete( cons[i] );
    117117                sum += sums[i];
  • tests/concurrent/examples/boundedBufferINT.cfa

    r3c6e417 r54dd994  
    1010// Created On       : Mon Oct 30 12:45:13 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:52 2019
    13 // Update Count     : 88
     12// Last Modified On : Fri Jun 21 08:20:46 2019
     13// Update Count     : 90
    1414//
    1515
     
    5353}
    5454
    55 const int Sentinel = -1;
     55enum { Sentinel = -1 };
    5656
    5757thread Producer {
     
    6060};
    6161void main( Producer & prod ) with( prod ) {
    62         for ( int i = 1; i <= N; i += 1 ) {
     62        for ( i; 1 ~= N ) {
    6363                yield( random( 5 ) );
    6464                insert( buffer, 1 );
     
    100100        srandom( 1003 );
    101101
    102         for ( i = 0; i < Cons; i += 1 ) {                                       // create consumers
     102        for ( i; Cons ) {                                                                       // create consumers
    103103                cons[i] = new( &buffer, sums[i] );
    104104        } // for
    105         for ( i = 0; i < Prods; i += 1 ) {                                      // create producers
     105        for ( i; Prods ) {                                                                      // create producers
    106106                prods[i] = new( &buffer, 100000 );
    107107        } // for
    108108
    109         for ( i = 0; i < Prods; i += 1 ) {                                      // wait for producers to finish
     109        for ( i; Prods ) {                                                                      // wait for producers to finish
    110110                delete( prods[i] );
    111111        } // for
    112         for ( i = 0; i < Cons; i += 1 ) {                                       // generate sentinal values to stop consumers
     112        for ( i; Cons ) {                                                                       // generate sentinal values to stop consumers
    113113                insert( buffer, Sentinel );
    114114        } // for
    115115        int sum = 0;
    116         for ( i = 0; i < Cons; i += 1 ) {                                       // wait for consumers to finish
     116        for ( i; Cons ) {                                                                       // wait for consumers to finish
    117117                delete( cons[i] );
    118118                sum += sums[i];
  • tests/concurrent/examples/datingService.cfa

    r3c6e417 r54dd994  
    1010// Created On       : Mon Oct 30 12:56:20 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:39 2019
    13 // Update Count     : 31
     12// Last Modified On : Fri Jun 21 11:32:34 2019
     13// Update Count     : 38
    1414//
    1515
     
    9595        srandom( /*getpid()*/ 103 );
    9696
    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
    9999                boys[i]  = new( &TheExchange, i, CompCodes - ( i + 1 ) );
    100100        } // for
    101101
    102         for ( unsigned int i = 0; i < CompCodes; i += 1 ) {
     102        for ( i; CompCodes ) {
    103103                delete( boys[i] );
    104104                delete( girls[i] );
    105105        } // for
    106106
    107         for ( unsigned int i = 0; i < CompCodes; i += 1 ) {
     107        for ( i; CompCodes ) {
    108108                if ( girlck[ boyck[i] ] != boyck[ girlck[i] ] ) abort();
    109109        } // for
  • tests/concurrent/examples/gortn.cfa

    r3c6e417 r54dd994  
    1010// Created On       : Wed Feb 20 08:02:37 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 08:35:55 2019
    13 // Update Count     : 3
     12// Last Modified On : Fri Jun 21 08:25:03 2019
     13// Update Count     : 4
    1414//
    1515
     
    1818
    1919struct Msg { int i, j; };
    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; }
     20thread GoRtn { int i;  float f;  Msg m; };
     21void ^?{}( GoRtn & mutex ) {}
     22void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; }
     23void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; }
     24void mem3( GoRtn & mutex gortn, Msg m ) { gortn.m = m; }
    2525
    26 void main( Gortn & gortn ) with( gortn ) {
    27         for ( ;; ) {
     26void main( GoRtn & gortn ) with( gortn ) {
     27        for () {
    2828                waitfor( mem1, gortn ) sout | i;
    2929                or waitfor( mem2, gortn ) sout | f;
     
    3333}
    3434int main() {
    35         Gortn gortn;                                                                            // start thread
     35        GoRtn gortn;                                                                            // start thread
    3636        mem1( gortn, 0 );
    3737        mem2( gortn, 2.5 );
  • tests/concurrent/examples/quickSort.cfa

    r3c6e417 r54dd994  
    1111// Created On       : Wed Dec  6 12:15:52 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Mar 22 13:42:01 2019
    14 // Update Count     : 170
     13// Last Modified On : Fri Jun 21 08:27:45 2019
     14// Update Count     : 172
    1515//
    1616
     
    138138                  if ( eof( unsortedfile ) ) break;
    139139                        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 numbers
     140                        for ( counter; size ) {                                         // read unsorted numbers
    141141                                unsortedfile | values[counter];
    142142                                if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | "  ";
     
    148148                                Quicksort QS = { values, size - 1, 0 }; // sort values
    149149                        } // wait until sort tasks terminate
    150                         for ( int counter = 0; counter < size; counter += 1 ) { // print sorted list
     150                        for ( counter; size ) {                                         // print sorted list
    151151                                if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | "  ";
    152152                                sortedfile | values[counter];
     
    163163
    164164                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 numbers
     165                for ( counter; size ) {                                         // generate unsorted numbers
    166166                        values[counter] = size - counter;                       // descending values
    167167                } // for
     
    170170                } // wait until sort tasks terminate
    171171
    172                 // for ( int counter = 0; counter < size - 1; counter += 1 ) { // check sorting
     172                // for ( counter; size - 1 ) {                          // check sorting
    173173                //      if ( values[counter] > values[counter + 1] ) abort();
    174174                // } // for
  • tests/concurrent/examples/quickSort.generic.cfa

    r3c6e417 r54dd994  
    1111// Created On       : Wed Dec  6 12:15:52 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Mar 15 14:52:41 2019
    14 // Update Count     : 147
     13// Last Modified On : Fri Jun 21 08:28:20 2019
     14// Update Count     : 149
    1515//
    1616
     
    141141                  if ( eof( unsortedfile ) ) break;
    142142                        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 numbers
     143                        for ( counter; size ) {                                         // read unsorted numbers
    144144                                unsortedfile | values[counter];
    145145                                if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | "  ";
     
    151151                                Quicksort(ELEMTYPE) QS = { values, size - 1, 0 }; // sort values
    152152                        } // wait until sort tasks terminate
    153                         for ( int counter = 0; counter < size; counter += 1 ) { // print sorted list
     153                        for ( counter; size ) {                                         // print sorted list
    154154                                if ( counter != 0 && counter % ValuesPerLine == 0 ) sortedfile | nl | "  ";
    155155                                sortedfile | values[counter];
     
    166166
    167167                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 numbers
     168                for ( counter; size ) {                                                 // generate unsorted numbers
    169169                        values[counter] = size - counter;                       // descending values
    170170                } // for
     
    173173                } // wait until sort tasks terminate
    174174
    175                 // for ( int counter = 0; counter < size - 1; counter += 1 ) { // check sorting
     175                // for ( counter; size - 1 ) {                                  // check sorting
    176176                //      if ( values[counter] > values[counter + 1] ) abort();
    177177                // } // for
  • tools/stat.py

    r3c6e417 r54dd994  
    1111                content = f.readlines()
    1212                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 )
    2020
    2121
Note: See TracChangeset for help on using the changeset viewer.