LaTex macht mich noch wahnsinnig

Redefinition von Makros, Definition eigener Befehle sowie neuer Umgebungen


Rolli
Forum-Guru
Forum-Guru
Beiträge: 345
Registriert: Mi 15. Feb 2017, 08:50
Wohnort: Mittelfranken

LaTex macht mich noch wahnsinnig

Beitrag von Rolli »

Hallo!

Ich bastele seit heute morgen 8 Uhr an diesem Problem:

Ich möchte eine Header-Datei haben, in der meine Standard-Präambel, mein Standard-Code rund um \begin{document}, und mein Standard-Code rund um \end{document} übersichtlich zusammen sind.

Hier ein abgespecktes Code-Beispiel, welches den Fehler zeigt, der mich gerade in die Verzweiflung treibt:

Code: Alles auswählen

\begin{filecontents*}{myTest.tex}
\ifdefined\aHeader%
\let\aHeader\undefined%
\documentclass{scrartcl}
\usepackage{xinttools}
      
\makeatletter
\newcommand\myCheck[2]{%
\xintFor*##1 in{#1}:
{%
\in@{##1}{#2}%
\unless\ifin@\expandafter\xintBreakFor\fi
}%
\ifin@\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\makeatother
\fi 
\end{filecontents*}

\def\aHeader{}
\input{myTest.tex}
\input{myTest.tex} % Führt zu Fehler Too many }'s

\begin{document}
   Hallo, Welt!
\end{document}

Wenn ich die viertletzte Zeile (das doppelte \input...) lösche, funktioniert es wie beabsichtigt.
Mit dem doppelten \input gibt es einen Fehler "Too many }'s" in meinem \myCheck.
1. Da sind nicht zu viele { oder } - die sind sauber gepaart …
2. Wieso wird das überhaupt ein zweites Mal ausgeführt???

Hilfe …

Gruß vom Rolli

Edit: Wenn ich den Code in myTest.tex in die Hauptdatei packe, anstatt es auszulagern, klappt alles wunderbar ...
Zuletzt geändert von Rolli am Di 21. Jan 2020, 13:50, insgesamt 1-mal geändert.

Gast

Beitrag von Gast »

Warum schreibst du nicht einfach eine Wrapper-Klasse?

Rolli
Forum-Guru
Forum-Guru
Beiträge: 345
Registriert: Mi 15. Feb 2017, 08:50
Wohnort: Mittelfranken

Beitrag von Rolli »

… habe ich noch nie gemacht, kannst Du mich etwas "ankicken"?

Gast

Beitrag von Gast »

https://texwelt.de/fragen/1479/wie-erst ... ntenklasse

So eine Wrapperklasse kann sehr einfach, aber auch sehr komplex sein. Die einfachste, denkbare Wrapperklasse wäre:

Code: Alles auswählen

\documentclass{myarticle}
\LoadClassWithOptions{article}
\endinput
Eine extrem komplexe Wrapperklasse ist beispielsweise tudscrbook aus tudscr.

Benutzeravatar
u_fischer
Forum-Meister
Forum-Meister
Beiträge: 4025
Registriert: Do 22. Nov 2012, 11:09
Kontaktdaten:

Beitrag von u_fischer »

Dein \makeatletter kommt zu spät.

Wenn der Header nicht definiert ist, wird es nicht ausgeführt, und dann wird \ifin@ nicht als if-Befehl erkannt, und \ifdefined findet das \else und versucht den Zweig auszuführen.

Ich kann nur davon abraten, komplizierte Codeblöcke in \if-Zweige zu stecken. Das ist oft ziemlich trickig.

Rolli
Forum-Guru
Forum-Guru
Beiträge: 345
Registriert: Mi 15. Feb 2017, 08:50
Wohnort: Mittelfranken

Beitrag von Rolli »

Danke für die Erläuterung, Ulrike!
Ich sehe, dass es so funktioniert:

Code: Alles auswählen

\begin{filecontents*}{myTest.tex}
 \ifdefined\aHeader%
  \let\aHeader\undefined%
  \documentclass{scrartcl}
  \usepackage{xinttools}

  %\makeatletter
  \newcommand\myCheck[2]{%
   \xintFor*##1 in{#1}:
	{%
	 \in@{##1}{#2}%
	 \unless\ifin@\expandafter\xintBreakFor\fi
	}%
	\ifin@\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  }
  %\makeatother
 \fi 
\end{filecontents*}

\def\aHeader{}
\makeatletter
\input{myTest.tex}
\makeatother
\makeatletter
\input{myTest.tex} % Führt nicht mehr zum Fehler “Too many }'s”.
\makeatother

\begin{document}
 Hallo, Welt!
\end{document}
Aber sehen heißt nicht: verstehen. Das TeXbook sagt doch auf S. 207
The general form of such “conditional text” is \if<condition><true text>\else<false text>\fi where the <true text> is skipped unless the <condition> is true, and the <false text> is skipped unless the <condition> is false. If the <false text> is empty, you can omit the \else.
Nach meinem Verständnis ist TeX doch ein single-pass-Compiler, stimmts? D.h. beim ersten Durchlauf meines “myTest-Codes” kommt \myCheck in die Symboltabelle. Beim zweiten Durchlauf dürfte daran doch nie etwas geändert werden, weil kein \else und \if falsch (S. 207 TeXbook) ???

Außerdem: Nach meinem Verständnis ändert \makeatletter lediglich temporär den CatCode für @ von 12 auf 11, bis zum \makeatother, der es wieder zurück auf 12 setzt. D.h., im puren TeX \catcode'@=11 bzw. \catcode'@=12. Damit wird @ rein textuell Teil des Makros und ist somit 1:1 in der Symboltabelle - oder habe ich das grob falsch verstanden???

Gruß vom Rolli

oft gesehener

Beitrag von oft gesehener »

Da TeX den nicht zutreffenden Zweig eines \if…\else…\fi nicht ausführt, sondern darin nur nach balancierten \if…, \else und \fi Ausschau hält, müssen dafür eben ein paar Bedingungen gelten. So würde beispielsweise bei:

Code: Alles auswählen

\iffalse
\newif\iftest
\iftest
Ja,
\else
Nein,
\fi
das wird nie ausgeführt.
\fi
das \iftest, das im nicht zutreffenden Zweig definiert wird, für TeX keine \if…-Anweisung und damit würden das \else und \fi danach bereits zum \iffalse gehören. Damit wird »Das wird nie ausgeführt.« eben doch ausgeführt und das zweite \fi wird als Fehler gemeldet:

Code: Alles auswählen

\documentclass{article}
\begin{document}
\iffalse
\newif\iftest
\iftest
Ja,
\else
Nein,
\fi
das wird nie ausgeführt.
\fi
\end{document}
ergibt also:

Code: Alles auswählen

Extra \fi.
l.11 \fi
und im Dokument steht der Satz »Nein, das wird nie ausgeführt.«

Angewendet auch dein Beispiel wird beim zweiten Einlesen, wenn \aHeader nicht definiert ist, \makeatletter nicht ausgeführt. Damit lautet die Anweisung nicht mehr \ifin@, sondern \ifin. Das ist für TeX keine definierte \if…-Anweisung. Also gehört das \fi dahinter bereits zu \ifdefined\aHeader und beendet dieses. Die weiteren \fi in der Datei sind dann zuviel.

Der Umgang mit \if… ist also weit weniger trivial, als man das auf den ersten Blick vermutet.

In einer Wrapper-Klasse wäre das übrigens in der Tat aus zwei Gründen nicht passiert:
  • Man braucht in einer Klasse kein \makeatlettetr, sondern @ sind automatisch Buchstaben.
  • LaTeX selbst verhindert das mehrfache Einlesen von Klassen und Paketen.
Dafür muss man in einer Wrapper-Klasse schon mit Patches arbeiten, wenn beispielsweise nach \begin{document} bereits automatisch Satzanweisungen folgen sollen, beispielweise um den Titel auszugeben o. ä. Es gibt jedoch Pakete, die den Klassenautor dabei unterstützen.

Rolli
Forum-Guru
Forum-Guru
Beiträge: 345
Registriert: Mi 15. Feb 2017, 08:50
Wohnort: Mittelfranken

Beitrag von Rolli »

Ich danke Euch allen für die Erläuterungen. So ganz verstehe ich es immer noch nicht, aber ich werde mich irgendwie durchwursteln …

Gruß vom Rolli

Antworten