Index: doc/generic_types/generic_types.tex
===================================================================
--- doc/generic_types/generic_types.tex	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ doc/generic_types/generic_types.tex	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -139,5 +139,5 @@
 \begin{lstlisting}
 forall(otype T)
-T identity(T x) {is_
+T identity(T x) {
     return x;
 }
@@ -294,5 +294,24 @@
 Since @pair(T*, T*)@ is a concrete type, there are no added implicit parameters to @lexcmp@, so the code generated by \CFA{} will be effectively identical to a version of this written in standard C using @void*@, yet the \CFA{} version will be type-checked to ensure that the fields of both pairs and the arguments to the comparison function match in type.
 
-\TODO{} The second is zero-cost ``tag'' structs.
+Another useful pattern enabled by re-used dtype-static type instantiations is zero-cost ``tag'' structs. Sometimes a particular bit of information is only useful for type-checking, and can be omitted at runtime. Tag structs can be used to provide this information to the compiler without further runtime overhead, as in the following example:
+\begin{lstlisting}
+forall(dtype Unit) struct scalar { unsigned long value; };
+
+struct metres {};
+struct litres {};
+
+forall(dtype U)
+scalar(U) ?+?(scalar(U) a, scalar(U) b) {
+	return (scalar(U)){ a.value + b.value };
+}
+
+scalar(metres) half_marathon = { 21093 };
+scalar(litres) swimming_pool = { 2500000 };
+
+scalar(metres) marathon = half_marathon + half_marathon;
+scalar(litres) two_pools = swimming_pool + swimming_pool;
+marathon + swimming_pool; // ERRORv -- caught by compiler
+\end{lstlisting}
+@scalar@ is a dtype-static type, so all uses of it will use a single struct definition, containing only a single @unsigned long@, and can share the same implementations of common routines like @?+?@ -- these implementations may even be separately compiled, unlike \CC{} template functions. However, the \CFA{} type-checker will ensure that matching types are used by all calls to @?+?@, preventing nonsensical computations like adding the length of a marathon to the volume of an olympic pool.
 
 \section{Tuples}
Index: doc/rob_thesis/Makefile
===================================================================
--- doc/rob_thesis/Makefile	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
+++ doc/rob_thesis/Makefile	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -0,0 +1,87 @@
+## Define the appropriate configuration variables.
+
+TeXLIB = .:../LaTeXmacros:../LaTeXmacros/listings:../LaTeXmacros/enumitem:../bibliography/:
+LaTeX  = TEXINPUTS=${TeXLIB} && export TEXINPUTS && pdflatex -halt-on-error
+BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex
+
+## Define the text source files.
+
+# SOURCES = ${addsuffix .tex, \
+# thesis \
+# }
+
+# FIGURES = ${addsuffix .tex, \
+# }
+
+# PICTURES = ${addsuffix .pstex, \
+# }
+
+# PROGRAMS = ${addsuffix .tex, \
+# }
+
+# GRAPHS = ${addsuffix .tex, \
+# }
+
+# ## Define the documents that need to be made.
+
+# DOCUMENT = thesis.pdf
+
+# Directives #
+
+# all : ${DOCUMENT}
+
+# clean :
+# 	rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \
+# 		${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT}
+
+# File Dependencies #
+
+# ${DOCUMENT} : ${basename ${DOCUMENT}}.ps
+# 	ps2pdf $<
+
+# ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi
+# 	dvips $< -o $@
+
+# ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \
+# 		../LaTeXmacros/common.tex ../LaTeXmacros/indexstyle ../bibliography/cfa.bib
+# 	# Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
+# 	if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi
+# 	# Must have *.aux file containing citations for bibtex
+# 	if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi
+# 	-${BibTeX} ${basename $@}
+# 	# Some citations reference others so run steps again to resolve these citations
+# 	${LaTeX} ${basename $@}.tex
+# 	-${BibTeX} ${basename $@}
+# 	# Make index from *.aux entries and input index at end of document
+# 	makeindex -s ../LaTeXmacros/indexstyle ${basename $@}.idx
+# 	${LaTeX} ${basename $@}.tex
+# 	# Run again to get index title into table of contents
+# 	${LaTeX} ${basename $@}.tex
+
+# predefined :
+# 	sed -f predefined.sed ${basename ${DOCUMENT}}.tex > ${basename $@}.cf
+
+# ## Define the default recipes.
+
+# %.tex : %.fig
+# 	fig2dev -L eepic $< > $@
+
+# %.ps : %.fig
+# 	fig2dev -L ps $< > $@
+
+# %.pstex : %.fig
+# 	fig2dev -L pstex $< > $@
+# 	fig2dev -L pstex_t -p $@ $< > $@_t
+
+
+all:
+	$(LaTeX) thesis
+	$(BibTeX) thesis
+	$(LaTeX) thesis
+	$(LaTeX) thesis
+
+clean:
+	rm -f *.aux *.bbl *.blg *.lof *.log *.lot *.out *.toc
+
+splotless: clean
+	rm -f thesis.pdf
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ doc/user/user.tex	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Mon Feb 20 12:35:48 2017
-%% Update Count     : 1377
+%% Last Modified On : Thu Mar 23 09:53:57 2017
+%% Update Count     : 1399
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -91,6 +91,8 @@
 }% title
 
-\author{\huge
-Peter A. Buhr and ...
+\author{
+\huge \CFA Team \medskip \\
+\Large Peter A. Buhr, Richard Bilson, Thierry Delisle, \smallskip \\
+\Large Glen Ditchfield, Rodolfo G. Esteves, Aaron Moss, Rob Schluntz
 }% author
 
@@ -4657,24 +4659,25 @@
 which is a local mechanism to disable insertion of the separator character.
 \item
-A separator does not appear before a C string starting with the (extended) \Index{ASCII}\index{ASCII!extended} characters: \lstinline[mathescape=off]@([{$£¥¡¿«@
+A separator does not appear before a C string starting with the (extended) \Index{ASCII}\index{ASCII!extended} characters: \lstinline[mathescape=off]@([{=$£¥¡¿«@
 %$
 \begin{lstlisting}[mathescape=off]
-sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x $" | 4 | "x £" | 5 | "x ¥" | 6 | "x ¡" | 7
-	 | "x ¿" | 8 | "x «" | 9 | endl;
+sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥" | 7
+	 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10 | endl;
 \end{lstlisting}
 %$
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
-x (1 x [2 x {3 x $4 x £5 x ¥6 x ¡7 x ¿8 x «9
+x (1 x [2 x {3 x =4 x $5 x £6 x ¥7 x ¡8 x ¿9 x «10
 \end{lstlisting}
 %$
 \item
+{\lstset{deletedelim=**[is][]{¢}{¢}}
 A seperator does not appear after a C string ending with the (extended) \Index{ASCII}\index{ASCII!extended} characters: ©,.:;!?)]}%¢»©
 \begin{lstlisting}[belowskip=0pt]
-sout | 1 | ", x" | 2 | ". x" | 3 | ": x" | 4 | "; x" | 5 | "! x" | 6 | "? x" | 7
-	 | ") x" | 8 | "] x" | 9 | "} x" | 10 | "% x" | 11 | "¢ x" | 12 | "» x" | endl;
+sout | 1 | ", x" | 2 | ". x" | 3 | ": x" | 4 | "; x" | 5 | "! x" | 6 | "? x" | 7 | "% x"
+	 | 8 | "¢ x" | 9 | "» x" | 10 | ") x" | 11 | "] x" | 12 | "} x" | endl;
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
-1, x 2. x 3: x 4; x 5! x 6? x 7) x 8] x 9} x 10% x 11¢ 12»
-\end{lstlisting}
+1, x 2. x 3: x 4; x 5! x 6? x 7% x 8¢ x 9» x 10) x 11] x 12} x
+\end{lstlisting}}%
 \item
 A seperator does not appear before or after a C string begining/ending with the \Index{ASCII} quote or whitespace characters: \lstinline[showspaces=true]@`'" \t\v\f\r\n@
@@ -4694,5 +4697,5 @@
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,aboveskip=0pt,belowskip=0pt]
-sout | 1 | sepOff | 2 | 3 | endl;			§\C{// turn off implicit separator temporarily}§
+sout | 1 | sepOff | 2 | 3 | endl;			§\C{// turn off implicit separator locally}§
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4700,5 +4703,5 @@
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,aboveskip=0pt,belowskip=0pt]
-sout | sepDisable | 1 | 2 | 3 | endl;		§\C{// turn off implicit separation, affects all subsequent prints}§
+sout | sepDisable | 1 | 2 | 3 | endl;		§\C{// turn off implicit separation globally}§
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4706,5 +4709,5 @@
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,aboveskip=0pt,belowskip=0pt]
-sout | 1 | sepOn | 2 | 3 | endl;			§\C{// turn on implicit separator temporarily}§
+sout | 1 | sepOn | 2 | 3 | endl;			§\C{// turn on implicit separator locally}§
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4712,5 +4715,5 @@
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,aboveskip=0pt,belowskip=0pt]
-sout | sepEnable | 1 | 2 | 3 | endl;		§\C{// turn on implicit separation, affects all subsequent prints}§
+sout | sepEnable | 1 | 2 | 3 | endl;		§\C{// turn on implicit separation globally}§
 \end{lstlisting}
 \begin{lstlisting}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4730,12 +4733,13 @@
 
 int main() {
-	int x = 3, y = 5, z = 7;
-	sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2) | endl;
+	int x = 0, y = 1, z = 2;
+	sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2) | endl | endl;
 	sout | 1 | 2 | 3 | endl;
 	sout | '1' | '2' | '3' | endl;
 	sout | 1 | "" | 2 | "" | 3 | endl;
-	sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x $" | 4 | "x £" | 5 | "x ¥" | 6 | "x ¡" | 7 | "x ¿" | 8 | "x «" | 9 | endl;
-	sout | 1 | ", x" | 2 | ". x" | 3 | ": x" | 4 | "; x" | 5 | "! x" | 6 | "? x" | 7 | ") x" | 8 | "] x" | 9 | "} x"
-		 | 10 | "% x" | 11 | "¢ x" | 12 | "» x" | endl;
+	sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥" | 7
+		| "x ¡" | 8 | "x ¿" | 9 | "x «" | 10 | endl;
+	sout | 1 | ", x" | 2 | ". x" | 3 | ": x" | 4 | "; x" | 5 | "! x" | 6 | "? x" | 7 | "% x"
+		| 8 | "¢ x" | 9 | "» x" | 10 | ") x" | 11 | "] x" | 12 | "} x" | endl;
 	sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x" | "x " | 4 | " x" | "x\t" | 1 | "\tx" | endl;
 	sout | sepOn | 1 | 2 | 3 | sepOn | endl;	// separator at start of line
Index: src/libcfa/Makefile.am
===================================================================
--- src/libcfa/Makefile.am	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/Makefile.am	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -35,5 +35,5 @@
 	 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@ -D__CFA_DEBUG__ -O0 -c -o $@ $<
 
-EXTRA_FLAGS = -g -Wall -Wno-unused-function -I${abs_top_srcdir}/src/libcfa/libhdr -imacros libcfa-prelude.c @CFA_FLAGS@
+EXTRA_FLAGS = -g -Wall -Werror -Wno-unused-function -I${abs_top_srcdir}/src/libcfa/libhdr -imacros libcfa-prelude.c @CFA_FLAGS@
 
 AM_CCASFLAGS = @CFA_FLAGS@
Index: src/libcfa/Makefile.in
===================================================================
--- src/libcfa/Makefile.in	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/Makefile.in	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -305,5 +305,5 @@
 AUTOMAKE_OPTIONS = subdir-objects
 lib_LIBRARIES = $(am__append_1) $(am__append_2)
-EXTRA_FLAGS = -g -Wall -Wno-unused-function -I${abs_top_srcdir}/src/libcfa/libhdr -imacros libcfa-prelude.c @CFA_FLAGS@
+EXTRA_FLAGS = -g -Wall -Werror -Wno-unused-function -I${abs_top_srcdir}/src/libcfa/libhdr -imacros libcfa-prelude.c @CFA_FLAGS@
 AM_CCASFLAGS = @CFA_FLAGS@
 headers = limits stdlib math iostream fstream iterator rational assert \
Index: src/libcfa/fstream
===================================================================
--- src/libcfa/fstream	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/fstream	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Mar  7 14:48:08 2017
-// Update Count     : 91
+// Last Modified On : Tue Mar 21 15:57:24 2017
+// Update Count     : 102
 //
 
@@ -21,8 +21,10 @@
 enum { separateSize = 16 };
 struct ofstream {
-	void *file;
+	void * file;
 	_Bool sepDefault;
 	_Bool sepOnOff;
+	const char * sepCur;
 	char separator[separateSize];
+	char tupleSeparator[separateSize];
 }; // ofstream
 
@@ -32,6 +34,10 @@
 void sepReset( ofstream * );
 void sepReset( ofstream *, _Bool );
+const char * sepGetCur( ofstream * );
+void sepSetCur( ofstream *, const char * );
 const char * sepGet( ofstream * );
 void sepSet( ofstream *, const char * );
+const char * sepGetTuple( ofstream * );
+void sepSetTuple( ofstream *, const char * );
 _Bool sepDisable( ofstream * );
 _Bool sepEnable( ofstream * );
@@ -42,5 +48,7 @@
 void close( ofstream * );
 ofstream * write( ofstream *, const char * data, unsigned long int size );
-int prtfmt( ofstream *, const char fmt[], ... );
+int fmt( ofstream *, const char fmt[], ... );
+
+void ?{}( ofstream * );
 
 extern ofstream * sout, * serr;
@@ -48,5 +56,5 @@
 // implement context istream
 struct ifstream {
-	void *file;
+	void * file;
 }; // ifstream
 
@@ -57,7 +65,7 @@
 ifstream * read( ifstream * is, char * data, unsigned long int size );
 ifstream * ungetc( ifstream * is, char c );
-int scanfmt( ifstream *, const char fmt[], ... );
+int fmt( ifstream *, const char fmt[], ... );
 
-extern ifstream *sin;
+extern ifstream * sin;
 
 #endif // __FSTREAM_H__
Index: src/libcfa/fstream.c
===================================================================
--- src/libcfa/fstream.c	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/fstream.c	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Mar  7 14:48:09 2017
-// Update Count     : 192
+// Last Modified On : Thu Mar 23 08:20:41 2017
+// Update Count     : 226
 //
 
@@ -25,6 +25,16 @@
 #include <complex.h>									// creal, cimag
 }
+#include "assert"
 
 #define IO_MSG "I/O error: "
+
+void ?{}( ofstream * this, void * file, _Bool sepDefault, _Bool sepOnOff, const char * separator, const char * tupleSeparator ) {
+	this->file = file;
+	this->sepDefault = sepDefault;
+	this->sepOnOff = sepOnOff;
+	sepSet( this, separator );
+	sepSetCur( this, sepGet( this ) );
+	sepSetTuple( this, tupleSeparator );
+}
 
 _Bool sepPrt( ofstream * os ) { return os->sepOnOff; }
@@ -33,9 +43,22 @@
 void sepReset( ofstream * os ) { os->sepOnOff = os->sepDefault; }
 void sepReset( ofstream * os, _Bool reset ) { os->sepDefault = reset; os->sepOnOff = os->sepDefault; }
-const char * sepGet( ofstream * os ) { return &(os->separator[0]); }
+
+const char * sepGetCur( ofstream * os ) { return os->sepCur; }
+void sepSetCur( ofstream * os, const char * sepCur ) { os->sepCur = sepCur; }
+
+const char * sepGet( ofstream * os ) { return os->separator; }
 
 void sepSet( ofstream * os, const char * s ) {
-	strncpy( &(os->separator[0]), s, separateSize - 1 );
+	assert( s );
+	strncpy( os->separator, s, separateSize - 1 );
 	os->separator[separateSize - 1] = '\0';
+} // sepSet
+
+const char * sepGetTuple( ofstream * os ) { return os->tupleSeparator; }
+
+void sepSetTuple( ofstream * os, const char * s ) {
+	assert( s );
+	strncpy( os->tupleSeparator, s, separateSize - 1 );
+	os->tupleSeparator[separateSize - 1] = '\0';
 } // sepSet
 
@@ -69,7 +92,5 @@
 		exit( EXIT_FAILURE );
 	} // if
-	os->file = file;
-	sepOff( os );
-	sepSet( os, " " );
+	?{}( os, file, 1, 0, " ", ", " );
 } // open
 
@@ -95,8 +116,8 @@
 } // write
 
-int prtfmt( ofstream * os, const char fmt[], ... ) {
+int fmt( ofstream * os, const char format[], ... ) {
 	va_list args;
-	va_start( args, fmt );
-	int len = vfprintf( (FILE *)(os->file), fmt, args );
+	va_start( args, format );
+	int len = vfprintf( (FILE *)(os->file), format, args );
 	if ( len == EOF ) {
 		if ( ferror( (FILE *)(os->file) ) ) {
@@ -109,10 +130,9 @@
 	sepReset( os );										// reset separator
 	return len;
-} // prtfmt
-
-
-static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), 1, 0, { ' ', '\0' } };
+} // fmt
+
+static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), 1, 0, " ", ", " };
 ofstream *sout = &soutFile;
-static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), 1, 0, { ' ', '\0' } };
+static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), 1, 0, " ", ", " };
 ofstream *serr = &serrFile;
 
@@ -173,9 +193,9 @@
 } // ungetc
 
-int scanfmt( ifstream * is, const char fmt[], ... ) {
+int fmt( ifstream * is, const char format[], ... ) {
 	va_list args;
 
-	va_start( args, fmt );
-	int len = vfscanf( (FILE *)(is->file), fmt, args );
+	va_start( args, format );
+	int len = vfscanf( (FILE *)(is->file), format, args );
 	if ( len == EOF ) {
 		if ( ferror( (FILE *)(is->file) ) ) {
@@ -186,5 +206,5 @@
 	va_end( args );
 	return len;
-} // prtfmt
+} // fmt
 
 
Index: src/libcfa/iostream
===================================================================
--- src/libcfa/iostream	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/iostream	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar  6 20:51:35 2017
-// Update Count     : 98
+// Last Modified On : Tue Mar 21 15:57:29 2017
+// Update Count     : 104
 //
 
@@ -25,6 +25,10 @@
 	void sepReset( ostype * );							// set separator state to default state
 	void sepReset( ostype *, _Bool );					// set separator and default state
+	const char * sepGetCur( ostype * );					// get current separator string
+	void sepSetCur( ostype *, const char * );			// set current separator string
+	const char * sepGet( ostype * );					// get separator string
 	void sepSet( ostype *, const char * );				// set separator to string (15 character maximum)
-	const char * sepGet( ostype * );					// get separator string
+	const char * sepGetTuple( ostype * );				// get tuple separator string
+	void sepSetTuple( ostype *, const char * );			// set tuple separator to string (15 character maximum)
 	_Bool sepDisable( ostype * );						// set default state to off, and return previous state
 	_Bool sepEnable( ostype * );						// set default state to on, and return previous state
@@ -35,5 +39,5 @@
 	void close( ostype * os );
 	ostype * write( ostype *, const char *, unsigned long int );
-	int prtfmt( ostype *, const char fmt[], ... );
+	int fmt( ostype *, const char fmt[], ... );
 };
 
@@ -95,5 +99,5 @@
 	istype * read( istype *, char *, unsigned long int );
 	istype * ungetc( istype *, char );
-	int scanfmt( istype *, const char fmt[], ... );
+	int fmt( istype *, const char fmt[], ... );
 };
 
Index: src/libcfa/iostream.c
===================================================================
--- src/libcfa/iostream.c	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/libcfa/iostream.c	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar  6 20:52:02 2017
-// Update Count     : 313
+// Last Modified On : Thu Mar 23 08:20:40 2017
+// Update Count     : 367
 //
 
@@ -24,6 +24,6 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, char c ) {
-	prtfmt( os, "%c", c );
+ostype * ?|?( ostype * os, char c ) {
+	fmt( os, "%c", c );
 	sepOff( os );
 	return os;
@@ -31,6 +31,6 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, signed char c ) {
-	prtfmt( os, "%hhd", c );
+ostype * ?|?( ostype * os, signed char c ) {
+	fmt( os, "%hhd", c );
 	sepOff( os );
 	return os;
@@ -38,6 +38,6 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, unsigned char c ) {
-	prtfmt( os, "%hhu", c );
+ostype * ?|?( ostype * os, unsigned char c ) {
+	fmt( os, "%hhu", c );
 	sepOff( os );
 	return os;
@@ -45,82 +45,82 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, short int si ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%hd", si );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, unsigned short int usi ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%hu", usi );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, int i ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%d", i );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, unsigned int ui ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%u", ui );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, long int li ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%ld", li );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, unsigned long int uli ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%lu", uli );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, long long int lli ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%lld", lli );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, unsigned long long int ulli ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%llu", ulli );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, float f ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%g", f );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, double d ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%.*lg", DBL_DIG, d );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, long double ld ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%.*Lg", LDBL_DIG, ld );
-	return os;
-} // ?|?
-
-forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, float _Complex fc ) {
+ostype * ?|?( ostype * os, short int si ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%hd", si );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, unsigned short int usi ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%hu", usi );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, int i ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%d", i );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, unsigned int ui ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%u", ui );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, long int li ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%ld", li );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, unsigned long int uli ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%lu", uli );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, long long int lli ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%lld", lli );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, unsigned long long int ulli ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%llu", ulli );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, float f ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%g", f );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, double d ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%.*lg", DBL_DIG, d );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, long double ld ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%.*Lg", LDBL_DIG, ld );
+	return os;
+} // ?|?
+
+forall( dtype ostype | ostream( ostype ) )
+ostype * ?|?( ostype * os, float _Complex fc ) {
 	os | crealf( fc );
 	_Bool temp = sepDisable( os );						// disable separators within complex value
@@ -132,5 +132,5 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, double _Complex dc ) {
+ostype * ?|?( ostype * os, double _Complex dc ) {
 	os | creal( dc );
 	_Bool temp = sepDisable( os );						// disable separators within complex value
@@ -142,5 +142,5 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, long double _Complex ldc ) {
+ostype * ?|?( ostype * os, long double _Complex ldc ) {
 	os | creall( ldc );
 	_Bool temp = sepDisable( os );						// disable separators within complex value
@@ -152,15 +152,15 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, const char *cp ) {
+ostype * ?|?( ostype * os, const char * cp ) {
 	enum { Open = 1, Close, OpenClose };
 	static const unsigned char mask[256] = {
 		// opening delimiters, no space after
 		['('] : Open, ['['] : Open, ['{'] : Open,
-		['$'] : Open, ['='] : Open, [(unsigned char)'£'] : Open, [(unsigned char)'¥'] : Open,
+		['='] : Open, ['$'] : Open, [(unsigned char)'£'] : Open, [(unsigned char)'¥'] : Open,
 		[(unsigned char)'¡'] : Open, [(unsigned char)'¿'] : Open, [(unsigned char)'«'] : Open,
 		// closing delimiters, no space before
 		[','] : Close, ['.'] : Close, [':'] : Close, [';'] : Close, ['!'] : Close, ['?'] : Close,
+		['%'] : Close, [(unsigned char)'¢'] : Close, [(unsigned char)'»'] : Close,
 		[')'] : Close, [']'] : Close, ['}'] : Close,
-		['%'] : Close, [(unsigned char)'¢'] : Close, [(unsigned char)'»'] : Close,
 		// opening-closing delimiters, no space before or after
 		['\''] : OpenClose, ['`'] : OpenClose, ['"'] : OpenClose,
@@ -173,5 +173,5 @@
 	unsigned char ch = cp[0];							// must make unsigned
 	if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
-		prtfmt( os, "%s", sepGet( os ) );
+		fmt( os, "%s", sepGetCur( os ) );
 	} // if
 
@@ -191,7 +191,7 @@
 
 forall( dtype ostype | ostream( ostype ) )
-ostype * ?|?( ostype *os, const void *p ) {
-	if ( sepPrt( os ) ) prtfmt( os, "%s", sepGet( os ) );
-	prtfmt( os, "%p", p );
+ostype * ?|?( ostype * os, const void * p ) {
+	if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+	fmt( os, "%p", p );
 	return os;
 } // ?|?
@@ -201,6 +201,8 @@
 forall( dtype ostype, otype T, ttype Params | ostream( ostype ) | writeable( T ) | { ostype * ?|?( ostype *, Params ); } )
 ostype * ?|?( ostype * os, T arg, Params rest ) {
-	os | arg | ", ";
-	os | rest;
+	sepSetCur( os, sepGetTuple( os ) );					// switch to tuple separator
+	os | arg;											// print first argument
+	os | rest;											// print remaining arguments
+	sepSetCur( os, sepGet( os ) );						// switch to regular separator
 	return os;
 } // ?|?
@@ -217,5 +219,5 @@
 	os | '\n';
 	flush( os );
-	sepOff( os );
+	sepOff( os );										// prepare for next line
 	return os;
 } // endl
@@ -248,5 +250,5 @@
 
 forall( otype elttype | writeable( elttype ), otype iteratortype | iterator( iteratortype, elttype ), dtype ostype | ostream( ostype ) )
-void write( iteratortype begin, iteratortype end, ostype *os ) {
+void write( iteratortype begin, iteratortype end, ostype * os ) {
 	void print( elttype i ) { os | i; }
 	for_each( begin, end, print );
@@ -254,5 +256,5 @@
 
 forall( otype elttype | writeable( elttype ), otype iteratortype | iterator( iteratortype, elttype ), dtype ostype | ostream( ostype ) )
-void write_reverse( iteratortype begin, iteratortype end, ostype *os ) {
+void write_reverse( iteratortype begin, iteratortype end, ostype * os ) {
 	void print( elttype i ) { os | i; }
 	for_each_reverse( begin, end, print );
@@ -263,5 +265,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, char * c ) {
-	scanfmt( is, "%c", c );
+	fmt( is, "%c", c );
 	return is;
 } // ?|?
@@ -269,5 +271,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, short int * si ) {
-	scanfmt( is, "%hd", si );
+	fmt( is, "%hd", si );
 	return is;
 } // ?|?
@@ -275,5 +277,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, unsigned short int * usi ) {
-	scanfmt( is, "%hu", usi );
+	fmt( is, "%hu", usi );
 	return is;
 } // ?|?
@@ -281,5 +283,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, int * i ) {
-	scanfmt( is, "%d", i );
+	fmt( is, "%d", i );
 	return is;
 } // ?|?
@@ -287,5 +289,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, unsigned int * ui ) {
-	scanfmt( is, "%u", ui );
+	fmt( is, "%u", ui );
 	return is;
 } // ?|?
@@ -293,5 +295,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, long int * li ) {
-	scanfmt( is, "%ld", li );
+	fmt( is, "%ld", li );
 	return is;
 } // ?|?
@@ -299,5 +301,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, unsigned long int * ulli ) {
-	scanfmt( is, "%lu", ulli );
+	fmt( is, "%lu", ulli );
 	return is;
 } // ?|?
@@ -305,5 +307,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, long long int * lli ) {
-	scanfmt( is, "%lld", lli );
+	fmt( is, "%lld", lli );
 	return is;
 } // ?|?
@@ -311,5 +313,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, unsigned long long int * ulli ) {
-	scanfmt( is, "%llu", ulli );
+	fmt( is, "%llu", ulli );
 	return is;
 } // ?|?
@@ -318,5 +320,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, float * f ) {
-	scanfmt( is, "%f", f );
+	fmt( is, "%f", f );
 	return is;
 } // ?|?
@@ -324,5 +326,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, double * d ) {
-	scanfmt( is, "%lf", d );
+	fmt( is, "%lf", d );
 	return is;
 } // ?|?
@@ -330,5 +332,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, long double * ld ) {
-	scanfmt( is, "%Lf", ld );
+	fmt( is, "%Lf", ld );
 	return is;
 } // ?|?
@@ -338,5 +340,5 @@
 istype * ?|?( istype * is, float _Complex * fc ) {
 	float re, im;
-	scanfmt( is, "%g%gi", &re, &im );
+	fmt( is, "%g%gi", &re, &im );
 	*fc = re + im * _Complex_I;
 	return is;
@@ -346,5 +348,5 @@
 istype * ?|?( istype * is, double _Complex * dc ) {
 	double re, im;
-	scanfmt( is, "%lf%lfi", &re, &im );
+	fmt( is, "%lf%lfi", &re, &im );
 	*dc = re + im * _Complex_I;
 	return is;
@@ -354,5 +356,5 @@
 istype * ?|?( istype * is, long double _Complex * ldc ) {
 	long double re, im;
-	scanfmt( is, "%Lf%Lfi", &re, &im );
+	fmt( is, "%Lf%Lfi", &re, &im );
 	*ldc = re + im * _Complex_I;
 	return is;
@@ -362,5 +364,5 @@
 forall( dtype istype | istream( istype ) )
 istype * ?|?( istype * is, _Istream_cstrUC cstr ) {
-	scanfmt( is, "%s", cstr.s );
+	fmt( is, "%s", cstr.s );
 	return is;
 } // cstr
@@ -371,5 +373,5 @@
 	char buf[16];
 	sprintf( buf, "%%%ds", cstr.size );
-	scanfmt( is, buf, cstr.s );
+	fmt( is, buf, cstr.s );
 	return is;
 } // cstr
Index: src/tests/.expect/io.txt
===================================================================
--- src/tests/.expect/io.txt	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/tests/.expect/io.txt	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -18,6 +18,6 @@
 abc, $xyz
 
-v(27 v[27 v{27 $27 £27 ¥27 ¡27 ¿27 «27
-25, 25. 25: 25; 25! 25? 25) 25] 25} 25% 25¢ 25»
+v(27 v[27 v{27 $27 =27 £27 ¥27 ¡27 ¿27 «27
+25, 25. 25: 25; 25! 25? 25% 25¢ 25» 25) 25] 25}
 25'27 25`27 25"27 25 27 25
 27 25
@@ -25,2 +25,7 @@
 27 25	27 25
 27
+3, 4, a, 7.2
+3, 4, a, 7.2
+3 4 a 7.2
+ 3 4 a 7.234a7.2 3 4 a 7.2
+3-4-a-7.2^3^4-3-4-a-7.2
Index: src/tests/Makefile.am
===================================================================
--- src/tests/Makefile.am	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/tests/Makefile.am	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -51,4 +51,7 @@
 	@+python test.py --list --concurrent=${concurrent}
 
+.dummy : .dummy.c
+	${CC} ${CFLAGS} -XCFA -n ${<} -o ${@}
+
 constant0-1DP : constant0-1.c
 	${CC} ${CFLAGS} -DDUPS ${<} -o ${@}
Index: src/tests/Makefile.in
===================================================================
--- src/tests/Makefile.in	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/tests/Makefile.in	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -669,4 +669,7 @@
 	@+python test.py --list --concurrent=${concurrent}
 
+.dummy : .dummy.c
+	${CC} ${CFLAGS} -XCFA -n ${<} -o ${@}
+
 constant0-1DP : constant0-1.c
 	${CC} ${CFLAGS} -DDUPS ${<} -o ${@}
Index: src/tests/io.c
===================================================================
--- src/tests/io.c	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/tests/io.c	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar  2 16:56:02 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jul  5 18:29:23 2016
-// Update Count     : 31
+// Last Modified On : Tue Mar 21 22:36:06 2017
+// Update Count     : 48
 // 
 
@@ -62,6 +62,6 @@
 
 	sepSet( sout, ", $" );										// change separator, maximum of 15 characters
-	sout | f | d | ld | endl									// floating point without separator
-		 | fc | dc | ldc | endl									// complex without separator
+	sout | f | d | ld | endl
+		 | fc | dc | ldc | endl
 		 | s1 | s2 | endl;
 	sout | endl;
@@ -74,4 +74,5 @@
 		| "v{" | 27
 		| "$" | 27
+		| "=" | 27
 		| "£" | 27
 		| "¥" | 27
@@ -87,10 +88,10 @@
 		| 25 | "!"
 		| 25 | "?"
+		| 25 | "%"
+		| 25 | "¢"
+		| 25 | "»"
 		| 25 | ")"
 		| 25 | "]"
 		| 25 | "}"
-		| 25 | "%"
-		| 25 | "¢"
-		| 25 | "»"
 		| endl
 		// opening-closing delimiters
@@ -105,4 +106,14 @@
 		| 25 | "\v" | 27
 		| endl;
+
+	[int, int, const char *, double] t = { 3, 4, "a", 7.2 };
+	sout | [ 3, 4, "a", 7.2 ] | endl;
+	sout | t | endl;
+	sepSetTuple( sout, " " );
+	sout | t | endl;
+	sout | sepOn | t | sepDisable | t | sepEnable | t | endl;
+	sepSet( sout, "^" );
+	sepSetTuple( sout, "-" );
+	sout | t | 3 | 4 | t | endl;
 }
 
Index: src/tests/test.py
===================================================================
--- src/tests/test.py	(revision 9fcdfa3168e27173a000528e387fcd2b4cd18b44)
+++ src/tests/test.py	(revision c58f4aba255b0e01fdb89c38a21ce7f264429e78)
@@ -25,5 +25,5 @@
 # parses the Makefile to find the machine type (32-bit / 64-bit)
 def getMachineType():
-	sh('echo "int main() { return 0; }" > .dummy.c')
+	sh('echo "void ?{}(int*a,int b){}int main(){return 0;}" > .dummy.c')
 	sh("make .dummy", print2stdout=False)
 	_, out = sh("file .dummy", print2stdout=False)
