Changeset 1ed9cb63


Ignore:
Timestamp:
Oct 27, 2021, 5:15:41 PM (8 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
enum, forall-pointer-decay, master
Children:
40a64f78
Parents:
8a039be (diff), c600df1 (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:
4 added
24 edited

Legend:

Unmodified
Added
Removed
  • doc/user/user.tex

    r8a039be r1ed9cb63  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon May 31 09:03:34 2021
    14 %% Update Count     : 5071
     13%% Last Modified On : Sun Oct 10 12:45:00 2021
     14%% Update Count     : 5095
    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 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 ";
     4446The 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 ";
    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, 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}$
     4468To lock a stream across multiple I/O operations, he long form of the mutex statement is used, \eg:
     4469\begin{cfa}
     4470®mutex( sout )® {
    44724471        sout | 1;
    4473         sout | ®acquire® | 2 | 3;                               $\C{// unnecessary, but ok to acquire and release again}$
     4472        ®mutex() sout® | 2 | 3;                         $\C{// unnecessary, but ok because of recursive lock}$
    44744473        sout | 4;
    4475 }       // implicitly release the lock when "acq" is deallocated
    4476 \end{cfa}
    4477 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
     4474} // implicitly release sout lock
     4475\end{cfa}
     4476Note, 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.
    44784477Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.
    44794478
    44804479The previous values written by threads 1 and 2 can be read in concurrently:
    44814480\begin{cfa}
    4482 {       // acquire sin lock for block duration
    4483         ®isacquire acq = { sin };®                              $\C{// named stream locker}$
     4481®mutex( sin )® {
    44844482        int x, y, z, w;
    44854483        sin | x;
    4486         sin | ®acquire® | y | z;                                $\C{// unnecessary, but ok to acquire and release again}$
     4484        ®mutex() sin® | y | z;                          $\C{// unnecessary, but ok because of recursive lock}$
    44874485        sin | w;
    4488 }       // implicitly release the lock when "acq" is deallocated
     4486} // implicitly release sin lock
    44894487\end{cfa}
    44904488Again, the order of the reading threads is non-deterministic.
     
    44934491\Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
    44944492\begin{cfa}
    4495 sout | ®acquire® | "data:" | rtn( mon );        $\C{// mutex call on monitor}$
     4493®mutex() sout® | "data:" | rtn( mon );  $\C{// mutex call on monitor}$
    44964494\end{cfa}
    44974495If 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.
     
    45004498\begin{cfa}
    45014499int ®data® = rtn( mon );
    4502 sout | acquire | "data:" | ®data®;
     4500mutex() sout | "data:" | ®data®;
    45034501\end{cfa}
    45044502
     
    45064504\section{String Stream}
    45074505
    4508 All 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.
     4506The 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.
     4508The only string stream operations different from a file stream are:
     4509\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     4510\item
     4511constructors 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}
     4513void ?{}( ostrstream &, char buf[], size_t size );
     4514void ?{}( 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}
     4519ostrstream & write( ostrstream & os, FILE * stream = stdout );
     4520\end{cfa}
     4521There is no ©read© for ©istrstream©.
     4522\end{itemize}
     4523
    45104524\begin{figure}
    45114525\begin{cfa}
     
    45204534        double x = 12345678.9, y = 98765.4321e-11;
    45214535
    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}$
     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}$
    45284542        ®istrstream isstr = { buf2 };®
    4529         isstr | i | j | k | x | y;
    4530         sout | i | j | k | x | y;
    4531 }
     4543        char s[10];
     4544        isstr | i | j | k | x | y | s;
     4545        sout  | i | j | k | x | y | s;
     4546}
     4547
     45483 0x5          7 1.234568e+07 987.654n abc
     45493 0x5          7 1.234568e+07 987.654n abc
     45503 0x5          7 1.234568e+07 987.654n abc
     455112 14 15 3.5 70000. abc
    45324552\end{cfa}
    45334553\caption{String Stream Processing}
    45344554\label{f:StringStreamProcessing}
    45354555\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}
    4542 The constructor functions:
    4543 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4544 \item
    4545 create 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 
    4552 ostrstream & write( ostrstream & os, FILE * stream = stdout );
    4553 
    4554 void ?{}( ostrstream &, char buf[], size_t size );
    4555 
    4556 // *********************************** istrstream ***********************************
    4557 
    4558 void ?{}( istrstream & is, char buf[] );
    4559 \end{cfa}
    4560 \caption{String Stream Functions}
    4561 \label{f:StringStreamFunctions}
    4562 \end{figure}
    4563 
    45644556
    45654557\begin{comment}
  • libcfa/src/fstream.cfa

    r8a039be r1ed9cb63  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Sep 21 21:51:38 2021
    13 // Update Count     : 460
     12// Last Modified On : Sun Oct 10 11:23:05 2021
     13// Update Count     : 512
    1414//
    1515
     
    2828#define IO_MSG "I/O error: "
    2929
    30 void ?{}( ofstream & os, void * file ) with(os) {
     30// private
     31void ?{}( ofstream & os, void * file ) with( os ) {
    3132        file$ = file;
    3233        sepDefault$ = true;
     
    3536        prt$ = false;
    3637        sawNL$ = false;
    37         acquired$ = false;
    3838        sepSetCur$( os, sepGet( os ) );
    3939        sepSet( os, " " );
     
    4141} // ?{}
    4242
    43 // private
    44 bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    45 void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    46 void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    47 const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
    48 void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    49 bool getNL$( ofstream & os ) { return os.sawNL$; }
    50 void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
    51 bool getANL$( ofstream & os ) { return os.nlOnOff$; }
    52 bool getPrt$( ofstream & os ) { return os.prt$; }
    53 void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
     43inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     44inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     45inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     46inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
     47inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     48inline bool getNL$( ofstream & os ) { return os.sawNL$; }
     49inline void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
     50inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
     51inline bool getPrt$( ofstream & os ) { return os.prt$; }
     52inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
     53
     54inline void lock( ofstream & os ) with( os ) {  lock( os.lock$ ); }
     55inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
    5456
    5557// public
    5658void ?{}( ofstream & os ) { os.file$ = 0p; }
    57 
    58 void ?{}( ofstream & os, const char name[], const char mode[] ) {
    59         open( os, name, mode );
    60 } // ?{}
    61 
    62 void ?{}( ofstream & os, const char name[] ) {
    63         open( os, name, "w" );
    64 } // ?{}
    65 
    66 void ^?{}( ofstream & os ) {
    67         close( os );
    68 } // ^?{}
     59void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); }
     60void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); }
     61void ^?{}( ofstream & os ) { close( os ); }
    6962
    7063void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
     
    107100        if ( &os == &exit ) exit( EXIT_FAILURE );
    108101        if ( &os == &abort ) abort();
    109         if ( os.acquired$ ) { os.acquired$ = false; release( os ); }
    110102} // ends
    111103
    112 bool fail( ofstream & os ) {
    113         return os.file$ == 0 || ferror( (FILE *)(os.file$) );
    114 } // fail
    115 
    116 void clear( ofstream & os ) {
    117         clearerr( (FILE *)(os.file$) );
    118 } // clear
    119 
    120 int flush( ofstream & os ) {
    121         return fflush( (FILE *)(os.file$) );
    122 } // flush
     104bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
     105void clear( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
     106int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
    123107
    124108void open( ofstream & os, const char name[], const char mode[] ) {
    125         FILE * file = fopen( name, 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
    126116        if ( file == 0p ) {
    127117                throw (Open_Failure){ os };
     
    131121} // open
    132122
    133 void open( ofstream & os, const char name[] ) {
    134         open( os, name, "w" );
    135 } // open
    136 
    137 void close( ofstream & os ) with(os) {
     123void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
     124
     125void close( ofstream & os ) with( os ) {
    138126  if ( (FILE *)(file$) == 0p ) return;
    139127  if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
    140128
    141         if ( fclose( (FILE *)(file$) ) == EOF ) {
     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 ) {
    142137                throw (Close_Failure){ os };
    143138                // abort | IO_MSG "close output" | nl | strerror( errno );
    144139        } // if
    145         file$ = 0p;
     140        file$ = 0p;                                                                                     // safety after close
    146141} // close
    147142
     
    162157        va_list args;
    163158        va_start( args, format );
    164         int len = vfprintf( (FILE *)(os.file$), format, args );
     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
    165167        if ( len == EOF ) {
    166168                if ( ferror( (FILE *)(os.file$) ) ) {
     
    175177} // fmt
    176178
    177 inline 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 
    183 inline void release( ofstream & os ) {
    184         unlock( os.lock$ );
    185 } // release
    186 
    187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }
    188 void ^?{}( osacquire & acq ) { release( acq.os ); }
    189 
    190179static ofstream soutFile = { (FILE *)stdout };
    191180ofstream & sout = soutFile, & stdout = soutFile;
     
    205194        flush( os );
    206195        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
    212196} // nl
    213197
     
    217201
    218202// private
    219 void ?{}( ifstream & is, void * file ) with(is) {
     203void ?{}( ifstream & is, void * file ) with( is ) {
    220204        file$ = file;
    221205        nlOnOff$ = false;
    222         acquired$ = false;
    223 } // ?{}
     206} // ?{}
     207
     208bool getANL$( ifstream & os ) { return os.nlOnOff$; }
     209
     210inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
     211inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
    224212
    225213// public
    226214void ?{}( ifstream & is ) { is.file$ = 0p; }
    227 
    228 void ?{}( ifstream & is, const char name[], const char mode[] ) {
    229         open( is, name, mode );
    230 } // ?{}
    231 
    232 void ?{}( ifstream & is, const char name[] ) {
    233         open( is, name, "r" );
    234 } // ?{}
    235 
    236 void ^?{}( ifstream & is ) {
    237         close( is );
    238 } // ^?{}
     215void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); }
     216void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); }
     217void ^?{}( ifstream & is ) { close( is ); }
     218
     219bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
     220void clear( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
    239221
    240222void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
    241223void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
    242 bool getANL( ifstream & os ) { return os.nlOnOff$; }
    243 
    244 bool fail( ifstream & is ) {
    245         return is.file$ == 0p || ferror( (FILE *)(is.file$) );
    246 } // fail
    247 
    248 void clear( ifstream & is ) {
    249         clearerr( (FILE *)(is.file$) );
    250 } // clear
    251 
    252 void ends( ifstream & is ) {
    253         if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
    254 } // ends
    255 
    256 bool eof( ifstream & is ) {
    257         return feof( (FILE *)(is.file$) );
    258 } // eof
     224
     225void ends( ifstream & is ) {}
     226
     227bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
    259228
    260229void open( ifstream & is, const char name[], const char mode[] ) {
    261         FILE * file = fopen( name, 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
    262237        if ( file == 0p ) {
    263238                throw (Open_Failure){ is };
     
    267242} // open
    268243
    269 void open( ifstream & is, const char name[] ) {
    270         open( is, name, "r" );
    271 } // open
    272 
    273 void close( ifstream & is ) with(is) {
     244void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
     245
     246void close( ifstream & is ) with( is ) {
    274247  if ( (FILE *)(file$) == 0p ) return;
    275248  if ( (FILE *)(file$) == (FILE *)stdin ) return;
    276249
    277         if ( fclose( (FILE *)(file$) ) == EOF ) {
     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 ) {
    278258                throw (Close_Failure){ is };
    279259                // abort | IO_MSG "close input" | nl | strerror( errno );
    280260        } // if
    281         file$ = 0p;
     261        file$ = 0p;                                                                                     // safety after close
    282262} // close
    283263
     
    308288int fmt( ifstream & is, const char format[], ... ) {
    309289        va_list args;
    310 
    311290        va_start( args, format );
    312         int len = vfscanf( (FILE *)(is.file$), format, args );
     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
    313298        if ( len == EOF ) {
    314299                if ( ferror( (FILE *)(is.file$) ) ) {
     
    319304        return len;
    320305} // fmt
    321 
    322 inline 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 
    328 inline void release( ifstream & is ) {
    329         unlock( is.lock$ );
    330 } // release
    331 
    332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }
    333 void ^?{}( isacquire & acq ) { release( acq.is ); }
    334306
    335307static ifstream sinFile = { (FILE *)stdin };
  • libcfa/src/fstream.hfa

    r8a039be r1ed9cb63  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 28 07:35:50 2021
    13 // Update Count     : 234
     12// Last Modified On : Sun Oct 10 09:37:32 2021
     13// Update Count     : 243
    1414//
    1515
     
    3636        char tupleSeparator$[ofstream_sepSize];
    3737        multiple_acquisition_lock lock$;
    38         bool acquired$;
    3938}; // ofstream
    4039
     
    5251bool getPrt$( ofstream & );
    5352void setPrt$( ofstream &, bool );
     53
     54void lock( ofstream & );
     55void unlock( ofstream & );
    5456
    5557// public
     
    7577void open( ofstream &, const char name[] );
    7678void close( ofstream & );
     79
    7780ofstream & write( ofstream &, const char data[], size_t size );
    78 
    79 void acquire( ofstream & );
    80 void release( ofstream & );
    81 
    82 void lock( ofstream & );
    83 void unlock( ofstream & );
    84 
    85 struct osacquire {
    86         ofstream & os;
    87 };
    88 void ?{}( osacquire & acq, ofstream & );
    89 void ^?{}( osacquire & acq );
    9081
    9182void ?{}( ofstream & );
     
    110101        bool nlOnOff$;
    111102        multiple_acquisition_lock lock$;
    112         bool acquired$;
    113103}; // ifstream
    114104
    115105// Satisfies istream
    116106
     107// private
     108bool getANL$( ifstream & );
     109
     110void lock( ifstream & );
     111void unlock( ifstream & );
     112
    117113// public
    118114void nlOn( ifstream & );
    119115void nlOff( ifstream & );
    120 bool getANL( ifstream & );
    121116void ends( ifstream & );
    122117int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    128123void open( ifstream & is, const char name[] );
    129124void close( ifstream & is );
     125
    130126ifstream & read( ifstream & is, char data[], size_t size );
    131127ifstream & ungetc( ifstream & is, char c );
    132 
    133 void acquire( ifstream & is );
    134 void release( ifstream & is );
    135 
    136 struct isacquire {
    137         ifstream & is;
    138 };
    139 void ?{}( isacquire & acq, ifstream & is );
    140 void ^?{}( isacquire & acq );
    141128
    142129void ?{}( ifstream & is );
  • libcfa/src/iostream.cfa

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

    r8a039be r1ed9cb63  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 28 20:37:56 2021
    13 // Update Count     : 401
     12// Last Modified On : Sun Oct 10 10:02:07 2021
     13// Update Count     : 407
    1414//
    1515
     
    5858        void close( ostype & );
    5959        ostype & write( ostype &, const char [], size_t );
    60         void acquire( ostype & );                                                       // concurrent access
    6160}; // ostream
    6261
     
    142141        ostype & nlOn( ostype & );
    143142        ostype & nlOff( ostype & );
    144 } // distribution
    145 
    146 forall( ostype & | ostream( ostype ) ) {
    147         ostype & acquire( ostype & );
    148143} // distribution
    149144
     
    296291
    297292trait basic_istream( istype & ) {
    298         bool getANL( istype & );                                                        // get scan newline (on/off)
     293        // private
     294        bool getANL$( istype & );                                                       // get scan newline (on/off)
     295        // public
    299296        void nlOn( istype & );                                                          // read newline
    300297        void nlOff( istype & );                                                         // scan newline
    301 
    302298        void ends( istype & os );                                                       // end of output statement
    303299        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    312308        void close( istype & is );
    313309        istype & read( istype &, char [], size_t );
    314         void acquire( istype & );                                                       // concurrent access
    315310}; // istream
    316311
     
    379374} // distribution
    380375
    381 forall( istype & | istream( istype ) ) {
    382         istype & acquire( istype & );
    383 } // distribution
    384 
    385376// *********************************** manipulators ***********************************
    386377
  • libcfa/src/strstream.cfa

    r8a039be r1ed9cb63  
    1010// Created On       : Thu Apr 22 22:24:35 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 20:59:53 2021
    13 // Update Count     : 78
     12// Last Modified On : Sun Oct 10 16:13:20 2021
     13// Update Count     : 101
    1414//
    1515
    1616#include "strstream.hfa"
     17#include "fstream.hfa"                                                                  // abort
    1718
    1819#include <stdio.h>                                                                              // vsnprintf
     
    3031
    3132// private
    32 bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    33 void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    34 void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    35 const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
    36 void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    37 bool getNL$( ostrstream & os ) { return os.sawNL$; }
    38 void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
    39 bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
    40 bool getPrt$( ostrstream & os ) { return os.prt$; }
    41 void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
     33inline bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     34inline void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     35inline void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     36inline const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
     37inline void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     38inline bool getNL$( ostrstream & os ) { return os.sawNL$; }
     39inline void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
     40inline bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
     41inline bool getPrt$( ostrstream & os ) { return os.prt$; }
     42inline void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
    4243
    4344// public
     
    128129// *********************************** istrstream ***********************************
    129130
     131// private
     132bool getANL$( istrstream & is ) { return is.nlOnOff$; }
    130133
    131134// public
     
    136139} // ?{}
    137140
    138 bool getANL( istrstream & is ) { return is.nlOnOff$; }
    139141void nlOn( istrstream & is ) { is.nlOnOff$ = true; }
    140142void nlOff( istrstream & is ) { is.nlOnOff$ = false; }
    141143
    142 void ends( istrstream & is ) {
    143 } // ends
     144void ends( istrstream & is ) {}
     145bool eof( istrstream & is ) { return false; }
    144146
    145 int eof( istrstream & is ) {
    146         return 0;
    147 } // eof
     147int 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
    148164
    149165istrstream &ungetc( istrstream & is, char c ) {
     
    154170} // ungetc
    155171
    156 int 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 
    170172// Local Variables: //
    171173// tab-width: 4 //
  • libcfa/src/strstream.hfa

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

    r8a039be r1ed9cb63  
    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.
    350351        template< typename T >
    351         void GuardValue( T& val ) {
     352        T& GuardValue( T& val ) {
    352353                at_cleanup( [ val ]( void * newVal ) {
    353354                        * static_cast< T * >( newVal ) = val;
    354355                }, static_cast< void * >( & val ) );
     356                return val;
    355357        }
    356358
     
    394396};
    395397
     398/// Used to get a pointer to the wrapping TranslationUnit.
     399struct 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
    396408}
    397409
  • src/AST/Pass.impl.hpp

    r8a039be r1ed9cb63  
    420420template< typename core_t >
    421421inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    422         return ast::accept_all( unit.decls, 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        }
    423429}
    424430
  • src/AST/Pass.proto.hpp

    r8a039be r1ed9cb63  
    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
    428442        template<typename core_t>
    429443        static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
  • src/AST/TranslationUnit.hpp

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

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

    r8a039be r1ed9cb63  
    156156                /// number of counting bins for linkages
    157157                static const unsigned n_named_specs = 8;
    158                 /// map from total number of specs to bins
    159                 static const unsigned ind_for_linkage[16];
     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                }
    160171
    161172                Stats for_linkage[n_named_specs];            ///< Stores separate stats per linkage
     
    366377                        const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName();
    367378                        if ( seen_names.insert( mangleName ).second ) {
    368                                 Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ];
     379                                Stats& stats = for_linkage[ linkage_index( decl->linkage ) ];
    369380
    370381                                ++stats.n_decls;
     
    527538        };
    528539
    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 
    532540        void printDeclStats( std::list< Declaration * > &translationUnit ) {
    533541                PassVisitor<DeclStats> stats;
  • src/Common/module.mk

    r8a039be r1ed9cb63  
    2222      Common/CompilerError.h \
    2323      Common/Debug.h \
     24      Common/DeclStats.hpp \
     25      Common/DeclStats.cpp \
    2426      Common/ErrorObjects.h \
    2527      Common/Eval.cc \
     
    3335      Common/PassVisitor.proto.h \
    3436      Common/PersistentMap.h \
     37      Common/ResolvProtoDump.hpp \
     38      Common/ResolvProtoDump.cpp \
    3539      Common/ScopedMap.h \
    3640      Common/SemanticError.cc \
  • src/InitTweak/GenInit.cc

    r8a039be r1ed9cb63  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:15:10 2019
    13 // Update Count     : 184
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Oct 25 13:53:00 2021
     13// Update Count     : 186
    1414//
    1515#include "GenInit.h"
     
    2424#include "AST/Decl.hpp"
    2525#include "AST/Init.hpp"
     26#include "AST/Pass.hpp"
    2627#include "AST/Node.hpp"
    2728#include "AST/Stmt.hpp"
     
    294295        }
    295296
     297namespace {
     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
    296426        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    297427                PassVisitor<CtorDtor> ctordtor;
  • src/InitTweak/GenInit.h

    r8a039be r1ed9cb63  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:31:19 2017
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 22 16:08:00 2021
     13// Update Count     : 6
    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 );
    2930
    3031        /// Converts return statements into copy constructor calls on the hidden return variable
  • src/Parser/parser.yy

    r8a039be r1ed9cb63  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Sep 11 08:20:44 2021
    13 // Update Count     : 5040
     12// Last Modified On : Fri Oct 15 09:20:17 2021
     13// Update Count     : 5163
    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         //    i.e., u"a" U"b" L"c" is disallowed.
     71        //    e.g., u"a" U"b" L"c" is disallowed.
    7272
    7373        if ( from[0] != '"' ) {                                                         // encoding ?
     
    310310%token ATassign                                                                                 // @=
    311311
    312 %type<tok> identifier
    313 %type<tok> identifier_or_type_name  attr_name
     312%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    314313%type<tok> quasi_keyword
    315314%type<constant> string_literal
     
    327326%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    328327%type<en> comma_expression                              comma_expression_opt
    329 %type<en> argument_expression_list_opt  argument_expression                     default_initializer_opt
     328%type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
    330329%type<ifctl> if_control_expression
    331330%type<fctl> for_control_expression              for_control_expression_list
     
    559558        IDENTIFIER
    560559        | quasi_keyword
     560        ;
     561
     562identifier_at:
     563        identifier
    561564        | '@'                                                                                           // CFA
    562565                { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; }
     
    693696        // empty
    694697                { $$ = nullptr; }
    695         | argument_expression
     698        | argument_expression_list
     699        ;
     700
     701argument_expression_list:
     702        argument_expression
    696703        | argument_expression_list_opt ',' argument_expression
    697704                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     
    731738        | FLOATINGconstant fraction_constants_opt
    732739                { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
    733         | identifier fraction_constants_opt
     740        | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
    734741                {
    735742                        $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
     
    10841091        comma_expression_opt ';'
    10851092                { $$ = 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; }
    10861096        ;
    10871097
     
    11821192
    11831193iteration_statement:
    1184         WHILE '(' push if_control_expression ')' statement pop
    1185                 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
    1186         | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
     1194        WHILE '(' ')' statement                                                         // CFA => while ( 1 )
    11871195                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    1188         | DO statement WHILE '(' comma_expression ')' ';'
    1189                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     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; }
    11901200        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    11911201                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    1192         | FOR '(' push for_control_expression_list ')' statement pop
    1193                 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
     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; }
    11941206        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    11951207                { $$ = 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; }
    11961212        ;
    11971213
     
    13391355with_statement:
    13401356        WITH '(' tuple_expression_list ')' statement
    1341                 {
    1342                         $$ = new StatementNode( build_with( $3, $5 ) );
    1343                 }
     1357                { $$ = new StatementNode( build_with( $3, $5 ) ); }
    13441358        ;
    13451359
    13461360// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    13471361mutex_statement:
    1348         MUTEX '(' argument_expression_list_opt ')' statement
     1362        MUTEX '(' argument_expression_list ')' statement
    13491363                { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
    13501364        ;
     
    24752489designation:
    24762490        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    2477         | identifier ':'                                                                        // GCC, field name
     2491        | identifier_at ':'                                                                     // GCC, field name
    24782492                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    24792493        ;
     
    24872501
    24882502designator:
    2489         '.' identifier                                                                          // C99, field name
     2503        '.' identifier_at                                                                       // C99, field name
    24902504                { $$ = new ExpressionNode( build_varref( $2 ) ); }
    24912505        | '[' push assignment_expression pop ']'                        // C99, single array element
     
    29192933
    29202934paren_identifier:
    2921         identifier
     2935        identifier_at
    29222936                { $$ = DeclarationNode::newName( $1 ); }
    29232937        | '(' paren_identifier ')'                                                      // redundant parenthesis
  • src/main.cc

    r8a039be r1ed9cb63  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Mon Aug 23 15:42:08 2021
    13 // Update Count     : 650
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 22 16:06:00 2021
     13// Update Count     : 653
    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
    4547#include "Common/Stats.h"
    4648#include "Common/PassVisitor.h"
     
    334336                PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    335337                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
    353338
    354339                CodeTools::fillLocations( translationUnit );
    355 
    356                 if ( resolvprotop ) {
    357                         CodeTools::dumpAsResolvProto( translationUnit );
    358                         return EXIT_SUCCESS;
    359                 } // if
    360340
    361341                if( useNewAST ) {
     
    366346                        auto transUnit = convert( move( translationUnit ) );
    367347
     348                        forceFillCodeLocations( transUnit );
     349
     350                        PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    368351                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
    369                        
     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
    370373                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    371374                        if ( exprp ) {
     
    377380
    378381                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     382
    379383                        translationUnit = convert( move( transUnit ) );
    380384                } else {
     385                        PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    381386                        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
    382410
    383411                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
  • tests/concurrent/semaphore.cfa

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

    r8a039be r1ed9cb63  
    11#include <fstream.hfa>
    22#include <thread.hfa>
     3#include <mutex_stmt.hfa>
    34#include <time.hfa>
    45
     
    2930
    3031int main() {
    31         sout | acquire | "start";
     32        mutex( sout ) sout | "start";
    3233        {
    3334                slow_sleeper slow;
     
    3637                yield();
    3738        }
    38         sout | acquire | "done";
     39        mutex( sout ) sout | "done";
    3940}
    4041
  • tests/io/io-acquire.cfa

    r8a039be r1ed9cb63  
    1010// Created On       : Mon Mar  1 18:40:09 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 11:49:34 2021
    13 // Update Count     : 18
     12// Last Modified On : Wed Oct  6 18:04:58 2021
     13// Update Count     : 72
    1414//
    1515
    1616#include <fstream.hfa>
    1717#include <thread.hfa>
     18#include <mutex_stmt.hfa>
    1819
    1920thread T {};
     
    2122        // output from parallel threads should not be scrambled
    2223
    23         for ( 100 ) {                                                                           // local protection
    24                 sout | acquire | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     24        for ( 100 ) {                                                                           // expression protection
     25                mutex(sout) sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    2526        }
    26         {                                                                                                       // global protection (RAII)
    27                 osacquire acq = { sout };
     27        mutex( sout ) {                                                                         // statement protection
    2828                for ( 100 ) {
    2929                        sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     
    3131        }
    3232        {                                                                                                       // duplicate protection demonstrating recursive lock
    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;
     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                        }
    3846                }
    3947        }
     
    4250
    4351        int 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;
     52        for ( 100 ) {                                                                           // expression protection
     53                mutex(sin) sin | a | b | c | d | e | f | g | h | i;
    4654        }
    47         {                                                                                                       // global protection (RAII)
    48                 isacquire acq = { sin };
     55        mutex( sin ) {                                                                          // statement protection
    4956                for ( 100 ) {
    5057                        sin  | a | b | c | d | e | f | g | h | i;
     
    5259        }
    5360        {                                                                                                       // duplicate protection demonstrating recursive lock
    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;
     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                        }
    5974                }
    6075        }
  • tests/linking/io-acquire.cfa

    r8a039be r1ed9cb63  
    1717#include <fstream.hfa>
    1818#include <stdlib.hfa>
     19#include <mutex_stmt.hfa>
    1920
    2021int main() {
    2122        int i;
    2223        if(threading_enabled()) {
    23                 stdout | acquire | "YES";
     24                mutex( stdout ) stdout | "YES";
    2425                stdin | i;
    2526        } else {
    26                 stdout | acquire | "NO";
     27                mutex( stdout ) stdout | "NO";
    2728                stdin | i;
    2829        }
  • tests/pybin/test_run.py

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

    r8a039be r1ed9cb63  
    257257
    258258                # update output based on current action
    259                 result_txt = TestResult.toString( retcode, duration )
     259                result_key, 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, text
     267                return retcode == TestResult.SUCCESS, result_key, text
    268268        except KeyboardInterrupt:
    269                 return False, ""
     269                return False, 'keybrd', ""
    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
    285287
    286288        # for each test to run
     
    294296                )
    295297
    296                 for i, (succ, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) :
     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
    297304                        if not succ :
    298305                                failed = True
     
    319326        # clean the workspace
    320327        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))
    321330
    322331        return failed
     
    443452                        failed = run_tests(local_tests, options.jobs)
    444453                        if failed:
    445                                 result = 1
    446454                                if not settings.continue_:
    447455                                        break
Note: See TracChangeset for help on using the changeset viewer.