This should be what you want. The mandatory argument to \fa should be a four character string:
- First byte: 1 or 2 (one way or two way)
- Second byte: S or M (single or multi head)
- Third byte: D or N (deterministic or non deterministic)
- Fourth byte: + or - (with or without stack)
The optional argument is the number of heads, while the macro \fa can be followed by * for printing the abbreviation in boldface or by + for the long version.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\fa}{ s t+ m o }
{
\IfNoValueTF{#4}
{% there is no trailing optional argument, set the boolean to false
\bool_set_false:N \l_clement_show_heads_bool
}
{% there is a trailing optional argument, set the boolean to false
\bool_set_true:N \l_clement_show_heads_bool
% and store the argument for later usage
\tl_set:Nn \l_clement_heads_tl { $#4$ }
}
\IfBooleanTF{#2}
{% the `+` modifier has been given, call the long version
\clement_fa_long:n { #3 }
}
{% no + modifier
\IfBooleanTF{#1}
{% the `*` modifier has been given, call the short version in \textbf
\textbf{\clement_fa_short:n { #3 }}
}
{% no `*` modifier, just call the short version
\clement_fa_short:n { #3 }
}
}
}
% First byte: 1 or 2 (one way or two way)
% Second byte: S or M (single or multi head)
% Third byte: D or N (deterministic or non deterministic)
% Fourth byte: + or - (with or without stack)
\bool_new:N \l_clement_show_heads_bool
\tl_new:N \l_clement_heads_tl
\cs_new_protected:Npn \clement_fa_short:n #1
{% separate the four characters
\clement_fa_short_aux:NNNN #1
}
\cs_new_protected:Npn \clement_fa_short_aux:NNNN #1 #2 #3 #4
{% just use #1, #2 and #3 and add FA
#1#2#3FA
\str_case:nn { #4 }
{% check if the fourth character is - or +
{-}{}% -: do nothing
{+}{+S}% +: add +S
}
% if the boolean is true, add the number of heads in parentheses
\bool_if:NT \l_clement_show_heads_bool { (\l_clement_heads_tl) }
}
\cs_new_protected:Npn \clement_fa_long:n #1
{% separate the four characters
\clement_fa_long_aux:NNNN #1
}
\cs_new_protected:Npn \clement_fa_long_aux:NNNN #1 #2 #3 #4
{% add 1-way or 2-way and a space
#1-way~%
\bool_if:NTF \l_clement_show_heads_bool
{% if the boolean is true, add the number of heads
\l_clement_heads_tl
}
{% else add S if single-head, M if multi-head
\str_case:nn { #2 }
{
{S}{single}
{M}{multi}
}
}
-head~% add -head and a space
\str_case:nn { #3 }
{% add `non` and a space if nondeterministic
{N}{non~}
{D}{}
}
deterministic~finite~automaton~% the words
\str_case:nn { #4 }
{% add `with` or `without`
{+}{with~}
{-}{without~}
}
stack% add `stack`
}
\ExplSyntaxOff
\begin{document}
\fa{2MD+} --- \fa+{2MD+}
\fa{2MD-}[3] --- \fa+{2MD-}[3]
\fa*{2MN+}[k+1] --- \fa+{2MN-}[k+1]
\end{document}

Note that the word is automaton (automata is plural) and there should be no “s” in the prefixes (two way, not two ways; 3-head, not 3-heads), according to English grammar.
A variation that prints the number of heads parenthesized in the long form, when it's not an explicit number and it contains more than a symbol.
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\fa}{ s t+ m o }
{
\IfNoValueTF{#4}
{% there is no trailing optional argument, set the boolean to false
\bool_set_false:N \l_clement_show_heads_bool
}
{% there is a trailing optional argument, set the boolean to false
\bool_set_true:N \l_clement_show_heads_bool
% and store the argument for later usage
\tl_set:Nn \l_clement_heads_tl { #4 }
}
\IfBooleanTF{#2}
{% the `+` modifier has been given, call the long version
\clement_fa_long:n { #3 }
}
{% no + modifier
\IfBooleanTF{#1}
{% the `*` modifier has been given, call the short version in \textbf
\textbf{\clement_fa_short:n { #3 }}
}
{% no `*` modifier, just call the short version
\clement_fa_short:n { #3 }
}
}
}
% First byte: 1 or 2 (one way or two way)
% Second byte: S or M (single or multi head)
% Third byte: D or N (deterministic or non deterministic)
% Fourth byte: + or - (with or without stack)
\bool_new:N \l_clement_show_heads_bool
\tl_new:N \l_clement_heads_tl
\cs_new_protected:Npn \clement_fa_short:n #1
{% separate the four characters
\clement_fa_short_aux:NNNN #1
}
\cs_new_protected:Npn \clement_fa_short_aux:NNNN #1 #2 #3 #4
{% just use #1, #2 and #3 and add FA
#1#2#3FA
\str_case:nn { #4 }
{% check if the fourth character is - or +
{-}{}% -: do nothing
{+}{+S}% +: add +S
}
% if the boolean is true, add the number of heads in parentheses
\bool_if:NT \l_clement_show_heads_bool { \__clement_parens:V \l_clement_heads_tl }
}
\cs_new_protected:Npn \clement_fa_long:n #1
{% separate the four characters
\clement_fa_long_aux:NNNN #1
}
\cs_new_protected:Npn \clement_fa_long_aux:NNNN #1 #2 #3 #4
{% add 1-way or 2-way and a space
#1-way~%
\bool_if:NTF \l_clement_show_heads_bool
{% if the boolean is true, add the number of heads
\tl_if_single:NTF \l_clement_heads_tl
{
\__clement_simple:V \l_clement_heads_tl
}
{% \D matches anything which is not a digit
\regex_match:nVTF { \D } \l_clement_heads_tl
{ \__clement_parens:V \l_clement_heads_tl }
{ \__clement_simple:V \l_clement_heads_tl }
}
}
{% else add S if single-head, M if multi-head
\str_case:nn { #2 }
{
{S}{single}
{M}{multi}
}
}
-head~% add -head and a space
\str_case:nn { #3 }
{% add `non` and a space if nondeterministic
{N}{non~}
{D}{}
}
deterministic~finite~automaton~% the words
\str_case:nn { #4 }
{% add `with` or `without`
{+}{with~}
{-}{without~}
}
stack% add `stack`
}
\cs_new:Npn \__clement_parens:n #1 { $( #1 )$ }
\cs_new:Npn \__clement_simple:n #1 { $ #1 $ }
\cs_generate_variant:Nn \__clement_parens:n { V }
\cs_generate_variant:Nn \__clement_simple:n { V }
\cs_generate_variant:Nn \regex_match:nnTF { nV }
\ExplSyntaxOff
\begin{document}
\fa{2MD+} --- \fa+{2MD+}
\fa{2MD-}[3] --- \fa+{2MD-}[3]
\fa{1MD+}[24] --- \fa+{1MN+}[24]
\fa{2MN+}[k] --- \fa+{2MN+}[k]
\fa*{2MN+}[k+1] --- \fa+{2MN+}[k+1]
\end{document}

\loop, or a more usual\foreach). But still: 48 lines is not that much. That said, I repeat, I don't know anything about what you want, I was just doing numbers :) – Manuel Jul 08 '14 at 15:42\automata{1MDF+S}be acceptable? – Manuel Jul 08 '14 at 15:56\automata{1MDF+S}the extended one,\automata*{…}the short version,\automata+{…}the “different font”. That's easy withxparse. Now to process the inside of the argument, some\tl_…functions fromexpl3would come in handy. However I think it would be easier if you only use 1 token for each variety, that is, instead of+Sjust+, and then let the macro see if it sees a+or no. I will think about it later, right now I can't compile :) – Manuel Jul 08 '14 at 16:01k,k+1, etc). – Clément Jul 08 '14 at 16:01