
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.sprint
ist es „gleichwertig“ mit einem \input
, das den gedruckten Inhalt enthält, und Sie können \input
hö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
\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
\endinput
zum 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}
\immediateassignment
wird verwendet, damit es im Nur-Erweiterungskontext funktioniert.
Beachten Sie, dass das folgende Token notexpanded
geä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].