Changes in / [1ed9cb63:8a039be]
- Files:
-
- 4 deleted
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/user/user.tex
r1ed9cb63 r8a039be 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Oct 10 12:45:00202114 %% Update Count : 50 9513 %% Last Modified On : Mon May 31 09:03:34 2021 14 %% Update Count : 5071 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 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 ";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 "; 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, he long form of the mutex statement is used, \eg: 4469 \begin{cfa} 4470 ®mutex( sout )® { 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}$ 4471 4472 sout | 1; 4472 ®mutex() sout® | 2 | 3; $\C{// unnecessary, but ok because of recursive lock}$4473 sout | ®acquire® | 2 | 3; $\C{// unnecessary, but ok to acquire and release again}$ 4473 4474 sout | 4; 4474 } // implicitly release sout lock4475 \end{cfa} 4476 Note, the unnecessary © mutex© in the middle of the mutex statement,works because the recursive stream-lock can be acquired/released multiple times by the owner thread.4475 } // implicitly release the lock when "acq" is deallocated 4476 \end{cfa} 4477 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread. 4477 4478 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}. 4478 4479 4479 4480 The previous values written by threads 1 and 2 can be read in concurrently: 4480 4481 \begin{cfa} 4481 ®mutex( sin )® { 4482 { // acquire sin lock for block duration 4483 ®isacquire acq = { sin };® $\C{// named stream locker}$ 4482 4484 int x, y, z, w; 4483 4485 sin | x; 4484 ®mutex() sin® | y | z; $\C{// unnecessary, but ok because of recursive lock}$4486 sin | ®acquire® | y | z; $\C{// unnecessary, but ok to acquire and release again}$ 4485 4487 sin | w; 4486 } // implicitly release sin lock4488 } // implicitly release the lock when "acq" is deallocated 4487 4489 \end{cfa} 4488 4490 Again, the order of the reading threads is non-deterministic. … … 4491 4493 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg: 4492 4494 \begin{cfa} 4493 ®mutex() sout® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$4495 sout | ®acquire® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$ 4494 4496 \end{cfa} 4495 4497 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. … … 4498 4500 \begin{cfa} 4499 4501 int ®data® = rtn( mon ); 4500 mutex() sout| "data:" | ®data®;4502 sout | acquire | "data:" | ®data®; 4501 4503 \end{cfa} 4502 4504 … … 4504 4506 \section{String Stream} 4505 4507 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 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. 4524 4510 \begin{figure} 4525 4511 \begin{cfa} … … 4534 4520 double x = 12345678.9, y = 98765.4321e-11; 4535 4521 4536 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";4537 write( osstr ); $\C{// write string to stdout}$4538 printf( "%s", buf ); $\C{// same lines of output}$4539 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";4540 4541 char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$4522 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); $\C{// same lines of output}$ 4523 write( osstr ); 4524 printf( "%s", buf ); 4525 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); 4526 4527 char buf2[] = "12 14 15 3.5 7e4"; $\C{// input buffer}$ 4542 4528 ®istrstream isstr = { buf2 };® 4543 char s[10]; 4544 isstr | i | j | k | x | y | s; 4545 sout | i | j | k | x | y | s; 4546 } 4547 4548 3 0x5 7 1.234568e+07 987.654n abc 4549 3 0x5 7 1.234568e+07 987.654n abc 4550 3 0x5 7 1.234568e+07 987.654n abc 4551 12 14 15 3.5 70000. abc 4529 isstr | i | j | k | x | y; 4530 sout | i | j | k | x | y; 4531 } 4552 4532 \end{cfa} 4553 4533 \caption{String Stream Processing} 4554 4534 \label{f:StringStreamProcessing} 4555 4535 \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 4556 4564 4557 4565 \begin{comment} -
libcfa/src/fstream.cfa
r1ed9cb63 r8a039be 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 10 11:23:05202113 // Update Count : 51212 // Last Modified On : Tue Sep 21 21:51:38 2021 13 // Update Count : 460 14 14 // 15 15 … … 28 28 #define IO_MSG "I/O error: " 29 29 30 // private 31 void ?{}( ofstream & os, void * file ) with( os ) { 30 void ?{}( ofstream & os, void * file ) with(os) { 32 31 file$ = file; 33 32 sepDefault$ = true; … … 36 35 prt$ = false; 37 36 sawNL$ = false; 37 acquired$ = false; 38 38 sepSetCur$( os, sepGet( os ) ); 39 39 sepSet( os, " " ); … … 41 41 } // ?{} 42 42 43 inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; } 44 inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; } 45 inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; } 46 inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; } 47 inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; } 48 inline bool getNL$( ofstream & os ) { return os.sawNL$; } 49 inline void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; } 50 inline bool getANL$( ofstream & os ) { return os.nlOnOff$; } 51 inline bool getPrt$( ofstream & os ) { return os.prt$; } 52 inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; } 53 54 inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); } 55 inline void unlock( ofstream & os ) { unlock( os.lock$ ); } 43 // private 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; } 56 54 57 55 // public 58 56 void ?{}( ofstream & os ) { os.file$ = 0p; } 59 void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); } 60 void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); } 61 void ^?{}( ofstream & os ) { close( os ); } 57 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 } // ^?{} 62 69 63 70 void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); } … … 100 107 if ( &os == &exit ) exit( EXIT_FAILURE ); 101 108 if ( &os == &abort ) abort(); 109 if ( os.acquired$ ) { os.acquired$ = false; release( os ); } 102 110 } // ends 103 111 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$) ); } 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 107 123 108 124 void open( ofstream & os, const char name[], const char mode[] ) { 109 FILE * file; 110 for ( cnt; 10 ) { 111 errno = 0; 112 file = fopen( name, mode ); 113 if ( file != 0p || errno != EINTR ) break; // timer interrupt ? 114 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" ); 115 } // for 125 FILE * file = fopen( name, mode ); 116 126 if ( file == 0p ) { 117 127 throw (Open_Failure){ os }; … … 121 131 } // open 122 132 123 void open( ofstream & os, const char name[] ) { open( os, name, "w" ); } 124 125 void close( ofstream & os ) with( os ) { 133 void open( ofstream & os, const char name[] ) { 134 open( os, name, "w" ); 135 } // open 136 137 void close( ofstream & os ) with(os) { 126 138 if ( (FILE *)(file$) == 0p ) return; 127 139 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return; 128 140 129 int ret; 130 for ( cnt; 10 ) { 131 errno = 0; 132 ret = fclose( (FILE *)(file$) ); 133 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ? 134 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" ); 135 } // for 136 if ( ret == EOF ) { 141 if ( fclose( (FILE *)(file$) ) == EOF ) { 137 142 throw (Close_Failure){ os }; 138 143 // abort | IO_MSG "close output" | nl | strerror( errno ); 139 144 } // if 140 file$ = 0p; // safety after close145 file$ = 0p; 141 146 } // close 142 147 … … 157 162 va_list args; 158 163 va_start( args, format ); 159 160 int len; 161 for ( cnt; 10 ) { 162 errno = 0; 163 len = vfprintf( (FILE *)(os.file$), format, args ); 164 if ( len != EOF || errno != EINTR ) break; // timer interrupt ? 165 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" ); 166 } // for 164 int len = vfprintf( (FILE *)(os.file$), format, args ); 167 165 if ( len == EOF ) { 168 166 if ( ferror( (FILE *)(os.file$) ) ) { … … 177 175 } // fmt 178 176 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 179 190 static ofstream soutFile = { (FILE *)stdout }; 180 191 ofstream & sout = soutFile, & stdout = soutFile; … … 194 205 flush( os ); 195 206 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 196 212 } // nl 197 213 … … 201 217 202 218 // private 203 void ?{}( ifstream & is, void * file ) with( is) {219 void ?{}( ifstream & is, void * file ) with(is) { 204 220 file$ = file; 205 221 nlOnOff$ = false; 206 } // ?{} 207 208 bool getANL$( ifstream & os ) { return os.nlOnOff$; } 209 210 inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); } 211 inline void unlock( ifstream & os ) { unlock( os.lock$ ); } 222 acquired$ = false; 223 } // ?{} 212 224 213 225 // public 214 226 void ?{}( ifstream & is ) { is.file$ = 0p; } 215 void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); } 216 void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); } 217 void ^?{}( ifstream & is ) { close( is ); } 218 219 bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); } 220 void clear( ifstream & is ) { clearerr( (FILE *)(is.file$) ); } 227 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 } // ^?{} 221 239 222 240 void nlOn( ifstream & os ) { os.nlOnOff$ = true; } 223 241 void nlOff( ifstream & os ) { os.nlOnOff$ = false; } 224 225 void ends( ifstream & is ) {} 226 227 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; } 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 228 259 229 260 void open( ifstream & is, const char name[], const char mode[] ) { 230 FILE * file; 231 for ( cnt; 10 ) { 232 errno = 0; 233 file = fopen( name, mode ); 234 if ( file != 0p || errno != EINTR ) break; // timer interrupt ? 235 if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" ); 236 } // for 261 FILE * file = fopen( name, mode ); 237 262 if ( file == 0p ) { 238 263 throw (Open_Failure){ is }; … … 242 267 } // open 243 268 244 void open( ifstream & is, const char name[] ) { open( is, name, "r" ); } 245 246 void close( ifstream & is ) with( is ) { 269 void open( ifstream & is, const char name[] ) { 270 open( is, name, "r" ); 271 } // open 272 273 void close( ifstream & is ) with(is) { 247 274 if ( (FILE *)(file$) == 0p ) return; 248 275 if ( (FILE *)(file$) == (FILE *)stdin ) return; 249 276 250 int ret; 251 for ( cnt; 10 ) { 252 errno = 0; 253 ret = fclose( (FILE *)(file$) ); 254 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ? 255 if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" ); 256 } // for 257 if ( ret == EOF ) { 277 if ( fclose( (FILE *)(file$) ) == EOF ) { 258 278 throw (Close_Failure){ is }; 259 279 // abort | IO_MSG "close input" | nl | strerror( errno ); 260 280 } // if 261 file$ = 0p; // safety after close281 file$ = 0p; 262 282 } // close 263 283 … … 288 308 int fmt( ifstream & is, const char format[], ... ) { 289 309 va_list args; 310 290 311 va_start( args, format ); 291 292 int len; 293 for () { // no check for EINTR limit waiting for keyboard input 294 errno = 0; 295 len = vfscanf( (FILE *)(is.file$), format, args ); 296 if ( len != EOF || errno != EINTR ) break; // timer interrupt ? 297 } // for 312 int len = vfscanf( (FILE *)(is.file$), format, args ); 298 313 if ( len == EOF ) { 299 314 if ( ferror( (FILE *)(is.file$) ) ) { … … 304 319 return len; 305 320 } // 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 ); } 306 334 307 335 static ifstream sinFile = { (FILE *)stdin }; -
libcfa/src/fstream.hfa
r1ed9cb63 r8a039be 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 10 09:37:32202113 // Update Count : 2 4312 // Last Modified On : Wed Jul 28 07:35:50 2021 13 // Update Count : 234 14 14 // 15 15 … … 36 36 char tupleSeparator$[ofstream_sepSize]; 37 37 multiple_acquisition_lock lock$; 38 bool acquired$; 38 39 }; // ofstream 39 40 … … 52 53 void setPrt$( ofstream &, bool ); 53 54 54 void lock( ofstream & );55 void unlock( ofstream & );56 57 55 // public 58 56 void sepOn( ofstream & ); … … 77 75 void open( ofstream &, const char name[] ); 78 76 void close( ofstream & ); 79 80 77 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 ); 81 90 82 91 void ?{}( ofstream & ); … … 101 110 bool nlOnOff$; 102 111 multiple_acquisition_lock lock$; 112 bool acquired$; 103 113 }; // ifstream 104 114 105 115 // Satisfies istream 106 107 // private108 bool getANL$( ifstream & );109 110 void lock( ifstream & );111 void unlock( ifstream & );112 116 113 117 // public 114 118 void nlOn( ifstream & ); 115 119 void nlOff( ifstream & ); 120 bool getANL( ifstream & ); 116 121 void ends( ifstream & ); 117 122 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 123 128 void open( ifstream & is, const char name[] ); 124 129 void close( ifstream & is ); 125 126 130 ifstream & read( ifstream & is, char data[], size_t size ); 127 131 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 ); 128 141 129 142 void ?{}( ifstream & is ); -
libcfa/src/iostream.cfa
r1ed9cb63 r8a039be 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S un Oct 10 09:28:17202113 // Update Count : 134 512 // Last Modified On : Sat May 15 09:39:21 2021 13 // Update Count : 1342 14 14 // 15 15 … … 398 398 return os; 399 399 } // 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 400 407 } // distribution 401 408 … … 822 829 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt 823 830 // do not overwrite parameter with newline unless appropriate 824 if ( temp != '\n' || getANL $( is ) ) { c = temp; break; }831 if ( temp != '\n' || getANL( is ) ) { c = temp; break; } 825 832 if ( eof( is ) ) break; 826 833 } // for … … 1028 1035 return is; 1029 1036 } // 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 1030 1044 } // distribution 1031 1045 -
libcfa/src/iostream.hfa
r1ed9cb63 r8a039be 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 10 10:02:07202113 // Update Count : 40 712 // Last Modified On : Wed Apr 28 20:37:56 2021 13 // Update Count : 401 14 14 // 15 15 … … 58 58 void close( ostype & ); 59 59 ostype & write( ostype &, const char [], size_t ); 60 void acquire( ostype & ); // concurrent access 60 61 }; // ostream 61 62 … … 141 142 ostype & nlOn( ostype & ); 142 143 ostype & nlOff( ostype & ); 144 } // distribution 145 146 forall( ostype & | ostream( ostype ) ) { 147 ostype & acquire( ostype & ); 143 148 } // distribution 144 149 … … 291 296 292 297 trait basic_istream( istype & ) { 293 // private 294 bool getANL$( istype & ); // get scan newline (on/off) 295 // public 298 bool getANL( istype & ); // get scan newline (on/off) 296 299 void nlOn( istype & ); // read newline 297 300 void nlOff( istype & ); // scan newline 301 298 302 void ends( istype & os ); // end of output statement 299 303 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 308 312 void close( istype & is ); 309 313 istype & read( istype &, char [], size_t ); 314 void acquire( istype & ); // concurrent access 310 315 }; // istream 311 316 … … 374 379 } // distribution 375 380 381 forall( istype & | istream( istype ) ) { 382 istype & acquire( istype & ); 383 } // distribution 384 376 385 // *********************************** manipulators *********************************** 377 386 -
libcfa/src/strstream.cfa
r1ed9cb63 r8a039be 10 10 // Created On : Thu Apr 22 22:24:35 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 10 16:13:20202113 // Update Count : 10112 // Last Modified On : Tue Apr 27 20:59:53 2021 13 // Update Count : 78 14 14 // 15 15 16 16 #include "strstream.hfa" 17 #include "fstream.hfa" // abort18 17 19 18 #include <stdio.h> // vsnprintf … … 31 30 32 31 // private 33 inlinebool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }34 inlinevoid sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }35 inlinevoid sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }36 inlineconst char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }37 inlinevoid sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }38 inlinebool getNL$( ostrstream & os ) { return os.sawNL$; }39 inlinevoid setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }40 inlinebool getANL$( ostrstream & os ) { return os.nlOnOff$; }41 inlinebool getPrt$( ostrstream & os ) { return os.prt$; }42 inlinevoid setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }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; } 43 42 44 43 // public … … 129 128 // *********************************** istrstream *********************************** 130 129 131 // private132 bool getANL$( istrstream & is ) { return is.nlOnOff$; }133 130 134 131 // public … … 139 136 } // ?{} 140 137 138 bool getANL( istrstream & is ) { return is.nlOnOff$; } 141 139 void nlOn( istrstream & is ) { is.nlOnOff$ = true; } 142 140 void nlOff( istrstream & is ) { is.nlOnOff$ = false; } 143 141 144 void ends( istrstream & is ) { }145 bool eof( istrstream & is ) { return false; } 142 void ends( istrstream & is ) { 143 } // ends 146 144 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 145 int eof( istrstream & is ) { 146 return 0; 147 } // eof 164 148 165 149 istrstream &ungetc( istrstream & is, char c ) { … … 170 154 } // ungetc 171 155 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 172 170 // Local Variables: // 173 171 // tab-width: 4 // -
libcfa/src/strstream.hfa
r1ed9cb63 r8a039be 10 10 // Created On : Thu Apr 22 22:20:59 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 10 10:14:22202113 // Update Count : 4 712 // Last Modified On : Tue Apr 27 20:58:50 2021 13 // Update Count : 41 14 14 // 15 15 … … 85 85 // Satisfies basic_istream 86 86 87 // private88 bool getANL$( istrstream & );89 90 87 // public 88 bool getANL( istrstream & ); 91 89 void nlOn( istrstream & ); 92 90 void nlOff( istrstream & ); 93 91 void ends( istrstream & ); 92 int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 93 istrstream & ungetc( istrstream & is, char c ); 94 int eof( istrstream & is ); 94 95 95 int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 96 istrstream & ungetc( istrstream &, char ); 97 bool eof( istrstream & ); 98 99 void ?{}( istrstream &, char buf[] ); 96 void ?{}( istrstream & is, char buf[] ); 100 97 101 98 // Local Variables: // -
src/AST/Pass.hpp
r1ed9cb63 r8a039be 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.351 350 template< typename T > 352 T&GuardValue( T& val ) {351 void GuardValue( T& val ) { 353 352 at_cleanup( [ val ]( void * newVal ) { 354 353 * static_cast< T * >( newVal ) = val; 355 354 }, static_cast< void * >( & val ) ); 356 return val;357 355 } 358 356 … … 396 394 }; 397 395 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 408 396 } 409 397 -
src/AST/Pass.impl.hpp
r1ed9cb63 r8a039be 420 420 template< typename core_t > 421 421 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 422 if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) { 423 ValueGuard<const TranslationUnit *> guard( *ptr ); 424 *ptr = &unit; 425 return ast::accept_all( unit.decls, visitor ); 426 } else { 427 return ast::accept_all( unit.decls, visitor ); 428 } 422 return ast::accept_all( unit.decls, visitor ); 429 423 } 430 424 -
src/AST/Pass.proto.hpp
r1ed9cb63 r8a039be 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 442 428 template<typename core_t> 443 429 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { -
src/AST/TranslationUnit.hpp
r1ed9cb63 r8a039be 26 26 std::list< ptr< Decl > > decls; 27 27 28 struct Global {28 struct Globals { 29 29 std::map< UniqueId, Decl * > idMap; 30 30 31 ptr<Type>sizeType;31 const Type * sizeType; 32 32 const FunctionDecl * dereference; 33 33 const StructDecl * dtorStruct; -
src/AST/porting.md
r1ed9cb63 r8a039be 98 98 * `Initializer` => `ast::Init` 99 99 * `Statement` => `ast::Stmt` 100 * `ReferenceToType` => `ast::BaseInstType`101 100 * any field names should follow a similar renaming 102 101 * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`): -
src/CodeTools/DeclStats.cc
r1ed9cb63 r8a039be 156 156 /// number of counting bins for linkages 157 157 static const unsigned n_named_specs = 8; 158 /// Mapping function from linkage to bin. 159 static unsigned linkage_index( LinkageSpec::Spec spec ) { 160 switch ( spec ) { 161 case LinkageSpec::Intrinsic: return 0; 162 case LinkageSpec::C: return 1; 163 case LinkageSpec::Cforall: return 2; 164 case LinkageSpec::AutoGen: return 3; 165 case LinkageSpec::Compiler: return 4; 166 case LinkageSpec::BuiltinCFA: return 5; 167 case LinkageSpec::BuiltinC: return 6; 168 default: return 7; 169 } 170 } 158 /// map from total number of specs to bins 159 static const unsigned ind_for_linkage[16]; 171 160 172 161 Stats for_linkage[n_named_specs]; ///< Stores separate stats per linkage … … 377 366 const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName(); 378 367 if ( seen_names.insert( mangleName ).second ) { 379 Stats& stats = for_linkage[ linkage_index( decl->linkage )];368 Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ]; 380 369 381 370 ++stats.n_decls; … … 538 527 }; 539 528 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 540 532 void printDeclStats( std::list< Declaration * > &translationUnit ) { 541 533 PassVisitor<DeclStats> stats; -
src/Common/module.mk
r1ed9cb63 r8a039be 22 22 Common/CompilerError.h \ 23 23 Common/Debug.h \ 24 Common/DeclStats.hpp \25 Common/DeclStats.cpp \26 24 Common/ErrorObjects.h \ 27 25 Common/Eval.cc \ … … 35 33 Common/PassVisitor.proto.h \ 36 34 Common/PersistentMap.h \ 37 Common/ResolvProtoDump.hpp \38 Common/ResolvProtoDump.cpp \39 35 Common/ScopedMap.h \ 40 36 Common/SemanticError.cc \ -
src/InitTweak/GenInit.cc
r1ed9cb63 r8a039be 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Oct 25 13:53:00 202113 // Update Count : 18 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:15:10 2019 13 // Update Count : 184 14 14 // 15 15 #include "GenInit.h" … … 24 24 #include "AST/Decl.hpp" 25 25 #include "AST/Init.hpp" 26 #include "AST/Pass.hpp"27 26 #include "AST/Node.hpp" 28 27 #include "AST/Stmt.hpp" … … 295 294 } 296 295 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->dimension355 )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 return391 // 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 } // namespace420 421 void genInit( ast::TranslationUnit & transUnit ) {422 ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );423 ast::Pass<ReturnFixer_New>::run( transUnit );424 }425 426 296 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 427 297 PassVisitor<CtorDtor> ctordtor; -
src/InitTweak/GenInit.h
r1ed9cb63 r8a039be 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Oct 22 16:08:00 202113 // Update Count : 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:31:19 2017 13 // Update Count : 4 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 );30 29 31 30 /// Converts return statements into copy constructor calls on the hidden return variable -
src/Parser/parser.yy
r1ed9cb63 r8a039be 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 15 09:20:17202113 // Update Count : 5 16312 // Last Modified On : Sat Sep 11 08:20:44 2021 13 // Update Count : 5040 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 // e.g., u"a" U"b" L"c" is disallowed.71 // i.e., 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 identifier_at identifier_or_type_name attr_name 312 %type<tok> identifier 313 %type<tok> identifier_or_type_name attr_name 313 314 %type<tok> quasi_keyword 314 315 %type<constant> string_literal … … 326 327 %type<en> conditional_expression constant_expression assignment_expression assignment_expression_opt 327 328 %type<en> comma_expression comma_expression_opt 328 %type<en> argument_expression_list_opt argument_expression _list argument_expressiondefault_initializer_opt329 %type<en> argument_expression_list_opt argument_expression default_initializer_opt 329 330 %type<ifctl> if_control_expression 330 331 %type<fctl> for_control_expression for_control_expression_list … … 558 559 IDENTIFIER 559 560 | quasi_keyword 560 ;561 562 identifier_at:563 identifier564 561 | '@' // CFA 565 562 { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; } … … 696 693 // empty 697 694 { $$ = nullptr; } 698 | argument_expression_list 699 ; 700 701 argument_expression_list: 702 argument_expression 695 | argument_expression 703 696 | argument_expression_list_opt ',' argument_expression 704 697 { $$ = (ExpressionNode *)($1->set_last( $3 )); } … … 738 731 | FLOATINGconstant fraction_constants_opt 739 732 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); } 740 | identifier _at fraction_constants_opt // CFA, allow anonymous fields733 | identifier fraction_constants_opt 741 734 { 742 735 $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) ); … … 1091 1084 comma_expression_opt ';' 1092 1085 { $$ = 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; }1096 1086 ; 1097 1087 … … 1192 1182 1193 1183 iteration_statement: 1194 WHILE '(' ')' statement // CFA => while ( 1 ) 1184 WHILE '(' push if_control_expression ')' statement pop 1185 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); } 1186 | WHILE '(' ')' statement // CFA => while ( 1 ) 1195 1187 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1196 | WHILE '(' if_control_expression ')' statement %prec THEN 1197 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); } 1198 | WHILE '(' if_control_expression ')' statement ELSE statement // CFA 1199 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1188 | DO statement WHILE '(' comma_expression ')' ';' 1189 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1200 1190 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1201 1191 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1202 | DO statement WHILE '(' comma_expression ')' ';' %prec THEN 1203 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1204 | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA 1205 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1192 | FOR '(' push for_control_expression_list ')' statement pop 1193 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); } 1206 1194 | FOR '(' ')' statement // CFA => for ( ;; ) 1207 1195 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1208 | FOR '(' for_control_expression_list ')' statement %prec THEN1209 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }1210 | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA1211 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }1212 1196 ; 1213 1197 … … 1355 1339 with_statement: 1356 1340 WITH '(' tuple_expression_list ')' statement 1357 { $$ = new StatementNode( build_with( $3, $5 ) ); } 1341 { 1342 $$ = new StatementNode( build_with( $3, $5 ) ); 1343 } 1358 1344 ; 1359 1345 1360 1346 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex". 1361 1347 mutex_statement: 1362 MUTEX '(' argument_expression_list ')' statement1348 MUTEX '(' argument_expression_list_opt ')' statement 1363 1349 { $$ = new StatementNode( build_mutex( $3, $5 ) ); } 1364 1350 ; … … 2489 2475 designation: 2490 2476 designator_list ':' // C99, CFA uses ":" instead of "=" 2491 | identifier _at':' // GCC, field name2477 | identifier ':' // GCC, field name 2492 2478 { $$ = new ExpressionNode( build_varref( $1 ) ); } 2493 2479 ; … … 2501 2487 2502 2488 designator: 2503 '.' identifier _at// C99, field name2489 '.' identifier // C99, field name 2504 2490 { $$ = new ExpressionNode( build_varref( $2 ) ); } 2505 2491 | '[' push assignment_expression pop ']' // C99, single array element … … 2933 2919 2934 2920 paren_identifier: 2935 identifier _at2921 identifier 2936 2922 { $$ = DeclarationNode::newName( $1 ); } 2937 2923 | '(' paren_identifier ')' // redundant parenthesis -
src/main.cc
r1ed9cb63 r8a039be 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Oct 22 16:06:00202113 // Update Count : 65 311 // Last Modified By : Henry Xue 12 // Last Modified On : Mon Aug 23 15:42:08 2021 13 // Update Count : 650 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 printDeclStats46 #include "Common/ResolvProtoDump.hpp" // for dumpAsResolverProto47 45 #include "Common/Stats.h" 48 46 #include "Common/PassVisitor.h" … … 336 334 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 337 335 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 338 353 339 354 CodeTools::fillLocations( translationUnit ); 355 356 if ( resolvprotop ) { 357 CodeTools::dumpAsResolvProto( translationUnit ); 358 return EXIT_SUCCESS; 359 } // if 340 360 341 361 if( useNewAST ) { … … 346 366 auto transUnit = convert( move( translationUnit ) ); 347 367 348 forceFillCodeLocations( transUnit );349 350 PASS( "Gen Init", InitTweak::genInit( transUnit ) );351 368 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) ); 352 353 if ( libcfap ) { 354 // Generate the bodies of cfa library functions. 355 LibCfa::makeLibCfa( transUnit ); 356 } // if 357 358 if ( declstatsp ) { 359 printDeclStats( transUnit ); 360 return EXIT_SUCCESS; 361 } // if 362 363 if ( bresolvep ) { 364 dump( move( transUnit ) ); 365 return EXIT_SUCCESS; 366 } // if 367 368 if ( resolvprotop ) { 369 dumpAsResolverProto( transUnit ); 370 return EXIT_SUCCESS; 371 } // if 372 369 373 370 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 374 371 if ( exprp ) { … … 380 377 381 378 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 382 383 379 translationUnit = convert( move( transUnit ) ); 384 380 } else { 385 PASS( "Gen Init", InitTweak::genInit( translationUnit ) );386 381 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) ); 387 388 if ( libcfap ) {389 // Generate the bodies of cfa library functions.390 LibCfa::makeLibCfa( translationUnit );391 } // if392 393 if ( declstatsp ) {394 CodeTools::printDeclStats( translationUnit );395 deleteAll( translationUnit );396 return EXIT_SUCCESS;397 } // if398 399 if ( bresolvep ) {400 dump( translationUnit );401 return EXIT_SUCCESS;402 } // if403 404 CodeTools::fillLocations( translationUnit );405 406 if ( resolvprotop ) {407 CodeTools::dumpAsResolvProto( translationUnit );408 return EXIT_SUCCESS;409 } // if410 382 411 383 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); -
tests/concurrent/semaphore.cfa
r1ed9cb63 r8a039be 2 2 #include <locks.hfa> 3 3 #include <thread.hfa> 4 #include <mutex_stmt.hfa>5 4 6 5 enum { num_blockers = 17, num_unblockers = 13 }; … … 29 28 thrash(); 30 29 P(ben); 31 if(((thread&)this).seqable.next != 0p) mutex(sout) sout |"Link not invalidated";30 if(((thread&)this).seqable.next != 0p) sout | acquire |"Link not invalidated"; 32 31 thrash(); 33 32 } -
tests/concurrent/sleep.cfa
r1ed9cb63 r8a039be 1 1 #include <fstream.hfa> 2 2 #include <thread.hfa> 3 #include <mutex_stmt.hfa>4 3 #include <time.hfa> 5 4 … … 30 29 31 30 int main() { 32 mutex( sout ) sout| "start";31 sout | acquire | "start"; 33 32 { 34 33 slow_sleeper slow; … … 37 36 yield(); 38 37 } 39 mutex( sout ) sout| "done";38 sout | acquire | "done"; 40 39 } 41 40 -
tests/io/io-acquire.cfa
r1ed9cb63 r8a039be 10 10 // Created On : Mon Mar 1 18:40:09 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 6 18:04:58202113 // Update Count : 7212 // Last Modified On : Tue Apr 27 11:49:34 2021 13 // Update Count : 18 14 14 // 15 15 16 16 #include <fstream.hfa> 17 17 #include <thread.hfa> 18 #include <mutex_stmt.hfa>19 18 20 19 thread T {}; … … 22 21 // output from parallel threads should not be scrambled 23 22 24 for ( 100 ) { // expressionprotection25 mutex(sout) sout| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;23 for ( 100 ) { // local protection 24 sout | acquire | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; 26 25 } 27 mutex( sout ) { // statement protection 26 { // global protection (RAII) 27 osacquire acq = { sout }; 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 ofstream & h1( ofstream & os ) { // helper 34 mutex( os ) return os | 1 | 2 | 3 | 4; // unnecessary mutex 35 } 36 ofstream & h2( ofstream & os ) { // helper 37 mutex( os ) return os | 6 | 7 | 8 | 9; // unnecessary mutex 38 } 39 mutex( sout ) { // unnecessary mutex 40 for ( 100 ) { 41 mutex( sout ) { 42 sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; 43 sout | h1 | 5 | h2; // refactored code 44 } 45 } 33 osacquire acq = { sout }; 34 for ( 100 ) { 35 osacquire acq = { sout }; 36 sout | acquire | 1 | 2 | 3 | 4 | 5 | acquire | 6 | 7 | 8 | 9; 37 sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; 46 38 } 47 39 } … … 50 42 51 43 int a, b, c, d, e, f, g, h, i; 52 for ( 100 ) { // expressionprotection53 mutex(sin) sin| a | b | c | d | e | f | g | h | i;44 for ( 100 ) { // local protection 45 sin | acquire | a | b | c | d | e | f | g | h | i; 54 46 } 55 mutex( sin ) { // statement protection 47 { // global protection (RAII) 48 isacquire acq = { sin }; 56 49 for ( 100 ) { 57 50 sin | a | b | c | d | e | f | g | h | i; … … 59 52 } 60 53 { // duplicate protection demonstrating recursive lock 61 ifstream & h1( ifstream & is ) { // helper 62 mutex( is ) return is | a | b | c | d; // unnecessary mutex 63 } 64 ifstream & h2( ifstream & is ) { // helper 65 mutex( is ) return is | f | g | h | i; // unnecessary mutex 66 } 67 mutex( sin ) { // unnecessary mutex 68 for ( 5 ) { 69 mutex( sin ) { 70 sin | a | b | c | d | e | f | g | h | i; 71 sin | h1 | e | h2; // refactored code 72 } 73 } 54 isacquire acq = { sin }; 55 for ( 100 ) { 56 isacquire acq = { sin }; 57 sin | acquire | a | b | c | d | e | acquire | f | g | h | i; 58 sin | a | b | c | d | e | f | g | h | i; 74 59 } 75 60 } -
tests/linking/io-acquire.cfa
r1ed9cb63 r8a039be 17 17 #include <fstream.hfa> 18 18 #include <stdlib.hfa> 19 #include <mutex_stmt.hfa>20 19 21 20 int main() { 22 21 int i; 23 22 if(threading_enabled()) { 24 mutex( stdout ) stdout| "YES";23 stdout | acquire | "YES"; 25 24 stdin | i; 26 25 } else { 27 mutex( stdout ) stdout| "NO";26 stdout | acquire | "NO"; 28 27 stdin | i; 29 28 } -
tests/pybin/test_run.py
r1ed9cb63 r8a039be 65 65 def toString( cls, retcode, duration ): 66 66 if settings.generating : 67 if retcode == TestResult.SUCCESS: key = 'pass';text = "Done "68 elif retcode == TestResult.TIMEOUT: key = 'time';text = "TIMEOUT"69 else : key = 'fail';text = "ERROR code %d" % retcode67 if retcode == TestResult.SUCCESS: text = "Done " 68 elif retcode == TestResult.TIMEOUT: text = "TIMEOUT" 69 else : text = "ERROR code %d" % retcode 70 70 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" % retcode71 if retcode == TestResult.SUCCESS: text = "PASSED " 72 elif retcode == TestResult.TIMEOUT: text = "TIMEOUT" 73 else : text = "FAILED with code %d" % retcode 74 74 75 75 text += " C%s - R%s" % (fmtDur(duration[0]), fmtDur(duration[1])) 76 return key,text76 return text -
tests/test.py
r1ed9cb63 r8a039be 257 257 258 258 # update output based on current action 259 result_ key, result_txt = TestResult.toString( retcode, duration )259 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, result_key,text267 return retcode == TestResult.SUCCESS, text 268 268 except KeyboardInterrupt: 269 return False, 'keybrd',""269 return False, "" 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 = 0287 285 288 286 # for each test to run … … 296 294 ) 297 295 298 for i, (succ, code, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) : 299 if code in rescnts.keys(): 300 rescnts[code] += 1 301 else: 302 other += 1 303 296 for i, (succ, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) : 304 297 if not succ : 305 298 failed = True … … 326 319 # clean the workspace 327 320 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))330 321 331 322 return failed … … 452 443 failed = run_tests(local_tests, options.jobs) 453 444 if failed: 445 result = 1 454 446 if not settings.continue_: 455 447 break
Note:
See TracChangeset
for help on using the changeset viewer.