beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / tex / scanning.w
blob0a9276c7db738e3ca2aa0cb7e5fa25a1fa6e6f1f
1 % scanning.w
3 % Copyright 2009-2012 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software; you can redistribute it and/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation; either version 2 of the License, or (at your
10 % option) any later version.
12 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20 @ @c
22 #include "ptexlib.h"
24 @ @c
25 #define prev_depth cur_list.prev_depth_field
26 #define space_factor cur_list.space_factor_field
27 #define par_shape_ptr equiv(par_shape_loc)
28 #define font_id_text(A) cs_text(font_id_base+(A))
30 #define attribute(A) eqtb[attribute_base+(A)].hh.rh
31 #define dimen(A) eqtb[scaled_base+(A)].hh.rh
32 #undef skip
33 #define skip(A) eqtb[skip_base+(A)].hh.rh
34 #define mu_skip(A) eqtb[mu_skip_base+(A)].hh.rh
35 #define count(A) eqtb[count_base+(A)].hh.rh
36 #define box(A) equiv(box_base+(A))
38 static void scan_expr(void);
40 @ Let's turn now to some procedures that \TeX\ calls upon frequently to digest
41 certain kinds of patterns in the input. Most of these are quite simple;
42 some are quite elaborate. Almost all of the routines call |get_x_token|,
43 which can cause them to be invoked recursively.
45 The |scan_left_brace| routine is called when a left brace is supposed to be
46 the next non-blank token. (The term ``left brace'' means, more precisely,
47 a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
48 appear before the |left_brace|.
51 void scan_left_brace(void)
52 { /* reads a mandatory |left_brace| */
53 /* Get the next non-blank non-relax non-call token */
54 do {
55 get_x_token();
56 } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
58 if (cur_cmd != left_brace_cmd) {
59 print_err("Missing { inserted");
60 help4("A left brace was mandatory here, so I've put one in.",
61 "You might want to delete and/or insert some corrections",
62 "so that I will find a matching right brace soon.",
63 "If you're confused by all this, try typing `I}' now.");
64 back_error();
65 cur_tok = left_brace_token + '{';
66 cur_cmd = left_brace_cmd;
67 cur_chr = '{';
68 incr(align_state);
72 @ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
73 by optional spaces; `\.{\\relax}' is not ignored here.
76 void scan_optional_equals(void)
78 /* Get the next non-blank non-call token */
79 do {
80 get_x_token();
81 } while (cur_cmd == spacer_cmd);
82 if (cur_tok != other_token + '=')
83 back_input();
86 @ Here is a procedure that sounds an alarm when mu and non-mu units
87 are being switched.
90 static void mu_error(void)
92 print_err("Incompatible glue units");
93 help1("I'm going to assume that 1mu=1pt when they're mixed.");
94 error();
97 @ The next routine `|scan_something_internal|' is used to fetch internal
98 numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
99 when expanding constructions like `\.{\\the\\toks0}' and
100 `\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
101 procedure, which calls |scan_something_internal|; on the other hand,
102 |scan_something_internal| also calls |scan_int|, for constructions like
103 `\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
104 have to declare |scan_int| as a |forward| procedure. A few other
105 procedures are also declared at this point.
107 \TeX\ doesn't know exactly what to expect when
108 |scan_something_internal| begins. For example, an integer or
109 dimension or glue value could occur immediately after `\.{\\hskip}';
110 and one can even say \.{\\the} with respect to token lists in
111 constructions like `\.{\\xdef\\o\{\\the\\output\}}'. On the other
112 hand, only integers are allowed after a construction like
113 `\.{\\count}'. To handle the various possibilities,
114 |scan_something_internal| has a |level| parameter, which tells the
115 ``highest'' kind of quantity that |scan_something_internal| is allowed
116 to produce. Eight levels are distinguished, namely |int_val|,
117 |attr_val|, |dimen_val|, |glue_val|, |mu_val|, |dir_val|, |ident_val|,
118 and |tok_val|.
120 The output of |scan_something_internal| (and of the other routines
121 |scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
122 variable |cur_val|, and its level is put into |cur_val_level|. The highest
123 values of |cur_val_level| are special: |mu_val| is used only when
124 |cur_val| points to something in a ``muskip'' register, or to one of the
125 three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
126 |ident_val| is used only when |cur_val| points to a font identifier;
127 |tok_val| is used only when |cur_val| points to |null| or to the reference
128 count of a token list. The last two cases are allowed only when
129 |scan_something_internal| is called with |level=tok_val|.
131 If the output is glue, |cur_val| will point to a glue specification, and
132 the reference count of that glue will have been updated to reflect this
133 reference; if the output is a nonempty token list, |cur_val| will point to
134 its reference count, but in this case the count will not have been updated.
135 Otherwise |cur_val| will contain the integer or scaled value in question.
138 int cur_val; /* value returned by numeric scanners */
139 int cur_val1; /* delcodes are sometimes 51 digits */
140 int cur_val_level; /* the ``level'' of this value */
142 #define scanned_result(A,B) do { \
143 cur_val=A; \
144 cur_val_level=B; \
145 } while (0)
147 @ When a |glue_val| changes to a |dimen_val|, we use the width component
148 of the glue; there is no need to decrease the reference count, since it
149 has not yet been increased. When a |dimen_val| changes to an |int_val|,
150 we use scaled points so that the value doesn't actually change. And when a
151 |mu_val| changes to a |glue_val|, the value doesn't change either.
154 static void downgrade_cur_val(boolean delete_glue)
156 halfword m;
157 if (cur_val_level == glue_val_level) {
158 m = cur_val;
159 cur_val = width(m);
160 if (delete_glue)
161 delete_glue_ref(m);
162 } else if (cur_val_level == mu_val_level) {
163 mu_error();
165 decr(cur_val_level);
168 static void negate_cur_val(boolean delete_glue)
170 halfword m;
171 if (cur_val_level >= glue_val_level) {
172 m = cur_val;
173 cur_val = new_spec(m);
174 if (delete_glue)
175 delete_glue_ref(m);
176 /* Negate all three glue components of |cur_val| */
177 negate(width(cur_val));
178 negate(stretch(cur_val));
179 negate(shrink(cur_val));
181 } else {
182 negate(cur_val);
186 @ Some of the internal items can be fetched both routines,
187 and these have been split off into the next routine, that
188 returns true if the command code was understood
191 static boolean short_scan_something_internal(int cmd, int chr, int level,
192 boolean negative)
194 halfword m; /* |chr_code| part of the operand token */
195 halfword q; /* general purpose index */
196 int p; /* index into |nest| */
197 int save_cur_chr;
198 boolean succeeded = true;
199 m = chr;
200 switch (cmd) {
201 case assign_toks_cmd:
202 scanned_result(equiv(m), tok_val_level);
203 break;
204 case assign_int_cmd:
205 scanned_result(eqtb[m].cint, int_val_level);
206 break;
207 case assign_attr_cmd:
208 scanned_result(eqtb[m].cint, int_val_level);
209 break;
210 case assign_dir_cmd:
211 scanned_result(eqtb[m].cint, dir_val_level);
212 break;
213 case assign_dimen_cmd:
214 scanned_result(eqtb[m].cint, dimen_val_level);
215 break;
216 case assign_glue_cmd:
217 scanned_result(equiv(m), glue_val_level);
218 break;
219 case assign_mu_glue_cmd:
220 scanned_result(equiv(m), mu_val_level);
221 break;
222 case math_style_cmd:
223 scanned_result(m, int_val_level);
224 break;
225 case set_aux_cmd:
226 /* Fetch the |space_factor| or the |prev_depth| */
227 if (abs(cur_list.mode_field) != m) {
228 print_err("Improper ");
229 print_cmd_chr(set_aux_cmd, m);
230 help4("You can refer to \\spacefactor only in horizontal mode;",
231 "you can refer to \\prevdepth only in vertical mode; and",
232 "neither of these is meaningful inside \\write. So",
233 "I'm forgetting what you said and using zero instead.");
234 error();
235 if (level != tok_val_level)
236 scanned_result(0, dimen_val_level);
237 else
238 scanned_result(0, int_val_level);
239 } else if (m == vmode) {
240 scanned_result(prev_depth, dimen_val_level);
241 } else {
242 scanned_result(space_factor, int_val_level);
244 break;
245 case set_prev_graf_cmd:
246 /* Fetch the |prev_graf| */
247 if (cur_list.mode_field == 0) {
248 scanned_result(0, int_val_level); /* |prev_graf=0| within \.{\\write} */
249 } else {
250 p = nest_ptr;
251 while (abs(nest[p].mode_field) != vmode)
252 decr(p);
253 scanned_result(nest[p].pg_field, int_val_level);
255 break;
256 case set_page_int_cmd:
257 /* Fetch the |dead_cycles| or the |insert_penalties| */
258 if (m == 0)
259 cur_val = dead_cycles;
260 else if (m == 2)
261 cur_val = interaction; /* interactionmode */
262 else
263 cur_val = insert_penalties;
264 cur_val_level = int_val_level;
265 break;
266 case set_page_dimen_cmd:
267 /* Fetch something on the |page_so_far| */
268 if ((page_contents == empty) && (!output_active)) {
269 if (m == 0)
270 cur_val = max_dimen;
271 else
272 cur_val = 0;
273 } else {
274 cur_val = page_so_far[m];
276 cur_val_level = dimen_val_level;
277 break;
278 case set_tex_shape_cmd:
279 /* Fetch the |par_shape| size */
280 if (par_shape_ptr == null)
281 cur_val = 0;
282 else
283 cur_val = vinfo(par_shape_ptr + 1);
284 cur_val_level = int_val_level;
285 break;
286 case set_etex_shape_cmd:
287 /* Fetch a penalties array element */
288 scan_int();
289 if ((equiv(m) == null) || (cur_val < 0)) {
290 cur_val = 0;
291 } else {
292 if (cur_val > penalty(equiv(m)))
293 cur_val = penalty(equiv(m));
294 cur_val = penalty(equiv(m) + cur_val);
296 cur_val_level = int_val_level;
297 break;
298 case char_given_cmd:
299 case math_given_cmd:
300 case xmath_given_cmd:
301 scanned_result(cur_chr, int_val_level);
302 break;
303 case last_item_cmd:
304 /* Because the items in this case directly refer to |cur_chr|,
305 it needs to be saved and restored */
306 save_cur_chr = cur_chr;
307 cur_chr = chr;
308 /* Fetch an item in the current node, if appropriate */
309 /* Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are
310 implemented. The reference count for \.{\\lastskip} will be updated later.
312 We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
313 legal in similar contexts. */
315 if (m >= input_line_no_code) {
316 if (m >= eTeX_glue) {
317 /* Process an expression and |return| */
318 if (m < eTeX_mu) {
319 switch (m) {
320 case mu_to_glue_code:
321 scan_mu_glue();
322 break;
323 }; /* there are no other cases */
324 cur_val_level = glue_val_level;
325 } else if (m < eTeX_expr) {
326 switch (m) {
327 case glue_to_mu_code:
328 scan_normal_glue();
329 break;
330 } /* there are no other cases */
331 cur_val_level = mu_val_level;
332 } else {
333 cur_val_level = m - eTeX_expr + int_val_level;
334 scan_expr();
336 /* This code for reducing |cur_val_level| and\slash or negating the
337 result is similar to the one for all the other cases of
338 |scan_something_internal|, with the difference that |scan_expr| has
339 already increased the reference count of a glue specification.
341 while (cur_val_level > level) {
342 downgrade_cur_val(true);
344 if (negative) {
345 negate_cur_val(true);
347 return succeeded;
349 } else if (m >= eTeX_dim) {
350 switch (m) {
351 case font_char_wd_code:
352 case font_char_ht_code:
353 case font_char_dp_code:
354 case font_char_ic_code:
355 scan_font_ident();
356 q = cur_val;
357 scan_char_num();
358 if (char_exists(q, cur_val)) {
359 switch (m) {
360 case font_char_wd_code:
361 cur_val = char_width(q, cur_val);
362 break;
363 case font_char_ht_code:
364 cur_val = char_height(q, cur_val);
365 break;
366 case font_char_dp_code:
367 cur_val = char_depth(q, cur_val);
368 break;
369 case font_char_ic_code:
370 cur_val = char_italic(q, cur_val);
371 break;
372 } /* there are no other cases */
373 } else {
374 cur_val = 0;
376 break;
377 case par_shape_length_code:
378 case par_shape_indent_code:
379 case par_shape_dimen_code:
380 q = cur_chr - par_shape_length_code;
381 scan_int();
382 if ((par_shape_ptr == null) || (cur_val <= 0)) {
383 cur_val = 0;
384 } else {
385 if (q == 2) {
386 q = cur_val % 2;
387 cur_val = (cur_val + q) / 2;
389 if (cur_val > vinfo(par_shape_ptr + 1))
390 cur_val = vinfo(par_shape_ptr + 1);
391 cur_val =
392 varmem[par_shape_ptr + 2 * cur_val - q + 1].cint;
394 cur_val_level = dimen_val_level;
395 break;
396 case glue_stretch_code:
397 case glue_shrink_code:
398 scan_normal_glue();
399 q = cur_val;
400 if (m == glue_stretch_code)
401 cur_val = stretch(q);
402 else
403 cur_val = shrink(q);
404 delete_glue_ref(q);
405 break;
406 } /* there are no other cases */
407 cur_val_level = dimen_val_level;
408 } else {
409 switch (m) {
410 case input_line_no_code:
411 cur_val = line;
412 break;
413 case badness_code:
414 cur_val = last_badness;
415 break;
416 case luatex_version_code:
417 cur_val = get_luatexversion();
418 break;
419 case last_saved_box_resource_index_code:
420 cur_val = last_saved_box_index;
421 break;
422 case last_saved_image_resource_index_code:
423 cur_val = last_saved_image_index;
424 break;
425 case last_saved_image_resource_pages_code:
426 cur_val = last_saved_image_pages;
427 break;
428 case last_x_pos_code:
429 cur_val = last_position.h;
430 break;
431 case last_y_pos_code:
432 cur_val = last_position.v;
433 break;
434 case random_seed_code:
435 cur_val = random_seed;
436 break;
437 case eTeX_version_code:
438 cur_val = eTeX_version;
439 break;
440 case eTeX_minor_version_code:
441 cur_val = eTeX_minor_version;
442 break;
443 case current_group_level_code:
444 cur_val = cur_level - level_one;
445 break;
446 case current_group_type_code:
447 cur_val = cur_group;
448 break;
449 case current_if_level_code:
450 q = cond_ptr;
451 cur_val = 0;
452 while (q != null) {
453 incr(cur_val);
454 q = vlink(q);
456 break;
457 case current_if_type_code:
458 if (cond_ptr == null)
459 cur_val = 0;
460 else if (cur_if < unless_code)
461 cur_val = cur_if + 1;
462 else
463 cur_val = -(cur_if - unless_code + 1);
464 break;
465 case current_if_branch_code:
466 if ((if_limit == or_code) || (if_limit == else_code))
467 cur_val = 1;
468 else if (if_limit == fi_code)
469 cur_val = -1;
470 else
471 cur_val = 0;
472 break;
473 case glue_stretch_order_code:
474 case glue_shrink_order_code:
475 scan_normal_glue();
476 q = cur_val;
477 if (m == glue_stretch_order_code)
478 cur_val = stretch_order(q);
479 else
480 cur_val = shrink_order(q);
481 delete_glue_ref(q);
482 break;
483 } /* there are no other cases */
484 cur_val_level = int_val_level;
486 } else {
487 if (cur_chr == glue_val_level)
488 cur_val = zero_glue;
489 else
490 cur_val = 0;
491 if (cur_chr == last_node_type_code) {
492 cur_val_level = int_val_level;
493 if ((cur_list.tail_field == cur_list.head_field)
494 || (cur_list.mode_field == 0))
495 cur_val = -1;
496 } else {
497 cur_val_level = cur_chr; /* assumes identical values */
499 if ((cur_list.tail_field != contrib_head) &&
500 !is_char_node(cur_list.tail_field) &&
501 (cur_list.mode_field != 0)) {
502 switch (cur_chr) {
503 case lastpenalty_code:
504 if (type(cur_list.tail_field) == penalty_node)
505 cur_val = penalty(cur_list.tail_field);
506 break;
507 case lastkern_code:
508 if (type(cur_list.tail_field) == kern_node)
509 cur_val = width(cur_list.tail_field);
510 break;
511 case lastskip_code:
512 if (type(cur_list.tail_field) == glue_node)
513 cur_val = glue_ptr(cur_list.tail_field);
514 if (subtype(cur_list.tail_field) == mu_glue)
515 cur_val_level = mu_val_level;
516 break;
517 case last_node_type_code:
518 cur_val = visible_last_node_type(cur_list.tail_field);
519 break;
520 } /* there are no other cases */
521 } else if ((cur_list.mode_field == vmode)
522 && (cur_list.tail_field == cur_list.head_field)) {
523 switch (cur_chr) {
524 case lastpenalty_code:
525 cur_val = last_penalty;
526 break;
527 case lastkern_code:
528 cur_val = last_kern;
529 break;
530 case lastskip_code:
531 if (last_glue != max_halfword)
532 cur_val = last_glue;
533 break;
534 case last_node_type_code:
535 cur_val = last_node_type;
536 break;
537 } /* there are no other cases */
540 cur_chr = save_cur_chr;
541 break;
542 default:
543 succeeded = false;
545 if (succeeded) {
546 while (cur_val_level > level) {
547 /* Convert |cur_val| to a lower level */
548 downgrade_cur_val(false);
550 /* Fix the reference count, if any, and negate |cur_val| if |negative| */
551 /* If |cur_val| points to a glue specification at this point, the reference
552 count for the glue does not yet include the reference by |cur_val|.
553 If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
555 if (negative) {
556 negate_cur_val(false);
557 } else if ((cur_val_level >= glue_val_level)
558 && (cur_val_level <= mu_val_level)) {
559 add_glue_ref(cur_val);
562 return succeeded;
565 @ First, here is a short routine that is called from lua code. All
566 the real work is delegated to |short_scan_something_internal| that
567 is shared between this routine and |scan_something_internal|.
570 void scan_something_simple(halfword cmd, halfword subitem)
572 /* negative is never true */
573 if (!short_scan_something_internal(cmd, subitem, tok_val_level, false)) {
574 /* Complain that |texlib| can not do this; give zero result */
575 print_err("You can't use `");
576 print_cmd_chr((quarterword) cmd, subitem);
577 tprint("' as tex library index");
578 help1("I'm forgetting what you said and using zero instead.");
579 error();
580 scanned_result(0, int_val_level);
584 @ OK, we're ready for |scan_something_internal| itself. A second parameter,
585 |negative|, is set |true| if the value that is found should be negated.
586 It is assumed that |cur_cmd| and |cur_chr| represent the first token of
587 the internal quantity to be scanned; an error will be signalled if
588 |cur_cmd<min_internal| or |cur_cmd>max_internal|.
591 void scan_something_internal(int level, boolean negative)
593 /* fetch an internal parameter */
594 halfword m; /* |chr_code| part of the operand token */
595 int n, k; /* accumulators */
596 RESTART:
597 m = cur_chr;
598 if (!short_scan_something_internal(cur_cmd, cur_chr, level, negative)) {
599 switch (cur_cmd) {
600 case def_char_code_cmd:
601 /* Fetch a character code from some table */
602 scan_char_num();
603 if (m == math_code_base) {
604 cur_val1 = get_math_code_num(cur_val);
605 scanned_result(cur_val1, int_val_level);
606 } else if (m == lc_code_base) {
607 cur_val1 = get_lc_code(cur_val);
608 scanned_result(cur_val1, int_val_level);
609 } else if (m == uc_code_base) {
610 cur_val1 = get_uc_code(cur_val);
611 scanned_result(cur_val1, int_val_level);
612 } else if (m == sf_code_base) {
613 cur_val1 = get_sf_code(cur_val);
614 scanned_result(cur_val1, int_val_level);
615 } else if (m == cat_code_base) {
616 cur_val1 = get_cat_code(int_par(cat_code_table_code), cur_val);
617 scanned_result(cur_val1, int_val_level);
618 } else {
619 confusion("def_char");
621 break;
622 case def_del_code_cmd:
623 case extdef_del_code_cmd: /* bonus */
624 /* Fetch a character code from some table */
625 scan_char_num();
626 cur_val1 = get_del_code_num(cur_val);
627 scanned_result(cur_val1, int_val_level);
628 break;
629 case extdef_math_code_cmd:
630 /* Fetch an extended math code table value */
631 scan_char_num();
632 cur_val1 = get_math_code_num(cur_val);
633 scanned_result(cur_val1, int_val_level);
634 break;
635 case toks_register_cmd:
636 case set_font_cmd:
637 case def_font_cmd:
638 case letterspace_font_cmd:
639 case copy_font_cmd:
640 /* Fetch a token list or font identifier, provided that |level=tok_val| */
641 if (level != tok_val_level) {
642 print_err("Missing number, treated as zero");
643 help3("A number should have been here; I inserted `0'.",
644 "(If you can't figure out why I needed to see a number,",
645 "look up `weird error' in the index to The TeXbook.)");
646 back_error();
647 scanned_result(0, dimen_val_level);
648 } else if (cur_cmd == toks_register_cmd) {
649 scan_register_num();
650 m = toks_base + cur_val;
651 scanned_result(equiv(m), tok_val_level);
652 } else {
653 back_input();
654 scan_font_ident();
655 scanned_result(font_id_base + cur_val, ident_val_level);
657 break;
658 case set_font_id_cmd:
659 scan_int();
660 scanned_result(font_id_base + cur_val, ident_val_level);
661 break;
662 case def_family_cmd:
663 /* Fetch a math font identifier */
664 scan_char_num();
665 cur_val1 = fam_fnt(cur_val, m);
666 scanned_result(font_id_base + cur_val1, ident_val_level);
667 break;
668 case set_math_param_cmd:
669 /* Fetch a math param */
670 cur_val1 = cur_chr;
671 get_token();
672 if (cur_cmd != math_style_cmd) {
673 print_err("Missing math style, treated as \\displaystyle");
674 help1
675 ("A style should have been here; I inserted `\\displaystyle'.");
676 cur_val = display_style;
677 back_error();
678 } else {
679 cur_val = cur_chr;
681 if (cur_val1 < math_param_first_mu_glue) {
682 if (cur_val1 == math_param_radical_degree_raise) {
683 cur_val1 = get_math_param(cur_val1, cur_chr);
684 scanned_result(cur_val1, int_val_level);
685 } else {
686 cur_val1 = get_math_param(cur_val1, cur_chr);
687 scanned_result(cur_val1, dimen_val_level);
689 } else {
690 cur_val1 = get_math_param(cur_val1, cur_chr);
691 if (cur_val1 == thin_mu_skip_code)
692 cur_val1 = glue_par(thin_mu_skip_code);
693 else if (cur_val1 == med_mu_skip_code)
694 cur_val1 = glue_par(med_mu_skip_code);
695 else if (cur_val1 == thick_mu_skip_code)
696 cur_val1 = glue_par(thick_mu_skip_code);
697 scanned_result(cur_val1, mu_val_level);
699 break;
700 case assign_box_dir_cmd:
701 scan_register_num();
702 m = cur_val;
703 if (box(m) != null)
704 cur_val = box_dir(box(m));
705 else
706 cur_val = 0;
707 cur_val_level = dir_val_level;
708 break;
709 case set_box_dimen_cmd:
710 /* Fetch a box dimension */
711 scan_register_num();
712 if (box(cur_val) == null)
713 cur_val = 0;
714 else
715 cur_val = varmem[box(cur_val) + m].cint;
716 cur_val_level = dimen_val_level;
717 break;
718 case assign_font_dimen_cmd:
719 /* Fetch a font dimension */
720 get_font_dimen();
721 break;
722 case assign_font_int_cmd:
723 /* Fetch a font integer */
724 scan_font_ident();
725 if (m == 0) {
726 scanned_result(hyphen_char(cur_val), int_val_level);
727 } else if (m == 1) {
728 scanned_result(skew_char(cur_val), int_val_level);
729 } else if (m == no_lig_code) {
730 scanned_result(test_no_ligatures(cur_val), int_val_level);
731 } else {
732 n = cur_val;
733 scan_char_num();
734 k = cur_val;
735 switch (m) {
736 case lp_code_base:
737 scanned_result(get_lp_code(n, k), int_val_level);
738 break;
739 case rp_code_base:
740 scanned_result(get_rp_code(n, k), int_val_level);
741 break;
742 case ef_code_base:
743 scanned_result(get_ef_code(n, k), int_val_level);
744 break;
745 case tag_code:
746 scanned_result(get_tag_code(n, k), int_val_level);
747 break;
750 break;
751 case register_cmd:
752 /* Fetch a register */
753 scan_register_num();
754 switch (m) {
755 case int_val_level:
756 cur_val = count(cur_val);
757 break;
758 case attr_val_level:
759 cur_val = attribute(cur_val);
760 break;
761 case dimen_val_level:
762 cur_val = dimen(cur_val);
763 break;
764 case glue_val_level:
765 cur_val = skip(cur_val);
766 break;
767 case mu_val_level:
768 cur_val = mu_skip(cur_val);
769 break;
770 } /* there are no other cases */
771 cur_val_level = m;
772 break;
773 case ignore_spaces_cmd: /* trap unexpandable primitives */
774 if (cur_chr == 1) {
775 /* Reset |cur_tok| for unexpandable primitives, goto restart */
776 /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
777 an integer or an internal values should have been found. It fetches the
778 next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
779 primitive value of that token. No expansion takes place, because the
780 next token may be all sorts of things. This could trigger further
781 expansion creating new errors.
783 get_token();
784 cur_cs = prim_lookup(cs_text(cur_cs));
785 if (cur_cs != undefined_primitive) {
786 cur_cmd = get_prim_eq_type(cur_cs);
787 cur_chr = get_prim_equiv(cur_cs);
788 cur_tok = token_val(cur_cmd, cur_chr);
789 } else {
790 cur_cmd = relax_cmd;
791 cur_chr = 0;
792 cur_tok = cs_token_flag + frozen_relax;
793 cur_cs = frozen_relax;
795 goto RESTART;
797 break;
798 case hyph_data_cmd:
799 switch (cur_chr) {
800 case 0:
801 case 1:
802 goto DEFAULT;
803 break;
804 case 2:
805 cur_val = get_pre_hyphen_char(int_par(language_code));
806 cur_val_level = int_val_level;
807 break;
808 case 3:
809 cur_val = get_post_hyphen_char(int_par(language_code));
810 cur_val_level = int_val_level;
811 break;
812 case 4:
813 cur_val = get_pre_exhyphen_char(int_par(language_code));
814 cur_val_level = int_val_level;
815 break;
816 case 5:
817 cur_val = get_post_exhyphen_char(int_par(language_code));
818 cur_val_level = int_val_level;
819 break;
820 case 6:
821 cur_val = get_hyphenation_min(int_par(language_code));
822 cur_val_level = int_val_level;
823 break;
824 case 7:
825 scan_int();
826 cur_val = get_hj_code(int_par(language_code),cur_val);
827 cur_val_level = int_val_level;
828 break;
830 break;
831 default:
832 DEFAULT:
833 /* Complain that \.{\\the} can not do this; give zero result */
834 print_err("You can't use `");
835 print_cmd_chr((quarterword) cur_cmd, cur_chr);
836 tprint("' after \\the");
837 help1("I'm forgetting what you said and using zero instead.");
838 error();
839 if (level != tok_val_level)
840 scanned_result(0, dimen_val_level);
841 else
842 scanned_result(0, int_val_level);
843 break;
845 while (cur_val_level > level) {
846 /* Convert |cur_val| to a lower level */
847 downgrade_cur_val(false);
849 /* Fix the reference count, if any, and negate |cur_val| if |negative| */
850 /* If |cur_val| points to a glue specification at this point, the reference
851 count for the glue does not yet include the reference by |cur_val|.
852 If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
854 if (negative) {
855 negate_cur_val(false);
856 } else if ((cur_val_level >= glue_val_level) &&
857 (cur_val_level <= mu_val_level)) {
858 add_glue_ref(cur_val);
863 @ It is nice to have routines that say what they do, so the original
864 |scan_eight_bit_int| is superceded by |scan_register_num| and
865 |scan_mark_num|. It may become split up even further in the future.
867 Many of the |restricted classes| routines are the essentially
868 the same except for the upper limit and the error message, so it makes
869 sense to combine these all into one function.
872 void scan_limited_int(int max, const char *name)
874 char hlp[80];
875 scan_int();
876 if ((cur_val < 0) || (cur_val > max)) {
877 if (name == NULL) {
878 snprintf(hlp, 80,
879 "Since I expected to read a number between 0 and %d,",
880 max);
881 print_err("Bad number");
882 } else {
883 char msg[80];
884 snprintf(hlp, 80, "A %s must be between 0 and %d.", name, max);
885 snprintf(msg, 80, "Bad %s", name);
886 print_err(msg);
888 help2(hlp, "I changed this one to zero.");
889 int_error(cur_val);
890 cur_val = 0;
894 @ @c
895 void scan_fifteen_bit_int(void)
897 scan_real_fifteen_bit_int();
898 cur_val = ((cur_val / 0x1000) * 0x1000000) +
899 (((cur_val % 0x1000) / 0x100) * 0x10000) + (cur_val % 0x100);
902 @ @c
903 void scan_fifty_one_bit_int(void)
905 int iiii;
906 scan_int();
907 if ((cur_val < 0) || (cur_val > 0777777777)) {
908 print_err("Bad delimiter code");
909 help2
910 ("A numeric delimiter (first part) must be between 0 and 2^{27}-1.",
911 "I changed this one to zero.");
912 int_error(cur_val);
913 cur_val = 0;
915 iiii = cur_val;
916 scan_int();
917 if ((cur_val < 0) || (cur_val > 0xFFFFFF)) {
918 print_err("Bad delimiter code");
919 help2
920 ("A numeric delimiter (second part) must be between 0 and 2^{24}-1.",
921 "I changed this one to zero.");
922 int_error(cur_val);
923 cur_val = 0;
925 cur_val1 = cur_val;
926 cur_val = iiii;
929 @ An integer number can be preceded by any number of spaces and `\.+' or
930 `\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
931 octal constant (i.e., radix 8, preceded by~'), a hexadecimal constant
932 (radix 16, preceded by~"), an alphabetic constant (preceded by~`), or
933 an internal variable. After scanning is complete,
934 |cur_val| will contain the answer, which must be at most
935 $2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
936 10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
937 otherwise |radix| is set to zero. An optional space follows a constant.
940 int radix; /* |scan_int| sets this to 8, 10, 16, or zero */
942 @ The |scan_int| routine is used also to scan the integer part of a
943 fraction; for example, the `\.3' in `\.{3.14159}' will be found by
944 |scan_int|. The |scan_dimen| routine assumes that |cur_tok=point_token|
945 after the integer part of such a fraction has been scanned by |scan_int|,
946 and that the decimal point has been backed up to be scanned again.
949 void scan_int(void)
950 { /* sets |cur_val| to an integer */
951 boolean negative; /* should the answer be negated? */
952 int m; /* |$2^{31}$ / radix|, the threshold of danger */
953 int d; /* the digit just scanned */
954 boolean vacuous; /* have no digits appeared? */
955 boolean OK_so_far; /* has an error message been issued? */
956 radix = 0;
957 OK_so_far = true;
958 /* Get the next non-blank non-sign token; set |negative| appropriately */
959 negative = false;
960 do {
961 /* Get the next non-blank non-call token */
962 do {
963 get_x_token();
964 } while (cur_cmd == spacer_cmd);
965 if (cur_tok == other_token + '-') {
966 negative = !negative;
967 cur_tok = other_token + '+';
969 } while (cur_tok == other_token + '+');
971 RESTART:
972 if (cur_tok == alpha_token) {
973 /* Scan an alphabetic character code into |cur_val| */
974 /* A space is ignored after an alphabetic character constant, so that
975 such constants behave like numeric ones. */
976 get_token(); /* suppress macro expansion */
977 if (cur_tok < cs_token_flag) {
978 cur_val = cur_chr;
979 if (cur_cmd <= right_brace_cmd) {
980 if (cur_cmd == right_brace_cmd)
981 incr(align_state);
982 else
983 decr(align_state);
985 } else { /* the value of a csname in this context is its name */
986 str_number txt = cs_text(cur_tok - cs_token_flag);
987 if (is_active_cs(txt))
988 cur_val = active_cs_value(txt);
989 else if (single_letter(txt))
990 cur_val = pool_to_unichar(str_string(txt));
991 else
992 cur_val = (biggest_char + 1);
994 if (cur_val > biggest_char) {
995 print_err("Improper alphabetic constant");
996 help2("A one-character control sequence belongs after a ` mark.",
997 "So I'm essentially inserting \\0 here.");
998 cur_val = '0';
999 back_error();
1000 } else {
1001 /* Scan an optional space */
1002 get_x_token();
1003 if (cur_cmd != spacer_cmd)
1004 back_input();
1007 } else if (cur_tok == cs_token_flag + frozen_primitive) {
1008 /* Reset |cur_tok| for unexpandable primitives, goto restart */
1009 /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
1010 an integer or an internal values should have been found. It fetches the
1011 next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
1012 primitive value of that token. No expansion takes place, because the
1013 next token may be all sorts of things. This could trigger further
1014 expansion creating new errors.
1016 get_token();
1017 cur_cs = prim_lookup(cs_text(cur_cs));
1018 if (cur_cs != undefined_primitive) {
1019 cur_cmd = get_prim_eq_type(cur_cs);
1020 cur_chr = get_prim_equiv(cur_cs);
1021 cur_tok = token_val(cur_cmd, cur_chr);
1022 } else {
1023 cur_cmd = relax_cmd;
1024 cur_chr = 0;
1025 cur_tok = cs_token_flag + frozen_relax;
1026 cur_cs = frozen_relax;
1028 goto RESTART;
1029 } else if (cur_cmd == math_style_cmd) {
1030 cur_val = cur_chr;
1031 } else if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1032 scan_something_internal(int_val_level, false);
1033 } else {
1034 /* Scan a numeric constant */
1035 radix = 10;
1036 m = 214748364;
1037 if (cur_tok == octal_token) {
1038 radix = 8;
1039 m = 02000000000;
1040 get_x_token();
1041 } else if (cur_tok == hex_token) {
1042 radix = 16;
1043 m = 01000000000;
1044 get_x_token();
1046 vacuous = true;
1047 cur_val = 0;
1048 /* Accumulate the constant until |cur_tok| is not a suitable digit */
1049 while (1) {
1050 if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token)
1051 && (cur_tok <= zero_token + 9)) {
1052 d = cur_tok - zero_token;
1053 } else if (radix == 16) {
1054 if ((cur_tok <= A_token + 5) && (cur_tok >= A_token)) {
1055 d = cur_tok - A_token + 10;
1056 } else if ((cur_tok <= other_A_token + 5)
1057 && (cur_tok >= other_A_token)) {
1058 d = cur_tok - other_A_token + 10;
1059 } else {
1060 break;
1062 } else {
1063 break;
1065 vacuous = false;
1066 if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10))) {
1067 if (OK_so_far) {
1068 print_err("Number too big");
1069 help2
1070 ("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
1071 "so I'm using that number instead of yours.");
1072 error();
1073 cur_val = infinity;
1074 OK_so_far = false;
1076 } else {
1077 cur_val = cur_val * radix + d;
1079 get_x_token();
1081 if (vacuous) {
1082 /* Express astonishment that no number was here */
1083 print_err("Missing number, treated as zero");
1084 help3("A number should have been here; I inserted `0'.",
1085 "(If you can't figure out why I needed to see a number,",
1086 "look up `weird error' in the index to The TeXbook.)");
1087 back_error();
1088 } else if (cur_cmd != spacer_cmd) {
1089 back_input();
1092 if (negative)
1093 negate(cur_val);
1096 @ The following code is executed when |scan_something_internal| was
1097 called asking for |mu_val|, when we really wanted a ``mudimen'' instead
1098 of ``muglue.''
1101 static void coerce_glue(void)
1103 int v;
1104 if (cur_val_level >= glue_val_level) {
1105 v = width(cur_val);
1106 delete_glue_ref(cur_val);
1107 cur_val = v;
1111 @ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
1112 a |scaled| value, i.e., an integral number of sp. One of its main tasks
1113 is therefore to interpret the abbreviations for various kinds of units and
1114 to convert measurements to scaled points.
1116 There are three parameters: |mu| is |true| if the finite units must be
1117 `\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
1118 |inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
1119 are permitted; and |shortcut| is |true| if |cur_val| already contains
1120 an integer and only the units need to be considered.
1122 The order of infinity that was found in the case of infinite glue is returned
1123 in the global variable |cur_order|.
1126 int cur_order; /* order of infinity found by |scan_dimen| */
1129 @ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
1130 may begin with |scan_int|. This explains why it is convenient to use
1131 |scan_int| also for the integer part of a decimal fraction.
1133 Several branches of |scan_dimen| work with |cur_val| as an integer and
1134 with an auxiliary fraction |f|, so that the actual quantity of interest is
1135 $|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
1136 representation is put into the single word |cur_val|, which suddenly
1137 switches significance from |integer| to |scaled|.
1140 The necessary conversion factors can all be specified exactly as
1141 fractions whose numerator and denominator add to 32768 or less.
1142 According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
1143 this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
1144 \^{Bosshard, Hans Rudolf}
1145 in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
1146 The Didot point has been newly standardized in 1978;
1147 it's now exactly $\rm 1\,nd=0.375\,mm$.
1148 Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$.
1149 The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$.
1150 These would lead to the ratios $21681/20320$ and $65043/5080$,
1151 respectively.
1152 The closest approximations supported by the algorithm would be
1153 $11183/10481$ and $1370/107$. In order to maintain the
1154 relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for
1155 $\rm nd$, however.
1159 static void scan_dimen_mu_error(void) {
1160 print_err("Illegal unit of measure (mu inserted)");
1161 help4("The unit of measurement in math glue must be mu.",
1162 "To recover gracefully from this error, it's best to",
1163 "delete the erroneous units; e.g., type `2' to delete",
1164 "two letters. (See Chapter 27 of The TeXbook.)");
1165 error();
1168 static void scan_dimen_unknown_unit_error(void) {
1169 print_err("Illegal unit of measure (pt inserted)");
1170 help6("Dimensions can be in units of em, ex, in, pt, pc,",
1171 "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
1172 "I'll assume that you meant to say pt, for printer's points.",
1173 "To recover gracefully from this error, it's best to",
1174 "delete the erroneous units; e.g., type `2' to delete",
1175 "two letters. (See Chapter 27 of The TeXbook.)");
1176 error();
1179 static void scan_dimen_out_of_range_error(void) {
1180 print_err("Dimension too large");
1181 help2("I can't work with sizes bigger than about 19 feet.",
1182 "Continue and I'll use the largest value I can.");
1183 error();
1186 #define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
1189 This function sets |cur_val| to a dimension. It could be optimized a bit
1190 more (but not now, something for luatex > 1).
1193 void scan_dimen(boolean mu, boolean inf, boolean shortcut)
1195 boolean negative; /* should the answer be negated? */
1196 int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */
1197 int num, denom; /* conversion ratio for the scanned units */
1198 halfword q; /* top of decimal digit stack */
1199 scaled v; /* an internal dimension */
1200 int save_cur_val; /* temporary storage of |cur_val| */
1201 arith_error = false;
1202 cur_order = normal;
1203 negative = false;
1204 if (!shortcut) {
1205 /* Get the next non-blank non-sign... */
1206 do {
1207 /* Get the next non-blank non-call token */
1208 do {
1209 get_x_token();
1210 } while (cur_cmd == spacer_cmd);
1211 if (cur_tok == other_token + '-') {
1212 negative = !negative;
1213 cur_tok = other_token + '+';
1215 } while (cur_tok == other_token + '+');
1216 if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1217 /* Fetch an internal dimension and |goto attach_sign|, or fetch an internal integer */
1218 if (mu) {
1219 scan_something_internal(mu_val_level, false);
1220 coerce_glue();
1221 if (cur_val_level == mu_val_level) {
1222 goto ATTACH_SIGN;
1223 } else if (cur_val_level != int_val_level) {
1224 mu_error();
1226 } else {
1227 scan_something_internal(dimen_val_level, false);
1228 if (cur_val_level == dimen_val_level) {
1229 goto ATTACH_SIGN;
1232 } else {
1233 back_input();
1234 if (cur_tok == continental_point_token) {
1235 cur_tok = point_token;
1237 if (cur_tok != point_token) {
1238 scan_int();
1239 } else {
1240 radix = 10;
1241 cur_val = 0;
1243 if (cur_tok == continental_point_token) {
1244 cur_tok = point_token;
1246 if ((radix == 10) && (cur_tok == point_token)) {
1248 Scan decimal fraction. When the following code is executed, we have
1249 |cur_tok=point_token|, but this token has been backed up using |back_input|;
1250 we must first discard it. It turns out that a decimal point all by itself
1251 is equivalent to `\.{0.0}'. Let's hope people don't use that fact.
1253 int k = 0;
1254 halfword p = null;
1255 int kk;
1256 get_token(); /* |point_token| is being re-scanned */
1257 while (1) {
1258 get_x_token();
1259 if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
1260 break;
1261 if (k < 17) {
1262 /* digits for |k>=17| cannot affect the result */
1263 q = get_avail();
1264 set_token_link(q, p);
1265 set_token_info(q, cur_tok - zero_token);
1266 p = q;
1267 incr(k);
1270 for (kk = k; kk >= 1; kk--) {
1271 dig[kk - 1] = token_info(p);
1272 q = p;
1273 p = token_link(p);
1274 free_avail(q);
1276 f = round_decimals(k);
1277 if (cur_cmd != spacer_cmd) {
1278 back_input();
1283 if (cur_val < 0) {
1284 /* in this case |f=0| */
1285 negative = !negative;
1286 negate(cur_val);
1289 Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
1290 are |x| sp per unit; |goto attach_sign| if the units are internal. Now comes
1291 the harder part: At this point in the program, |cur_val| is a nonnegative
1292 integer and $f/2^{16}$ is a nonnegative fraction less than 1; we want to
1293 multiply the sum of these two quantities by the appropriate factor, based
1294 on the specified units, in order to produce a |scaled| result, and we want
1295 to do the calculation with fixed point arithmetic that does not overflow.
1297 if (inf) {
1299 Scan for (f)\.{fil} units; |goto attach_fraction| if found. In traditional
1300 \TeX, a specification like `\.{filllll}' or `\.{fill L L L}' will lead to
1301 two error messages (one for each additional keyword \.{"l"}). Not so for
1302 \LuaTeX, it just parses the construct in reverse.
1304 if (scan_keyword("filll")) {
1305 cur_order = filll;
1306 goto ATTACH_FRACTION;
1307 } else if (scan_keyword("fill")) {
1308 cur_order = fill;
1309 goto ATTACH_FRACTION;
1310 } else if (scan_keyword("fil")) {
1311 cur_order = fil;
1312 goto ATTACH_FRACTION;
1313 } else if (scan_keyword("fi")) {
1314 cur_order = sfi;
1315 goto ATTACH_FRACTION;
1319 Scan for (u)units that are internal dimensions; |goto attach_sign| with
1320 |cur_val| set if found
1322 save_cur_val = cur_val;
1323 /* Get the next non-blank non-call... a pitty if just backed up the input */
1324 do {
1325 get_x_token();
1326 } while (cur_cmd == spacer_cmd);
1328 if ((cur_cmd < min_internal_cmd) || (cur_cmd > max_internal_cmd)) {
1329 back_input();
1330 } else {
1331 /* math_given_cmd xmath_given_cmd last_item_cmd */
1332 if (mu) {
1333 scan_something_internal(mu_val_level, false);
1334 coerce_glue();
1335 if (cur_val_level != mu_val_level) {
1336 mu_error();
1338 } else {
1339 scan_something_internal(dimen_val_level, false);
1341 v = cur_val;
1342 goto FOUND;
1344 /* bah ... true forces to split the unit scanner */
1345 if (mu) {
1346 /* Scan for (m)\.{mu} units and |goto attach_fraction| */
1347 if (! scan_keyword("mu")) {
1348 scan_dimen_mu_error();
1350 goto ATTACH_FRACTION;
1351 } else if (scan_keyword("em")) {
1352 v = quad(get_cur_font());
1353 } else if (scan_keyword("ex")) {
1354 v = x_height(get_cur_font());
1355 } else if (scan_keyword("px")) {
1356 v = dimen_par(px_dimen_code);
1357 } else {
1358 goto PICKUP_UNIT;
1360 /* Scan an optional space (after em, ex or px) */
1361 get_x_token();
1362 if (cur_cmd != spacer_cmd) {
1363 back_input();
1365 FOUND:
1366 cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
1367 goto ATTACH_SIGN;
1369 Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
1370 |goto done| in the case of scaled points
1372 PICKUP_UNIT:
1373 if (scan_keyword("pt")) {
1374 goto ATTACH_FRACTION; /* the easy case */
1375 } else if (scan_keyword("mm")) {
1376 set_conversion(7227, 2540);
1377 goto SCALE_VALUE;
1378 } else if (scan_keyword("cm")) {
1379 set_conversion(7227, 254);
1380 goto SCALE_VALUE;
1381 } else if (scan_keyword("sp")) {
1382 goto DONE;
1383 } else if (scan_keyword("bp")) {
1384 set_conversion(7227, 7200);
1385 goto SCALE_VALUE;
1386 } else if (scan_keyword("in")) {
1387 set_conversion(7227, 100);
1388 goto SCALE_VALUE;
1389 } else if (scan_keyword("dd")) {
1390 set_conversion(1238, 1157);
1391 goto SCALE_VALUE;
1392 } else if (scan_keyword("cc")) {
1393 set_conversion(14856, 1157);
1394 goto SCALE_VALUE;
1395 } else if (scan_keyword("pc")) {
1396 set_conversion(12, 1);
1397 goto SCALE_VALUE;
1398 } else if (scan_keyword("nd")) {
1399 set_conversion(685, 642);
1400 goto SCALE_VALUE;
1401 } else if (scan_keyword("nc")) {
1402 set_conversion(1370, 107);
1403 goto SCALE_VALUE;
1404 } else if (scan_keyword("true")) {
1405 /* Adjust (f)for the magnification ratio */
1406 if (output_mode_used == OMODE_DVI) {
1407 prepare_mag();
1408 if (int_par(mag_code) != 1000) {
1409 cur_val = xn_over_d(cur_val, 1000, int_par(mag_code));
1410 f = (1000 * f + 0200000 * tex_remainder) / int_par(mag_code);
1411 cur_val = cur_val + (f / 0200000);
1412 f = f % 0200000;
1415 goto PICKUP_UNIT;
1416 } else {
1417 /* Complain about unknown unit and |goto done2| */
1418 scan_dimen_unknown_unit_error();
1419 goto BAD_NEWS;
1421 SCALE_VALUE:
1422 cur_val = xn_over_d(cur_val, num, denom);
1423 f = (num * f + 0200000 * tex_remainder) / denom;
1424 cur_val = cur_val + (f / 0200000);
1425 f = f % 0200000;
1426 BAD_NEWS:
1427 ATTACH_FRACTION:
1428 if (cur_val >= 040000) {
1429 arith_error = true;
1430 } else {
1431 cur_val = cur_val * unity + f;
1433 DONE:
1434 /* Scan an optional space */ /* happens too often */
1435 get_x_token();
1436 if (cur_cmd != spacer_cmd) {
1437 back_input();
1439 ATTACH_SIGN:
1440 if (arith_error || (abs(cur_val) >= 010000000000)) {
1441 /* Report that this dimension is out of range */
1442 scan_dimen_out_of_range_error();
1443 cur_val = max_dimen;
1444 arith_error = false;
1446 if (negative) {
1447 negate(cur_val);
1451 @ The final member of \TeX's value-scanning trio is |scan_glue|, which
1452 makes |cur_val| point to a glue specification. The reference count of that
1453 glue spec will take account of the fact that |cur_val| is pointing to~it.
1455 The |level| parameter should be either |glue_val| or |mu_val|.
1457 Since |scan_dimen| was so much more complex than |scan_int|, we might expect
1458 |scan_glue| to be even worse. But fortunately, it is very simple, since
1459 most of the work has already been done.
1462 void scan_glue(int level)
1463 { /* sets |cur_val| to a glue spec pointer */
1464 boolean negative; /* should the answer be negated? */
1465 halfword q; /* new glue specification */
1466 boolean mu; /* does |level=mu_val|? */
1467 mu = (level == mu_val_level);
1468 /* Get the next non-blank non-sign... */
1469 negative = false;
1470 do {
1471 /* Get the next non-blank non-call token */
1472 do {
1473 get_x_token();
1474 } while (cur_cmd == spacer_cmd);
1475 if (cur_tok == other_token + '-') {
1476 negative = !negative;
1477 cur_tok = other_token + '+';
1479 } while (cur_tok == other_token + '+');
1481 if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1482 scan_something_internal(level, negative);
1483 if (cur_val_level >= glue_val_level) {
1484 if (cur_val_level != level)
1485 mu_error();
1486 return;
1488 if (cur_val_level == int_val_level)
1489 scan_dimen(mu, false, true);
1490 else if (level == mu_val_level)
1491 mu_error();
1492 } else {
1493 back_input();
1494 scan_dimen(mu, false, false);
1495 if (negative)
1496 negate(cur_val);
1498 /* Create a new glue specification whose width is |cur_val|; scan for its
1499 stretch and shrink components */
1500 q = new_spec(zero_glue);
1501 width(q) = cur_val;
1502 if (scan_keyword("plus")) {
1503 scan_dimen(mu, true, false);
1504 stretch(q) = cur_val;
1505 stretch_order(q) = (quarterword) cur_order;
1507 if (scan_keyword("minus")) {
1508 scan_dimen(mu, true, false);
1509 shrink(q) = cur_val;
1510 shrink_order(q) = (quarterword) cur_order;
1512 cur_val = q;
1515 @ This is an omega routine
1517 void scan_scaled(void)
1518 { /* sets |cur_val| to a scaled value */
1519 boolean negative; /* should the answer be negated? */
1520 int f; /* numerator of a fraction whose denominator is $2^{16}$ */
1521 int k, kk; /* number of digits in a decimal fraction */
1522 halfword p, q; /* top of decimal digit stack */
1523 f = 0;
1524 arith_error = false;
1525 negative = false;
1526 /* Get the next non-blank non-sign... */
1527 do {
1528 /* Get the next non-blank non-call token */
1529 do {
1530 get_x_token();
1531 } while (cur_cmd == spacer_cmd);
1532 if (cur_tok == other_token + '-') {
1533 negative = !negative;
1534 cur_tok = other_token + '+';
1536 } while (cur_tok == other_token + '+');
1538 back_input();
1539 if (cur_tok == continental_point_token)
1540 cur_tok = point_token;
1541 if (cur_tok != point_token) {
1542 scan_int();
1543 } else {
1544 radix = 10;
1545 cur_val = 0;
1547 if (cur_tok == continental_point_token)
1548 cur_tok = point_token;
1549 if ((radix == 10) && (cur_tok == point_token)) {
1550 /* Scan decimal fraction */
1551 /* TODO: merge this with the same block in |scan_dimen| */
1552 /* When the following code is executed, we have |cur_tok=point_token|, but this
1553 token has been backed up using |back_input|; we must first discard it.
1555 It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
1556 Let's hope people don't use that fact. */
1558 k = 0;
1559 p = null;
1560 get_token(); /* |point_token| is being re-scanned */
1561 while (1) {
1562 get_x_token();
1563 if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
1564 break;
1565 if (k < 17) { /* digits for |k>=17| cannot affect the result */
1566 q = get_avail();
1567 set_token_link(q, p);
1568 set_token_info(q, cur_tok - zero_token);
1569 p = q;
1570 incr(k);
1573 for (kk = k; kk >= 1; kk--) {
1574 dig[kk - 1] = token_info(p);
1575 q = p;
1576 p = token_link(p);
1577 free_avail(q);
1579 f = round_decimals(k);
1580 if (cur_cmd != spacer_cmd)
1581 back_input();
1584 if (cur_val < 0) { /* in this case |f=0| */
1585 negative = !negative;
1586 negate(cur_val);
1588 if (cur_val > 040000)
1589 arith_error = true;
1590 else
1591 cur_val = cur_val * unity + f;
1592 if (arith_error || (abs(cur_val) >= 010000000000)) {
1593 print_err("Stack number too large");
1594 error();
1596 if (negative)
1597 negate(cur_val);
1600 @ This procedure is supposed to scan something like `\.{\\skip\\count12}',
1601 i.e., whatever can follow `\.{\\the}', and it constructs a token list
1602 containing something like `\.{-3.0pt minus 0.5fill}'.
1605 halfword the_toks(void)
1607 int old_setting; /* holds |selector| setting */
1608 halfword p, q, r; /* used for copying a token list */
1609 int c; /* value of |cur_chr| */
1610 str_number s;
1611 halfword retval;
1612 /* Handle \.{\\unexpanded} or \.{\\detokenize} and |return| */
1613 if (odd(cur_chr)) {
1614 c = cur_chr;
1615 scan_general_text();
1616 if (c == 1) {
1617 return cur_val;
1618 } else {
1619 old_setting = selector;
1620 selector = new_string;
1621 p = get_avail();
1622 set_token_link(p, token_link(temp_token_head));
1623 token_show(p);
1624 flush_list(p);
1625 selector = old_setting;
1626 s = make_string();
1627 retval = str_toks(str_lstring(s));
1628 flush_str(s);
1629 return retval;
1632 get_x_token();
1633 scan_something_internal(tok_val_level, false);
1634 if (cur_val_level >= ident_val_level) {
1635 /* Copy the token list */
1636 p = temp_token_head;
1637 set_token_link(p, null);
1638 if (cur_val_level == ident_val_level) {
1639 store_new_token(cs_token_flag + cur_val);
1640 } else if (cur_val != null) {
1641 r = token_link(cur_val); /* do not copy the reference count */
1642 while (r != null) {
1643 fast_store_new_token(token_info(r));
1644 r = token_link(r);
1647 return p;
1648 } else {
1649 old_setting = selector;
1650 selector = new_string;
1651 switch (cur_val_level) {
1652 case int_val_level:
1653 print_int(cur_val);
1654 break;
1655 case attr_val_level:
1656 print_int(cur_val);
1657 break;
1658 case dir_val_level:
1659 print_dir(cur_val);
1660 break;
1661 case dimen_val_level:
1662 print_scaled(cur_val);
1663 tprint("pt");
1664 break;
1665 case glue_val_level:
1666 print_spec(cur_val, "pt");
1667 delete_glue_ref(cur_val);
1668 break;
1669 case mu_val_level:
1670 print_spec(cur_val, "mu");
1671 delete_glue_ref(cur_val);
1672 break;
1673 } /* there are no other cases */
1674 selector = old_setting;
1675 s = make_string();
1676 retval = str_toks(str_lstring(s));
1677 flush_str(s);
1678 return retval;
1682 @ @c
1683 str_number the_scanned_result(void)
1685 int old_setting; /* holds |selector| setting */
1686 str_number r; /* return value * */
1687 old_setting = selector;
1688 selector = new_string;
1689 if (cur_val_level >= ident_val_level) {
1690 if (cur_val != null) {
1691 show_token_list(token_link(cur_val), null, -1);
1692 r = make_string();
1693 } else {
1694 r = get_nullstr();
1696 } else {
1697 switch (cur_val_level) {
1698 case int_val_level:
1699 print_int(cur_val);
1700 break;
1701 case attr_val_level:
1702 print_int(cur_val);
1703 break;
1704 case dir_val_level:
1705 print_dir(cur_val);
1706 break;
1707 case dimen_val_level:
1708 print_scaled(cur_val);
1709 tprint("pt");
1710 break;
1711 case glue_val_level:
1712 print_spec(cur_val, "pt");
1713 delete_glue_ref(cur_val);
1714 break;
1715 case mu_val_level:
1716 print_spec(cur_val, "mu");
1717 delete_glue_ref(cur_val);
1718 break;
1719 } /* there are no other cases */
1720 r = make_string();
1722 selector = old_setting;
1723 return r;
1726 @ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
1727 The boolean parameter |writing| is set |true| if the calling program
1728 intends to change the parameter value.
1731 static void font_param_error(int f)
1733 print_err("Font ");
1734 print_esc(font_id_text(f));
1735 tprint(" has only ");
1736 print_int(font_params(f));
1737 tprint(" fontdimen parameters");
1738 help2("To increase the number of font parameters, you must",
1739 "use \\fontdimen immediately after the \\font is loaded.");
1740 error();
1743 void set_font_dimen(void)
1745 internal_font_number f;
1746 int n; /* the parameter number */
1747 scan_int();
1748 n = cur_val;
1749 scan_font_ident();
1750 f = cur_val;
1751 if (n <= 0) {
1752 font_param_error(f);
1753 } else {
1754 if (n > font_params(f)) {
1755 if (font_used(f)) {
1756 font_param_error(f);
1757 } else {
1758 /* Increase the number of parameters in the font */
1759 do {
1760 set_font_param(f, (font_params(f) + 1), 0);
1761 } while (n != font_params(f));
1765 scan_optional_equals();
1766 scan_normal_dimen();
1767 set_font_param(f, n, cur_val);
1770 void get_font_dimen(void)
1772 internal_font_number f;
1773 int n; /* the parameter number */
1774 scan_int();
1775 n = cur_val;
1776 scan_font_ident();
1777 f = cur_val;
1778 cur_val = 0; /* initialize return value */
1779 if (n <= 0) {
1780 font_param_error(f);
1781 goto EXIT;
1782 } else {
1783 if (n > font_params(f)) {
1784 if (font_used(f)) {
1785 font_param_error(f);
1786 goto EXIT;
1787 } else {
1788 /* Increase the number of parameters in the font */
1789 do {
1790 set_font_param(f, (font_params(f) + 1), 0);
1791 } while (n != font_params(f));
1796 cur_val = font_param(f, n);
1797 EXIT:
1798 scanned_result(cur_val, dimen_val_level);
1801 @ Here's a similar procedure that returns a pointer to a rule node. This
1802 routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
1803 therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
1804 the default rule dimensions in the node, then to override them if
1805 `\.{height}' or `\.{width}' or `\.{depth}' specifications are
1806 found (in any order).
1809 halfword scan_rule_spec(void)
1811 /* |width|, |depth|, and |height| all equal |null_flag| now */
1812 halfword q;
1813 if (cur_cmd == no_vrule_cmd) {
1814 q = new_rule(empty_rule);
1815 cur_cmd = vrule_cmd;
1816 } else if (cur_cmd == no_hrule_cmd) {
1817 q = new_rule(empty_rule);
1818 cur_cmd = hrule_cmd;
1819 } else {
1820 q = new_rule(normal_rule);
1822 if (cur_cmd == vrule_cmd) {
1823 width(q) = default_rule;
1824 rule_dir(q) = body_direction;
1825 } else {
1826 height(q) = default_rule;
1827 depth(q) = 0;
1828 rule_dir(q) = text_direction;
1830 RESWITCH:
1831 if (scan_keyword("width")) {
1832 scan_normal_dimen();
1833 width(q) = cur_val;
1834 goto RESWITCH;
1836 if (scan_keyword("height")) {
1837 scan_normal_dimen();
1838 height(q) = cur_val;
1839 goto RESWITCH;
1841 if (scan_keyword("depth")) {
1842 scan_normal_dimen();
1843 depth(q) = cur_val;
1844 goto RESWITCH;
1846 return q;
1850 @ Declare procedures that scan font-related stuff
1853 void scan_font_ident(void)
1855 internal_font_number f;
1856 halfword m;
1857 /* Get the next non-blank non-call... */
1858 do {
1859 get_x_token();
1860 } while (cur_cmd == spacer_cmd);
1862 if ((cur_cmd == def_font_cmd) || (cur_cmd == letterspace_font_cmd) || (cur_cmd == copy_font_cmd)) {
1863 f = get_cur_font();
1864 } else if (cur_cmd == set_font_cmd) {
1865 f = cur_chr;
1866 set_font_touched(f, 1);
1867 } else if (cur_cmd == def_family_cmd) {
1868 m = cur_chr;
1869 scan_math_family_int();
1870 f = fam_fnt(cur_val, m);
1871 set_font_touched(f, 1);
1872 } else {
1873 print_err("Missing font identifier");
1874 help2("I was looking for a control sequence whose",
1875 "current meaning has been defined by \\font.");
1876 back_error();
1877 f = null_font;
1879 cur_val = f;
1882 @ The |scan_general_text| procedure is much like |scan_toks(false,false)|,
1883 but will be invoked via |expand|, i.e., recursively.
1885 The token list (balanced text) created by |scan_general_text| begins
1886 at |link(temp_token_head)| and ends at |cur_val|. (If |cur_val=temp_token_head|,
1887 the list is empty.)
1890 void scan_general_text(void)
1892 int s; /* to save |scanner_status| */
1893 halfword w; /* to save |warning_index| */
1894 halfword d; /* to save |def_ref| */
1895 halfword p; /* tail of the token list being built */
1896 halfword q; /* new node being added to the token list via |store_new_token| */
1897 halfword unbalance; /* number of unmatched left braces */
1898 s = scanner_status;
1899 w = warning_index;
1900 d = def_ref;
1901 scanner_status = absorbing;
1902 warning_index = cur_cs;
1903 p = get_avail();
1904 def_ref = p;
1905 set_token_ref_count(def_ref, 0);
1906 p = def_ref;
1907 scan_left_brace(); /* remove the compulsory left brace */
1908 unbalance = 1;
1909 while (1) {
1910 get_token();
1911 if (cur_tok < right_brace_limit) {
1912 if (cur_cmd < right_brace_cmd) {
1913 incr(unbalance);
1914 } else {
1915 decr(unbalance);
1916 if (unbalance == 0)
1917 break;
1920 store_new_token(cur_tok);
1922 q = token_link(def_ref);
1923 free_avail(def_ref); /* discard reference count */
1924 if (q == null)
1925 cur_val = temp_token_head;
1926 else
1927 cur_val = p;
1928 set_token_link(temp_token_head, q);
1929 scanner_status = s;
1930 warning_index = w;
1931 def_ref = d;
1934 @ The |get_x_or_protected| procedure is like |get_x_token| except that
1935 protected macros are not expanded.
1938 void get_x_or_protected(void)
1939 { /* sets |cur_cmd|, |cur_chr|, |cur_tok|,
1940 and expands non-protected macros */
1941 while (1) {
1942 get_token();
1943 if (cur_cmd <= max_command_cmd)
1944 return;
1945 if ((cur_cmd >= call_cmd) && (cur_cmd < end_template_cmd)) {
1946 if (token_info(token_link(cur_chr)) == protected_token)
1947 return;
1949 expand();
1953 @ |scan_toks|. This function returns a pointer to the tail of a new token
1954 list, and it also makes |def_ref| point to the reference count at the
1955 head of that list.
1957 There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
1958 is true, the goal is to create the token list for a macro definition;
1959 otherwise the goal is to create the token list for some other \TeX\
1960 primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
1961 \.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
1962 \.{\\special}. In the latter cases a left brace must be scanned next; this
1963 left brace will not be part of the token list, nor will the matching right
1964 brace that comes at the end. If |xpand| is false, the token list will
1965 simply be copied from the input using |get_token|. Otherwise all expandable
1966 tokens will be expanded until unexpandable tokens are left, except that
1967 the results of expanding `\.{\\the}' are not expanded further.
1968 If both |macro_def| and |xpand| are true, the expansion applies
1969 only to the macro body (i.e., to the material following the first
1970 |left_brace| character).
1972 The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
1973 address of the control sequence to display in ``runaway'' error
1974 messages.
1977 halfword scan_toks(boolean macro_def, boolean xpand)
1979 halfword t; /* token representing the highest parameter number */
1980 halfword s; /* saved token */
1981 halfword p; /* tail of the token list being built */
1982 halfword q; /* new node being added to the token list via |store_new_token| */
1983 halfword unbalance; /* number of unmatched left braces */
1984 halfword hash_brace; /* possible `\.{\#\{}' token */
1985 if (macro_def)
1986 scanner_status = defining;
1987 else
1988 scanner_status = absorbing;
1989 warning_index = cur_cs;
1990 p = get_avail();
1991 def_ref = p;
1992 set_token_ref_count(def_ref, 0);
1993 p = def_ref;
1994 hash_brace = 0;
1995 t = zero_token;
1996 if (macro_def) {
1997 /* Scan and build the parameter part of the macro definition */
1998 while (1) {
1999 get_token(); /* set |cur_cmd|, |cur_chr|, |cur_tok| */
2000 if (cur_tok < right_brace_limit)
2001 break;
2002 if (cur_cmd == mac_param_cmd) {
2003 /* If the next character is a parameter number, make |cur_tok|
2004 a |match| token; but if it is a left brace, store
2005 `|left_brace|, |end_match|', set |hash_brace|, and |goto done|;
2007 s = match_token + cur_chr;
2008 get_token();
2009 if (cur_cmd == left_brace_cmd) {
2010 hash_brace = cur_tok;
2011 store_new_token(cur_tok);
2012 store_new_token(end_match_token);
2013 goto DONE;
2015 if (t == zero_token + 9) {
2016 print_err("You already have nine parameters");
2017 help1("I'm going to ignore the # sign you just used.");
2018 error();
2019 } else {
2020 incr(t);
2021 if (cur_tok != t) {
2022 print_err("Parameters must be numbered consecutively");
2023 help2
2024 ("I've inserted the digit you should have used after the #.",
2025 "Type `1' to delete what you did use.");
2026 back_error();
2028 cur_tok = s;
2031 store_new_token(cur_tok);
2033 store_new_token(end_match_token);
2034 if (cur_cmd == right_brace_cmd) {
2035 /* Express shock at the missing left brace; |goto found| */
2036 print_err("Missing { inserted");
2037 incr(align_state);
2038 help2
2039 ("Where was the left brace? You said something like `\\def\\a}',",
2040 "which I'm going to interpret as `\\def\\a{}'.");
2041 error();
2042 goto FOUND;
2045 } else {
2046 scan_left_brace(); /* remove the compulsory left brace */
2048 DONE:
2049 /* Scan and build the body of the token list; |goto found| when finished */
2050 unbalance = 1;
2051 while (1) {
2052 if (xpand) {
2053 /* Expand the next part of the input */
2054 /* Here we insert an entire token list created by |the_toks| without
2055 expanding it further. */
2056 while (1) {
2057 get_next();
2058 if (cur_cmd >= call_cmd) {
2059 if (token_info(token_link(cur_chr)) == protected_token) {
2060 cur_cmd = relax_cmd;
2061 cur_chr = no_expand_flag;
2064 if (cur_cmd <= max_command_cmd)
2065 break;
2066 if (cur_cmd != the_cmd) {
2067 expand();
2068 } else {
2069 q = the_toks();
2070 if (token_link(temp_token_head) != null) {
2071 set_token_link(p, token_link(temp_token_head));
2072 p = q;
2076 x_token();
2078 } else {
2079 get_token();
2081 if (cur_tok < right_brace_limit) {
2082 if (cur_cmd < right_brace_cmd) {
2083 incr(unbalance);
2084 } else {
2085 decr(unbalance);
2086 if (unbalance == 0)
2087 goto FOUND;
2089 } else if (cur_cmd == mac_param_cmd) {
2090 if (macro_def) {
2091 /* Look for parameter number or \.{\#\#} */
2092 s = cur_tok;
2093 if (xpand)
2094 get_x_token();
2095 else
2096 get_token();
2097 if (cur_cmd != mac_param_cmd) {
2098 if ((cur_tok <= zero_token) || (cur_tok > t)) {
2099 print_err("Illegal parameter number in definition of ");
2100 sprint_cs(warning_index);
2101 help3("You meant to type ## instead of #, right?",
2102 "Or maybe a } was forgotten somewhere earlier, and things",
2103 "are all screwed up? I'm going to assume that you meant ##.");
2104 back_error();
2105 cur_tok = s;
2106 } else {
2107 cur_tok = out_param_token - '0' + cur_chr;
2112 store_new_token(cur_tok);
2114 FOUND:
2115 scanner_status = normal;
2116 if (hash_brace != 0)
2117 store_new_token(hash_brace);
2118 return p;
2121 @ Here we declare two trivial procedures in order to avoid mutually
2122 recursive procedures with parameters.
2125 void scan_normal_glue(void)
2127 scan_glue(glue_val_level);
2130 void scan_mu_glue(void)
2132 scan_glue(mu_val_level);
2135 @ The |scan_expr| procedure scans and evaluates an expression.
2137 @ Evaluating an expression is a recursive process: When the left
2138 parenthesis of a subexpression is scanned we descend to the next level
2139 of recursion; the previous level is resumed with the matching right
2140 parenthesis.
2143 typedef enum {
2144 expr_none = 0, /* \.( seen, or \.( $\langle\it expr\rangle$ \.) seen */
2145 expr_add = 1, /* \.( $\langle\it expr\rangle$ \.+ seen */
2146 expr_sub = 2, /* \.( $\langle\it expr\rangle$ \.- seen */
2147 expr_mult = 3, /* $\langle\it term\rangle$ \.* seen */
2148 expr_div = 4, /* $\langle\it term\rangle$ \./ seen */
2149 expr_scale = 5, /* $\langle\it term\rangle$ \.* $\langle\it factor\rangle$ \./ seen */
2150 } expression_states;
2153 @ We want to make sure that each term and (intermediate) result is in
2154 the proper range. Integer values must not exceed |infinity|
2155 ($2^{31}-1$) in absolute value, dimensions must not exceed |max_dimen|
2156 ($2^{30}-1$). We avoid the absolute value of an integer, because this
2157 might fail for the value $-2^{31}$ using 32-bit arithmetic.
2159 @ clear a number or dimension and set |arith_error|
2162 #define num_error(A) do { \
2163 arith_error=true; \
2164 A=0; \
2165 } while (0)
2167 @ clear a glue spec and set |arith_error|
2170 #define glue_error(A) do { \
2171 arith_error=true; \
2172 delete_glue_ref(A); \
2173 A=new_spec(zero_glue); \
2174 } while (0)
2176 #define normalize_glue(A) do { \
2177 if (stretch(A)==0) stretch_order(A)=normal; \
2178 if (shrink(A)==0) shrink_order(A)=normal; \
2179 } while (0)
2181 @ Parenthesized subexpressions can be inside expressions, and this
2182 nesting has a stack. Seven local variables represent the top of the
2183 expression stack: |p| points to pushed-down entries, if any; |l|
2184 specifies the type of expression currently beeing evaluated; |e| is the
2185 expression so far and |r| is the state of its evaluation; |t| is the
2186 term so far and |s| is the state of its evaluation; finally |n| is the
2187 numerator for a combined multiplication and division, if any.
2190 #define expr_type(A) type((A)+1)
2191 #define expr_state(A) subtype((A)+1)
2192 #define expr_e_field(A) vlink((A)+1) /* saved expression so far */
2193 #define expr_t_field(A) vlink((A)+2) /* saved term so far */
2194 #define expr_n_field(A) vinfo((A)+2) /* saved numerator */
2196 #define expr_add_sub(A,B,C) add_or_sub((A),(B),(C),(r==expr_sub))
2197 #define expr_a(A,B) expr_add_sub((A),(B),max_dimen)
2200 The function |add_or_sub(x,y,max_answer,negative)| computes the sum
2201 (for |negative=false|) or difference (for |negative=true|) of |x| and
2202 |y|, provided the absolute value of the result does not exceed
2203 |max_answer|.
2206 inline static int add_or_sub(int x, int y, int max_answer, boolean negative)
2208 int a; /* the answer */
2209 if (negative)
2210 negate(y);
2211 if (x >= 0) {
2212 if (y <= max_answer - x)
2213 a = x + y;
2214 else
2215 num_error(a);
2216 } else if (y >= -max_answer - x) {
2217 a = x + y;
2218 } else {
2219 num_error(a);
2221 return a;
2224 #define expr_m(A) A = nx_plus_y((A),f,0)
2225 #define expr_d(A) A=quotient((A),f)
2227 @ The function |quotient(n,d)| computes the rounded quotient
2228 $q=\lfloor n/d+{1\over2}\rfloor$, when $n$ and $d$ are positive.
2231 inline static int quotient(int n, int d)
2233 boolean negative; /* should the answer be negated? */
2234 int a; /* the answer */
2235 if (d == 0) {
2236 num_error(a);
2237 } else {
2238 if (d > 0) {
2239 negative = false;
2240 } else {
2241 negate(d);
2242 negative = true;
2244 if (n < 0) {
2245 negate(n);
2246 negative = !negative;
2248 a = n / d;
2249 n = n - a * d;
2250 d = n - d; /* avoid certain compiler optimizations! */
2251 if (d + n >= 0)
2252 incr(a);
2253 if (negative)
2254 negate(a);
2256 return a;
2259 #define expr_s(A) A=fract((A),n,f,max_dimen)
2261 @ Finally, the function |fract(x,n,d,max_answer)| computes the integer
2262 $q=\lfloor xn/d+{1\over2}\rfloor$, when $x$, $n$, and $d$ are positive
2263 and the result does not exceed |max_answer|. We can't use floating
2264 point arithmetic since the routine must produce identical results in all
2265 cases; and it would be too dangerous to multiply by~|n| and then divide
2266 by~|d|, in separate operations, since overflow might well occur. Hence
2267 this subroutine simulates double precision arithmetic, somewhat
2268 analogous to Metafont's |make_fraction| and |take_fraction| routines.
2271 int fract(int x, int n, int d, int max_answer)
2273 boolean negative; /* should the answer be negated? */
2274 int a; /* the answer */
2275 int f; /* a proper fraction */
2276 int h; /* smallest integer such that |2*h>=d| */
2277 int r; /* intermediate remainder */
2278 int t; /* temp variable */
2279 if (d == 0)
2280 goto TOO_BIG;
2281 a = 0;
2282 if (d > 0) {
2283 negative = false;
2284 } else {
2285 negate(d);
2286 negative = true;
2288 if (x < 0) {
2289 negate(x);
2290 negative = !negative;
2291 } else if (x == 0) {
2292 goto DONE;
2294 if (n < 0) {
2295 negate(n);
2296 negative = !negative;
2298 t = n / d;
2299 if (t > max_answer / x)
2300 goto TOO_BIG;
2301 a = t * x;
2302 n = n - t * d;
2303 if (n == 0)
2304 goto FOUND;
2305 t = x / d;
2306 if (t > (max_answer - a) / n)
2307 goto TOO_BIG;
2308 a = a + t * n;
2309 x = x - t * d;
2310 if (x == 0)
2311 goto FOUND;
2312 if (x < n) {
2313 t = x;
2314 x = n;
2315 n = t;
2317 /* now |0<n<=x<d| */
2318 /* Compute $f=\lfloor xn/d+{1\over2}\rfloor$; */
2319 /* The loop here preserves the following invariant relations
2320 between |f|, |x|, |n|, and~|r|:
2321 (i)~$f+\lfloor(xn+(r+d))/d\rfloor=\lfloor x_0n_0/d+{1\over2}\rfloor$;
2322 (ii)~|-d<=r<0<n<=x<d|, where $x_0$, $n_0$ are the original values of~$x$
2323 and $n$. */
2324 /* Notice that the computation specifies |(x-d)+x| instead of |(x+x)-d|,
2325 because the latter could overflow. */
2326 f = 0;
2327 r = (d / 2) - d;
2328 h = -r;
2329 while (1) {
2330 if (odd(n)) {
2331 r = r + x;
2332 if (r >= 0) {
2333 r = r - d;
2334 incr(f);
2337 n = n / 2;
2338 if (n == 0)
2339 break;
2340 if (x < h) {
2341 x = x + x;
2342 } else {
2343 t = x - d;
2344 x = t + x;
2345 f = f + n;
2346 if (x < n) {
2347 if (x == 0)
2348 break;
2349 t = x;
2350 x = n;
2351 n = t;
2356 if (f > (max_answer - a))
2357 goto TOO_BIG;
2358 a = a + f;
2359 FOUND:
2360 if (negative)
2361 negate(a);
2362 goto DONE;
2363 TOO_BIG:
2364 num_error(a);
2365 DONE:
2366 return a;
2369 @ @c
2370 static void scan_expr(void)
2371 { /* scans and evaluates an expression */
2372 boolean a, b; /* saved values of |arith_error| */
2373 int l; /* type of expression */
2374 int r; /* state of expression so far */
2375 int s; /* state of term so far */
2376 int o; /* next operation or type of next factor */
2377 int e; /* expression so far */
2378 int t; /* term so far */
2379 int f; /* current factor */
2380 int n; /* numerator of combined multiplication and division */
2381 halfword p; /* top of expression stack */
2382 halfword q; /* for stack manipulations */
2383 l = cur_val_level;
2384 a = arith_error;
2385 b = false;
2386 p = null;
2387 /* Scan and evaluate an expression |e| of type |l| */
2388 RESTART:
2389 r = expr_none;
2390 e = 0;
2391 s = expr_none;
2392 t = 0;
2393 n = 0;
2394 CONTINUE:
2395 if (s == expr_none)
2396 o = l;
2397 else
2398 o = int_val_level;
2399 /* Scan a factor |f| of type |o| or start a subexpression */
2400 /* Get the next non-blank non-call token */
2401 do {
2402 get_x_token();
2403 } while (cur_cmd == spacer_cmd);
2405 if (cur_tok == other_token + '(') {
2406 /* Push the expression stack and |goto restart| */
2407 q = new_node(expr_node, 0);
2408 vlink(q) = p;
2409 expr_type(q) = (quarterword) l;
2410 expr_state(q) = (quarterword) (4 * s + r);
2411 expr_e_field(q) = e;
2412 expr_t_field(q) = t;
2413 expr_n_field(q) = n;
2414 p = q;
2415 l = o;
2416 goto RESTART;
2418 back_input();
2419 if ((o == int_val_level) || (o == attr_val_level))
2420 scan_int();
2421 else if (o == dimen_val_level)
2422 scan_normal_dimen();
2423 else if (o == glue_val_level)
2424 scan_normal_glue();
2425 else
2426 scan_mu_glue();
2427 f = cur_val;
2429 FOUND:
2430 /* Scan the next operator and set |o| */
2431 /* Get the next non-blank non-call token */
2432 do {
2433 get_x_token();
2434 } while (cur_cmd == spacer_cmd);
2436 if (cur_tok == other_token + '+') {
2437 o = expr_add;
2438 } else if (cur_tok == other_token + '-') {
2439 o = expr_sub;
2440 } else if (cur_tok == other_token + '*') {
2441 o = expr_mult;
2442 } else if (cur_tok == other_token + '/') {
2443 o = expr_div;
2444 } else {
2445 o = expr_none;
2446 if (p == null) {
2447 if (cur_cmd != relax_cmd)
2448 back_input();
2449 } else if (cur_tok != other_token + ')') {
2450 print_err("Missing ) inserted for expression");
2451 help1("I was expecting to see `+', `-', `*', `/', or `)'. Didn't.");
2452 back_error();
2456 arith_error = b;
2457 /* Make sure that |f| is in the proper range */
2458 if (((l == int_val_level) || (l == attr_val_level)) || (s > expr_sub)) {
2459 if ((f > infinity) || (f < -infinity))
2460 num_error(f);
2461 } else if (l == dimen_val_level) {
2462 if (abs(f) > max_dimen)
2463 num_error(f);
2464 } else {
2465 if ((abs(width(f)) > max_dimen) || (abs(stretch(f)) > max_dimen) || (abs(shrink(f)) > max_dimen))
2466 glue_error(f);
2469 switch (s) {
2470 /* Cases for evaluation of the current term */
2471 case expr_none:
2473 Applying the factor |f| to the partial term |t| (with the operator
2474 |s|) is delayed until the next operator |o| has been scanned. Here we
2475 handle the first factor of a partial term. A glue spec has to be copied
2476 unless the next operator is a right parenthesis; this allows us later on
2477 to simply modify the glue components.
2479 if ((l >= glue_val_level) && (o != expr_none)) {
2480 t = new_spec(f);
2481 delete_glue_ref(f);
2482 normalize_glue(t);
2483 } else {
2484 t = f;
2486 break;
2487 case expr_mult:
2488 /* If a multiplication is followed by a division, the two operations are
2489 combined into a `scaling' operation. Otherwise the term |t| is
2490 multiplied by the factor |f|. */
2491 if (o == expr_div) {
2492 n = f;
2493 o = expr_scale;
2494 } else if ((l == int_val_level) || (l == attr_val_level)) {
2495 t = mult_integers(t, f);
2496 } else if (l == dimen_val_level) {
2497 expr_m(t);
2498 } else {
2499 expr_m(width(t));
2500 expr_m(stretch(t));
2501 expr_m(shrink(t));
2503 break;
2504 case expr_div:
2505 /* Here we divide the term |t| by the factor |f| */
2506 if (l < glue_val_level) {
2507 expr_d(t);
2508 } else {
2509 expr_d(width(t));
2510 expr_d(stretch(t));
2511 expr_d(shrink(t));
2513 break;
2514 case expr_scale:
2515 /* Here the term |t| is multiplied by the quotient $n/f$. */
2516 if ((l == int_val_level) || (l == attr_val_level)) {
2517 t = fract(t, n, f, infinity);
2518 } else if (l == dimen_val_level) {
2519 expr_s(t);
2520 } else {
2521 expr_s(width(t));
2522 expr_s(stretch(t));
2523 expr_s(shrink(t));
2525 break;
2526 } /* there are no other cases */
2527 if (o > expr_sub) {
2528 s = o;
2529 } else {
2530 /* Evaluate the current expression */
2531 /* When a term |t| has been completed it is copied to, added to, or
2532 subtracted from the expression |e|. */
2533 s = expr_none;
2534 if (r == expr_none) {
2535 e = t;
2536 } else if ((l == int_val_level) || (l == attr_val_level)) {
2537 e = expr_add_sub(e, t, infinity);
2538 } else if (l == dimen_val_level) {
2539 e = expr_a(e, t);
2540 } else {
2541 /* Compute the sum or difference of two glue specs */
2542 /* We know that |stretch_order(e)>normal| implies |stretch(e)<>0| and
2543 |shrink_order(e)>normal| implies |shrink(e)<>0|. */
2544 width(e) = expr_a(width(e), width(t));
2545 if (stretch_order(e) == stretch_order(t)) {
2546 stretch(e) = expr_a(stretch(e), stretch(t));
2547 } else if ((stretch_order(e) < stretch_order(t)) && (stretch(t) != 0)) {
2548 stretch(e) = stretch(t);
2549 stretch_order(e) = stretch_order(t);
2551 if (shrink_order(e) == shrink_order(t)) {
2552 shrink(e) = expr_a(shrink(e), shrink(t));
2553 } else if ((shrink_order(e) < shrink_order(t)) && (shrink(t) != 0)) {
2554 shrink(e) = shrink(t);
2555 shrink_order(e) = shrink_order(t);
2557 delete_glue_ref(t);
2558 normalize_glue(e);
2560 r = o;
2562 b = arith_error;
2563 if (o != expr_none)
2564 goto CONTINUE;
2565 if (p != null) {
2566 /* Pop the expression stack and |goto found| */
2567 f = e;
2568 q = p;
2569 e = expr_e_field(q);
2570 t = expr_t_field(q);
2571 n = expr_n_field(q);
2572 s = expr_state(q) / 4;
2573 r = expr_state(q) % 4;
2574 l = expr_type(q);
2575 p = vlink(q);
2576 flush_node(q);
2577 goto FOUND;
2580 if (b) {
2581 print_err("Arithmetic overflow");
2582 help2("I can't evaluate this expression,",
2583 "since the result is out of range.");
2584 error();
2585 if (l >= glue_val_level) {
2586 delete_glue_ref(e);
2587 e = zero_glue;
2588 add_glue_ref(e);
2589 } else {
2590 e = 0;
2593 arith_error = a;
2594 cur_val = e;
2595 cur_val_level = l;