lowlevel-scope.tex /size: 9 Kb    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/lowlevel
2
3% \hfil \hss
4% spread
5
6\environment lowlevel-style
7
8\startdocument
9  [title=scope,
10   color=middleblue]
11
12\startsectionlevel[title=Introduction]
13
14When I visited the file where register allocations are implemented I wondered to
15what extend it made sense to limit allocation to global instances only. This
16chapter deals with this phenomena.
17
18\stopsectionlevel
19
20\startsectionlevel[title=Registers]
21
22In \TEX\ definitions can be local or global. Most assignments are local within a
23group. Registers and definitions can be assigned global by using the \type
24{\global} prefix. There are also some properties that are global by design, like
25\type {\prevdepth}. A mixed breed are boxes. When you tweak its dimensions you
26actually tweak the current box, which can be an outer level. Compare:
27
28\starttyping[option=TEX]
29\scratchcounter = 1
30here the counter has value 1
31\begingroup
32    \scratchcounter = 2
33    here the counter has value 2
34\endgroup
35here the counter has value 1
36\stoptyping
37
38with:
39
40\starttyping[option=TEX]
41\setbox\scratchbox=\hbox{}
42here the box has zero width
43\begingroup
44    \wd\scratchbox=10pt
45    here the box is 10pt wide
46\endgroup
47here the box is 10pt wide
48\stoptyping
49
50It all makes sense so a remark like \quotation {Assignments to box dimensions are
51always global} are sort of confusing. Just look at this:
52
53\startbuffer
54\setbox\scratchbox=\hbox to 20pt{}
55here the box is \the\wd\scratchbox\ wide\par
56\begingroup
57    \setbox\scratchbox=\hbox{}
58    here the box is \the\wd\scratchbox\ wide\par
59    \begingroup
60        \wd\scratchbox=15pt
61        here the box is \the\wd\scratchbox\ wide\par
62    \endgroup
63    here the box is \the\wd\scratchbox\ wide\par
64\endgroup
65here the box is \the\wd\scratchbox\ wide\par
66\stopbuffer
67
68\typebuffer[option=TEX] \startlines \getbuffer \stoplines
69
70If you don't think about it, what happens is what you expect. Now watch the next
71variant:
72
73\startbuffer
74\setbox\scratchbox=\hbox to 20pt{}
75here the box is \the\wd\scratchbox\ wide\par
76\begingroup
77    \setbox\scratchbox=\hbox{}
78    here the box is \the\wd\scratchbox\ wide\par
79    \begingroup
80        \global\wd\scratchbox=15pt
81        here the box is \the\wd\scratchbox\ wide\par
82    \endgroup
83    here the box is \the\wd\scratchbox\ wide\par
84\endgroup
85here the box is \the\wd\scratchbox\ wide\par
86\stopbuffer
87
88The \type {\global} is only effective for the current box. It is good to realize
89that when we talk registers, the box register behaves just like any other
90register but the manipulations happen to the current one.
91
92\typebuffer \startlines \getbuffer \stoplines
93
94\startbuffer
95\scratchdimen=20pt
96here the dimension is \the\scratchdimen\par
97\begingroup
98    \scratchdimen=0pt
99    here the dimension is \the\scratchdimen\par
100    \begingroup
101        \global\scratchdimen=15pt
102        here the dimension is \the\scratchdimen\par
103    \endgroup
104    here the dimension is \the\scratchdimen\par
105\endgroup
106here the dimension is \the\scratchdimen\par
107\stopbuffer
108
109\typebuffer[option=TEX] \startlines \getbuffer \stoplines
110
111\stopsectionlevel
112
113\startsectionlevel[title=Allocation]
114
115The plain \TEX\ format has set some standards and one of them is that registers
116are allocated with \type {\new...} commands. So we can say:
117
118\starttyping[option=TEX]
119\newcount\mycounta
120\newdimen\mydimena
121\stoptyping
122
123These commands take a register from the pool and relate the given name to that
124entry. In \CONTEXT\ we have a bunch of predefined scratch registers for general
125use, like:
126
127\startbuffer
128scratchcounter    : \meaningfull\scratchcounter
129scratchcounterone : \meaningfull\scratchcounterone
130scratchcountertwo : \meaningfull\scratchcountertwo
131scratchdimen      : \meaningfull\scratchdimen
132scratchdimenone   : \meaningfull\scratchdimenone
133scratchdimentwo   : \meaningfull\scratchdimentwo
134\stopbuffer
135
136\typebuffer[option=TEX]
137
138The meaning reveals what these are:
139
140\startlines \tttf \getbuffer \stoplines
141
142You can use the numbers directly but that is a bad idea because they can clash!
143In the original \TEX\ engine there are only 256 registers and some are used by
144the engine and the core of a macro package itself, so that leaves a little amount
145for users. The \ETEX\ extension lifted that limitation and bumped to 32K and
146\LUATEX\ upped that to 64K. One could go higher but what makes sense? These
147registers are taking part of the fixed memory slots because that makes nested
148(grouped) usage efficient and access fast. The number you see above is deduced
149from the so called command code (here indicated by \type {\count}) and an index
150encoded in the same token. So, \type {\scratchcounter} takes a single token
151contrary to the verbose \type {\count257} that takes four tokens where the number
152gets parsed every time it is needed. But those are details that a user can
153forget.
154
155As mentioned, commands like \type {\newcount \foo} create a global control
156sequence \type {\foo} referencing a counter. You can locally redefine that
157control sequence unless in \LUAMETATEX\ you have so called overload mode enabled.
158You can do local or global assignments to these registers.
159
160\starttyping[option=TEX]
161\scratchcounter = 123
162\begingroup
163    \scratchcounter = 456
164    \begingroup
165        \global\scratchcounter = 789
166    \endgroup
167\endgroup
168\stoptyping
169
170And in both cases count register 257 is set. When an assignment is global,
171all current values to that register get the same value. Normally this is all
172quite transparent: you get what you ask for. However the drawback is that
173as a user you cannot know what variables are already defined, which means
174that this will fail (that is: it will issue a message):
175
176\starttyping[option=TEX]
177\newcount\scratchcounter
178\stoptyping
179
180as will the second line in:
181
182\starttyping[option=TEX]
183\newcount\myscratchcounter
184\newcount\myscratchcounter
185\stoptyping
186
187In \CONTEXT\ the scratch registers are visible but there are lots of internally
188used ones are protected from the user by more obscure names. So what if you want
189to use your own register names without \CONTEXT\ barking to you about not being
190able to define it. This is why in \LMTX\ (and maybe some day in \MKIV) we now
191have local definitions:
192
193\startbuffer
194\begingroup
195  \newlocaldimen\mydimena     \mydimena1\onepoint
196  \newlocaldimen\mydimenb     \mydimenb2\onepoint
197  (\the\mydimena,\the\mydimenb)
198  \begingroup
199    \newlocaldimen\mydimena   \mydimena3\onepoint
200    \newlocaldimen\mydimenb   \mydimenb4\onepoint
201    \newlocaldimen\mydimenc   \mydimenc5\onepoint
202    (\the\mydimena,\the\mydimenb,\the\mydimenc)
203    \begingroup
204      \newlocaldimen\mydimena \mydimena6\onepoint
205      \newlocaldimen\mydimenb \mydimenb7\onepoint
206      (\the\mydimena,\the\mydimenb)
207    \endgroup
208    \newlocaldimen\mydimend   \mydimend8\onepoint
209    (\the\mydimena,\the\mydimenb,\the\mydimenc,\the\mydimend)
210  \endgroup
211  (\the\mydimena,\the\mydimenb)
212\endgroup
213\stopbuffer
214
215\typebuffer[option=TEX]
216
217The allocated registers get zero values but you can of course set them to any
218value that fits their nature:
219
220\startlines \getbuffer \stoplines
221
222\startbuffer
223\begingroup
224  \setnewlocaldimen\mydimena     1\onepoint
225  \setnewlocaldimen\mydimenb     2\onepoint
226  (\the\mydimena,\the\mydimenb)
227  \begingroup
228    \setnewlocaldimen\mydimena   3\onepoint
229    \setnewlocaldimen\mydimenb   4\onepoint
230    \setnewlocaldimen\mydimenc   5\onepoint
231    (\the\mydimena,\the\mydimenb,\the\mydimenc)
232    \begingroup
233      \setnewlocaldimen\mydimena 6\onepoint
234      \setnewlocaldimen\mydimenb 7\onepoint
235      (\the\mydimena,\the\mydimenb)
236    \endgroup
237    \setnewlocaldimen\mydimend   8\onepoint
238    (\the\mydimena,\the\mydimenb,\the\mydimenc,\the\mydimend)
239  \endgroup
240  (\the\mydimena,\the\mydimenb)
241\endgroup
242\stopbuffer
243
244You can also use the next variant where you also pass the initial value:
245
246\typebuffer[option=TEX]
247
248So, again we get:
249
250\startlines \getbuffer \stoplines
251
252When used in the body of the macro there is of course a little overhead
253involved in the repetitive allocation but normally that can be neglected.
254
255\stopsectionlevel
256
257\startsectionlevel[title=Files]
258
259When adding these new allocators I also wondered about the read and write
260allocators. We don't use them in \CONTEXT\ but maybe users like them, so let's
261give an example and see what more demands they have:
262
263\starttyping[option=TEX]
264\integerdef\StartHere\numexpr\inputlineno+2\relax
265\starthiding
266SOME LINE 1
267SOME LINE 2
268SOME LINE 3
269SOME LINE 4
270\stophiding
271\integerdef\StopHere\numexpr\inputlineno-2\relax
272\stoptyping
273
274% We need to be in the file!
275
276\integerdef\StartHere\numexpr\inputlineno+2\relax
277\starthiding
278SOME LINE 1
279SOME LINE 2
280SOME LINE 3
281SOME LINE 4
282\stophiding
283\integerdef\StopHere\numexpr\inputlineno-2\relax
284
285\startbuffer
286\begingroup
287  \newlocalread\myreada
288  \immediate\openin\myreada {lowlevel-scope.tex}
289  \dostepwiserecurse{\StopHere}{\StartHere}{-1}{
290    \readline\myreada line #1 to \scratchstring #1 : \scratchstring \par
291  }
292  \blank
293  \dostepwiserecurse{\StartHere}{\StopHere}{1}{
294    \read    \myreada line #1 to \scratchstring #1 : \scratchstring \par
295  }
296  \immediate\closein\myreada
297\endgroup
298\stopbuffer
299
300\typebuffer[option=TEX]
301
302Here, instead of hard coded line numbers we used the stored values. The
303optional \type {line} keyword is a \LMTX\ speciality.
304
305\startlines \getbuffer \stoplines
306
307Actually an application can be found in a small (demonstration) module:
308
309\startbuffer
310\usemodule[system-readers]
311\stopbuffer
312
313\typebuffer[option=TEX] \getbuffer
314
315This provides the code for doing this:
316
317\starttyping[option=TEX]
318\startmarkedlines[test]
319SOME LINE 1
320SOME LINE 2
321SOME LINE 3
322\stopmarkedlines
323
324\begingroup
325  \newlocalread\myreada
326  \immediate\openin\myreada {\markedfilename{test}}
327  \dostepwiserecurse{\lastmarkedline{test}}{\firstmarkedline{test}}{-1}{
328    \readline\myreada line #1 to \scratchstring #1 : \scratchstring \par
329  }
330  \immediate\closein\myreada
331\endgroup
332\stoptyping
333
334As you see in these examples, we an locally define a read channel without
335getting a message about it already being defined.
336
337\stopsectionlevel
338
339\stopdocument
340
341
342