You're missing a couple of \expandafter
's:
\ifx\init\@empty\else\expandafter\writer\expandafter{\init}\fi
If I change the corresponding line, I get this output to the terminal:
writer:Takes several words as argument
split:Takes several words as argument
1:Takes
2:s
1:several
2:w
1:words
2:a
1:as
2:a
1:argument
2:
writer-init:Takes several words as
writer-last:argument
writer:Takes several words as
split:Takes several words as
1:Takes
2:s
1:several
2:w
1:words
2:a
1:as
2:
writer-init:Takes several words
writer-last:as
writer:Takes several words
split:Takes several words
1:Takes
2:s
1:several
2:w
1:words
2:
writer-init:Takes several
writer-last:words
writer:Takes several
split:Takes several
1:Takes
2:s
1:several
2:
writer-init:Takes
writer-last:several
writer:Takes
split:Takes
1:Takes
2:
writer-init:
writer-last:Takes
Here's a perhaps better implementation, which exploits token registers instead of those complex chain of \expandafter
's or, in alternative, \unexpanded
which is from e-TeX. Note that all recent TeX distributions use e-TeX when LaTeX is called.
\documentclass{article}
\makeatletter
\def\split#1{%
\typeout{split:#1}%
\def\init{}%
\def\last{}%
\@split#1 \@empty
}
\def\@split#1 #2{%
\typeout{1:#1}%
\typeout{2:\noexpand#2}% \noexpand for showing also `\@empty`
\ifx #2\@empty
\def\last{#1}%
\else
\ifx\init\@empty
\def\init{#1}%
\else
% with e-TeX use the following line
\edef\init{\unexpanded\expandafter{\init}\space\unexpanded{#1}}%
% without e-TeX use the following two lines
%\toks@=\expandafter\expandafter\expandafter{\expandafter\init\space#1}%
%\edef\init{\the\toks@}%
\fi
\expandafter\@split
\fi
#2%
}
\def\writer#1{%
\typeout{writer:#1}%
\split{#1}%
\typeout{writer-init:\init}%
\typeout{writer-last:\last}%
\ifx\init\@empty\else\expandafter\writer\expandafter{\init}\fi
}
\makeatother
\begin{document}
\writer{Takes several words as argument}
\end{document}
Here's a LaTeX3 implementation of what you seem to want. Note that this is rather straightforward and also avoids your mixing of \split
and \writer
.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\bronislavsplit}{m}
{
\bronislav_split:n { #1 }
}
\seq_new:N \l_bronislav_input_seq
\tl_new:N \l_bronislav_last_tl
\cs_new_protected:Npn \bronislav_split:n #1
{
% split the input at spaces
\seq_set_split:Nnn \l_bronislav_input_seq { ~ } { #1 }
% start the recursion
\__bronislav_iterate:
}
\cs_new_protected:Npn \__bronislav_iterate:
{
\seq_if_empty:NF \l_bronislav_input_seq
{% this is executed only if the sequence is not empty
% for debugging, show the what's in the sequence
\typeout{writer: ~ \seq_use:Nn \l_bronislav_input_seq { ~ }}
% split off the last element
\seq_pop_right:NN \l_bronislav_input_seq \l_bronislav_last_tl
\seq_map_inline:Nn \l_bronislav_input_seq
{
% do something with each item
\bronislav_do_item:n { ##1 }
}
% do something with the last item
\bronislav_do_last_item:V \l_bronislav_last_tl
% keep on the recursion
\__bronislav_iterate:
}
}
\cs_new_protected:Npn \bronislav_do_item:n #1
{
\typeout { item: ~ #1 }
}
\cs_new_protected:Npn \bronislav_do_last_item:n #1
{
\typeout { last ~ item: ~ #1 }
}
% generate a variant because a variable is passed
\cs_generate_variant:Nn \bronislav_do_last_item:n { V }
\ExplSyntaxOff
\begin{document}
\bronislavsplit{Takes several words as argument}
\end{document}
Here's the output on the terminal:
writer: Takes several words as argument
item: Takes
item: several
item: words
item: as
last item: argument
writer: Takes several words as
item: Takes
item: several
item: words
last item: as
writer: Takes several words
item: Takes
item: several
last item: words
writer: Takes several
item: Takes
last item: several
writer: Takes
last item: Takes
Of course you want to do something more useful with the last two commands.