When you want to maintain token lists where something can be added or removed at either end, it's best to add a separator:
\catcode`@=11 % \makeatletter
\def\prependtolist#1#2{% #1=list name, #2=item to add
\toks@={\listitem{#2}}%
\toks@=\expandafter{\the\expandafter\toks@#1}%
\edef#1{\the\toks@}
}
\def\appendtolist#1#2{%
\expandafter\def\expandafter#1\expandafter{#1\listitem{#2}}%
}
\def\removetop#1#2{% #1=list,#2=macro to store the removed item
\expandafter\removetopaux#1\removetop{#1}{#2}}
\def\removetopaux\listitem#1#2\removetop#3#4{%
\def#2{#1}%
\def#3{#2}%
}
\catcode`@=12
(there are better ways, this is just to give the flavor).
When the list has to be used, just set
\def\listitem#1{#1}
With LaTeX3 there are a bunch of facilities for easing the job. The "sequence" data type is the easiest:
\usepackage{expl3}
\seq_new:N \l_werner_my_seq
\seq_put_left:Nn \l_werner_my_seq {a} % analog of \prependtolist
\seq_put_right:Nn \l_werner_my_seq {a} % analog of \appendtolist
\seq_pop_left:NN \l_werner_my_seq \l_tmpa_tl % analog of \removetop
\seq_pop_right:NN \l_werner_my_seq \l_tmpa_tl % analog of \removebottom
% How to deliver the contents of a sequence
\seq_map_function:NN \l_werner_my_seq \use:n
The last line shows how to deliver the contents of the list (the implicit separator is redefined to do nothing).
Working with token lists is possible too, but one can remove items rather than tokens, where an item is either a token which is not an explicit brace or a braced group.
\tl_new:N \l_werner_my_tl
\tl_put_left:Nn \l_werner_my_tl {a} % analog of \prependto
\tl_put_right:Nn \l_werner_my_tl {a} % analog of \appendto
\tl_set:Nx \l_werner_my_tl { \tl_tail:N \l_werner_my_tl } % your \gobblefirst
The \gobblelast macro can be obtained by reversing twice the token list:
\cs_generate_variant:Nn \tl_reverse:n {f}
\tl_set:Nx \l_werner_my_tl { \tl_reverse:f { \tl_tail:f { \tl_reverse:V \l_werner_my_tl } } }
Implementation of the "token list" approach:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\uselist}{ m }{ \tl_use:c { l_werner_#1_tl } }
\NewDocumentCommand{\createlist}{ m }{ \tl_new:c { l_werner_#1_tl } }
\NewDocumentCommand{\prependtolist}{ m m }
{
\werner_prepend:nn { #1 } { #2 }
}
\NewDocumentCommand{\appendtolist}{ m m }
{
\werner_append:nn { #1 } { #2 }
}
\NewDocumentCommand{\gobblefirst}{ m }
{
\werner_gobble_first:n { #1 }
}
\NewDocumentCommand{\gobblelast}{ m }
{
\werner_gobble_last:n { #1 }
}
\cs_new_protected:Npn \werner_prepend:nn #1 #2
{
\tl_put_left:cn { l_werner_#1_tl } { #2 }
}
\cs_new_protected:Npn \werner_append:nn #1 #2
{
\tl_put_right:cn { l_werner_#1_tl } { #2 }
}
\cs_new_protected:Npn \werner_gobble_first:n #1
{
\tl_set:cx { l_werner_#1_tl } { \tl_tail:v { l_werner_#1_tl } }
}
\cs_new_protected:Npn \werner_gobble_last:n #1
{
\tl_set:cx { l_werner_#1_tl } { \tl_reverse:v { l_werner_#1_tl } }
\werner_gobble_first:n { #1 }
\tl_set:cx { l_werner_#1_tl } { \tl_reverse:v { l_werner_#1_tl } }
}
\cs_generate_variant:Nn \tl_reverse:n {v}
\NewDocumentCommand{\showlist}{m}{ \tl_show:c { l_werner_#1_tl } }
\ExplSyntaxOff
\createlist{my}
\appendtolist{my}{z}
\prependtolist{my}{{ab}c}
\appendtolist{my}{\texttt}
\showlist{my} % {ab}cz\texttt
\gobblefirst{my}
\showlist{my} % cz\texttt
\gobblelast{my}
\showlist{my} % cz
\gobblelast{my}
\showlist{my} % c
Instead of \showlist you can say \uselist{my} to deliver the list's content.
Implementation of the "sequence" approach
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\createlist}{ m }{ \seq_new:c { l_werner_#1_seq } }
\NewDocumentCommand{\uselist}{ m } { \seq_map_function:cN { l_werner_#1_seq } \use:n }
\NewDocumentCommand{\showlist}{ m } { \seq_show:c { l_werner_#1_seq } }
\NewDocumentCommand{\prependtolist}{ m m }{ \werner_prepend:nn { #1 } { #2 } }
\NewDocumentCommand{\appendtolist}{ m m }{ \werner_append:nn { #1 } { #2 } }
\NewDocumentCommand{\gobblefirst}{ m }{ \werner_gobble_first:n { #1 } }
\NewDocumentCommand{\gobblelast}{ m }{ \werner_gobble_last:n { #1 } }
\cs_new_protected:Npn \werner_prepend:nn #1 #2
{
\seq_put_left:cn { l_werner_#1_seq } { #2 }
}
\cs_new_protected:Npn \werner_append:nn #1 #2
{
\seq_put_right:cn { l_werner_#1_seq } { #2 }
}
\cs_new_protected:Npn \werner_gobble_first:n #1
{
\seq_pop_left:cN { l_werner_#1_seq } \l_tmpa_tl
}
\cs_new_protected:Npn \werner_gobble_last:n #1
{
\seq_pop_right:cN { l_werner_#1_seq } \l_tmpa_tl
}
\ExplSyntaxOff
The same input as before will do, with the difference that \gobblefirst will remove {ab}c and not {ab}.