tex.print tail-recursive에서 호출되는 매크로를 어떻게 만들 수 있나요?

tex.print tail-recursive에서 호출되는 매크로를 어떻게 만들 수 있나요?

고려하다

\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}

문제:

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

내가 볼 수 있는 한 은 인쇄된 콘텐츠를 포함하는 tex.sprinta 와 "동등"하며 최대 15개 레벨까지 \input가능합니다 .\input

질문:

  • 왜?꼬리 재귀 제거입력이 토큰 목록 대신 라인에서 오는 경우 작동하지 않습니까?
  • 문제를 해결하는 방법? 예를 들어 tex.sprint()오른쪽에 문자열 내용을 더 인쇄 해야 한다고 가정합니다 \F.

그동안 을 사용하여 해결 방법을 찾았습니다 token.put_next(). \relax를 입력하고 나중에 얻으세요.

답변1

다음을 사용하여 반복하기 전에 tex가 입력 스택을 풀도록 강제할 수 있습니다.\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}

답변2

0.texio.closeinput()

의 생각코멘트

암호:


%! 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}

설명서에 설명이...

이 기능은 주의해서 사용해야 합니다. 이는 \endinput 역할을 하지만 Lua 끝에 있습니다. 이를 사용하여 TeX으로 강제로 다시 점프할 수 있습니다.

이는 최상위 "파일"의 나머지 내용을 삭제한다는 의미입니다.

매뉴얼의 참고/설명,

  • 그렇지 않다정말TeX으로 돌아가면 다음 Lua 콘텐츠가 계속 실행됩니다.
  • tex.print()그 이전 명령도 삭제됩니다.
  • \endinput다음 줄의 내용 과 달리 삭제되었습니다.
  • 하지만보류 중인 토큰이 있는 경우 token.put_next()그 이후의 토큰은 그대로 유지됩니다.
  • 예를 들어 인수 토큰 목록 대신 실제 "파일"/의사 파일에만 적용됩니다.

1. 연속 토큰에 token.put_next를 사용하세요.

%! 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}

(실험적으로 코드의 순서에 관계없이 모두 token.put_next()뒤에 옵니다 )tex.*print()

이 방법이 작동하는 이유는 매크로를 확장하는 동안 token.get_next()또는 token.scan_toks()등이 실행될 때와 달리 TeX가 입력 스택을 풀기 때문이라고 생각합니다(이 경우와 같이 매크로에 인수가 없는 경우에도).

2. 퓨처렛을 사용하세요

%! 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확장 전용 컨텍스트에서 작동하도록 만드는 데 사용됩니다.

다음 토큰이 notexpanded토큰이면 변경된다는 점에 유의하세요.

3. (부분적으로만 작동함, 사용하지 않음) 다른 토큰에 token.put_next를 사용하고 Lua 내부에서 get_next

%! 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}

이는 적절한 꼬리 재귀를 수행하지 않으므로(어쨌든 token.get_next()소진된 경우 입력 레벨을 제거하지 않음) 3000을 더 큰 값으로 늘리면 다음과 같은 결과가 나타납니다.

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

관련 정보