summaryrefslogtreecommitdiff
path: root/info/challenges/aro-bend/answer.008
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /info/challenges/aro-bend/answer.008
Initial commit
Diffstat (limited to 'info/challenges/aro-bend/answer.008')
-rw-r--r--info/challenges/aro-bend/answer.008295
1 files changed, 295 insertions, 0 deletions
diff --git a/info/challenges/aro-bend/answer.008 b/info/challenges/aro-bend/answer.008
new file mode 100644
index 0000000000..b333a5c567
--- /dev/null
+++ b/info/challenges/aro-bend/answer.008
@@ -0,0 +1,295 @@
+[The addendum at bottom was not posted with the answer but added in my
+archives later ---mjd]
+
+Date: 22 Jul 1993 15:54:57 -0400 (EDT)
+From: Michael Downes <MJD@MATH.AMS.ORG>
+Subject: Around the Bend #8 answers
+To: info-tex@shsu.edu
+X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu>
+
+Exercise 8 asked for a way to trap missing }, \endgroup, or \fi at the
+end of a [La]TeX document, in order to give error messages instead
+of the warning messages issued by TeX:
+
+ (\end occurred inside a group at level 1)
+ (\end occurred when \iffalse on line 6 was incomplete)
+
+This review of solutions is posted later than expected because I
+needed time to try out and understand solutions submitted by Peter
+Schmitt last week. For clarity's sake, I have split the solutions
+into two parts, one dealing with groups, the other with conditionals.
+
+GROUPS
+
+Peter Schmitt remarked that if TeX can give a warning message for a
+missing endgroup there is nothing to prevent it from giving an error
+message except the choice of TeX's author. In some cursory perusal of
+TeX: the Program, I wasn't able to find any explanation from Knuth as
+to why he didn't make it a real error message instead of just a
+warning. Perhaps someone else can shed some light here?
+
+Now for solutions. The first one was submitted by Peter Schmitt. My
+commentary: Assume the body of the TeX document is enclosed within
+start and end commands (here named \BEGIN and \END), with the starting
+command contributing a \begingroup and the closing command providing
+the matching \endgroup, with some juggling to make a group mismatch
+trigger an error.
+
+If the document contains any unclosed groups that were opened with {
+or \bgroup, the \endgroup will trigger TeX's low-level error recovery,
+which is to insert matching }s (`Missing } inserted'). Thus only the
+case of an unmatched \begingroup needs to be handled. Schmitt does
+this by (essentially) making a local redefinition of \end that
+produces an error message; if all groups are closed properly, the
+local definition will disappear, restoring the normal definition,
+which will execute a normal endgame.
+
+Here now Schmitt's submitted solution. I have simplified it slightly
+by disentangling some other stuff that will be discussed later below.
+
+>>Solution 1 (Peter Schmitt)
+[a8131dal@awiuni11.edvz.univie.ac.at, schmitt@awirap.bitnet]
+
+\catcode`_11
+
+\let\standard_end\end % save original meaning of end
+ % define modified end
+\def\unexpected_end{%
+ {\errorcontextlines=0 % minimize errormessage
+ \errmessage{Unexpected \string\END\space inside group}% errormessage
+ }\standard_end % continue with \standard_end
+}
+
+\let\End\standard_end
+
+\def\END{\endgroup\End}
+
+\def\BEGIN{\begingroup
+ \let\End\unexpected_end
+ }
+
+\BEGIN
+
+%%% some tests:
+
+% \bgroup\egroup\end % balanced
+ \begingroup\end \endgroup % unbalanced
+% \bgroup\end % unbalanced
+% { \end % unbalanced
+
+% } \begingroup \end % this is reported
+% \endgroup \begingroup \end % this is not reported
+
+>>EndSolution
+
+>>Solution 2 (mine)
+This solution uses a rather dirty trick with \batchmode. Jonathan
+Fine also found the same idea, though in his mail to me he did not
+elaborate it into a fully wrapped solution.
+
+Enclosing the entire document inside a \begingroup \endgroup places an
+extra burden on the save stack (one would presume this is why LaTeX's
+\begin{document} and \end{document} take some pains to avoid
+constructing such a group, although the comments in latex.tex don't
+provide an explicit reason). (Extra credit question: Just how much of
+a burden would it place on the save stack in, say, an average LaTeX
+document?) So my solution seeks to trap unmatched { or \begingroup
+without enclosing the document body in a group. The reason the
+\batchmode trick is `dirty' is that it leaves a spurious extra error
+message in the log file. On screen for the typical interactive user,
+this error message is hidden by the temporary switch to \batchmode,
+but if for example the user has as part of their TeX system an editor
+setup that automatically proceeds through the .log file to help the
+user take care of all error messages, then the spurious error message
+will be somewhat inconvenient.
+
+The following clip shows what a user would typically see on screen if
+their document contained an unmatched {.
+
+ ! Missing } added.
+ \bgrouperr ...ffalse {\fi \string } added}
+
+ \enddocument ...rgroup \bgrouperr \egroup
+ \if \errorstopping \batchmo...
+ l.50 \enddocument
+
+ ? h
+ There appears to be an unmatched opening brace or \bgroup somewhere
+ in your document.
+ ?
+
+ )
+ No pages of output.
+
+Here then is the code for the solution. As it stands, only the most
+recent unmatched open-group is dealt with in the error message. As
+the on-screen result from the test section marked as `test 2' will
+indicate, a recursive definition for \bgrouperr would be better for
+maximum robustness, but I haven't had the spare time to work out the
+extra details.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\def\enddocument{%
+% Go into \batchmode to suppress possible error messages that we
+% don't want to bring to the user's attention.
+ \batchmode
+% Set a flag to enable us to handle the \endgroup properly if the
+% \egroup pairs up with an unmatched { or \bgroup.
+ \def\errorstopping{TF}%
+% If the following \egroup matches with a preceding unmatched { or
+% \bgroup in the user document, then the aftergroup tokens
+% \errorstopmode \bgrouperr will be executed. Otherwise they will
+% go away into uncharted limbo.
+ \aftergroup\errorstopmode\aftergroup\bgrouperr
+ \egroup
+% If there was no unmatched { or \bgroup, then the preceding
+% \egroup was discarded by TeX. And \errorstopping is still false.
+% Otherwise we need to insert some new \aftergroup tokens.
+ \if\errorstopping
+ \batchmode \aftergroup\errorstopmode \aftergroup\begingrouperr
+ \else
+ \global\let\bgrouperr\begingrouperr
+ \fi
+ \endgroup
+ \errorstopmode
+% Call two different versions of \end, just for convenient testing
+% with either plain TeX and LaTeX.
+ \csname\string @\string @end\endcsname
+ \end
+}
+
+\def\bgrouperr{%
+ \def\errorstopping{TT}%
+ \errhelp{%
+There appears to be an unmatched opening brace or \bgroup somewhere^^J%
+in your document.}%
+ \errmessage{Missing \iffalse{\fi\string} added}%
+}
+
+\def\begingrouperr{%
+ \errhelp{%
+There appears to be an unmatched \begingroup somewhere in
+your document.}%
+ \errmessage{Missing \noexpand\endgroup added}%
+}
+
+\newlinechar=`\^^J
+
+% % Test 0: Leave the following three lines commented out.
+%{ % Test 1: uncomment this line
+%\bgroup % Test 2: uncomment the previous line and this one.
+%\begingroup % Test 3: uncomment all three lines.
+
+\enddocument
+
+>>EndSolution
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+CONDITIONALS
+
+Now, what about \if...\fi matching? Can a method analogous to the one
+for groups be applied here? Well, it seems not, since there is no
+\afterfi primitive that works like \aftergroup. If you insert an
+`extra' \fi it will generate an error message in the case when it is
+not needed, and nothing in the case when it is needed; I would have
+sworn there's no *detectable* change of state between before the
+nonextra \fi and after the nonextra \fi.
+
+But Peter Schmitt found a scintillating idea, which is to make sure
+the \fi is never extra but use the need or non-need of an \else to
+control the triggering of an error message. This is done by enclosing
+the entire document in a pair of conditions:
+
+ \iftrue\iffalse\else
+ ...
+ \fi...\else<error>\fi
+
+If the \if's and \fi's in the body of the document are properly
+matched, then the <error> branch will be skipped over without
+execution. But if an unmatched \ifsomething in the document body uses
+up the \fi that is supposed to match up with the \iffalse\else, then
+the following \else will trigger an error message (which Schmitt hides
+with \batchmode, using the same trick as discussed above in Solution
+2), then be discarded, and the <error> branch will now be true.
+
+The extra two conditional structures place no significant burden on
+any of TeX's stacks, only a little bit of main memory to keep track of
+the line number and type of \if.
+
+Peter had the group and conditional trapping combined in his original
+solution; here is the conditional trapping part as I disentangled it.
+
+>>Solution 3 (Peter Schmitt):
+\catcode`_11
+
+\def\fi_message{{\newlinechar`|% % | is used to format screen messages
+ \errorcontextlines=0 % minimize errormessage
+ \errhelp{% % help text (if requested by the user)
+ \END occurred inside a conditional group. |%
+ You probably have forgotten to close some \fi before.
+ }%
+ \errmessage{Unexpected \string\END\space inside conditon} % errormessage
+ }}
+
+\def\BEGIN{\def\END{\fi\batchmode\else\errorstopmode\fi_message\fi
+ \errorstopmode\end}%
+ \iftrue\iffalse\else
+ }
+
+\BEGIN
+
+%%% some tests:
+
+% \iftrue \fi \END % balanced
+ \iftrue \END \fi % error message
+% \iffalse \else \END \fi % error message
+% \iftrue \iffalse \else \END \fi \fi % warning only
+% \iftrue \iffalse \else \fi \END \fi % error message
+% \iffalse \else \iffalse \else \END \fi \fi % error message
+% \iffalse \else \iffalse \else \END \fi \fi % error message
+
+>>EndSolution
+
+In closing, I want to point out that missing \fi's or \endgroup's are
+more likely to arise from a TeX programmer's error than from ordinary
+use of a macro package like LaTeX. So it might be minimally sufficient
+to trap only the missing } case, if the goal is to provide an explicit
+error message to end users of such a package.
+
+Michael Downes
+
+PS. Hint for Exercise 10: Run the body of the posting through plain TeX.
+
+ASCII 32--64,65--126:
+ !"#$%&'()*+,-./0123456789:;<=>?@
+ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Addendum: Found this in comp.text.tex. The line number question is
+significant; in Schmitt's solution for handling missing \fi's, you
+lose information about the line number where the unmatched \if really
+started.
+
+===========================================================================
+Archive-Date: Wed, 04 Aug 1993 13:30:24 CST
+Sender: bed_gdg@SHSU.EDU
+From: morje@math.ohio-state.edu (Prabhav Morje)
+Reply-To: morje@math.ohio-state.edu (Prabhav Morje)
+Subject: "end occurs inside a group" error in LaTeX
+Date: 3 Aug 1993 22:36:30 -0400
+Message-ID: <23n7be$e32@math.mps.ohio-state.edu>
+Keywords: line number group error
+To: tex-news@SHSU.EDU
+
+ Hi,
+
+ I sometimes get the error "\end occured while inside a group
+on level 1" while running LaTeX. I know it means there is an extra
+"{" somewhere. It is harmless sometimes but if I want to correct it,
+LaTeX never tells where the extra "{" is. Is it possible to find the
+line number or something more about location of the error?
+
+ Any pointers will be greatly appreciated.
+
+ - Prabhav