Changeset 1ed9cb63
- Timestamp:
- Oct 27, 2021, 5:15:41 PM (4 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
- 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. - Files:
-
- 4 added
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/user/user.tex
r8a039be r1ed9cb63 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon May 31 09:03:34202114 %% Update Count : 50 7113 %% Last Modified On : Sun Oct 10 12:45:00 2021 14 %% Update Count : 5095 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 4444 4444 \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. 4445 4445 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 "; // manipulator4449 $\emph{thread\(_2\)}$ : sout | ®acquire®| "uvw " | "xyz ";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 "; 4450 4450 \end{cfa} 4451 4451 Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order. … … 4466 4466 In 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. 4467 4467 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}$ 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 )® { 4472 4471 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}$ 4474 4473 sout | 4; 4475 } // implicitly release the lock when "acq" is deallocated4476 \end{cfa} 4477 Note, the unnecessary © acquire© manipulatorworks because the recursive stream-lock can be acquired/released multiple times by the owner thread.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. 4478 4477 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}. 4479 4478 4480 4479 The previous values written by threads 1 and 2 can be read in concurrently: 4481 4480 \begin{cfa} 4482 { // acquire sin lock for block duration 4483 ®isacquire acq = { sin };® $\C{// named stream locker}$ 4481 ®mutex( sin )® { 4484 4482 int x, y, z, w; 4485 4483 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}$ 4487 4485 sin | w; 4488 } // implicitly release the lock when "acq" is deallocated4486 } // implicitly release sin lock 4489 4487 \end{cfa} 4490 4488 Again, the order of the reading threads is non-deterministic. … … 4493 4491 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg: 4494 4492 \begin{cfa} 4495 sout | ®acquire® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$4493 ®mutex() sout® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$ 4496 4494 \end{cfa} 4497 4495 If 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. … … 4500 4498 \begin{cfa} 4501 4499 int ®data® = rtn( mon ); 4502 sout | acquire| "data:" | ®data®;4500 mutex() sout | "data:" | ®data®; 4503 4501 \end{cfa} 4504 4502 … … 4506 4504 \section{String Stream} 4507 4505 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. 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 4510 4524 \begin{figure} 4511 4525 \begin{cfa} … … 4520 4534 double x = 12345678.9, y = 98765.4321e-11; 4521 4535 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}$ 4528 4542 ®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 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 4532 4552 \end{cfa} 4533 4553 \caption{String Stream Processing} 4534 4554 \label{f:StringStreamProcessing} 4535 4555 \end{figure} 4536 4537 \VRef[Figure]{f:StringStreamFunctions} shows the string stream operations.4538 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]4539 \item4540 \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 \item4545 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 4564 4556 4565 4557 \begin{comment} -
libcfa/src/fstream.cfa
r8a039be r1ed9cb63 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Sep 21 21:51:38202113 // Update Count : 46012 // Last Modified On : Sun Oct 10 11:23:05 2021 13 // Update Count : 512 14 14 // 15 15 … … 28 28 #define IO_MSG "I/O error: " 29 29 30 void ?{}( ofstream & os, void * file ) with(os) { 30 // private 31 void ?{}( ofstream & os, void * file ) with( os ) { 31 32 file$ = file; 32 33 sepDefault$ = true; … … 35 36 prt$ = false; 36 37 sawNL$ = false; 37 acquired$ = false;38 38 sepSetCur$( os, sepGet( os ) ); 39 39 sepSet( os, " " ); … … 41 41 } // ?{} 42 42 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; } 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$ ); } 54 56 55 57 // public 56 58 void ?{}( 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 } // ^?{} 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 ); } 69 62 70 63 void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); } … … 107 100 if ( &os == &exit ) exit( EXIT_FAILURE ); 108 101 if ( &os == &abort ) abort(); 109 if ( os.acquired$ ) { os.acquired$ = false; release( os ); }110 102 } // ends 111 103 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 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$) ); } 123 107 124 108 void 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 126 116 if ( file == 0p ) { 127 117 throw (Open_Failure){ os }; … … 131 121 } // open 132 122 133 void open( ofstream & os, const char name[] ) { 134 open( os, name, "w" ); 135 } // open 136 137 void close( ofstream & os ) with(os) { 123 void open( ofstream & os, const char name[] ) { open( os, name, "w" ); } 124 125 void close( ofstream & os ) with( os ) { 138 126 if ( (FILE *)(file$) == 0p ) return; 139 127 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return; 140 128 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 ) { 142 137 throw (Close_Failure){ os }; 143 138 // abort | IO_MSG "close output" | nl | strerror( errno ); 144 139 } // if 145 file$ = 0p; 140 file$ = 0p; // safety after close 146 141 } // close 147 142 … … 162 157 va_list args; 163 158 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 165 167 if ( len == EOF ) { 166 168 if ( ferror( (FILE *)(os.file$) ) ) { … … 175 177 } // fmt 176 178 177 inline void acquire( ofstream & os ) with(os) {178 lock( lock$ ); // may increase recursive lock179 if ( ! acquired$ ) acquired$ = true; // not locked ?180 else unlock( lock$ ); // unwind recursive lock at start181 } // acquire182 183 inline void release( ofstream & os ) {184 unlock( os.lock$ );185 } // release186 187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }188 void ^?{}( osacquire & acq ) { release( acq.os ); }189 190 179 static ofstream soutFile = { (FILE *)stdout }; 191 180 ofstream & sout = soutFile, & stdout = soutFile; … … 205 194 flush( os ); 206 195 return os; 207 // (ofstream &)(os | '\n');208 // setPrt$( os, false ); // turn off209 // setNL$( os, true );210 // flush( os );211 // return sepOff( os ); // prepare for next line212 196 } // nl 213 197 … … 217 201 218 202 // private 219 void ?{}( ifstream & is, void * file ) with( is) {203 void ?{}( ifstream & is, void * file ) with( is ) { 220 204 file$ = file; 221 205 nlOnOff$ = false; 222 acquired$ = false; 223 } // ?{} 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$ ); } 224 212 225 213 // public 226 214 void ?{}( 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 } // ^?{} 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$) ); } 239 221 240 222 void nlOn( ifstream & os ) { os.nlOnOff$ = true; } 241 223 void 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 225 void ends( ifstream & is ) {} 226 227 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; } 259 228 260 229 void 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 262 237 if ( file == 0p ) { 263 238 throw (Open_Failure){ is }; … … 267 242 } // open 268 243 269 void open( ifstream & is, const char name[] ) { 270 open( is, name, "r" ); 271 } // open 272 273 void close( ifstream & is ) with(is) { 244 void open( ifstream & is, const char name[] ) { open( is, name, "r" ); } 245 246 void close( ifstream & is ) with( is ) { 274 247 if ( (FILE *)(file$) == 0p ) return; 275 248 if ( (FILE *)(file$) == (FILE *)stdin ) return; 276 249 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 ) { 278 258 throw (Close_Failure){ is }; 279 259 // abort | IO_MSG "close input" | nl | strerror( errno ); 280 260 } // if 281 file$ = 0p; 261 file$ = 0p; // safety after close 282 262 } // close 283 263 … … 308 288 int fmt( ifstream & is, const char format[], ... ) { 309 289 va_list args; 310 311 290 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 313 298 if ( len == EOF ) { 314 299 if ( ferror( (FILE *)(is.file$) ) ) { … … 319 304 return len; 320 305 } // fmt 321 322 inline void acquire( ifstream & is ) with(is) {323 lock( lock$ ); // may increase recursive lock324 if ( ! acquired$ ) acquired$ = true; // not locked ?325 else unlock( lock$ ); // unwind recursive lock at start326 } // acquire327 328 inline void release( ifstream & is ) {329 unlock( is.lock$ );330 } // release331 332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }333 void ^?{}( isacquire & acq ) { release( acq.is ); }334 306 335 307 static ifstream sinFile = { (FILE *)stdin }; -
libcfa/src/fstream.hfa
r8a039be r1ed9cb63 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 28 07:35:50202113 // Update Count : 2 3412 // Last Modified On : Sun Oct 10 09:37:32 2021 13 // Update Count : 243 14 14 // 15 15 … … 36 36 char tupleSeparator$[ofstream_sepSize]; 37 37 multiple_acquisition_lock lock$; 38 bool acquired$;39 38 }; // ofstream 40 39 … … 52 51 bool getPrt$( ofstream & ); 53 52 void setPrt$( ofstream &, bool ); 53 54 void lock( ofstream & ); 55 void unlock( ofstream & ); 54 56 55 57 // public … … 75 77 void open( ofstream &, const char name[] ); 76 78 void close( ofstream & ); 79 77 80 ofstream & 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 );90 81 91 82 void ?{}( ofstream & ); … … 110 101 bool nlOnOff$; 111 102 multiple_acquisition_lock lock$; 112 bool acquired$;113 103 }; // ifstream 114 104 115 105 // Satisfies istream 116 106 107 // private 108 bool getANL$( ifstream & ); 109 110 void lock( ifstream & ); 111 void unlock( ifstream & ); 112 117 113 // public 118 114 void nlOn( ifstream & ); 119 115 void nlOff( ifstream & ); 120 bool getANL( ifstream & );121 116 void ends( ifstream & ); 122 117 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 128 123 void open( ifstream & is, const char name[] ); 129 124 void close( ifstream & is ); 125 130 126 ifstream & read( ifstream & is, char data[], size_t size ); 131 127 ifstream & 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 );141 128 142 129 void ?{}( ifstream & is ); -
libcfa/src/iostream.cfa
r8a039be r1ed9cb63 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at May 15 09:39:21202113 // Update Count : 134 212 // Last Modified On : Sun Oct 10 09:28:17 2021 13 // Update Count : 1345 14 14 // 15 15 … … 398 398 return os; 399 399 } // nlOff 400 } // distribution401 402 forall( ostype & | ostream( ostype ) ) {403 ostype & acquire( ostype & os ) {404 acquire( os ); // call void returning405 return os;406 } // acquire407 400 } // distribution 408 401 … … 829 822 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt 830 823 // 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; } 832 825 if ( eof( is ) ) break; 833 826 } // for … … 1035 1028 return is; 1036 1029 } // nlOff 1037 } // distribution1038 1039 forall( istype & | istream( istype ) ) {1040 istype & acquire( istype & is ) {1041 acquire( is ); // call void returning1042 return is;1043 } // acquire1044 1030 } // distribution 1045 1031 -
libcfa/src/iostream.hfa
r8a039be r1ed9cb63 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 28 20:37:56202113 // Update Count : 40 112 // Last Modified On : Sun Oct 10 10:02:07 2021 13 // Update Count : 407 14 14 // 15 15 … … 58 58 void close( ostype & ); 59 59 ostype & write( ostype &, const char [], size_t ); 60 void acquire( ostype & ); // concurrent access61 60 }; // ostream 62 61 … … 142 141 ostype & nlOn( ostype & ); 143 142 ostype & nlOff( ostype & ); 144 } // distribution145 146 forall( ostype & | ostream( ostype ) ) {147 ostype & acquire( ostype & );148 143 } // distribution 149 144 … … 296 291 297 292 trait 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 299 296 void nlOn( istype & ); // read newline 300 297 void nlOff( istype & ); // scan newline 301 302 298 void ends( istype & os ); // end of output statement 303 299 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 312 308 void close( istype & is ); 313 309 istype & read( istype &, char [], size_t ); 314 void acquire( istype & ); // concurrent access315 310 }; // istream 316 311 … … 379 374 } // distribution 380 375 381 forall( istype & | istream( istype ) ) {382 istype & acquire( istype & );383 } // distribution384 385 376 // *********************************** manipulators *********************************** 386 377 -
libcfa/src/strstream.cfa
r8a039be r1ed9cb63 10 10 // Created On : Thu Apr 22 22:24:35 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 20:59:53202113 // Update Count : 7812 // Last Modified On : Sun Oct 10 16:13:20 2021 13 // Update Count : 101 14 14 // 15 15 16 16 #include "strstream.hfa" 17 #include "fstream.hfa" // abort 17 18 18 19 #include <stdio.h> // vsnprintf … … 30 31 31 32 // 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; }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; } 42 43 43 44 // public … … 128 129 // *********************************** istrstream *********************************** 129 130 131 // private 132 bool getANL$( istrstream & is ) { return is.nlOnOff$; } 130 133 131 134 // public … … 136 139 } // ?{} 137 140 138 bool getANL( istrstream & is ) { return is.nlOnOff$; }139 141 void nlOn( istrstream & is ) { is.nlOnOff$ = true; } 140 142 void nlOff( istrstream & is ) { is.nlOnOff$ = false; } 141 143 142 void ends( istrstream & is ) { 143 } // ends 144 void ends( istrstream & is ) {} 145 bool eof( istrstream & is ) { return false; } 144 146 145 int eof( istrstream & is ) { 146 return 0; 147 } // eof 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 148 164 149 165 istrstream &ungetc( istrstream & is, char c ) { … … 154 170 } // ungetc 155 171 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 } // if166 is.cursor$ += len;167 return len;168 } // fmt169 170 172 // Local Variables: // 171 173 // tab-width: 4 // -
libcfa/src/strstream.hfa
r8a039be r1ed9cb63 10 10 // Created On : Thu Apr 22 22:20:59 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 20:58:50202113 // Update Count : 4 112 // Last Modified On : Sun Oct 10 10:14:22 2021 13 // Update Count : 47 14 14 // 15 15 … … 85 85 // Satisfies basic_istream 86 86 87 // private 88 bool getANL$( istrstream & ); 89 87 90 // public 88 bool getANL( istrstream & );89 91 void nlOn( istrstream & ); 90 92 void nlOff( istrstream & ); 91 93 void ends( istrstream & ); 94 92 95 int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 93 istrstream & ungetc( istrstream & is, char c);94 int eof( istrstream & is);96 istrstream & ungetc( istrstream &, char ); 97 bool eof( istrstream & ); 95 98 96 void ?{}( istrstream & is, char buf[] );99 void ?{}( istrstream &, char buf[] ); 97 100 98 101 // Local Variables: // -
src/AST/Pass.hpp
r8a039be r1ed9cb63 348 348 349 349 /// 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. 350 351 template< typename T > 351 voidGuardValue( T& val ) {352 T& GuardValue( T& val ) { 352 353 at_cleanup( [ val ]( void * newVal ) { 353 354 * static_cast< T * >( newVal ) = val; 354 355 }, static_cast< void * >( & val ) ); 356 return val; 355 357 } 356 358 … … 394 396 }; 395 397 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 396 408 } 397 409 -
src/AST/Pass.impl.hpp
r8a039be r1ed9cb63 420 420 template< typename core_t > 421 421 inline 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 } 423 429 } 424 430 -
src/AST/Pass.proto.hpp
r8a039be r1ed9cb63 426 426 } // namespace forall 427 427 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 428 442 template<typename core_t> 429 443 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { -
src/AST/TranslationUnit.hpp
r8a039be r1ed9cb63 26 26 std::list< ptr< Decl > > decls; 27 27 28 struct Global s{28 struct Global { 29 29 std::map< UniqueId, Decl * > idMap; 30 30 31 const Type *sizeType;31 ptr<Type> sizeType; 32 32 const FunctionDecl * dereference; 33 33 const StructDecl * dtorStruct; -
src/AST/porting.md
r8a039be r1ed9cb63 98 98 * `Initializer` => `ast::Init` 99 99 * `Statement` => `ast::Stmt` 100 * `ReferenceToType` => `ast::BaseInstType` 100 101 * any field names should follow a similar renaming 101 102 * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`): -
src/CodeTools/DeclStats.cc
r8a039be r1ed9cb63 156 156 /// number of counting bins for linkages 157 157 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 } 160 171 161 172 Stats for_linkage[n_named_specs]; ///< Stores separate stats per linkage … … 366 377 const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName(); 367 378 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 ) ]; 369 380 370 381 ++stats.n_decls; … … 527 538 }; 528 539 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 532 540 void printDeclStats( std::list< Declaration * > &translationUnit ) { 533 541 PassVisitor<DeclStats> stats; -
src/Common/module.mk
r8a039be r1ed9cb63 22 22 Common/CompilerError.h \ 23 23 Common/Debug.h \ 24 Common/DeclStats.hpp \ 25 Common/DeclStats.cpp \ 24 26 Common/ErrorObjects.h \ 25 27 Common/Eval.cc \ … … 33 35 Common/PassVisitor.proto.h \ 34 36 Common/PersistentMap.h \ 37 Common/ResolvProtoDump.hpp \ 38 Common/ResolvProtoDump.cpp \ 35 39 Common/ScopedMap.h \ 36 40 Common/SemanticError.cc \ -
src/InitTweak/GenInit.cc
r8a039be r1ed9cb63 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:15:10 201913 // Update Count : 18 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 25 13:53:00 2021 13 // Update Count : 186 14 14 // 15 15 #include "GenInit.h" … … 24 24 #include "AST/Decl.hpp" 25 25 #include "AST/Init.hpp" 26 #include "AST/Pass.hpp" 26 27 #include "AST/Node.hpp" 27 28 #include "AST/Stmt.hpp" … … 294 295 } 295 296 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 296 426 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 297 427 PassVisitor<CtorDtor> ctordtor; -
src/InitTweak/GenInit.h
r8a039be r1ed9cb63 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:31:19 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 22 16:08:00 2021 13 // Update Count : 6 14 14 // 15 15 … … 27 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 28 void genInit( std::list< Declaration * > & translationUnit ); 29 void genInit( ast::TranslationUnit & translationUnit ); 29 30 30 31 /// Converts return statements into copy constructor calls on the hidden return variable -
src/Parser/parser.yy
r8a039be r1ed9cb63 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 11 08:20:44202113 // Update Count : 5 04012 // Last Modified On : Fri Oct 15 09:20:17 2021 13 // Update Count : 5163 14 14 // 15 15 … … 31 31 // from ANSI90 to ANSI11 C are marked with the comment "C99/C11". 32 32 33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions All of the33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions. All of the 34 34 // syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall (CFA), which 35 35 // fixes several of C's outstanding problems and extends C with many modern language concepts. All of the syntactic … … 69 69 // 2. String encodings are transformed into canonical form (one encoding at start) so the encoding can be found 70 70 // 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. 72 72 73 73 if ( from[0] != '"' ) { // encoding ? … … 310 310 %token ATassign // @= 311 311 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 314 313 %type<tok> quasi_keyword 315 314 %type<constant> string_literal … … 327 326 %type<en> conditional_expression constant_expression assignment_expression assignment_expression_opt 328 327 %type<en> comma_expression comma_expression_opt 329 %type<en> argument_expression_list_opt argument_expression default_initializer_opt328 %type<en> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt 330 329 %type<ifctl> if_control_expression 331 330 %type<fctl> for_control_expression for_control_expression_list … … 559 558 IDENTIFIER 560 559 | quasi_keyword 560 ; 561 562 identifier_at: 563 identifier 561 564 | '@' // CFA 562 565 { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; } … … 693 696 // empty 694 697 { $$ = nullptr; } 695 | argument_expression 698 | argument_expression_list 699 ; 700 701 argument_expression_list: 702 argument_expression 696 703 | argument_expression_list_opt ',' argument_expression 697 704 { $$ = (ExpressionNode *)($1->set_last( $3 )); } … … 731 738 | FLOATINGconstant fraction_constants_opt 732 739 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); } 733 | identifier fraction_constants_opt740 | identifier_at fraction_constants_opt // CFA, allow anonymous fields 734 741 { 735 742 $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) ); … … 1084 1091 comma_expression_opt ';' 1085 1092 { $$ = 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; } 1086 1096 ; 1087 1097 … … 1182 1192 1183 1193 iteration_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 ) 1187 1195 { $$ = 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; } 1190 1200 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1191 1201 { $$ = 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; } 1194 1206 | FOR '(' ')' statement // CFA => for ( ;; ) 1195 1207 { $$ = 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; } 1196 1212 ; 1197 1213 … … 1339 1355 with_statement: 1340 1356 WITH '(' tuple_expression_list ')' statement 1341 { 1342 $$ = new StatementNode( build_with( $3, $5 ) ); 1343 } 1357 { $$ = new StatementNode( build_with( $3, $5 ) ); } 1344 1358 ; 1345 1359 1346 1360 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex". 1347 1361 mutex_statement: 1348 MUTEX '(' argument_expression_list _opt')' statement1362 MUTEX '(' argument_expression_list ')' statement 1349 1363 { $$ = new StatementNode( build_mutex( $3, $5 ) ); } 1350 1364 ; … … 2475 2489 designation: 2476 2490 designator_list ':' // C99, CFA uses ":" instead of "=" 2477 | identifier ':' // GCC, field name2491 | identifier_at ':' // GCC, field name 2478 2492 { $$ = new ExpressionNode( build_varref( $1 ) ); } 2479 2493 ; … … 2487 2501 2488 2502 designator: 2489 '.' identifier 2503 '.' identifier_at // C99, field name 2490 2504 { $$ = new ExpressionNode( build_varref( $2 ) ); } 2491 2505 | '[' push assignment_expression pop ']' // C99, single array element … … 2919 2933 2920 2934 paren_identifier: 2921 identifier 2935 identifier_at 2922 2936 { $$ = DeclarationNode::newName( $1 ); } 2923 2937 | '(' paren_identifier ')' // redundant parenthesis -
src/main.cc
r8a039be r1ed9cb63 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Henry Xue12 // Last Modified On : Mon Aug 23 15:42:08202113 // Update Count : 65 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 22 16:06:00 2021 13 // Update Count : 653 14 14 // 15 15 … … 43 43 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 44 44 #include "Common/CompilerError.h" // for CompilerError 45 #include "Common/DeclStats.hpp" // for printDeclStats 46 #include "Common/ResolvProtoDump.hpp" // for dumpAsResolverProto 45 47 #include "Common/Stats.h" 46 48 #include "Common/PassVisitor.h" … … 334 336 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 335 337 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); 336 PASS( "Gen Init", InitTweak::genInit( translationUnit ) );337 338 if ( libcfap ) {339 // generate the bodies of cfa library functions340 LibCfa::makeLibCfa( translationUnit );341 } // if342 343 if ( declstatsp ) {344 CodeTools::printDeclStats( translationUnit );345 deleteAll( translationUnit );346 return EXIT_SUCCESS;347 } // if348 349 if ( bresolvep ) {350 dump( translationUnit );351 return EXIT_SUCCESS;352 } // if353 338 354 339 CodeTools::fillLocations( translationUnit ); 355 356 if ( resolvprotop ) {357 CodeTools::dumpAsResolvProto( translationUnit );358 return EXIT_SUCCESS;359 } // if360 340 361 341 if( useNewAST ) { … … 366 346 auto transUnit = convert( move( translationUnit ) ); 367 347 348 forceFillCodeLocations( transUnit ); 349 350 PASS( "Gen Init", InitTweak::genInit( transUnit ) ); 368 351 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 370 373 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 371 374 if ( exprp ) { … … 377 380 378 381 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 382 379 383 translationUnit = convert( move( transUnit ) ); 380 384 } else { 385 PASS( "Gen Init", InitTweak::genInit( translationUnit ) ); 381 386 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 382 410 383 411 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); -
tests/concurrent/semaphore.cfa
r8a039be r1ed9cb63 2 2 #include <locks.hfa> 3 3 #include <thread.hfa> 4 #include <mutex_stmt.hfa> 4 5 5 6 enum { num_blockers = 17, num_unblockers = 13 }; … … 28 29 thrash(); 29 30 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"; 31 32 thrash(); 32 33 } -
tests/concurrent/sleep.cfa
r8a039be r1ed9cb63 1 1 #include <fstream.hfa> 2 2 #include <thread.hfa> 3 #include <mutex_stmt.hfa> 3 4 #include <time.hfa> 4 5 … … 29 30 30 31 int main() { 31 sout | acquire| "start";32 mutex( sout ) sout | "start"; 32 33 { 33 34 slow_sleeper slow; … … 36 37 yield(); 37 38 } 38 sout | acquire| "done";39 mutex( sout ) sout | "done"; 39 40 } 40 41 -
tests/io/io-acquire.cfa
r8a039be r1ed9cb63 10 10 // Created On : Mon Mar 1 18:40:09 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 11:49:34202113 // Update Count : 1812 // Last Modified On : Wed Oct 6 18:04:58 2021 13 // Update Count : 72 14 14 // 15 15 16 16 #include <fstream.hfa> 17 17 #include <thread.hfa> 18 #include <mutex_stmt.hfa> 18 19 19 20 thread T {}; … … 21 22 // output from parallel threads should not be scrambled 22 23 23 for ( 100 ) { // localprotection24 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; 25 26 } 26 { // global protection (RAII) 27 osacquire acq = { sout }; 27 mutex( sout ) { // statement protection 28 28 for ( 100 ) { 29 29 sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; … … 31 31 } 32 32 { // 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 } 38 46 } 39 47 } … … 42 50 43 51 int a, b, c, d, e, f, g, h, i; 44 for ( 100 ) { // localprotection45 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; 46 54 } 47 { // global protection (RAII) 48 isacquire acq = { sin }; 55 mutex( sin ) { // statement protection 49 56 for ( 100 ) { 50 57 sin | a | b | c | d | e | f | g | h | i; … … 52 59 } 53 60 { // 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 } 59 74 } 60 75 } -
tests/linking/io-acquire.cfa
r8a039be r1ed9cb63 17 17 #include <fstream.hfa> 18 18 #include <stdlib.hfa> 19 #include <mutex_stmt.hfa> 19 20 20 21 int main() { 21 22 int i; 22 23 if(threading_enabled()) { 23 stdout | acquire| "YES";24 mutex( stdout ) stdout | "YES"; 24 25 stdin | i; 25 26 } else { 26 stdout | acquire| "NO";27 mutex( stdout ) stdout | "NO"; 27 28 stdin | i; 28 29 } -
tests/pybin/test_run.py
r8a039be r1ed9cb63 65 65 def toString( cls, retcode, duration ): 66 66 if settings.generating : 67 if retcode == TestResult.SUCCESS: text = "Done "68 elif retcode == TestResult.TIMEOUT: text = "TIMEOUT"69 else : 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 70 70 else : 71 if retcode == TestResult.SUCCESS: text = "PASSED "72 elif retcode == TestResult.TIMEOUT: text = "TIMEOUT"73 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 74 74 75 75 text += " C%s - R%s" % (fmtDur(duration[0]), fmtDur(duration[1])) 76 return text76 return key, text -
tests/test.py
r8a039be r1ed9cb63 257 257 258 258 # update output based on current action 259 result_ txt = TestResult.toString( retcode, duration )259 result_key, result_txt = TestResult.toString( retcode, duration ) 260 260 261 261 #print result with error if needed … … 265 265 text = text + '\n' + error 266 266 267 return retcode == TestResult.SUCCESS, text267 return retcode == TestResult.SUCCESS, result_key, text 268 268 except KeyboardInterrupt: 269 return False, ""269 return False, 'keybrd', "" 270 270 # except Exception as ex: 271 271 # print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr) … … 283 283 284 284 failed = False 285 rescnts = { 'pass': 0, 'fail': 0, 'time': 0, 'keybrd': 0 } 286 other = 0 285 287 286 288 # for each test to run … … 294 296 ) 295 297 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 297 304 if not succ : 298 305 failed = True … … 319 326 # clean the workspace 320 327 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)) 321 330 322 331 return failed … … 443 452 failed = run_tests(local_tests, options.jobs) 444 453 if failed: 445 result = 1446 454 if not settings.continue_: 447 455 break
Note: See TracChangeset
for help on using the changeset viewer.