Wie kann ich von tex.print aufgerufene Makros endrekursiv machen?

Wie kann ich von tex.print aufgerufene Makros endrekursiv machen?

In Betracht ziehen

\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{luacr}
%\usepackage{miscellaneous}
\begin{document}

\global\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
    if i<30 then
        i=i+1
        tex.sprint(i .. [[, \F]])
    end
end
\end{luacode*}
\F

\end{document}

Problem:

TeX capacity exceeded, sorry [text input levels=15].

Soweit ich das sehe, tex.sprintist es „gleichwertig“ mit einem \input, das den gedruckten Inhalt enthält, und Sie können \inputhöchstens 15 Ebenen erstellen.

Frage:

  • Warum ist dasEliminierung der Endrekursionfunktioniert nicht, wenn die Eingabe aus einer Zeile statt aus einer Token-Liste stammt?
  • wie kann ich das Problem beheben? Angenommen, ich muss tex.sprint()z. B. rechts von etwas mehr String-Inhalt drucken \F.

in der Zwischenzeit habe ich einen Workaround gefunden token.put_next(), indem ich ein \relax eingebe und es später abhole.

Antwort1

Sie können tex zwingen, den Eingabestapel vor der Rekursion abzuwickeln, indem Sie mit\expandafter

Bildbeschreibung hier eingeben

\documentclass[12pt]{article}

%\usepackage{luacr}
%\usepackage{miscellaneous}
\begin{document}

\def\F{\expanded{\noexpand\directlua{f()}\expandafter}}
\directlua{
i=0
function f()
    if i<30 then
        i=i+1
        tex.sprint(i .. [[, \string\F]])
    end
end
}
\F

\end{document}

Antwort2

0.texio.closeinput()

Vorgeschlagen vonein Kommentar

Code:


%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
\begin{document}

\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
    if i~=0 then
        texio.closeinput()
    end
    if i<20000 then
        i=i+1
        tex.sprint(i .. [[, \F]])
    end
end
\end{luacode*}
\F

\end{document}

Das Handbuch erklärt...

Diese Funktion sollte mit Vorsicht verwendet werden. Sie fungiert als \endinput, jedoch am Lua-Ende. Sie können sie verwenden, um (sozusagen) einen Sprung zurück zu TeX zu erzwingen.

Das bedeutet, dass der verbleibende Inhalt der obersten „Datei“ gelöscht wird.

Hinweis/Erläuterung zum Handbuch,

  • das tut es nichtWirklichzurück zu TeX springen, der folgende Lua-Inhalt wird noch ausgeführt
  • tex.print()vorangehende Befehle werden ebenfalls gelöscht
  • Im Gegensatz \endinputzum Folgenden wird der Inhalt der Zeile gelöscht
  • AberWenn noch ausstehende Token vorhanden sind, token.put_next()werden diese so lange aufbewahrt wie die darauffolgenden
  • nur auf echte "Datei"/Pseudodatei anwenden, statt zB auf Argument-Token-Liste

1. Verwenden Sie token.put_next für das Fortsetzungstoken

%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
\begin{document}

\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
    if i<20000 then
        i=i+1
        tex.sprint(i .. [[, ]])
        token.put_next(token.create("F"))
    end
end
\end{luacode*}
\F

\end{document}

(experimentell token.put_next()kommt alles schließlich tex.*print(), unabhängig von ihrer Reihenfolge im Code)

Ich denke, der Grund, warum diese Methode funktioniert, liegt darin, dass TeX beim Erweitern eines Makros, anders als bei der Ausführung von token.get_next()oder token.scan_toks()usw., den Eingabestapel abwickelt (selbst wenn das Makro wie in diesem Fall kein Argument hat).

2. Verwenden Sie Futurelet

%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{miscellaneous}
%\tracingmacros=1
\begin{document}

\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
    if i<20000 then
        i=i+1
        tex.sprint(i .. [[, \immediateassignment\futurelet\a\F]])
    end
end
\end{luacode*}
\expanded{\F}
\end{document}

\immediateassignmentwird verwendet, damit es im Nur-Erweiterungskontext funktioniert.

Beachten Sie, dass das folgende Token notexpandedgeändert wird, falls es sich um ein Token handelt.

3. (funktioniert nur teilweise, nicht verwenden) Verwenden Sie token.put_next auf einem anderen Token und get_next es innerhalb von Lua

%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage{luacode}
%\usepackage{miscellaneous}
%\tracingmacros=1
\begin{document}

\def\F{\directlua{f()}}
\begin{luacode*}
i=0
function f()
    token.get_next()  -- the relax token, either the original one or result of put_next
    if i<3000 then
        i=i+1
        tex.sprint(i .. [[, \F]])
        token.put_next(token.create("relax"))
    end
end
\end{luacode*}
\F\relax
\end{document}

Dies führt keine richtige Endrekursion durch ( token.get_next()eliminiert den Eingangspegel nicht, wenn er erschöpft ist), sodass, wenn 3000 auf einen größeren Wert erhöht wird,

TeX capacity exceeded, sorry [input stack size=5000].

verwandte Informationen