I've found the following code in another question:
\def\scan#1{\scanA#1*}
\def\scanA{\futurelet\next\scanB}
\def\scanB{\expandafter\ifx\next\space \expandafter\scanC \else \expandafter\scanE \fi}
\def\scanC{\afterassignment\scanD \let\next= }
\def\scanD{\scanE{ }}
\def\scanE#1{\ifx*#1\else \dosomething{#1} \expandafter\scanA \fi}
The effect is to convert a string like ABC into \dosomething{A}\dosomething{B}\dosomething{C}.
If \let\dosomething=\uppercase, then \scan{Hello World!} obtains HELLO WORLD!.
I understand when \ifx\next\space in \scanB gets false, it expands to \scanE, which captures the next unread token as its parameter and \dosomething.
However, when it gets true, it expands to \scanC. \scanD expands to \scanE{ } so that we may handle the spaces. But why the next \scanA will skip the space, and how \afterassignment and \let\next= work?
===== update by OrthoPole =====
I think I've understood the process myself.
When the \ifx get true, the stream looks like \futurelet·\next·\scanB·_·... (_ stands for a space token), and it expands to \afterassignment·\scanD·\let·\next·=·_·_·.... We see \let allows an optional space token, hence the first space after = will be omitted, and \next will be assigned the second space. After this assignment, \scanD will be expanded. Since the two spaces after = are absorbed by \let, we get \scanD·....
unravelwhich allows you to walk through single steps by emulating parts of TeX. For TeX primitives I think it can be quite helpful. https://tex.stackexchange.com/questions/61010/a-latex-log-analyzer-application-visualizing-tex-expansion – user202729 Apr 12 '23 at 08:20