Changes in / [1ed9cb63:8a039be]


Ignore:
Files:
4 deleted
24 edited

Legend:

Unmodified
Added
Removed
  • doc/user/user.tex

    r1ed9cb63 r8a039be  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Oct 10 12:45:00 2021
    14 %% Update Count     : 5095
     13%% Last Modified On : Mon May 31 09:03:34 2021
     14%% Update Count     : 5071
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    44444444\CFA provides a fine-grained solution where a \Index{recursive lock} is acquired and released indirectly via a manipulator ©acquire© or instantiating an \Index{RAII} type specific for the kind of stream: ©osacquire©\index{ostream@©ostream©!osacquire@©osacquire©} for output streams and ©isacquire©\index{isacquire@©isacquire©}\index{istream@©istream©!isacquire@©isacquire©} for input streams.
    44454445
    4446 The common usage is the short form of the mutex statement\index{ostream@©ostream©!mutex@©mutex©} to lock a stream during a single cascaded I/O expression, \eg:
    4447 \begin{cfa}
    4448 $\emph{thread\(_1\)}$ : ®mutex()® sout | "abc " | "def ";
    4449 $\emph{thread\(_2\)}$ : ®mutex()® sout | "uvw " | "xyz ";
     4446The common usage is manipulator ©acquire©\index{ostream@©ostream©!acquire@©acquire©} to lock a stream during a single cascaded I/O expression, with the manipulator appearing as the first item in a cascade list, \eg:
     4447\begin{cfa}
     4448$\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def ";   // manipulator
     4449$\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz ";
    44504450\end{cfa}
    44514451Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order.
     
    44664466In summary, the stream lock is acquired by the ©acquire© manipulator and implicitly released at the end of the cascaded I/O expression ensuring all operations in the expression occur atomically.
    44674467
    4468 To lock a stream across multiple I/O operations, he long form of the mutex statement is used, \eg:
    4469 \begin{cfa}
    4470 ®mutex( sout )® {
     4468To lock a stream across multiple I/O operations, an object of type ©osacquire© or ©isacquire© is declared to implicitly acquire/release the stream lock providing mutual exclusion for the object's duration, \eg:
     4469\begin{cfa}
     4470{       // acquire sout for block duration
     4471        ®osacquire® acq = { sout };                             $\C{// named stream locker}$
    44714472        sout | 1;
    4472         ®mutex() sout® | 2 | 3;                         $\C{// unnecessary, but ok because of recursive lock}$
     4473        sout | ®acquire® | 2 | 3;                               $\C{// unnecessary, but ok to acquire and release again}$
    44734474        sout | 4;
    4474 } // implicitly release sout lock
    4475 \end{cfa}
    4476 Note, the unnecessary ©mutex© in the middle of the mutex statement, works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
     4475}       // implicitly release the lock when "acq" is deallocated
     4476\end{cfa}
     4477Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
    44774478Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.
    44784479
    44794480The previous values written by threads 1 and 2 can be read in concurrently:
    44804481\begin{cfa}
    4481 ®mutex( sin )® {
     4482{       // acquire sin lock for block duration
     4483        ®isacquire acq = { sin };®                              $\C{// named stream locker}$
    44824484        int x, y, z, w;
    44834485        sin | x;
    4484         ®mutex() sin® | y | z;                          $\C{// unnecessary, but ok because of recursive lock}$
     4486        sin | ®acquire® | y | z;                                $\C{// unnecessary, but ok to acquire and release again}$
    44854487        sin | w;
    4486 } // implicitly release sin lock
     4488}       // implicitly release the lock when "acq" is deallocated
    44874489\end{cfa}
    44884490Again, the order of the reading threads is non-deterministic.
     
    44914493\Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
    44924494\begin{cfa}
    4493 ®mutex() sout® | "data:" | rtn( mon );  $\C{// mutex call on monitor}$
     4495sout | ®acquire® | "data:" | rtn( mon );        $\C{// mutex call on monitor}$
    44944496\end{cfa}
    44954497If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it.
     
    44984500\begin{cfa}
    44994501int ®data® = rtn( mon );
    4500 mutex() sout | "data:" | ®data®;
     4502sout | acquire | "data:" | ®data®;
    45014503\end{cfa}
    45024504
     
    45044506\section{String Stream}
    45054507
    4506 The stream types ©ostrstream© and ©istrstream© provide all the stream formatting capabilities to/from a C string rather than a stream file.
    4507 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) to and reading (input) from a C string.
    4508 The only string stream operations different from a file stream are:
    4509 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4510 \item
    4511 constructors to create a stream that writes to a write buffer (©ostrstream©) of ©size©, or reads from a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.
    4512 \begin{cfa}
    4513 void ?{}( ostrstream &, char buf[], size_t size );
    4514 void ?{}( istrstream & is, char buf[] );
    4515 \end{cfa}
    4516 \item
    4517 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).
    4518 \begin{cfa}
    4519 ostrstream & write( ostrstream & os, FILE * stream = stdout );
    4520 \end{cfa}
    4521 There is no ©read© for ©istrstream©.
    4522 \end{itemize}
    4523 
     4508All the stream formatting capabilities are available to format text to/from a C string rather than to a stream file.
     4509\VRef[Figure]{f:StringStreamProcessing} shows writing (output) and reading (input) from a C string.
    45244510\begin{figure}
    45254511\begin{cfa}
     
    45344520        double x = 12345678.9, y = 98765.4321e-11;
    45354521
    4536         osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
    4537         write( osstr ); $\C{// write string to stdout}$
    4538         printf( "%s", buf ); $\C{// same lines of output}$
    4539         sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
    4540 
    4541         char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$
     4522        osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); $\C{// same lines of output}$
     4523        write( osstr );
     4524        printf( "%s", buf );
     4525        sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
     4526
     4527        char buf2[] = "12 14 15 3.5 7e4"; $\C{// input buffer}$
    45424528        ®istrstream isstr = { buf2 };®
    4543         char s[10];
    4544         isstr | i | j | k | x | y | s;
    4545         sout  | i | j | k | x | y | s;
    4546 }
    4547 
    4548 3 0x5          7 1.234568e+07 987.654n abc
    4549 3 0x5          7 1.234568e+07 987.654n abc
    4550 3 0x5          7 1.234568e+07 987.654n abc
    4551 12 14 15 3.5 70000. abc
     4529        isstr | i | j | k | x | y;
     4530        sout | i | j | k | x | y;
     4531}
    45524532\end{cfa}
    45534533\caption{String Stream Processing}
    45544534\label{f:StringStreamProcessing}
    45554535\end{figure}
     4536
     4537\VRef[Figure]{f:StringStreamFunctions} shows the string stream operations.
     4538\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     4539\item
     4540\Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).
     4541\end{itemize}
     4542The constructor functions:
     4543\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     4544\item
     4545create a bound stream to a write buffer (©ostrstream©) of ©size© or a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.
     4546\end{itemize}
     4547
     4548\begin{figure}
     4549\begin{cfa}
     4550// *********************************** ostrstream ***********************************
     4551
     4552ostrstream & write( ostrstream & os, FILE * stream = stdout );
     4553
     4554void ?{}( ostrstream &, char buf[], size_t size );
     4555
     4556// *********************************** istrstream ***********************************
     4557
     4558void ?{}( istrstream & is, char buf[] );
     4559\end{cfa}
     4560\caption{String Stream Functions}
     4561\label{f:StringStreamFunctions}
     4562\end{figure}
     4563
    45564564
    45574565\begin{comment}
  • libcfa/src/fstream.cfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 11:23:05 2021
    13 // Update Count     : 512
     12// Last Modified On : Tue Sep 21 21:51:38 2021
     13// Update Count     : 460
    1414//
    1515
     
    2828#define IO_MSG "I/O error: "
    2929
    30 // private
    31 void ?{}( ofstream & os, void * file ) with( os ) {
     30void ?{}( ofstream & os, void * file ) with(os) {
    3231        file$ = file;
    3332        sepDefault$ = true;
     
    3635        prt$ = false;
    3736        sawNL$ = false;
     37        acquired$ = false;
    3838        sepSetCur$( os, sepGet( os ) );
    3939        sepSet( os, " " );
     
    4141} // ?{}
    4242
    43 inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    44 inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    45 inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    46 inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
    47 inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    48 inline bool getNL$( ofstream & os ) { return os.sawNL$; }
    49 inline void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
    50 inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
    51 inline bool getPrt$( ofstream & os ) { return os.prt$; }
    52 inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
    53 
    54 inline void lock( ofstream & os ) with( os ) {  lock( os.lock$ ); }
    55 inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
     43// private
     44bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     45void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     46void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     47const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
     48void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     49bool getNL$( ofstream & os ) { return os.sawNL$; }
     50void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
     51bool getANL$( ofstream & os ) { return os.nlOnOff$; }
     52bool getPrt$( ofstream & os ) { return os.prt$; }
     53void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
    5654
    5755// public
    5856void ?{}( ofstream & os ) { os.file$ = 0p; }
    59 void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); }
    60 void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); }
    61 void ^?{}( ofstream & os ) { close( os ); }
     57
     58void ?{}( ofstream & os, const char name[], const char mode[] ) {
     59        open( os, name, mode );
     60} // ?{}
     61
     62void ?{}( ofstream & os, const char name[] ) {
     63        open( os, name, "w" );
     64} // ?{}
     65
     66void ^?{}( ofstream & os ) {
     67        close( os );
     68} // ^?{}
    6269
    6370void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
     
    100107        if ( &os == &exit ) exit( EXIT_FAILURE );
    101108        if ( &os == &abort ) abort();
     109        if ( os.acquired$ ) { os.acquired$ = false; release( os ); }
    102110} // ends
    103111
    104 bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
    105 void clear( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
    106 int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
     112bool fail( ofstream & os ) {
     113        return os.file$ == 0 || ferror( (FILE *)(os.file$) );
     114} // fail
     115
     116void clear( ofstream & os ) {
     117        clearerr( (FILE *)(os.file$) );
     118} // clear
     119
     120int flush( ofstream & os ) {
     121        return fflush( (FILE *)(os.file$) );
     122} // flush
    107123
    108124void open( ofstream & os, const char name[], const char mode[] ) {
    109         FILE * file;
    110     for ( cnt; 10 ) {
    111                 errno = 0;
    112                 file = fopen( name, mode );
    113           if ( file != 0p || errno != EINTR ) break;            // timer interrupt ?
    114           if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
    115     } // for
     125        FILE * file = fopen( name, mode );
    116126        if ( file == 0p ) {
    117127                throw (Open_Failure){ os };
     
    121131} // open
    122132
    123 void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
    124 
    125 void close( ofstream & os ) with( os ) {
     133void open( ofstream & os, const char name[] ) {
     134        open( os, name, "w" );
     135} // open
     136
     137void close( ofstream & os ) with(os) {
    126138  if ( (FILE *)(file$) == 0p ) return;
    127139  if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
    128140
    129         int ret;
    130     for ( cnt; 10 ) {
    131                 errno = 0;
    132                 ret = fclose( (FILE *)(file$) );
    133           if ( ret != EOF || errno != EINTR ) break;            // timer interrupt ?
    134           if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
    135     } // for
    136         if ( ret == EOF ) {
     141        if ( fclose( (FILE *)(file$) ) == EOF ) {
    137142                throw (Close_Failure){ os };
    138143                // abort | IO_MSG "close output" | nl | strerror( errno );
    139144        } // if
    140         file$ = 0p;                                                                                     // safety after close
     145        file$ = 0p;
    141146} // close
    142147
     
    157162        va_list args;
    158163        va_start( args, format );
    159                
    160         int len;
    161     for ( cnt; 10 ) {
    162                 errno = 0;
    163                 len = vfprintf( (FILE *)(os.file$), format, args );
    164           if ( len != EOF || errno != EINTR ) break;            // timer interrupt ?
    165           if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
    166     } // for
     164        int len = vfprintf( (FILE *)(os.file$), format, args );
    167165        if ( len == EOF ) {
    168166                if ( ferror( (FILE *)(os.file$) ) ) {
     
    177175} // fmt
    178176
     177inline void acquire( ofstream & os ) with(os) {
     178        lock( lock$ );                                                                          // may increase recursive lock
     179        if ( ! acquired$ ) acquired$ = true;                            // not locked ?
     180        else unlock( lock$ );                                                           // unwind recursive lock at start
     181} // acquire
     182
     183inline void release( ofstream & os ) {
     184        unlock( os.lock$ );
     185} // release
     186
     187void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }
     188void ^?{}( osacquire & acq ) { release( acq.os ); }
     189
    179190static ofstream soutFile = { (FILE *)stdout };
    180191ofstream & sout = soutFile, & stdout = soutFile;
     
    194205        flush( os );
    195206        return os;
     207        // (ofstream &)(os | '\n');
     208        // setPrt$( os, false );                                                        // turn off
     209        // setNL$( os, true );
     210        // flush( os );
     211        // return sepOff( os );                                                 // prepare for next line
    196212} // nl
    197213
     
    201217
    202218// private
    203 void ?{}( ifstream & is, void * file ) with( is ) {
     219void ?{}( ifstream & is, void * file ) with(is) {
    204220        file$ = file;
    205221        nlOnOff$ = false;
    206 } // ?{}
    207 
    208 bool getANL$( ifstream & os ) { return os.nlOnOff$; }
    209 
    210 inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
    211 inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
     222        acquired$ = false;
     223} // ?{}
    212224
    213225// public
    214226void ?{}( ifstream & is ) { is.file$ = 0p; }
    215 void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); }
    216 void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); }
    217 void ^?{}( ifstream & is ) { close( is ); }
    218 
    219 bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
    220 void clear( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
     227
     228void ?{}( ifstream & is, const char name[], const char mode[] ) {
     229        open( is, name, mode );
     230} // ?{}
     231
     232void ?{}( ifstream & is, const char name[] ) {
     233        open( is, name, "r" );
     234} // ?{}
     235
     236void ^?{}( ifstream & is ) {
     237        close( is );
     238} // ^?{}
    221239
    222240void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
    223241void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
    224 
    225 void ends( ifstream & is ) {}
    226 
    227 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
     242bool getANL( ifstream & os ) { return os.nlOnOff$; }
     243
     244bool fail( ifstream & is ) {
     245        return is.file$ == 0p || ferror( (FILE *)(is.file$) );
     246} // fail
     247
     248void clear( ifstream & is ) {
     249        clearerr( (FILE *)(is.file$) );
     250} // clear
     251
     252void ends( ifstream & is ) {
     253        if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
     254} // ends
     255
     256bool eof( ifstream & is ) {
     257        return feof( (FILE *)(is.file$) );
     258} // eof
    228259
    229260void open( ifstream & is, const char name[], const char mode[] ) {
    230         FILE * file;
    231     for ( cnt; 10 ) {
    232                 errno = 0;
    233                 file = fopen( name, mode );
    234           if ( file != 0p || errno != EINTR ) break;            // timer interrupt ?
    235           if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" );
    236     } // for
     261        FILE * file = fopen( name, mode );
    237262        if ( file == 0p ) {
    238263                throw (Open_Failure){ is };
     
    242267} // open
    243268
    244 void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
    245 
    246 void close( ifstream & is ) with( is ) {
     269void open( ifstream & is, const char name[] ) {
     270        open( is, name, "r" );
     271} // open
     272
     273void close( ifstream & is ) with(is) {
    247274  if ( (FILE *)(file$) == 0p ) return;
    248275  if ( (FILE *)(file$) == (FILE *)stdin ) return;
    249276
    250         int ret;
    251     for ( cnt; 10 ) {
    252                 errno = 0;
    253                 ret = fclose( (FILE *)(file$) );
    254           if ( ret != EOF || errno != EINTR ) break;            // timer interrupt ?
    255           if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" );
    256     } // for
    257         if ( ret == EOF ) {
     277        if ( fclose( (FILE *)(file$) ) == EOF ) {
    258278                throw (Close_Failure){ is };
    259279                // abort | IO_MSG "close input" | nl | strerror( errno );
    260280        } // if
    261         file$ = 0p;                                                                                     // safety after close
     281        file$ = 0p;
    262282} // close
    263283
     
    288308int fmt( ifstream & is, const char format[], ... ) {
    289309        va_list args;
     310
    290311        va_start( args, format );
    291 
    292         int len;
    293     for () {                                                                                    // no check for EINTR limit waiting for keyboard input
    294                 errno = 0;
    295                 len = vfscanf( (FILE *)(is.file$), format, args );
    296           if ( len != EOF || errno != EINTR ) break;            // timer interrupt ?
    297     } // for
     312        int len = vfscanf( (FILE *)(is.file$), format, args );
    298313        if ( len == EOF ) {
    299314                if ( ferror( (FILE *)(is.file$) ) ) {
     
    304319        return len;
    305320} // fmt
     321
     322inline void acquire( ifstream & is ) with(is) {
     323        lock( lock$ );                                                                          // may increase recursive lock
     324        if ( ! acquired$ ) acquired$ = true;                            // not locked ?
     325        else unlock( lock$ );                                                           // unwind recursive lock at start
     326} // acquire
     327
     328inline void release( ifstream & is ) {
     329        unlock( is.lock$ );
     330} // release
     331
     332void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }
     333void ^?{}( isacquire & acq ) { release( acq.is ); }
    306334
    307335static ifstream sinFile = { (FILE *)stdin };
  • libcfa/src/fstream.hfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 09:37:32 2021
    13 // Update Count     : 243
     12// Last Modified On : Wed Jul 28 07:35:50 2021
     13// Update Count     : 234
    1414//
    1515
     
    3636        char tupleSeparator$[ofstream_sepSize];
    3737        multiple_acquisition_lock lock$;
     38        bool acquired$;
    3839}; // ofstream
    3940
     
    5253void setPrt$( ofstream &, bool );
    5354
    54 void lock( ofstream & );
    55 void unlock( ofstream & );
    56 
    5755// public
    5856void sepOn( ofstream & );
     
    7775void open( ofstream &, const char name[] );
    7876void close( ofstream & );
    79 
    8077ofstream & write( ofstream &, const char data[], size_t size );
     78
     79void acquire( ofstream & );
     80void release( ofstream & );
     81
     82void lock( ofstream & );
     83void unlock( ofstream & );
     84
     85struct osacquire {
     86        ofstream & os;
     87};
     88void ?{}( osacquire & acq, ofstream & );
     89void ^?{}( osacquire & acq );
    8190
    8291void ?{}( ofstream & );
     
    101110        bool nlOnOff$;
    102111        multiple_acquisition_lock lock$;
     112        bool acquired$;
    103113}; // ifstream
    104114
    105115// Satisfies istream
    106 
    107 // private
    108 bool getANL$( ifstream & );
    109 
    110 void lock( ifstream & );
    111 void unlock( ifstream & );
    112116
    113117// public
    114118void nlOn( ifstream & );
    115119void nlOff( ifstream & );
     120bool getANL( ifstream & );
    116121void ends( ifstream & );
    117122int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    123128void open( ifstream & is, const char name[] );
    124129void close( ifstream & is );
    125 
    126130ifstream & read( ifstream & is, char data[], size_t size );
    127131ifstream & ungetc( ifstream & is, char c );
     132
     133void acquire( ifstream & is );
     134void release( ifstream & is );
     135
     136struct isacquire {
     137        ifstream & is;
     138};
     139void ?{}( isacquire & acq, ifstream & is );
     140void ^?{}( isacquire & acq );
    128141
    129142void ?{}( ifstream & is );
  • libcfa/src/iostream.cfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 09:28:17 2021
    13 // Update Count     : 1345
     12// Last Modified On : Sat May 15 09:39:21 2021
     13// Update Count     : 1342
    1414//
    1515
     
    398398                return os;
    399399        } // nlOff
     400} // distribution
     401
     402forall( ostype & | ostream( ostype ) ) {
     403        ostype & acquire( ostype & os ) {
     404                acquire( os );                                                                  // call void returning
     405                return os;
     406        } // acquire
    400407} // distribution
    401408
     
    822829                        fmt( is, "%c", &temp );                                         // must pass pointer through varg to fmt
    823830                        // do not overwrite parameter with newline unless appropriate
    824                         if ( temp != '\n' || getANL$( is ) ) { c = temp; break; }
     831                        if ( temp != '\n' || getANL( is ) ) { c = temp; break; }
    825832                        if ( eof( is ) ) break;
    826833                } // for
     
    10281035                return is;
    10291036        } // nlOff
     1037} // distribution
     1038
     1039forall( istype & | istream( istype ) ) {
     1040        istype & acquire( istype & is ) {
     1041                acquire( is );                                                                  // call void returning
     1042                return is;
     1043        } // acquire
    10301044} // distribution
    10311045
  • libcfa/src/iostream.hfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 10:02:07 2021
    13 // Update Count     : 407
     12// Last Modified On : Wed Apr 28 20:37:56 2021
     13// Update Count     : 401
    1414//
    1515
     
    5858        void close( ostype & );
    5959        ostype & write( ostype &, const char [], size_t );
     60        void acquire( ostype & );                                                       // concurrent access
    6061}; // ostream
    6162
     
    141142        ostype & nlOn( ostype & );
    142143        ostype & nlOff( ostype & );
     144} // distribution
     145
     146forall( ostype & | ostream( ostype ) ) {
     147        ostype & acquire( ostype & );
    143148} // distribution
    144149
     
    291296
    292297trait basic_istream( istype & ) {
    293         // private
    294         bool getANL$( istype & );                                                       // get scan newline (on/off)
    295         // public
     298        bool getANL( istype & );                                                        // get scan newline (on/off)
    296299        void nlOn( istype & );                                                          // read newline
    297300        void nlOff( istype & );                                                         // scan newline
     301
    298302        void ends( istype & os );                                                       // end of output statement
    299303        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    308312        void close( istype & is );
    309313        istype & read( istype &, char [], size_t );
     314        void acquire( istype & );                                                       // concurrent access
    310315}; // istream
    311316
     
    374379} // distribution
    375380
     381forall( istype & | istream( istype ) ) {
     382        istype & acquire( istype & );
     383} // distribution
     384
    376385// *********************************** manipulators ***********************************
    377386
  • libcfa/src/strstream.cfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Thu Apr 22 22:24:35 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 16:13:20 2021
    13 // Update Count     : 101
     12// Last Modified On : Tue Apr 27 20:59:53 2021
     13// Update Count     : 78
    1414//
    1515
    1616#include "strstream.hfa"
    17 #include "fstream.hfa"                                                                  // abort
    1817
    1918#include <stdio.h>                                                                              // vsnprintf
     
    3130
    3231// private
    33 inline bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    34 inline void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    35 inline void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    36 inline const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
    37 inline void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    38 inline bool getNL$( ostrstream & os ) { return os.sawNL$; }
    39 inline void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
    40 inline bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
    41 inline bool getPrt$( ostrstream & os ) { return os.prt$; }
    42 inline void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
     32bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     33void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     34void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     35const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
     36void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     37bool getNL$( ostrstream & os ) { return os.sawNL$; }
     38void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
     39bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
     40bool getPrt$( ostrstream & os ) { return os.prt$; }
     41void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
    4342
    4443// public
     
    129128// *********************************** istrstream ***********************************
    130129
    131 // private
    132 bool getANL$( istrstream & is ) { return is.nlOnOff$; }
    133130
    134131// public
     
    139136} // ?{}
    140137
     138bool getANL( istrstream & is ) { return is.nlOnOff$; }
    141139void nlOn( istrstream & is ) { is.nlOnOff$ = true; }
    142140void nlOff( istrstream & is ) { is.nlOnOff$ = false; }
    143141
    144 void ends( istrstream & is ) {}
    145 bool eof( istrstream & is ) { return false; }
     142void ends( istrstream & is ) {
     143} // ends
    146144
    147 int fmt( istrstream & is, const char format[], ... ) with(is) {
    148         va_list args;
    149         va_start( args, format );
    150         // THIS DOES NOT WORK BECAUSE VSSCANF RETURNS NUMBER OF VALUES READ VERSUS BUFFER POSITION SCANNED.
    151         int len = vsscanf( buf$ + cursor$, format, args );
    152         va_end( args );
    153         if ( len == EOF ) {
    154                 abort | IO_MSG "invalid read";
    155         } // if
    156         // SKULLDUGGERY: This hack skips over characters read by vsscanf by moving to the next whitespace but it does not
    157         // handle C reads with wdi manipulators that leave the cursor at a non-whitespace character.
    158         for ( ; buf$[cursor$] != ' ' && buf$[cursor$] != '\t' && buf$[cursor$] != '\0'; cursor$ += 1 ) {
    159                 //printf( "X \'%c\'\n", buf$[cursor$] );
    160         } // for
    161         if ( buf$[cursor$] != '\0' ) cursor$ += 1;      // advance to whitespace
    162         return len;
    163 } // fmt
     145int eof( istrstream & is ) {
     146        return 0;
     147} // eof
    164148
    165149istrstream &ungetc( istrstream & is, char c ) {
     
    170154} // ungetc
    171155
     156int fmt( istrstream & is, const char format[], ... ) {
     157        va_list args;
     158        va_start( args, format );
     159        // This does not work because vsscanf does not return buffer position.
     160        int len = vsscanf( is.buf$ + is.cursor$, format, args );
     161        va_end( args );
     162        if ( len == EOF ) {
     163                int j;
     164                printf( "X %d%n\n", len, &j );
     165        } // if
     166        is.cursor$ += len;
     167        return len;
     168} // fmt
     169
    172170// Local Variables: //
    173171// tab-width: 4 //
  • libcfa/src/strstream.hfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Thu Apr 22 22:20:59 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 10:14:22 2021
    13 // Update Count     : 47
     12// Last Modified On : Tue Apr 27 20:58:50 2021
     13// Update Count     : 41
    1414//
    1515
     
    8585// Satisfies basic_istream
    8686
    87 // private
    88 bool getANL$( istrstream & );
    89 
    9087// public
     88bool getANL( istrstream & );
    9189void nlOn( istrstream & );
    9290void nlOff( istrstream & );
    9391void ends( istrstream & );
     92int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     93istrstream & ungetc( istrstream & is, char c );
     94int eof( istrstream & is );
    9495
    95 int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    96 istrstream & ungetc( istrstream &, char );
    97 bool eof( istrstream & );
    98 
    99 void ?{}( istrstream &, char buf[] );
     96void ?{}( istrstream & is, char buf[] );
    10097
    10198// Local Variables: //
  • src/AST/Pass.hpp

    r1ed9cb63 r8a039be  
    348348
    349349        /// When this node is finished being visited, restore the value of a variable
    350         /// You may assign to the return value to set the new value in the same statement.
    351350        template< typename T >
    352         T& GuardValue( T& val ) {
     351        void GuardValue( T& val ) {
    353352                at_cleanup( [ val ]( void * newVal ) {
    354353                        * static_cast< T * >( newVal ) = val;
    355354                }, static_cast< void * >( & val ) );
    356                 return val;
    357355        }
    358356
     
    396394};
    397395
    398 /// Used to get a pointer to the wrapping TranslationUnit.
    399 struct WithConstTranslationUnit {
    400         const TranslationUnit * translationUnit = nullptr;
    401 
    402         const TranslationUnit & transUnit() const {
    403                 assertf( translationUnit, "WithConstTranslationUnit not set-up." );
    404                 return *translationUnit;
    405         }
    406 };
    407 
    408396}
    409397
  • src/AST/Pass.impl.hpp

    r1ed9cb63 r8a039be  
    420420template< typename core_t >
    421421inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    422         if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
    423                 ValueGuard<const TranslationUnit *> guard( *ptr );
    424                 *ptr = &unit;
    425                 return ast::accept_all( unit.decls, visitor );
    426         } else {
    427                 return ast::accept_all( unit.decls, visitor );
    428         }
     422        return ast::accept_all( unit.decls, visitor );
    429423}
    430424
  • src/AST/Pass.proto.hpp

    r1ed9cb63 r8a039be  
    426426        } // namespace forall
    427427
    428         // For passes that need access to the global context. Sreaches `translationUnit`
    429         namespace translation_unit {
    430                 template<typename core_t>
    431                 static inline auto get_cptr( core_t & core, int )
    432                                 -> decltype( &core.translationUnit ) {
    433                         return &core.translationUnit;
    434                 }
    435 
    436                 template<typename core_t>
    437                 static inline const TranslationUnit ** get_cptr( core_t &, long ) {
    438                         return nullptr;
    439                 }
    440         }
    441 
    442428        template<typename core_t>
    443429        static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
  • src/AST/TranslationUnit.hpp

    r1ed9cb63 r8a039be  
    2626        std::list< ptr< Decl > > decls;
    2727
    28         struct Global {
     28        struct Globals {
    2929                std::map< UniqueId, Decl * > idMap;
    3030
    31                 ptr<Type> sizeType;
     31                const Type * sizeType;
    3232                const FunctionDecl * dereference;
    3333                const StructDecl * dtorStruct;
  • src/AST/porting.md

    r1ed9cb63 r8a039be  
    9898        * `Initializer` => `ast::Init`
    9999    * `Statement` => `ast::Stmt`
    100     * `ReferenceToType` => `ast::BaseInstType`
    101100        * any field names should follow a similar renaming
    102101  * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`):
  • src/CodeTools/DeclStats.cc

    r1ed9cb63 r8a039be  
    156156                /// number of counting bins for linkages
    157157                static const unsigned n_named_specs = 8;
    158                 /// Mapping function from linkage to bin.
    159                 static unsigned linkage_index( LinkageSpec::Spec spec ) {
    160                         switch ( spec ) {
    161                         case LinkageSpec::Intrinsic:  return 0;
    162                         case LinkageSpec::C:          return 1;
    163                         case LinkageSpec::Cforall:    return 2;
    164                         case LinkageSpec::AutoGen:    return 3;
    165                         case LinkageSpec::Compiler:   return 4;
    166                         case LinkageSpec::BuiltinCFA: return 5;
    167                         case LinkageSpec::BuiltinC:   return 6;
    168                         default:                      return 7;
    169                         }
    170                 }
     158                /// map from total number of specs to bins
     159                static const unsigned ind_for_linkage[16];
    171160
    172161                Stats for_linkage[n_named_specs];            ///< Stores separate stats per linkage
     
    377366                        const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName();
    378367                        if ( seen_names.insert( mangleName ).second ) {
    379                                 Stats& stats = for_linkage[ linkage_index( decl->linkage ) ];
     368                                Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ];
    380369
    381370                                ++stats.n_decls;
     
    538527        };
    539528
     529        const unsigned DeclStats::ind_for_linkage[]
     530                = { 7, 7, 2, 1,   7, 7, 7, 3,   4, 7, 6, 5,   7, 7, 7, 0 };
     531
    540532        void printDeclStats( std::list< Declaration * > &translationUnit ) {
    541533                PassVisitor<DeclStats> stats;
  • src/Common/module.mk

    r1ed9cb63 r8a039be  
    2222      Common/CompilerError.h \
    2323      Common/Debug.h \
    24       Common/DeclStats.hpp \
    25       Common/DeclStats.cpp \
    2624      Common/ErrorObjects.h \
    2725      Common/Eval.cc \
     
    3533      Common/PassVisitor.proto.h \
    3634      Common/PersistentMap.h \
    37       Common/ResolvProtoDump.hpp \
    38       Common/ResolvProtoDump.cpp \
    3935      Common/ScopedMap.h \
    4036      Common/SemanticError.cc \
  • src/InitTweak/GenInit.cc

    r1ed9cb63 r8a039be  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct 25 13:53:00 2021
    13 // Update Count     : 186
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:15:10 2019
     13// Update Count     : 184
    1414//
    1515#include "GenInit.h"
     
    2424#include "AST/Decl.hpp"
    2525#include "AST/Init.hpp"
    26 #include "AST/Pass.hpp"
    2726#include "AST/Node.hpp"
    2827#include "AST/Stmt.hpp"
     
    295294        }
    296295
    297 namespace {
    298 
    299 #       warning Remove the _New suffix after the conversion is complete.
    300         struct HoistArrayDimension_NoResolve_New final :
    301                         public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
    302                         public ast::WithGuards, public ast::WithConstTranslationUnit,
    303                         public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
    304                 void previsit( const ast::ObjectDecl * decl );
    305                 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
    306                 // Do not look for objects inside there declarations (and type).
    307                 void previsit( const ast::AggregateDecl * ) { visit_children = false; }
    308                 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
    309                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    310 
    311                 const ast::Type * hoist( const ast::Type * type );
    312 
    313                 ast::Storage::Classes storageClasses;
    314         };
    315 
    316         void HoistArrayDimension_NoResolve_New::previsit(
    317                         const ast::ObjectDecl * decl ) {
    318                 GuardValue( storageClasses ) = decl->storage;
    319         }
    320 
    321         const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
    322                         const ast::ObjectDecl * objectDecl ) {
    323                 return mutate_field( objectDecl, &ast::ObjectDecl::type,
    324                                 hoist( objectDecl->type ) );
    325         }
    326 
    327         const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
    328                         const ast::Type * type ) {
    329                 static UniqueName dimensionName( "_array_dim" );
    330 
    331                 if ( !isInFunction() || storageClasses.is_static ) {
    332                         return type;
    333                 }
    334 
    335                 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    336                         if ( nullptr == arrayType->dimension ) {
    337                                 return type;
    338                         }
    339 
    340                         if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
    341                                 return type;
    342                         }
    343 
    344                         ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
    345                         assert( dimType );
    346                         add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
    347 
    348                         ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
    349                                 arrayType->dimension->location,
    350                                 dimensionName.newName(),
    351                                 dimType,
    352                                 new ast::SingleInit(
    353                                         arrayType->dimension->location,
    354                                         arrayType->dimension
    355                                 )
    356                         );
    357 
    358                         ast::ArrayType * mutType = ast::mutate( arrayType );
    359                         mutType->dimension = new ast::VariableExpr(
    360                                         arrayDimension->location, arrayDimension );
    361                         declsToAddBefore.push_back( arrayDimension );
    362 
    363                         mutType->base = hoist( mutType->base );
    364                         return mutType;
    365                 }
    366                 return type;
    367         }
    368 
    369         struct ReturnFixer_New final :
    370                         public ast::WithStmtsToAdd<>, ast::WithGuards {
    371                 void previsit( const ast::FunctionDecl * decl );
    372                 const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
    373         private:
    374                 const ast::FunctionDecl * funcDecl = nullptr;
    375         };
    376 
    377         void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
    378                 GuardValue( funcDecl ) = decl;
    379         }
    380 
    381         const ast::ReturnStmt * ReturnFixer_New::previsit(
    382                         const ast::ReturnStmt * stmt ) {
    383                 auto & returns = funcDecl->returns;
    384                 assert( returns.size() < 2 );
    385                 // Hands off if the function returns a reference.
    386                 // Don't allocate a temporary if the address is returned.
    387                 if ( stmt->expr && 1 == returns.size() ) {
    388                         ast::ptr<ast::DeclWithType> retDecl = returns.front();
    389                         if ( isConstructable( retDecl->get_type() ) ) {
    390                                 // Explicitly construct the return value using the return
    391                                 // expression and the retVal object.
    392                                 assertf( "" != retDecl->name,
    393                                         "Function %s has unnamed return value.\n",
    394                                         funcDecl->name.c_str() );
    395 
    396                                 auto retVal = retDecl.strict_as<ast::ObjectDecl>();
    397                                 if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
    398                                         // Check if the return statement is already set up.
    399                                         if ( varExpr->var == retVal ) return stmt;
    400                                 }
    401                                 ast::ptr<ast::Stmt> ctorStmt = genCtorDtor(
    402                                         retVal->location, "?{}", retVal, stmt->expr );
    403                                 assertf( ctorStmt,
    404                                         "ReturnFixer: genCtorDtor returned nllptr: %s / %s",
    405                                         toString( retVal ).c_str(),
    406                                         toString( stmt->expr ).c_str() );
    407                                         stmtsToAddBefore.push_back( ctorStmt );
    408 
    409                                 // Return the retVal object.
    410                                 ast::ReturnStmt * mutStmt = ast::mutate( stmt );
    411                                 mutStmt->expr = new ast::VariableExpr(
    412                                         stmt->location, retDecl );
    413                                 return mutStmt;
    414                         }
    415                 }
    416                 return stmt;
    417         }
    418 
    419 } // namespace
    420 
    421         void genInit( ast::TranslationUnit & transUnit ) {
    422                 ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );
    423                 ast::Pass<ReturnFixer_New>::run( transUnit );
    424         }
    425 
    426296        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    427297                PassVisitor<CtorDtor> ctordtor;
  • src/InitTweak/GenInit.h

    r1ed9cb63 r8a039be  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct 22 16:08:00 2021
    13 // Update Count     : 6
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:31:19 2017
     13// Update Count     : 4
    1414//
    1515
     
    2727        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    2828        void genInit( std::list< Declaration * > & translationUnit );
    29         void genInit( ast::TranslationUnit & translationUnit );
    3029
    3130        /// Converts return statements into copy constructor calls on the hidden return variable
  • src/Parser/parser.yy

    r1ed9cb63 r8a039be  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 15 09:20:17 2021
    13 // Update Count     : 5163
     12// Last Modified On : Sat Sep 11 08:20:44 2021
     13// Update Count     : 5040
    1414//
    1515
     
    3131// from ANSI90 to ANSI11 C are marked with the comment "C99/C11".
    3232
    33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions. All of the
     33// This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions All of the
    3434// syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall (CFA), which
    3535// fixes several of C's outstanding problems and extends C with many modern language concepts. All of the syntactic
     
    6969        // 2. String encodings are transformed into canonical form (one encoding at start) so the encoding can be found
    7070        //    without searching the string, e.g.: "abc" L"def" L"ghi" => L"abc" "def" "ghi". Multiple encodings must match,
    71         //    e.g., u"a" U"b" L"c" is disallowed.
     71        //    i.e., u"a" U"b" L"c" is disallowed.
    7272
    7373        if ( from[0] != '"' ) {                                                         // encoding ?
     
    310310%token ATassign                                                                                 // @=
    311311
    312 %type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
     312%type<tok> identifier
     313%type<tok> identifier_or_type_name  attr_name
    313314%type<tok> quasi_keyword
    314315%type<constant> string_literal
     
    326327%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    327328%type<en> comma_expression                              comma_expression_opt
    328 %type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
     329%type<en> argument_expression_list_opt  argument_expression                     default_initializer_opt
    329330%type<ifctl> if_control_expression
    330331%type<fctl> for_control_expression              for_control_expression_list
     
    558559        IDENTIFIER
    559560        | quasi_keyword
    560         ;
    561 
    562 identifier_at:
    563         identifier
    564561        | '@'                                                                                           // CFA
    565562                { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; }
     
    696693        // empty
    697694                { $$ = nullptr; }
    698         | argument_expression_list
    699         ;
    700 
    701 argument_expression_list:
    702         argument_expression
     695        | argument_expression
    703696        | argument_expression_list_opt ',' argument_expression
    704697                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     
    738731        | FLOATINGconstant fraction_constants_opt
    739732                { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
    740         | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
     733        | identifier fraction_constants_opt
    741734                {
    742735                        $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
     
    10911084        comma_expression_opt ';'
    10921085                { $$ = new StatementNode( build_expr( $1 ) ); }
    1093         | MUTEX '(' ')' comma_expression ';'
    1094                 { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
    1095                 // { SemanticError( yylloc, "Mutex expression is currently unimplemented." ); $$ = nullptr; }
    10961086        ;
    10971087
     
    11921182
    11931183iteration_statement:
    1194         WHILE '(' ')' statement                                                         // CFA => while ( 1 )
     1184        WHILE '(' push if_control_expression ')' statement pop
     1185                { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
     1186        | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
    11951187                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    1196         | WHILE '(' if_control_expression ')' statement         %prec THEN
    1197                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
    1198         | WHILE '(' if_control_expression ')' statement ELSE statement // CFA
    1199                 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
     1188        | DO statement WHILE '(' comma_expression ')' ';'
     1189                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    12001190        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    12011191                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    1202         | DO statement WHILE '(' comma_expression ')' ';'       %prec THEN
    1203                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    1204         | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    1205                 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
     1192        | FOR '(' push for_control_expression_list ')' statement pop
     1193                { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
    12061194        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    12071195                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
    1208         | FOR '(' for_control_expression_list ')' statement     %prec THEN
    1209                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
    1210         | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
    1211                 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    12121196        ;
    12131197
     
    13551339with_statement:
    13561340        WITH '(' tuple_expression_list ')' statement
    1357                 { $$ = new StatementNode( build_with( $3, $5 ) ); }
     1341                {
     1342                        $$ = new StatementNode( build_with( $3, $5 ) );
     1343                }
    13581344        ;
    13591345
    13601346// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    13611347mutex_statement:
    1362         MUTEX '(' argument_expression_list ')' statement
     1348        MUTEX '(' argument_expression_list_opt ')' statement
    13631349                { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
    13641350        ;
     
    24892475designation:
    24902476        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    2491         | identifier_at ':'                                                                     // GCC, field name
     2477        | identifier ':'                                                                        // GCC, field name
    24922478                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    24932479        ;
     
    25012487
    25022488designator:
    2503         '.' identifier_at                                                                       // C99, field name
     2489        '.' identifier                                                                          // C99, field name
    25042490                { $$ = new ExpressionNode( build_varref( $2 ) ); }
    25052491        | '[' push assignment_expression pop ']'                        // C99, single array element
     
    29332919
    29342920paren_identifier:
    2935         identifier_at
     2921        identifier
    29362922                { $$ = DeclarationNode::newName( $1 ); }
    29372923        | '(' paren_identifier ')'                                                      // redundant parenthesis
  • src/main.cc

    r1ed9cb63 r8a039be  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct 22 16:06:00 2021
    13 // Update Count     : 653
     11// Last Modified By : Henry Xue
     12// Last Modified On : Mon Aug 23 15:42:08 2021
     13// Update Count     : 650
    1414//
    1515
     
    4343#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4444#include "Common/CompilerError.h"           // for CompilerError
    45 #include "Common/DeclStats.hpp"             // for printDeclStats
    46 #include "Common/ResolvProtoDump.hpp"       // for dumpAsResolverProto
    4745#include "Common/Stats.h"
    4846#include "Common/PassVisitor.h"
     
    336334                PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    337335                PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
     336                PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
     337
     338                if ( libcfap ) {
     339                        // generate the bodies of cfa library functions
     340                        LibCfa::makeLibCfa( translationUnit );
     341                } // if
     342
     343                if ( declstatsp ) {
     344                        CodeTools::printDeclStats( translationUnit );
     345                        deleteAll( translationUnit );
     346                        return EXIT_SUCCESS;
     347                } // if
     348
     349                if ( bresolvep ) {
     350                        dump( translationUnit );
     351                        return EXIT_SUCCESS;
     352                } // if
    338353
    339354                CodeTools::fillLocations( translationUnit );
     355
     356                if ( resolvprotop ) {
     357                        CodeTools::dumpAsResolvProto( translationUnit );
     358                        return EXIT_SUCCESS;
     359                } // if
    340360
    341361                if( useNewAST ) {
     
    346366                        auto transUnit = convert( move( translationUnit ) );
    347367
    348                         forceFillCodeLocations( transUnit );
    349 
    350                         PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    351368                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
    352 
    353                         if ( libcfap ) {
    354                                 // Generate the bodies of cfa library functions.
    355                                 LibCfa::makeLibCfa( transUnit );
    356                         } // if
    357 
    358                         if ( declstatsp ) {
    359                                 printDeclStats( transUnit );
    360                                 return EXIT_SUCCESS;
    361                         } // if
    362 
    363                         if ( bresolvep ) {
    364                                 dump( move( transUnit ) );
    365                                 return EXIT_SUCCESS;
    366                         } // if
    367 
    368                         if ( resolvprotop ) {
    369                                 dumpAsResolverProto( transUnit );
    370                                 return EXIT_SUCCESS;
    371                         } // if
    372 
     369                       
    373370                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    374371                        if ( exprp ) {
     
    380377
    381378                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
    382 
    383379                        translationUnit = convert( move( transUnit ) );
    384380                } else {
    385                         PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    386381                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
    387 
    388                         if ( libcfap ) {
    389                                 // Generate the bodies of cfa library functions.
    390                                 LibCfa::makeLibCfa( translationUnit );
    391                         } // if
    392 
    393                         if ( declstatsp ) {
    394                                 CodeTools::printDeclStats( translationUnit );
    395                                 deleteAll( translationUnit );
    396                                 return EXIT_SUCCESS;
    397                         } // if
    398 
    399                         if ( bresolvep ) {
    400                                 dump( translationUnit );
    401                                 return EXIT_SUCCESS;
    402                         } // if
    403 
    404                         CodeTools::fillLocations( translationUnit );
    405 
    406                         if ( resolvprotop ) {
    407                                 CodeTools::dumpAsResolvProto( translationUnit );
    408                                 return EXIT_SUCCESS;
    409                         } // if
    410382
    411383                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
  • tests/concurrent/semaphore.cfa

    r1ed9cb63 r8a039be  
    22#include <locks.hfa>
    33#include <thread.hfa>
    4 #include <mutex_stmt.hfa>
    54
    65enum { num_blockers = 17, num_unblockers = 13 };
     
    2928                thrash();
    3029                P(ben);
    31                 if(((thread&)this).seqable.next != 0p) mutex(sout) sout | "Link not invalidated";
     30                if(((thread&)this).seqable.next != 0p) sout | acquire |"Link not invalidated";
    3231                thrash();
    3332        }
  • tests/concurrent/sleep.cfa

    r1ed9cb63 r8a039be  
    11#include <fstream.hfa>
    22#include <thread.hfa>
    3 #include <mutex_stmt.hfa>
    43#include <time.hfa>
    54
     
    3029
    3130int main() {
    32         mutex( sout ) sout | "start";
     31        sout | acquire | "start";
    3332        {
    3433                slow_sleeper slow;
     
    3736                yield();
    3837        }
    39         mutex( sout ) sout | "done";
     38        sout | acquire | "done";
    4039}
    4140
  • tests/io/io-acquire.cfa

    r1ed9cb63 r8a039be  
    1010// Created On       : Mon Mar  1 18:40:09 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Oct  6 18:04:58 2021
    13 // Update Count     : 72
     12// Last Modified On : Tue Apr 27 11:49:34 2021
     13// Update Count     : 18
    1414//
    1515
    1616#include <fstream.hfa>
    1717#include <thread.hfa>
    18 #include <mutex_stmt.hfa>
    1918
    2019thread T {};
     
    2221        // output from parallel threads should not be scrambled
    2322
    24         for ( 100 ) {                                                                           // expression protection
    25                 mutex(sout) sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     23        for ( 100 ) {                                                                           // local protection
     24                sout | acquire | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    2625        }
    27         mutex( sout ) {                                                                         // statement protection
     26        {                                                                                                       // global protection (RAII)
     27                osacquire acq = { sout };
    2828                for ( 100 ) {
    2929                        sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     
    3131        }
    3232        {                                                                                                       // duplicate protection demonstrating recursive lock
    33                 ofstream & h1( ofstream & os ) {                                // helper
    34                         mutex( os ) return os | 1 | 2 | 3 | 4;          // unnecessary mutex
    35                 }
    36                 ofstream & h2( ofstream & os ) {                                // helper
    37                         mutex( os ) return os | 6 | 7 | 8 | 9;          // unnecessary mutex
    38                 }
    39                 mutex( sout ) {                                                                 // unnecessary mutex
    40                         for ( 100 ) {
    41                                 mutex( sout ) {
    42                                         sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    43                                         sout | h1 | 5 | h2;                                     // refactored code
    44                                 }
    45                         }
     33                osacquire acq = { sout };
     34                for ( 100 ) {
     35                        osacquire acq = { sout };
     36                        sout | acquire | 1 | 2 | 3 | 4 | 5 | acquire | 6 | 7 | 8 | 9;
     37                        sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    4638                }
    4739        }
     
    5042
    5143        int a, b, c, d, e, f, g, h, i;
    52         for ( 100 ) {                                                                           // expression protection
    53                 mutex(sin) sin | a | b | c | d | e | f | g | h | i;
     44        for ( 100 ) {                                                                           // local protection
     45                sin | acquire | a | b | c | d | e | f | g | h | i;
    5446        }
    55         mutex( sin ) {                                                                          // statement protection
     47        {                                                                                                       // global protection (RAII)
     48                isacquire acq = { sin };
    5649                for ( 100 ) {
    5750                        sin  | a | b | c | d | e | f | g | h | i;
     
    5952        }
    6053        {                                                                                                       // duplicate protection demonstrating recursive lock
    61                 ifstream & h1( ifstream & is ) {                                // helper
    62                         mutex( is ) return is | a | b | c | d;          // unnecessary mutex
    63                 }
    64                 ifstream & h2( ifstream & is ) {                                // helper
    65                         mutex( is ) return is | f | g | h | i;          // unnecessary mutex
    66                 }
    67                 mutex( sin ) {                                                                  // unnecessary mutex
    68                         for ( 5 ) {
    69                                 mutex( sin ) {
    70                                         sin  | a | b | c | d | e | f | g | h | i;
    71                                         sin  | h1 | e | h2;                                     // refactored code
    72                                 }
    73                         }
     54                isacquire acq = { sin };
     55                for ( 100 ) {
     56                        isacquire acq = { sin };
     57                        sin | acquire | a | b | c | d | e | acquire | f | g | h | i;
     58                        sin | a | b | c | d | e | f | g | h | i;
    7459                }
    7560        }
  • tests/linking/io-acquire.cfa

    r1ed9cb63 r8a039be  
    1717#include <fstream.hfa>
    1818#include <stdlib.hfa>
    19 #include <mutex_stmt.hfa>
    2019
    2120int main() {
    2221        int i;
    2322        if(threading_enabled()) {
    24                 mutex( stdout ) stdout | "YES";
     23                stdout | acquire | "YES";
    2524                stdin | i;
    2625        } else {
    27                 mutex( stdout ) stdout | "NO";
     26                stdout | acquire | "NO";
    2827                stdin | i;
    2928        }
  • tests/pybin/test_run.py

    r1ed9cb63 r8a039be  
    6565        def toString( cls, retcode, duration ):
    6666                if settings.generating :
    67                         if   retcode == TestResult.SUCCESS:     key = 'pass'; text = "Done   "
    68                         elif retcode == TestResult.TIMEOUT:     key = 'time'; text = "TIMEOUT"
    69                         else :  key = 'fail';   text = "ERROR code %d" % retcode
     67                        if   retcode == TestResult.SUCCESS:     text = "Done   "
     68                        elif retcode == TestResult.TIMEOUT:     text = "TIMEOUT"
     69                        else :                                          text = "ERROR code %d" % retcode
    7070                else :
    71                         if   retcode == TestResult.SUCCESS:     key = 'pass'; text = "PASSED "
    72                         elif retcode == TestResult.TIMEOUT:     key = 'time'; text = "TIMEOUT"
    73                         else :  key = 'fail';   text = "FAILED with code %d" % retcode
     71                        if   retcode == TestResult.SUCCESS:     text = "PASSED "
     72                        elif retcode == TestResult.TIMEOUT:     text = "TIMEOUT"
     73                        else :                                          text = "FAILED with code %d" % retcode
    7474
    7575                text += "    C%s - R%s" % (fmtDur(duration[0]), fmtDur(duration[1]))
    76                 return key, text
     76                return text
  • tests/test.py

    r1ed9cb63 r8a039be  
    257257
    258258                # update output based on current action
    259                 result_key, result_txt = TestResult.toString( retcode, duration )
     259                result_txt = TestResult.toString( retcode, duration )
    260260
    261261                #print result with error if needed
     
    265265                        text = text + '\n' + error
    266266
    267                 return retcode == TestResult.SUCCESS, result_key, text
     267                return retcode == TestResult.SUCCESS, text
    268268        except KeyboardInterrupt:
    269                 return False, 'keybrd', ""
     269                return False, ""
    270270        # except Exception as ex:
    271271        #       print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
     
    283283
    284284        failed = False
    285         rescnts = {     'pass': 0, 'fail': 0, 'time': 0, 'keybrd': 0 }
    286         other = 0
    287285
    288286        # for each test to run
     
    296294                )
    297295
    298                 for i, (succ, code, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) :
    299                         if code in rescnts.keys():
    300                                 rescnts[code] += 1
    301                         else:
    302                                 other += 1
    303 
     296                for i, (succ, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) :
    304297                        if not succ :
    305298                                failed = True
     
    326319        # clean the workspace
    327320        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    328 
    329         print("{} passes, {} failures, {} timeouts, {} cancelled, {} other".format(rescnts['pass'], rescnts['fail'], rescnts['time'], rescnts['keybrd'], other))
    330321
    331322        return failed
     
    452443                        failed = run_tests(local_tests, options.jobs)
    453444                        if failed:
     445                                result = 1
    454446                                if not settings.continue_:
    455447                                        break
Note: See TracChangeset for help on using the changeset viewer.