\def \CodeVersion {1.04} \def \CodeDate {11th March 1999} % % \iffalse ^^A Comment out driver code, so LaTeX can read this file as it is. % %<*driver> \documentclass{ltxdoc} \usepackage{varioref,amssymbols} \EnableCrossrefs \RecordChanges \CodelineIndex \renewcommand{\levelchar}{?} \title{The \starTeX{} source code} \author{Dag Langmyhr\\ Department of Informatics\\ University of Oslo\\[3mm] \textsf{dag@ifi.uio.no}}% \date{Version \CodeVersion, \CodeDate} \newcommand{\hex}[1]{\texttt{``#1}} \newcommand{\stcs}[1]{\texttt{<#1>}} \newcommand{\stenv}[1]{\stcs{#1}\dots\hspace{0.1pt}\stcs{/#1}} \newcommand{\ParX}{\texttt{\textit{x}}} \newcommand{\ps}{\textsc{Post\-Script}} \newcommand{\starTeX}{Star\TeX} \newcommand{\xx}{\textit{x}} \newfont{\StdECR}{ecrm1000} \newfont{\CompECR}{tcrm1000} \begin{document} \maketitle \DoNotIndex{\#,\$,\&,\\,\{,\},\^,\_,\~} \DoNotIndex{\active,\advance,\alpha} \DoNotIndex{\begingroup,\beta,\bgroup} \DoNotIndex{\catcode,\Cdef,\chi,\csname} \DoNotIndex{\day,\def,\Delta,\delta,\Df,\dots,\dump} \DoNotIndex{\edef,\egroup,\endcsname,\endgraf,\endgroup,\epsilon,\eta} \DoNotIndex{\Gamma,\gamma,\gdef,\global} \DoNotIndex{\halign,\hangafter,\hangindent,\hbadness,\hbox,\hfil,\hfuzz} \DoNotIndex{\hoffset,\hrule,\hsize} \DoNotIndex{\iota,\input,\inputlineno} \DoNotIndex{\kappa,\kern} \DoNotIndex{\Lambda,\lambda,\language,\LaTeX,\leavevmode,\leftskip,\let,\llap} \DoNotIndex{\magstep,\magstephalf,\mathcode,\message,\month,\mu} \DoNotIndex{\newbox,\newcount,\newdimen,\newif,\newlinechar,\newread} \DoNotIndex{\newskip,\newwrite,\next,\Next,\noalign,\nu} \DoNotIndex{\obeylines,\obeyspaces,\offinterlineskip,\Omega,\omega} \DoNotIndex{\openin,\openout,\over} \DoNotIndex{\pageno,\par,\parindent,\parskip,\penalty,\Phi,\phi,\pm,\Pr} \DoNotIndex{\Pi,\pi,\Psi,\psi} \DoNotIndex{\raggedright,\Re,\relax,\rightskip,\rho,\rlap} \DoNotIndex{\setbox,\Sigma,\sigma,\space,\string,\strut,\supereject} \DoNotIndex{\tau,\TeX,\the,\Theta,\theta,\time,\times,\TmpA,\TmpB,\tolerance} \DoNotIndex{\topinsert} \DoNotIndex{\tracingcommands,\tracingmacros,\tracingoutput,\tracingrestores} \DoNotIndex{\uccode,\unskip,\Uparrow,\Updownarrow,\uppercase,\Upsilon,\upsilon} \DoNotIndex{\varepsilon,\varphi,\varpi,\varrho,\varsigma,\vartheta} \DoNotIndex{\vbox,\vdots,\vfill,\voffset,\vrule,\vsize,\vskip} \DoNotIndex{\wd} \DoNotIndex{\Xi,\xi} \DoNotIndex{\year} \DoNotIndex{\zeta} \DeleteShortVerb{\|}\MakeShortVerb{\"} \DocInput{startex.dtx} \end{document} % % % \fi % % \CheckSum{2563} %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % % \tableofcontents % % \RecordChanges % \StopEventually{\PrintIndex\PrintChanges} % % \section{The \starTeX{} format} % \begin{macrocode} %<*code> % \end{macrocode} % This file contains the documented source code of \starTeX{}, a % simplified and more robust \TeX{} format intended for students % writing their first report or essay. For more information on % \starTeX{}, see the other files accompanying this. % % The main guidelines for this implementation are: % \begin{itemize} % \item \starTeX{} is implemented on top of plain \TeX{}. % % \item All names defined in the \starTeX{} implementation contain % at least one uppercase letter, like \cs{Cdef} or \cs{NewEnvir}. % This makes it easier to distinguish % them from \TeX's internal names and the names defined in plain % \TeX{}, nearly all of which consist of lowercase letters only. % % \item Most \TeX{} macro packages tend to use a rather terse % programming style, like % \begin{quote} % \verb*:\advance\var\@ne: % \end{quote} % This improves processing speed and reduces storage, but make the % code more difficult to read. Since this is a package which aims to % be easily understandable and adaptable, I will use a more verbose style: % \begin{quote} % \verb*:\advance \var by 1: % \end{quote} % \end{itemize} % To avoid possible confusion, \starTeX{} commands will be called % \emph{commands} in this document, while \TeX{} commands will be % called \emph{macros}. % % \subsection{States} % \begin{macro}{\State} % To avoid improper nesting, such as use of \stcs{psfig} within a % \stcs{table}, we introduce a global state variable. Its values are % given in table~\ref{tab:states}. % \begin{table} % \begin{center} % \begin{tabular}{|c|l|} % \hline % \textbf{Value}& \textbf{State}\\ % \hline\hline % \texttt{x}& Ordinary body text\\ % \texttt{p}& Inside a \stcs{psfig} caption\\ % \texttt{t}& Inside a \stcs{table} caption\\ % \texttt{r}& Inside a \stcs{table} row\\ % \hline % \end{tabular} % \end{center} % \caption{The possible values of \cs{State}}\label{tab:states} % \end{table} % The initial state is body text: % \begin{macrocode} \let \State = x % \end{macrocode} % \end{macro} % % \subsection{Command handling} % \begin{macro}{\Command} % \starTeX{} uses the syntax \stcs{\xx} for its commands rather than % the usual \cs{\xx}. This is easily implemented by making "<" an % active character calling the macro \cs{Command}. The command name is % the text between the "<" and a subsequent ">". % % \cs{Command} first checks whether the command immediately % follows a "" in which case it is being defined; % \cs{DefineCmd} handles that. Otherwise, \cs{Command} converts the % command name into lowercase and % checks whether it has been defined. If so, it is called; % otherwise an error message is produced and the command is ignored. % \begin{macrocode} \def \Command #1>{\ifDefining \def \Next {\lowercase{\DefineCmd{#1}}}% \else \lowercase{\expandafter\ifx \csname >#1\endcsname}\relax \Error{Unknown command <#1> ignored.}{}% \let \Next = \relax \else \def \Next {\lowercase{\csname >#1\endcsname}}% \fi \fi \Next } % \end{macrocode} % \end{macro} % The "<" character must be bound to \cs{Command}: % \begin{macrocode} {\catcode `\< = \active \global\let < = \Command } % \end{macrocode} % % \subsubsection{Internal form of command names} % All \starTeX{} commands are represented by a \TeX{} macro whose name % is constructed by \cs{csname}. To avoid confusion with predefined % \TeX{} macros, an initial ">"\footnote{The character \texttt{>} was % chosen as it cannot possibly occur in a command name.} % is inserted; for example, the name of \stcs{h1} is % represented by "\csname >h1\endcsname". % % \begin{macro}{\Cdef} % To simplify the declaration of \starTeX{} commands, the macro % \cs{Cdef} is defined. It takes two parameters: "#1" is the command name % (with no uppercase letters and no angle brackets), and % "#2" is the command definition. % \begin{macrocode} \def \Cdef #1#2{\expandafter\gdef \csname >#1\endcsname{#2}} % \end{macrocode} % \end{macro} % \begin{macro}{\Ccall} % In case we need to call \starTeX{} commands from \TeX{} code, a % \cs{Ccall} macro is introduced. % \begin{macrocode} \def \Ccall #1{\csname >#1\endcsname} % \end{macrocode} % \end{macro} % % \subsubsection{User-defined commands} % \begin{macro}{} % \begin{macro}{\ifDefining} % The implementation of \stcs{define} is a little sneaky; it just sets % a flag \cs{ifDefining}. When the following command name is % found, the \cs{Command} routine checks the state of the flag and % calls \cs{DefineCmd} when the flag is raised.\footnote{This means that % the user can insert text between the \stcs{define} and the command % name, and this will be typeset as normal text. There is a % slight chance that this might confuse some users, but I prefer this % solution to using much more complicated code.} % \begin{macrocode} \newif \ifDefining \Cdef {define}{\Definingtrue} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\DefineCmd} % The command \cs{DefineCmd} is used to define a new user command; % "#1" is the new command name (already translated into lowercase) and % "#2" is the definition. % The main job of \cs{DefineCmd} is to check whether the definition is % legal. There are two reasons why it may not be legal: % \begin{itemize} % \item The definition may be nested, as in % \begin{quote} % "......" % \end{quote} % This is checked using a counter \cs{CallLevel} which is % incremented whenever a user-defined command is called, and % decremented on return; see the definition of \cs{Call} and % \cs{Return} below. % % \item The command may already be defined. % \end{itemize} % If the definition is legal, \cs{FetchDef} is called to perform the % actual defining. % \begin{macrocode} \def \DefineCmd #1{\Definingfalse \ifnum \CallLevel>0 \Error{Nested definitions are not allowed;}% {the definition of <#1> is ignored.}\let \Next = \relax \else \expandafter\ifx \csname>#1\endcsname\relax \def \Next {\begingroup \catcode`\^^M = 12 \FetchDef{#1}}% \else \Error{Command <#1> already defined;}{this definition ignored.}% \def \Next {\begingroup \catcode`\^^M = 12 \IgnoreDef{#1}}% \fi \fi \Next } % \end{macrocode} % \end{macro} % \begin{macro}{\FetchDef} % \cs{FetchDef} defines the macro by using everything up to the % end-of-line mark as the definition. This implies modifying the % \cs{catcode} of the end-of-line character ("^^M"). Also note % that calls on \cs{Call} and \cs{Return} are inserted into the % definition. % \begin{macrocode} \begingroup \catcode`\^^M = 12 \gdef \FetchDef #1#2^^M{\expandafter% \gdef\csname>#1\endcsname {\Call #2\Return }\endgroup }% % \end{macrocode} % \end{macro} % \begin{macro}{\IgnoreDef} % I also define \cs{IgnoreDef} which is quite similar to % \cs{FetchDef}, but no command is % defined. It is used to ignore the rest of the line in case % the user tries an illegal definition. % \begin{macrocode} \gdef \IgnoreDef #1#2^^M{\endgroup }% \endgroup % \end{macrocode} % \end{macro} % \begin{macro}{\CallLevel} % Finally, we must declare the user command level counter % \cs{CallLevel}: % \begin{macrocode} \newcount \CallLevel % \end{macrocode} % \end{macro} % \begin{macro}{\Call} % \begin{macro}{\Return} % We must also define the two commands used for incrementing and % decrementing the counter: % \begin{macrocode} \def \Call {\global\advance \CallLevel by 1 } \def \Return {\global\advance \CallLevel by -1 } % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Catcode modifications} % \starTeX{} uses only one special character: "<", which must be % active. All the other special characters of \TeX{} and \LaTeX{} are % assigned suitable \cs{catcode}s turning them into ordinary % characters. % % \begin{macro}{\SpecialCatCodes} % \cs{SpecialCatCodes} sets the \cs{catcode}s to the \starTeX{} % values: % \begin{macrocode} \def \SpecialCatCodes {% \catcode `\\ = 12 \catcode `\{ = 12 \catcode `\} = 12 \catcode `\$ = 12 \catcode `\& = 12 \catcode `\# = 12 \catcode `\^ = 12 \catcode `\_ = 12 \catcode `\~ = 12 \catcode `\% = 12 \catcode `\< = \active } % \end{macrocode} % \end{macro} % \begin{macro}{\StandardCatCodes} % \cs{StandardCatCodes} restores the \cs{catcode}s to their normal % values. This is necessary when reading for instance style files. % \begin{macrocode} \def \StandardCatCodes {% \catcode `\\ = 0 \catcode `\{ = 1 \catcode `\} = 2 \catcode `\$ = 3 \catcode `\& = 4 \catcode `\# = 6 \catcode `\^ = 7 \catcode `\_ = 8 \catcode `\~ = \active \catcode `\% = 14 \catcode `\< = 12 } % \end{macrocode} % \end{macro} % % \subsubsection{Environments} % A \starTeX{} environment is a piece of text enclosed in a % \stcs{\xx}\dots\stcs{/\xx} pair. % % \begin{macro}{\NewEnvir} % \cs{NewEnvir} is used to start a new environment. It has three % parameters: "#1" is the name of the environment, "#2" is % the \TeX{} commands used to start the new environment (usually just % a \cs{begingroup}), and "#3" is % the \TeX{} commands used to terminate the environment (usually just % a \cs{endgroup}). % % \begin{macro}{\PrevEnv} % \begin{macro}{\PrevEnvLine} % \begin{macro}{\CurEnv} % \begin{macro}{\CurEnvExit} % \begin{macro}{\CurEnvLine} % \cs{NewEnvir} saves information about the current environment's name % (in \cs{CurEnv}), the line on which it starts (in \cs{CurEnvLine}) and % which command is used to exit it (in \cs{CurEnvExit}). It also keeps % tracks of the outer environment's name (in \cs{PrevEnv}) and start line % (in \cs{PrevEnvLine}) for better error reporting and error recovery. % \begin{macrocode} \def \NewEnvir #1#2#3{#2\relax \let \PrevEnv = \CurEnv \PrevEnvLine = \CurEnvLine \def \CurEnv {#1}\def \CurEnvExit {#3}\CurEnvLine = \inputlineno } % \end{macrocode} % We need default definitions of \cs{CurEnv} and \cs{CurEnvExit}: % \begin{macrocode} \def \CurEnv {}\def \CurEnvExit {\relax} % \end{macrocode} % We also need to declare the two line counters: % \begin{macrocode} \newcount \CurEnvLine \newcount \PrevEnvLine % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\EndEnvir} % \cs{EndEnvir} is used to terminate an environment. It check that the % correct environment is terminated, and tries to correct user % mistakes. It checks for the following situations: % \begin{itemize} % \item If the name of the environment to be terminated is the same as % that of the current environment, everything is OK, and we can safely % leave the current environment. % % \item If the name of the terminated environment is not the name of % the current one, but matches the name of the outer environment, % we assume that the user has forgotten a \stcs{/\xx} command. % An error message is given, and both the current environment and the % outer one are terminated. % % \item If the name of the terminated environment matches neither the % current nor the outer environment, we assume that the user has just % misspelled the command. The best thing we can do in this case is to % give an error message and ignore the command. If the user had % intended to terminate the current environment, we get erroneous % processing of the following text, but the situation will normalize % when the outer environment is terminated. % \end{itemize} % \begin{macrocode} \def \EndEnvir #1{% \ifTextEqual{#1}{\CurEnv}\let \Next = \CurEnvExit \else \EnvirError{#1}\fi \Next } % \end{macrocode} % \end{macro} % \begin{macro}{\EnvirError} % \cs{EnvirError} is an auxiliary command giving a proper error % message and placing---in \cs{Next}---the best command to recover % from the error. % \begin{macrocode} \def \EnvirError #1{\ifTextEqual{#1}{\PrevEnv}% \Error{<\CurEnv> on line \the\CurEnvLine\space terminated by .}{An extra has been inserted.}% \def \Next {\CurEnvExit \CurEnvExit }% \else \Error{<\CurEnv> on line \the\CurEnvLine\space terminated by .}{The will be ignored.}% \let \Next = \relax \fi } % \end{macrocode} % \end{macro} % % \subsection{Document styles} % \begin{macro}{