% % TeX version of the Inform Technical Manual, last revised 18/1/95 % \newif\iffiles % % Manual macros % % Page layout % \newif\ifshutup\shutupfalse \magnification=\magstep 1 \hoffset=0.15 true in \voffset=2\baselineskip % % General hacks % \def\PAR{\par} % % Font loading % \font\medfont=cmr10 scaled \magstep2 \font\bigfont=cmr10 scaled \magstep3 %\def\sectfont{\bf} \font\sectfont=cmbx12 \def\small{\sevenrm} \font\rhrm=cmr8 \font\rhit=cmsl8 % % Titles % \newcount\subsectno % Subsection number \def\rhead{} % The running head will go here % \def\newsection#1#2{% To begin a section... %\global\titletrue% Declare this as a title page \xdef\rhead{{\rhrm #1}\quad #2}% Initialise running head and ssn \subsectno=0% \iffiles \write\conts{\string\sli\string{#1\string}\string{#2\string}\string{\the\pageno\string}}% \fi } % \def\section#1#2{\vskip 1 true in\goodbreak\newsection{#1}{#2} \noindent{\sectfont #1\quad #2}\bigskip\noindent} % % Headers and footers % \newif\iftitle \headline={\iftitle\hfil\global\titlefalse% \else{\hfil{\rhit \rhead}}% \fi} \footline={\ifnum\pageno<0\hfil{\tenbf\romannumeral -\pageno}% \else\hfil{\tenbf \number\pageno}\fi} %\footline={\ifnum\pageno=1\hfil\else\hfil{\tenbf \number\pageno}\fi} % % (Old date-stamping version:) % \footline={\hfil{\rm \number\pageno}\hfil{\rm \number\day/\number\month}} % % If this works I'll be impressed % \font\ninerm=cmr9 \font\ninei=cmmi9 \font\ninesy=cmsy9 \font\ninebf=cmbx9 \font\eightbf=cmbx8 \font\ninett=cmtt9 \font\nineit=cmti9 \font\ninesl=cmsl9 \def\ninepoint{\def\rm{\fam0\ninerm}% \textfont0=\ninerm \textfont1=\ninei \textfont2=\ninesy \textfont3=\tenex \textfont\itfam=\nineit \def\it{\fam\itfam\nineit}% \textfont\slfam=\ninesl \def\sl{\fam\slfam\ninesl}% \textfont\ttfam=\ninett \def\tt{\fam\ttfam\ninett}% \textfont\bffam=\ninebf \normalbaselineskip=11pt \setbox\strutbox=\hbox{\vrule height8pt depth3pt width0pt}% \normalbaselines\rm} \def\tenpoint{\def\rm{\fam0\tenrm}% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont3=\tenex \textfont\itfam=\tenit \def\it{\fam\itfam\tenit}% \textfont\slfam=\tensl \def\sl{\fam\slfam\tensl}% \textfont\ttfam=\tentt \def\tt{\fam\ttfam\tentt}% \textfont\bffam=\tenbf \normalbaselineskip=12pt \setbox\strutbox=\hbox{\vrule height8.5pt depth3.5pt width0pt}% \normalbaselines\rm} \parindent=30pt \def\inpar{\hangindent40pt\hangafter1\qquad} \def\onpar{\par\hangindent40pt\hangafter0} \newskip\ttglue \ttglue=.5em plus.25em minus.15em \def\orsign{$\mid\mid$} \outer\def\begindisplay{\obeylines\startdisplay} {\obeylines\gdef\startdisplay#1 {\catcode`\^^M=5$$#1\halign\bgroup\indent##\hfil&&\qquad##\hfil\cr}} \outer\def\enddisplay{\crcr\egroup$$} \chardef\other=12 \def\ttverbatim{\begingroup \catcode`\\=\other \catcode`\{=\other \catcode`\}=\other \catcode`\$=\other \catcode`\&=\other \catcode`\#=\other \catcode`\%=\other \catcode`\~=\other \catcode`\_=\other \catcode`\^=\other \obeyspaces \obeylines \tt} {\obeyspaces\gdef {\ }} \outer\def\beginstt{$$\let\par=\endgraf \ttverbatim\ninett \parskip=0pt \catcode`\|=0 \rightskip=-5pc \ttfinish} \outer\def\begintt{$$\let\par=\endgraf \ttverbatim \parskip=0pt \catcode`\|=0 \rightskip=-5pc \ttfinish} {\catcode`\|=0 |catcode`|\=\other |obeylines |gdef|ttfinish#1^^M#2\endtt{#1|vbox{#2}|endgroup$$}} \catcode`\|=\active {\obeylines\gdef|{\ttverbatim\spaceskip=\ttglue\let^^M=\ \let|=\endgroup}} \def\beginlines{\par\begingroup\nobreak\medskip\parindent=0pt \nobreak\ninepoint \obeylines \everypar{\strut}} \def\endlines{\endgroup\medbreak\noindent} \def\<#1>{\leavevmode\hbox{$\langle$#1\/$\rangle$}} \def\dbend{{$\triangle$}} \def\d@nger{\medbreak\begingroup\clubpenalty=10000 \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2 \hbox to0pt{\hskip-\hangindent\dbend\hfill}\ninepoint} \outer\def\danger{\d@nger} \def\dd@nger{\medskip\begingroup\clubpenalty=10000 \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2 \hbox to0pt{\hskip-\hangindent\dbend\kern 1pt\dbend\hfill}\ninepoint} \outer\def\ddanger{\dd@nger} \def\enddanger{\endgraf\endsubgroup} \def\cstok#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt \hbox{\vphantom{\tt/}\thinspace{\tt#1}\thinspace}} \kern1pt\hrule}\vrule}\thinspace} \newcount\exno \exno=0 \def\xd@nger{% \begingroup\def\par{\endgraf\endgroup\medbreak}\ninepoint} \outer\def\warning{\medbreak \noindent\llap{$\bullet$\rm\kern.15em}% {\ninebf WARNING}\par\nobreak\noindent} \outer\def\exercise{\medbreak \global\advance\exno by 1 \noindent\llap{$\bullet$\rm\kern.15em}% {\ninebf EXERCISE \bf\the\exno}\par\nobreak\noindent} \def\dexercise#1{\global\advance\exno by 1 \medbreak\noindent\llap{$\bullet$\rm\kern.15em}% #1{\eightbf ~EXERCISE \bf\the\exno}\hfil\break} \outer\def\dangerexercise{\xd@nger \dexercise{\dbend}} \outer\def\ddangerexercise{\xd@nger \dexercise{\dbend\dbend}} \newwrite\ans% \newwrite\conts% \iffiles \immediate\openout\conts=$.games.infocom.ftp.toolkit.mandir.conts \fi \iffiles\else\outer\def\answer#1{\par\medbreak}\shutuptrue\fi \newwrite\inx \ifshutup\else \immediate\openout\inx=$.games.infocom.ftp.toolkit.mandir.inxdata \fi \def\marginstyle{\sevenrm % \vrule height6pt depth2pt width0pt } % \newif\ifsilent \def\specialhat{\ifmmode\def\next{^}\else\let\next=\beginxref\fi\next} \def\beginxref{\futurelet\next\beginxrefswitch} \def\beginxrefswitch{\ifx\next\specialhat\let\next=\silentxref \else\silentfalse\let\next=\xref\fi \next} \catcode`\^=\active \let ^=\specialhat \def\silentxref^{\silenttrue\xref} \newif\ifproofmode \proofmodetrue % \def\xref{\futurelet\next\xrefswitch} \def\xrefswitch{\begingroup\ifx\next|\aftergroup\vxref \else\ifx\next\<\aftergroup\anglexref \else\aftergroup\normalxref \fi\fi \endgroup} \def\vxref|{\catcode`\\=\active \futurelet\next\vxrefswitch} \def\vxrefswitch#1|{\catcode`\\=0 \ifx\next\empty\def\xreftype{2}% \def\next{{\tt\text}}% \else\def\xreftype{1}\def\next{{\tt\text}}\fi % \edef\text{#1}\makexref} {\catcode`\|=0 \catcode`\\=\active |gdef\{}} \def\anglexref\<#1>{\def\xreftype{3}\def\text{#1}% \def\next{\<\text>}\makexref} % \def\normalxref#1{\def\xreftype{0}\def\text{#1}\let\next=\text\makexref} \def\makexref{\ifproofmode% \xdef\writeit{\write\inx{\text\space!\xreftype\space \noexpand\number\pageno.}}\iffiles\writeit\fi \else\ifhmode\kern0pt \fi\fi \ifsilent\ignorespaces\else\next\fi} \newdimen\fullhsize \def\fullline{\hbox to\fullhsize} \let\lr=L \newbox\leftcolumn \def\doubleformat{\shipout\vbox{\makeheadline \fullline{\box\leftcolumn\hfil\columnbox} \makefootline} \advancepageno} \def\tripleformat{\shipout\vbox{\makeheadline \fullline{\box\leftcolumn\hfil\box\midcolumn\hfil\columnbox} \makefootline} \advancepageno} \def\columnbox{\leftline{\pagebody}} \newbox\leftcolumn \newbox\midcolumn \def\beginindex{ \fullhsize=6.5true in \hsize=2.1true in \global\def\makeheadline{\vbox to 0pt{\vskip-22.5pt \fullline{\vbox to8.5pt{}\the\headline}\vss}\nointerlineskip} \global\def\makefootline{\baselineskip=24pt \fullline{\the\footline}} \output={\if L\lr \global\setbox\leftcolumn=\columnbox \global\let\lr=M \else\if M\lr \global\setbox\midcolumn=\columnbox \global\let\lr=R \else\tripleformat \global\let\lr=L\fi\fi \ifnum\outputpenalty>-20000 \else\dosupereject\fi} \begingroup \parindent=1em \maxdepth=\maxdimen \def\par{\endgraf \futurelet\next\inxentry} \obeylines \everypar={\hangindent 2\parindent} \exhyphenpenalty=10000 \raggedright} \def\inxentry{\ifx\next\sub \let\next=\subentry \else\ifx\next\endindex \let\next=\vfill \else\let\next=\mainentry \fi\fi\next} \def\endindex{\mark{}\break\endgroup \supereject \if L\lr \else\null\vfill\eject\fi \if L\lr \else\null\vfill\eject\fi } \let\sub=\indent \newtoks\maintoks \newtoks\subtoks \def\mainentry#1,{\mark{}\noindent \maintoks={#1}\mark{\the\maintoks}#1,} \def\subentry\sub#1,{\mark{\the\maintoks}\indent \subtoks={#1}\mark{\the\maintoks\sub\the\subtoks}#1,} \def\subsection#1{\medbreak\par\noindent{\bf #1}\qquad} % For contents \def\cl#1#2{\bigskip\par\noindent{\bf #1}\quad {\bf #2}} \def\li#1#2#3{\smallskip\par\noindent\hbox to 5 in{{\bf #1}\quad #2\dotfill #3}} \def\sli#1#2#3{\par\noindent\hbox to 5 in{\qquad\item{#1}\quad #2\dotfill #3}} \def\fcl#1#2{\bigskip\par\noindent\hbox to 5 in{\phantom{\bf 1}\quad {\bf #1}\dotfill #2}} % Epigrams \def\poem{\begingroup\narrower\narrower\narrower\obeylines\ninepoint} \def\widepoem{\begingroup\narrower\narrower\obeylines\ninepoint} \def\verywidepoem{\begingroup\narrower\obeylines\ninepoint} \def\quote{\medskip\begingroup\narrower\narrower\noindent\ninepoint} \def\poemby#1#2{\par\smallskip\qquad\qquad\qquad\qquad\qquad -- #1, {\it #2} \tenpoint\endgroup\bigskip} \def\widepoemby#1#2{\par\smallskip\qquad\qquad\qquad -- #1, {\it #2} \tenpoint\endgroup\bigskip} \def\quoteby#1{\par\smallskip\qquad\qquad\qquad\qquad\qquad -- #1\tenpoint\endgroup\bigskip} \def\endquote{\par\tenpoint\endgroup\medskip} % % End of macros \def\subtitle#1{\bigbreak\noindent{\bf #1}\medskip} \titletrue\tenpoint \centerline{\bigfont The Inform Technical Manual} \vskip 0.5in \centerline{\sl for revision 5.4, last updated 18/1/95} \vskip 0.5in \sli{1}{Introduction}{2} \sli{2}{Recondite directives}{2} \sli{3}{Unusual constant forms}{4} \sli{4}{String indirection and low strings}{5} \sli{5}{Game control commands and keyboard reading}{5} \sli{6}{Obselete commands}{7} \sli{7}{The abbreviations optimiser}{8} \sli{8}{Dictionary and parsing table formats}{9} \sli{9}{Porter's notes}{12} \sli{10}{Geography and history of the source code}{14} \vfill\eject \section{1}{Introduction} This is a short collection of notes on low-level matters covering what is neither in {\sl The Inform Designer's Manual} nor the assembly-language documentation in {\sl The Specification of the Z-machine}. The Designer's Manual is, however, intended to be entirely self-contained for all practical purposes. If this document contains nothing either interesting or useful, I feel I shall have achieved my purpose. It contains much of the commentary which used to be in the source code's header, such as its modification history, notes on porting the Inform compiler to new machines and documentation of obselete or internally-used features. I anticipate revising this (though not necessarily the Designer's Manual) each time the source code is updated. \medskip \hbox to\hsize{\hfill\it Graham Nelson} \hbox to\hsize{\hfill\it Magdalen College, Oxford} \hbox to\hsize{\hfill\it September 1994} \medskip This is now updated to v1405 (still of release 5.4) and covers recent maintenance. \medskip \hbox to\hsize{\hfill\it January 1995} \ninepoint \section{2}{Recondite directives} These are the directives airily dismissed as `recondite' in \S A1 to the Designer's Manual. \beginstt Default ; \endtt If the constant has not yet been defined, define it with this value. (In |Verblib| this is used to give constants like |MAX_CARRIED| their default values if the main game source has not already set them; hence the name.) \beginstt Stub ; \endtt If the routine has not yet been defined, define one which has $n$ local variables and simply returns false. (Setting the number of local variables prevents the game from calling a routine with more arguments than it has local variables to put them in; this should not do any harm to the interpreter, but neither does a little caution.) This is how ``entry point'' routines are handled: the |Grammar| library file stubs out any undeclared entry points. \beginstt Dictionary ; \endtt Enters || in dictionary, and makes a new constant for its address. This is not so much recondite as obselete; nowadays one would write something like \beginstt Constant frog_word 'frog'; \endtt but in any case now that one can write simply |'frog'| the need has gone away. \beginstt System_file; \endtt Declares the present file to be a `system file'. The only way in which these differ from other files is that if Inform has been told to |Replace| a given routine, it will ignore a definition of this routine in a `system file'. Thus |Parser| and |Verblib| are system files, and conceivably other user-written library extensions (for magic, say) might want to be. \beginstt Lowstring ; \endtt Puts |string| in the ``low strings" area of the Z-machine (an area in the lowest 64K of memory which holds static strings, usually to hold abbreviations), and creates a constant with the given |name| to hold its word address. Any string which is to be used with the |@| string escape must be declared in this low strings area. (But the use of the |@| string escape is clumsy and there are probably better ways to get the effect in Inform 5.) \beginstt Version ; \endtt sets the game file version (3 for Standard games, 5 for Advanced; 4 and 6 are present for completeness). This directive isn't so much recondite as redundant; the preferred way is to either set |-v3| or some such at the command line, or to include a |switches| directive, e.g. \beginstt Switches v3; \endtt \medskip The remaining directives are for debugging Inform only: \beginstt Listsymbols; Listdict; Listverbs; Listobjects; \endtt are fairly self-explanatory (be warned: they can produce a lot of output). In addition, a number of tracing modes can be turned on and off in mid-pass: \beginstt Trace Btrace Ltrace Etrace NoTrace NoBtrace NoLtrace NoEtrace \endtt |Trace| is an assembly-language style trace, with addresses and bytes as compiled; |Btrace| is the same, but produced on both passes, not just on pass 2; |Ltrace| traces each internal line of code; and |Etrace|, the highest-level of these, traces the expression evaluator at work by printing out the expression trees made and the assembly source these are reduced to. (A more vehement, less legible version is |etrace full|, which shows the process in minute detail.) \section{3}{Unusual constant forms} There are more constant forms in Inform 5 than are dreamt of in the Designer's Manual. Some are obselete, others obscure. To begin with, Inform predefines a number of constants which are used by the library: \beginstt adjectives_table (byte address) preactions_table (byte address) actions_table (byte address) code_offset (packed address of code) strings_offset (packed address of strings) version_number (3 or 5 as appropriate) largest_object (the number of the largest created object + 255) dict_par1 dict_par2 dict_par3 \endtt which can be read by something like \beginstt lookup = #adjectives_table; \endtt One does occasionally want to know the largest object number in high-level code, but the library provides a variable |top_object| such that the legal object numbers are $$ 1 \leq n \leq \hbox{|top_object|} $$ and using this is preferable. The |dict_par| constants are byte offsets into a dictionary entry of the three bytes of data about the word, and are provided because these offsets are different between Standard and Advanced games; thus, the parser uses these constants to ensure portability between the two. \medskip A constant beginning |#a$| means ``the action number of this action routine''. Thus, |#a$TakeSub| is equivalent to the more usual |##Take|. \medskip A constant beginning |#w$|, followed by a word of text, has as value the address of the given word in the dictionary (Inform will give an error at compile time if no such word is present). Largely obselete. \medskip A constant beginning |#n$|, followed by a word of text, has as value the address of the given word in the dictionary (Inform adds it to the dictionary as a new word if it is not already there). Thus, |#n$leopard| is equivalent to |'leopard'|. However, this constant form is still useful to enter single-letter words into the dictionary (like |y|, which the parser defines as an abbreviation for ``yes'') since |'y'| would instead mean the ASCII value of the character `y'. \medskip A constant beginning |#r$|, followed by a routine name, gives the (packed) address of the given routine. This is chiefly useful for changing the routine-valued properties of an object in mid-game, e.g. \beginstt lamp.before = #r$NewBeforeRoutine; \endtt where |NewBeforeRoutine| is defined as a global routine somewhere. \section{4}{String indirection and low strings} Inside a static string (in double-quotes), the string escape |@nn|, an |@| sign followed by a two digit number, means ``print the $n$-th string variable here''. |nn| is a decimal number from |00| to |31|. Now such a variable string can be set with the \beginstt String ; \endtt which means that any string to be used in this way has to have been defined as a ``low string'' (see above). For example, \beginstt Lowstring L_Frog "little green frog"; ... String 0 #L_Frog; "You notice a @00!^"; \endtt will result in the output \beginstt You notice a little green frog! \endtt Actually, since the first 32 entries of the ``synonyms table'' in the Z-machine are reserved for this purpose, the command |String n x| is in fact equivalent to \beginstt (0-->12)-->n=x; \endtt Due to a minor design infelicity of the Z-machine, the more friendly-looking usage \beginstt String 0 "illegal frog"; \endtt will work in a Standard game but may unpredictably fail in an Advanced one exceeding 128K in length; hence the need to ensure all relevant strings are ``low'' (in the bottom 128K of memory). \section{5}{Game control commands and keyboard reading} \beginstt quit; \endtt (Actually an assembly language opcode.) This quits the game (at once, with no confirmatory question to the user): all games must end this way, since it is illegal to return from the |Main| routine). \beginstt restart; \endtt (Similarly an opcode.) Restarts the game exactly to its initial state, losing the previous state for good. \beginstt save