Macro che restituisce l’ultimo token

  • Creatore
    Topic
  • #24482
    Up
    0
    Down
    ::


    Ciao ragazzi,

    mi è venuta l’idea di fare una macro (più per esercizio) la cui espansione è l’ultimo token non più espandibile dell’argomento. Per esempio:
    `\newcommand*\ciao{ciao}
    \lastof{\ciao} o`

    Avevo pensato a questo codice:
    `
    \def\lastof#1{\begingroup\last@f{#1}\endgroup}
    \def\last@f#1{%
    \edef\next{\expandafter\@gobble#1}%
    \ifx\next\@empty
    #1\else
    \last@f\next
    \fi
    }
    ` ma non va. Mentre funziona il seguente (ipotizzando che l’argomento iniziale non sia vuoto):
    `
    \def\lastof#1{\begingroup\last@f{#1}\endgroup}
    \def\last@f#1{%
    \edef\next{\expandafter\@gobble#1}%
    \ifx\next\@empty
    #1\else
    \expandafter\last@f\expandafter{\next}%
    \fi
    }
    `

    Quello che mi chiedo… perché il primo non funziona? L’espansione effuettuata dagli \expandafter non dovrebbe essere “inutili” dato che c’è l’\edef? 😯 😕

    Grazie, Daniele.

Visualizzazione 2 filoni di risposte
  • Autore
    Risposte
    • #24483
      Up
      0
      Down
      ::

      Ciao ragazzi,

      mi è venuta l’idea di fare una macro (più per esercizio) la cui espansione è l’ultimo token non più espandibile dell’argomento. Per esempio:
      `\newcommand*\ciao{ciao}
      \lastof{\ciao} o`

      Avevo pensato a questo codice:
      `
      \def\lastof#1{\begingroup\last@f{#1}\endgroup}
      \def\last@f#1{%
      \edef\next{\expandafter\@gobble#1}%
      \ifx\next\@empty
      #1\else
      \last@f\next
      \fi
      }
      ` ma non va. Mentre funziona il seguente (ipotizzando che l’argomento iniziale non sia vuoto):
      `
      \def\lastof#1{\begingroup\last@f{#1}\endgroup}
      \def\last@f#1{%
      \edef\next{\expandafter\@gobble#1}%
      \ifx\next\@empty
      #1\else
      \expandafter\last@f\expandafter{\next}%
      \fi
      }
      `

      Quello che mi chiedo… perché il primo non funziona? L’espansione effuettuata dagli \expandafter non dovrebbe essere “inutili” dato che c’è l’\edef? 😯 😕

      Intanto la macro \last@f è inutile, non c’è alcun pericolo nel ridefinire \next; puoi mettere il codice direttamente in \lastof. Perché dici che il primo non funziona? Non mi pare di avere osservato differenze.

      Ciao
      Enrico

    • #24484
      Up
      0
      Down
      ::

      Intanto la macro \last@f è inutile, non c’è alcun pericolo nel ridefinire \next; puoi mettere il codice direttamente in \lastof. Perché dici che il primo non funziona? Non mi pare di avere osservato differenze.

      Ciao
      Enrico

      Il gruppo lo metto lo stesso? O credi sia inutile anche quello? Comunque ora non posso provare il codice dato che non sono a casa, ma ieri con il primo codice il risultato di
      `
      % Preambolo
      \def\ciao{ciao}
      % Documento
      :\lastof{\ciao}:` era `::` mentre del secondo codice era giustamente `:o:`

      Riproverò e farò sapere.
      Grazie, Daniele.

    • #24485
      Up
      0
      Down
      ::

      Intanto la macro \last@f è inutile, non c’è alcun pericolo nel ridefinire \next; puoi mettere il codice direttamente in \lastof. Perché dici che il primo non funziona? Non mi pare di avere osservato differenze.

      Ciao
      Enrico

      Il gruppo lo metto lo stesso? O credi sia inutile anche quello? Comunque ora non posso provare il codice dato che non sono a casa, ma ieri con il primo codice il risultato di
      `
      % Preambolo
      \def\ciao{ciao}
      % Documento
      :\lastof{\ciao}:` era `::` mentre del secondo codice era giustamente `:o:`

      È vero: ma la spiegazione è piuttosto complessa. Facciamo una semplificazione:
      `\def\test{AB}
      \def\lastof#1{\edef\next{\expandafter\@gobble#1}%
      \ifx\next\@empty
      #1%
      \else
      \expandafter\lastof\expandafter[\next}%
      \fi}`
      La chiamata \lastof{\test} esegue “\edef\next{\expandafter\@gobble\test}” che diventa “\edef\next{\@gobble AB}” cioè come “\def\next{B}”. Adesso c’è \ifx che risulta falso, quindi viene eseguito “\expandafter\lastof\expandafter[\next}” che diventa “\lastof{B}”. Ora c’è \edef\next{\expandafter\@gobble B} che è come “\def\next{}”. Il test è vero e quindi viene prodotto #1, cioè “B”.

      Proviamo con
      `\def\test{AB}
      \def\Xlastof#1{\edef\next{\expandafter\@gobble#1}%
      \ifx\next\@empty
      #1%
      \else
      \Xlastof\next
      \fi}`
      Se diamo \Xlastof{\test} il primo passo è come prima ed equivale a scrivere “\def\next{B}”. Il condizionale è falso, quindi viene eseguito \Xlastof\next e qui avviene il pasticcio: viene eseguito “\edef\next{\expandafter\@gobble\next}” che equivale a “\def\next{}” e quindi viene seguito il ramo vero che produce #1, che in questo caso è \next, ed ecco che non salta fuori nulla.

      Non è il modo migliore per mangiare un token alla volta, in effetti. Prova con altre strategie: di solito questo si fa con macro con argomenti delimitati.
      `\def\lastof#1{\expandafter\@lastof#1\@lastof}
      \def\@lastof#1#2\@lastof{\def\@last@f{#1}\def\next{#2}%
      \ifx\next\@empty
      \@last@f
      \else
      \expandafter\@lastof\next\@lastof
      \fi}`
      Non funzionerebbe se l’argomento di \lastof ha espansione vuota, ma questo si può controllare prima. Sarebbe meno complicato se si dovesse usare un token alla volta, ci sono esempi sugli Appunti (\slowromancaps, se non ricordo male). Qui la richiesta è un po’ diversa e bisogna tenersi in mente un token. Per questo \@lastof ha due argomenti, il primo non delimitato, il secondo delimitato. Perciò con
      `\@lastof ciao\@lastof`
      il primo argomento è “c”, il secondo è “iao”.

      Ciao
      Enrico

Visualizzazione 2 filoni di risposte
  • Devi essere connesso per rispondere a questo topic.

Go to top