fixed a bug in openMemStream (LS); deleted unused close_lua_node (HH)
[luatex.git] / source / texk / web2c / luatexdir / tex / scanning.w
blob1adeb5770faf758ee11cc8e5b69081ad0d4424f3
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
23 #include "ptexlib.h"
25 @ @c
26 #define prev_depth cur_list.prev_depth_field
27 #define space_factor cur_list.space_factor_field
28 #define par_shape_ptr equiv(par_shape_loc)
29 #define font_id_text(A) cs_text(font_id_base+(A))
31 #define attribute(A) eqtb[attribute_base+(A)].hh.rh
32 #define dimen(A) eqtb[scaled_base+(A)].hh.rh
33 #undef skip
34 #define skip(A) eqtb[skip_base+(A)].hh.rh
35 #define mu_skip(A) eqtb[mu_skip_base+(A)].hh.rh
36 #define count(A) eqtb[count_base+(A)].hh.rh
37 #define box(A) equiv(box_base+(A))
39 #define text_direction int_par(text_direction_code)
40 #define body_direction int_par(body_direction_code)
43 @ Let's turn now to some procedures that \TeX\ calls upon frequently to digest
44 certain kinds of patterns in the input. Most of these are quite simple;
45 some are quite elaborate. Almost all of the routines call |get_x_token|,
46 which can cause them to be invoked recursively.
48 The |scan_left_brace| routine is called when a left brace is supposed to be
49 the next non-blank token. (The term ``left brace'' means, more precisely,
50 a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
51 appear before the |left_brace|.
54 void scan_left_brace(void)
55 { /* reads a mandatory |left_brace| */
56 /* Get the next non-blank non-relax non-call token */
57 do {
58 get_x_token();
59 } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
61 if (cur_cmd != left_brace_cmd) {
62 print_err("Missing { inserted");
63 help4("A left brace was mandatory here, so I've put one in.",
64 "You might want to delete and/or insert some corrections",
65 "so that I will find a matching right brace soon.",
66 "If you're confused by all this, try typing `I}' now.");
67 back_error();
68 cur_tok = left_brace_token + '{';
69 cur_cmd = left_brace_cmd;
70 cur_chr = '{';
71 incr(align_state);
76 @ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
77 by optional spaces; `\.{\\relax}' is not ignored here.
80 void scan_optional_equals(void)
82 /* Get the next non-blank non-call token */
83 do {
84 get_x_token();
85 } while (cur_cmd == spacer_cmd);
86 if (cur_tok != other_token + '=')
87 back_input();
91 @ Here is a procedure that sounds an alarm when mu and non-mu units
92 are being switched.
95 static void mu_error(void)
97 print_err("Incompatible glue units");
98 help1("I'm going to assume that 1mu=1pt when they're mixed.");
99 error();
103 @ The next routine `|scan_something_internal|' is used to fetch internal
104 numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
105 when expanding constructions like `\.{\\the\\toks0}' and
106 `\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
107 procedure, which calls |scan_something_internal|; on the other hand,
108 |scan_something_internal| also calls |scan_int|, for constructions like
109 `\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
110 have to declare |scan_int| as a |forward| procedure. A few other
111 procedures are also declared at this point.
113 \TeX\ doesn't know exactly what to expect when
114 |scan_something_internal| begins. For example, an integer or
115 dimension or glue value could occur immediately after `\.{\\hskip}';
116 and one can even say \.{\\the} with respect to token lists in
117 constructions like `\.{\\xdef\\o\{\\the\\output\}}'. On the other
118 hand, only integers are allowed after a construction like
119 `\.{\\count}'. To handle the various possibilities,
120 |scan_something_internal| has a |level| parameter, which tells the
121 ``highest'' kind of quantity that |scan_something_internal| is allowed
122 to produce. Eight levels are distinguished, namely |int_val|,
123 |attr_val|, |dimen_val|, |glue_val|, |mu_val|, |dir_val|, |ident_val|,
124 and |tok_val|.
126 The output of |scan_something_internal| (and of the other routines
127 |scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
128 variable |cur_val|, and its level is put into |cur_val_level|. The highest
129 values of |cur_val_level| are special: |mu_val| is used only when
130 |cur_val| points to something in a ``muskip'' register, or to one of the
131 three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
132 |ident_val| is used only when |cur_val| points to a font identifier;
133 |tok_val| is used only when |cur_val| points to |null| or to the reference
134 count of a token list. The last two cases are allowed only when
135 |scan_something_internal| is called with |level=tok_val|.
137 If the output is glue, |cur_val| will point to a glue specification, and
138 the reference count of that glue will have been updated to reflect this
139 reference; if the output is a nonempty token list, |cur_val| will point to
140 its reference count, but in this case the count will not have been updated.
141 Otherwise |cur_val| will contain the integer or scaled value in question.
144 int cur_val; /* value returned by numeric scanners */
145 int cur_val1; /* delcodes are sometimes 51 digits */
146 int cur_val_level; /* the ``level'' of this value */
148 #define scanned_result(A,B) do { \
149 cur_val=A; \
150 cur_val_level=B; \
151 } while (0)
154 @ When a |glue_val| changes to a |dimen_val|, we use the width component
155 of the glue; there is no need to decrease the reference count, since it
156 has not yet been increased. When a |dimen_val| changes to an |int_val|,
157 we use scaled points so that the value doesn't actually change. And when a
158 |mu_val| changes to a |glue_val|, the value doesn't change either.
161 static void downgrade_cur_val(boolean delete_glue)
163 halfword m;
164 if (cur_val_level == glue_val_level) {
165 m = cur_val;
166 cur_val = width(m);
167 if (delete_glue)
168 delete_glue_ref(m);
169 } else if (cur_val_level == mu_val_level) {
170 mu_error();
172 decr(cur_val_level);
175 static void negate_cur_val(boolean delete_glue)
177 halfword m;
178 if (cur_val_level >= glue_val_level) {
179 m = cur_val;
180 cur_val = new_spec(m);
181 if (delete_glue)
182 delete_glue_ref(m);
183 /* Negate all three glue components of |cur_val| */
184 negate(width(cur_val));
185 negate(stretch(cur_val));
186 negate(shrink(cur_val));
188 } else {
189 negate(cur_val);
194 @ Some of the internal items can be fetched both routines,
195 and these have been split off into the next routine, that
196 returns true if the command code was understood
199 static boolean short_scan_something_internal(int cmd, int chr, int level,
200 boolean negative)
202 halfword m; /* |chr_code| part of the operand token */
203 halfword q; /* general purpose index */
204 int p; /* index into |nest| */
205 int save_cur_chr;
206 boolean succeeded = true;
207 m = chr;
208 switch (cmd) {
209 case assign_toks_cmd:
210 scanned_result(equiv(m), tok_val_level);
211 break;
212 case assign_int_cmd:
213 scanned_result(eqtb[m].cint, int_val_level);
214 break;
215 case assign_attr_cmd:
216 scanned_result(eqtb[m].cint, int_val_level);
217 break;
218 case assign_dir_cmd:
219 scanned_result(eqtb[m].cint, dir_val_level);
220 break;
221 case assign_dimen_cmd:
222 scanned_result(eqtb[m].cint, dimen_val_level);
223 break;
224 case assign_glue_cmd:
225 scanned_result(equiv(m), glue_val_level);
226 break;
227 case assign_mu_glue_cmd:
228 scanned_result(equiv(m), mu_val_level);
229 break;
230 case math_style_cmd:
231 scanned_result(m, int_val_level);
232 break;
233 case set_aux_cmd:
234 /* Fetch the |space_factor| or the |prev_depth| */
235 if (abs(cur_list.mode_field) != m) {
236 print_err("Improper ");
237 print_cmd_chr(set_aux_cmd, m);
238 help4("You can refer to \\spacefactor only in horizontal mode;",
239 "you can refer to \\prevdepth only in vertical mode; and",
240 "neither of these is meaningful inside \\write. So",
241 "I'm forgetting what you said and using zero instead.");
242 error();
243 if (level != tok_val_level)
244 scanned_result(0, dimen_val_level);
245 else
246 scanned_result(0, int_val_level);
247 } else if (m == vmode) {
248 scanned_result(prev_depth, dimen_val_level);
249 } else {
250 scanned_result(space_factor, int_val_level);
252 break;
253 case set_prev_graf_cmd:
254 /* Fetch the |prev_graf| */
255 if (cur_list.mode_field == 0) {
256 scanned_result(0, int_val_level); /* |prev_graf=0| within \.{\\write} */
257 } else {
258 p = nest_ptr;
259 while (abs(nest[p].mode_field) != vmode)
260 decr(p);
261 scanned_result(nest[p].pg_field, int_val_level);
263 break;
264 case set_page_int_cmd:
265 /* Fetch the |dead_cycles| or the |insert_penalties| */
266 if (m == 0)
267 cur_val = dead_cycles;
268 else if (m == 2)
269 cur_val = interaction; /* interactionmode */
270 else
271 cur_val = insert_penalties;
272 cur_val_level = int_val_level;
273 break;
274 case set_page_dimen_cmd:
275 /* Fetch something on the |page_so_far| */
276 if ((page_contents == empty) && (!output_active)) {
277 if (m == 0)
278 cur_val = max_dimen;
279 else
280 cur_val = 0;
281 } else {
282 cur_val = page_so_far[m];
284 cur_val_level = dimen_val_level;
285 break;
286 case set_tex_shape_cmd:
287 /* Fetch the |par_shape| size */
288 if (par_shape_ptr == null)
289 cur_val = 0;
290 else
291 cur_val = vinfo(par_shape_ptr + 1);
292 cur_val_level = int_val_level;
293 break;
294 case set_etex_shape_cmd:
295 /* Fetch a penalties array element */
296 scan_int();
297 if ((equiv(m) == null) || (cur_val < 0)) {
298 cur_val = 0;
299 } else {
300 if (cur_val > penalty(equiv(m)))
301 cur_val = penalty(equiv(m));
302 cur_val = penalty(equiv(m) + cur_val);
304 cur_val_level = int_val_level;
305 break;
306 case char_given_cmd:
307 case math_given_cmd:
308 case xmath_given_cmd:
309 scanned_result(cur_chr, int_val_level);
310 break;
311 case last_item_cmd:
312 /* Because the items in this case directly refer to |cur_chr|,
313 it needs to be saved and restored */
314 save_cur_chr = cur_chr;
315 cur_chr = chr;
316 /* Fetch an item in the current node, if appropriate */
317 /* Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are
318 implemented. The reference count for \.{\\lastskip} will be updated later.
320 We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
321 legal in similar contexts. */
323 if (m >= input_line_no_code) {
324 if (m >= eTeX_glue) {
325 /* Process an expression and |return| */
326 if (m < eTeX_mu) {
327 switch (m) {
328 case mu_to_glue_code:
329 scan_mu_glue();
330 break;
331 }; /* there are no other cases */
332 cur_val_level = glue_val_level;
333 } else if (m < eTeX_expr) {
334 switch (m) {
335 case glue_to_mu_code:
336 scan_normal_glue();
337 break;
338 } /* there are no other cases */
339 cur_val_level = mu_val_level;
340 } else {
341 cur_val_level = m - eTeX_expr + int_val_level;
342 scan_expr();
344 /* This code for reducing |cur_val_level| and\slash or negating the
345 result is similar to the one for all the other cases of
346 |scan_something_internal|, with the difference that |scan_expr| has
347 already increased the reference count of a glue specification.
349 while (cur_val_level > level) {
350 downgrade_cur_val(true);
352 if (negative) {
353 negate_cur_val(true);
355 return succeeded;
357 } else if (m >= eTeX_dim) {
358 switch (m) {
359 case font_char_wd_code:
360 case font_char_ht_code:
361 case font_char_dp_code:
362 case font_char_ic_code:
363 scan_font_ident();
364 q = cur_val;
365 scan_char_num();
366 if (char_exists(q, cur_val)) {
367 switch (m) {
368 case font_char_wd_code:
369 cur_val = char_width(q, cur_val);
370 break;
371 case font_char_ht_code:
372 cur_val = char_height(q, cur_val);
373 break;
374 case font_char_dp_code:
375 cur_val = char_depth(q, cur_val);
376 break;
377 case font_char_ic_code:
378 cur_val = char_italic(q, cur_val);
379 break;
380 } /* there are no other cases */
381 } else {
382 cur_val = 0;
384 break;
385 case par_shape_length_code:
386 case par_shape_indent_code:
387 case par_shape_dimen_code:
388 q = cur_chr - par_shape_length_code;
389 scan_int();
390 if ((par_shape_ptr == null) || (cur_val <= 0)) {
391 cur_val = 0;
392 } else {
393 if (q == 2) {
394 q = cur_val % 2;
395 cur_val = (cur_val + q) / 2;
397 if (cur_val > vinfo(par_shape_ptr + 1))
398 cur_val = vinfo(par_shape_ptr + 1);
399 cur_val =
400 varmem[par_shape_ptr + 2 * cur_val - q + 1].cint;
402 cur_val_level = dimen_val_level;
403 break;
404 case glue_stretch_code:
405 case glue_shrink_code:
406 scan_normal_glue();
407 q = cur_val;
408 if (m == glue_stretch_code)
409 cur_val = stretch(q);
410 else
411 cur_val = shrink(q);
412 delete_glue_ref(q);
413 break;
414 } /* there are no other cases */
415 cur_val_level = dimen_val_level;
416 } else {
417 switch (m) {
418 case input_line_no_code:
419 cur_val = line;
420 break;
421 case badness_code:
422 cur_val = last_badness;
423 break;
424 case luatex_version_code:
425 cur_val = get_luatexversion();
426 break;
427 case pdf_last_obj_code:
428 cur_val = pdf_last_obj;
429 break;
430 case pdf_last_xform_code:
431 cur_val = pdf_last_xform;
432 break;
433 case pdf_last_ximage_code:
434 cur_val = pdf_last_ximage;
435 break;
436 case pdf_last_ximage_pages_code:
437 cur_val = pdf_last_ximage_pages;
438 break;
439 case pdf_last_annot_code:
440 cur_val = pdf_last_annot;
441 break;
442 case last_x_pos_code:
443 cur_val = pdf_last_pos.h;
444 break;
445 case last_y_pos_code:
446 cur_val = pdf_last_pos.v;
447 break;
448 case pdf_retval_code:
449 cur_val = pdf_retval;
450 break;
451 case pdf_last_ximage_colordepth_code:
452 cur_val = pdf_last_ximage_colordepth;
453 break;
454 case random_seed_code:
455 cur_val = random_seed;
456 break;
457 case pdf_last_link_code:
458 cur_val = pdf_last_link;
459 break;
460 case eTeX_version_code:
461 cur_val = eTeX_version;
462 break;
463 case eTeX_minor_version_code:
464 cur_val = eTeX_minor_version;
465 break;
466 case current_group_level_code:
467 cur_val = cur_level - level_one;
468 break;
469 case current_group_type_code:
470 cur_val = cur_group;
471 break;
472 case current_if_level_code:
473 q = cond_ptr;
474 cur_val = 0;
475 while (q != null) {
476 incr(cur_val);
477 q = vlink(q);
479 break;
480 case current_if_type_code:
481 if (cond_ptr == null)
482 cur_val = 0;
483 else if (cur_if < unless_code)
484 cur_val = cur_if + 1;
485 else
486 cur_val = -(cur_if - unless_code + 1);
487 break;
488 case current_if_branch_code:
489 if ((if_limit == or_code) || (if_limit == else_code))
490 cur_val = 1;
491 else if (if_limit == fi_code)
492 cur_val = -1;
493 else
494 cur_val = 0;
495 break;
496 case glue_stretch_order_code:
497 case glue_shrink_order_code:
498 scan_normal_glue();
499 q = cur_val;
500 if (m == glue_stretch_order_code)
501 cur_val = stretch_order(q);
502 else
503 cur_val = shrink_order(q);
504 delete_glue_ref(q);
505 break;
507 } /* there are no other cases */
508 cur_val_level = int_val_level;
510 } else {
511 if (cur_chr == glue_val_level)
512 cur_val = zero_glue;
513 else
514 cur_val = 0;
515 if (cur_chr == last_node_type_code) {
516 cur_val_level = int_val_level;
517 if ((cur_list.tail_field == cur_list.head_field)
518 || (cur_list.mode_field == 0))
519 cur_val = -1;
520 } else {
521 cur_val_level = cur_chr; /* assumes identical values */
523 if ((cur_list.tail_field != contrib_head) &&
524 !is_char_node(cur_list.tail_field) &&
525 (cur_list.mode_field != 0)) {
526 switch (cur_chr) {
527 case lastpenalty_code:
528 if (type(cur_list.tail_field) == penalty_node)
529 cur_val = penalty(cur_list.tail_field);
530 break;
531 case lastkern_code:
532 if (type(cur_list.tail_field) == kern_node)
533 cur_val = width(cur_list.tail_field);
534 break;
535 case lastskip_code:
536 if (type(cur_list.tail_field) == glue_node)
537 cur_val = glue_ptr(cur_list.tail_field);
538 if (subtype(cur_list.tail_field) == mu_glue)
539 cur_val_level = mu_val_level;
540 break;
541 case last_node_type_code:
542 cur_val = visible_last_node_type(cur_list.tail_field);
543 break;
544 } /* there are no other cases */
545 } else if ((cur_list.mode_field == vmode)
546 && (cur_list.tail_field == cur_list.head_field)) {
547 switch (cur_chr) {
548 case lastpenalty_code:
549 cur_val = last_penalty;
550 break;
551 case lastkern_code:
552 cur_val = last_kern;
553 break;
554 case lastskip_code:
555 if (last_glue != max_halfword)
556 cur_val = last_glue;
557 break;
558 case last_node_type_code:
559 cur_val = last_node_type;
560 break;
561 } /* there are no other cases */
564 cur_chr = save_cur_chr;
565 break;
566 default:
567 succeeded = false;
569 if (succeeded) {
570 while (cur_val_level > level) {
571 /* Convert |cur_val| to a lower level */
572 downgrade_cur_val(false);
574 /* Fix the reference count, if any, and negate |cur_val| if |negative| */
575 /* If |cur_val| points to a glue specification at this point, the reference
576 count for the glue does not yet include the reference by |cur_val|.
577 If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
579 if (negative) {
580 negate_cur_val(false);
581 } else if ((cur_val_level >= glue_val_level)
582 && (cur_val_level <= mu_val_level)) {
583 add_glue_ref(cur_val);
586 return succeeded;
589 @ First, here is a short routine that is called from lua code. All
590 the real work is delegated to |short_scan_something_internal| that
591 is shared between this routine and |scan_something_internal|.
594 void scan_something_simple(halfword cmd, halfword subitem)
596 /* negative is never true */
597 if (!short_scan_something_internal(cmd, subitem, tok_val_level, false)) {
598 /* Complain that |texlib| can not do this; give zero result */
599 print_err("You can't use `");
600 print_cmd_chr((quarterword) cmd, subitem);
601 tprint("' as tex library index");
602 help1("I'm forgetting what you said and using zero instead.");
603 error();
604 scanned_result(0, int_val_level);
610 @ OK, we're ready for |scan_something_internal| itself. A second parameter,
611 |negative|, is set |true| if the value that is found should be negated.
612 It is assumed that |cur_cmd| and |cur_chr| represent the first token of
613 the internal quantity to be scanned; an error will be signalled if
614 |cur_cmd<min_internal| or |cur_cmd>max_internal|.
617 void scan_something_internal(int level, boolean negative)
619 /* fetch an internal parameter */
620 halfword m; /* |chr_code| part of the operand token */
621 int n, k; /* accumulators */
622 RESTART:
623 m = cur_chr;
624 if (!short_scan_something_internal(cur_cmd, cur_chr, level, negative)) {
625 switch (cur_cmd) {
626 case def_char_code_cmd:
627 /* Fetch a character code from some table */
628 scan_char_num();
629 if (m == math_code_base) {
630 cur_val1 = get_math_code_num(cur_val, true);
631 scanned_result(cur_val1, int_val_level);
632 } else if (m == lc_code_base) {
633 cur_val1 = get_lc_code(cur_val);
634 scanned_result(cur_val1, int_val_level);
635 } else if (m == uc_code_base) {
636 cur_val1 = get_uc_code(cur_val);
637 scanned_result(cur_val1, int_val_level);
638 } else if (m == sf_code_base) {
639 cur_val1 = get_sf_code(cur_val);
640 scanned_result(cur_val1, int_val_level);
641 } else if (m == cat_code_base) {
642 cur_val1 = get_cat_code(int_par(cat_code_table_code), cur_val);
643 scanned_result(cur_val1, int_val_level);
644 } else {
645 confusion("def_char");
647 break;
648 case def_del_code_cmd:
649 /* Fetch a character code from some table */
650 scan_char_num();
651 cur_val1 = get_del_code_num(cur_val);
652 scanned_result(cur_val1, int_val_level);
653 break;
654 case extdef_math_code_cmd:
655 /* Fetch an extended math code table value */
656 scan_char_num();
657 cur_val1 = get_math_code_num(cur_val, false);
658 scanned_result(cur_val1, int_val_level);
659 break;
660 case toks_register_cmd:
661 case set_font_cmd:
662 case def_font_cmd:
663 case letterspace_font_cmd:
664 case pdf_copy_font_cmd:
665 /* Fetch a token list or font identifier, provided that |level=tok_val| */
666 if (level != tok_val_level) {
667 print_err("Missing number, treated as zero");
668 help3("A number should have been here; I inserted `0'.",
669 "(If you can't figure out why I needed to see a number,",
670 "look up `weird error' in the index to The TeXbook.)");
671 back_error();
672 scanned_result(0, dimen_val_level);
673 } else if (cur_cmd == toks_register_cmd) {
674 scan_register_num();
675 m = toks_base + cur_val;
676 scanned_result(equiv(m), tok_val_level);
677 } else {
678 back_input();
679 scan_font_ident();
680 scanned_result(font_id_base + cur_val, ident_val_level);
682 break;
683 case def_family_cmd:
684 /* Fetch a math font identifier */
685 scan_char_num();
686 cur_val1 = fam_fnt(cur_val, m);
687 scanned_result(font_id_base + cur_val1, ident_val_level);
688 break;
689 case set_math_param_cmd:
690 /* Fetch a math param */
691 cur_val1 = cur_chr;
692 get_token();
693 if (cur_cmd != math_style_cmd) {
694 print_err("Missing math style, treated as \\displaystyle");
695 help1
696 ("A style should have been here; I inserted `\\displaystyle'.");
697 cur_val = display_style;
698 back_error();
699 } else {
700 cur_val = cur_chr;
702 if (cur_val1 < math_param_first_mu_glue) {
703 if (cur_val1 == math_param_radical_degree_raise) {
704 cur_val1 = get_math_param(cur_val1, cur_chr);
705 scanned_result(cur_val1, int_val_level);
706 } else {
707 cur_val1 = get_math_param(cur_val1, cur_chr);
708 scanned_result(cur_val1, dimen_val_level);
710 } else {
711 cur_val1 = get_math_param(cur_val1, cur_chr);
712 if (cur_val1 == thin_mu_skip_code)
713 cur_val1 = glue_par(thin_mu_skip_code);
714 else if (cur_val1 == med_mu_skip_code)
715 cur_val1 = glue_par(med_mu_skip_code);
716 else if (cur_val1 == thick_mu_skip_code)
717 cur_val1 = glue_par(thick_mu_skip_code);
718 scanned_result(cur_val1, mu_val_level);
720 break;
721 case assign_box_dir_cmd:
722 scan_register_num();
723 m = cur_val;
724 if (box(m) != null)
725 cur_val = box_dir(box(m));
726 else
727 cur_val = 0;
728 cur_val_level = dir_val_level;
729 break;
730 case set_box_dimen_cmd:
731 /* Fetch a box dimension */
732 scan_register_num();
733 if (box(cur_val) == null)
734 cur_val = 0;
735 else
736 cur_val = varmem[box(cur_val) + m].cint;
737 cur_val_level = dimen_val_level;
738 break;
739 case assign_font_dimen_cmd:
740 /* Fetch a font dimension */
741 get_font_dimen();
742 break;
743 case assign_font_int_cmd:
744 /* Fetch a font integer */
745 scan_font_ident();
746 if (m == 0) {
747 scanned_result(hyphen_char(cur_val), int_val_level);
748 } else if (m == 1) {
749 scanned_result(skew_char(cur_val), int_val_level);
750 } else if (m == no_lig_code) {
751 scanned_result(test_no_ligatures(cur_val), int_val_level);
752 } else {
753 n = cur_val;
754 scan_char_num();
755 k = cur_val;
756 switch (m) {
757 case lp_code_base:
758 scanned_result(get_lp_code(n, k), int_val_level);
759 break;
760 case rp_code_base:
761 scanned_result(get_rp_code(n, k), int_val_level);
762 break;
763 case ef_code_base:
764 scanned_result(get_ef_code(n, k), int_val_level);
765 break;
766 case tag_code:
767 scanned_result(get_tag_code(n, k), int_val_level);
768 break;
771 break;
772 case register_cmd:
773 /* Fetch a register */
774 scan_register_num();
775 switch (m) {
776 case int_val_level:
777 cur_val = count(cur_val);
778 break;
779 case attr_val_level:
780 cur_val = attribute(cur_val);
781 break;
782 case dimen_val_level:
783 cur_val = dimen(cur_val);
784 break;
785 case glue_val_level:
786 cur_val = skip(cur_val);
787 break;
788 case mu_val_level:
789 cur_val = mu_skip(cur_val);
790 break;
791 } /* there are no other cases */
792 cur_val_level = m;
793 break;
794 case ignore_spaces_cmd: /* trap unexpandable primitives */
795 if (cur_chr == 1) {
796 /* Reset |cur_tok| for unexpandable primitives, goto restart */
797 /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
798 an integer or an internal values should have been found. It fetches the
799 next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
800 primitive value of that token. No expansion takes place, because the
801 next token may be all sorts of things. This could trigger further
802 expansion creating new errors.
804 get_token();
805 cur_cs = prim_lookup(cs_text(cur_cs));
806 if (cur_cs != undefined_primitive) {
807 cur_cmd = get_prim_eq_type(cur_cs);
808 cur_chr = get_prim_equiv(cur_cs);
809 cur_tok = token_val(cur_cmd, cur_chr);
810 } else {
811 cur_cmd = relax_cmd;
812 cur_chr = 0;
813 cur_tok = cs_token_flag + frozen_relax;
814 cur_cs = frozen_relax;
816 goto RESTART;
818 break;
819 default:
820 /* Complain that \.{\\the} can not do this; give zero result */
821 print_err("You can't use `");
822 print_cmd_chr((quarterword) cur_cmd, cur_chr);
823 tprint("' after \\the");
824 help1("I'm forgetting what you said and using zero instead.");
825 error();
826 if (level != tok_val_level)
827 scanned_result(0, dimen_val_level);
828 else
829 scanned_result(0, int_val_level);
830 break;
832 while (cur_val_level > level) {
833 /* Convert |cur_val| to a lower level */
834 downgrade_cur_val(false);
836 /* Fix the reference count, if any, and negate |cur_val| if |negative| */
837 /* If |cur_val| points to a glue specification at this point, the reference
838 count for the glue does not yet include the reference by |cur_val|.
839 If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
841 if (negative) {
842 negate_cur_val(false);
843 } else if ((cur_val_level >= glue_val_level) &&
844 (cur_val_level <= mu_val_level)) {
845 add_glue_ref(cur_val);
851 @ It is nice to have routines that say what they do, so the original
852 |scan_eight_bit_int| is superceded by |scan_register_num| and
853 |scan_mark_num|. It may become split up even further in the future.
855 Many of the |restricted classes| routines are the essentially
856 the same except for the upper limit and the error message, so it makes
857 sense to combine these all into one function.
860 void scan_limited_int(int max, const char *name)
862 char hlp[80];
863 scan_int();
864 if ((cur_val < 0) || (cur_val > max)) {
865 if (name == NULL) {
866 snprintf(hlp, 80,
867 "Since I expected to read a number between 0 and %d,",
868 max);
869 print_err("Bad number");
870 } else {
871 char msg[80];
872 snprintf(hlp, 80, "A %s must be between 0 and %d.", name, max);
873 snprintf(msg, 80, "Bad %s", name);
874 print_err(msg);
876 help2(hlp, "I changed this one to zero.");
877 int_error(cur_val);
878 cur_val = 0;
882 @ @c
883 void scan_fifteen_bit_int(void)
885 scan_real_fifteen_bit_int();
886 cur_val = ((cur_val / 0x1000) * 0x1000000) +
887 (((cur_val % 0x1000) / 0x100) * 0x10000) + (cur_val % 0x100);
890 @ @c
891 void scan_fifty_one_bit_int(void)
893 int iiii;
894 scan_int();
895 if ((cur_val < 0) || (cur_val > 0777777777)) {
896 print_err("Bad delimiter code");
897 help2
898 ("A numeric delimiter (first part) must be between 0 and 2^{27}-1.",
899 "I changed this one to zero.");
900 int_error(cur_val);
901 cur_val = 0;
903 iiii = cur_val;
904 scan_int();
905 if ((cur_val < 0) || (cur_val > 0xFFFFFF)) {
906 print_err("Bad delimiter code");
907 help2
908 ("A numeric delimiter (second part) must be between 0 and 2^{24}-1.",
909 "I changed this one to zero.");
910 int_error(cur_val);
911 cur_val = 0;
913 cur_val1 = cur_val;
914 cur_val = iiii;
918 @ To be able to determine whether \.{\\write18} is enabled from within
919 \TeX\ we also implement \.{\\eof18}. We sort of cheat by having an
920 additional route |scan_four_bit_int_or_18| which is the same as
921 |scan_four_bit_int| except it also accepts the value 18.
924 void scan_four_bit_int_or_18(void)
926 scan_int();
927 if ((cur_val < 0) || ((cur_val > 15) && (cur_val != 18))) {
928 print_err("Bad number");
929 help2("Since I expected to read a number between 0 and 15,",
930 "I changed this one to zero.");
931 int_error(cur_val);
932 cur_val = 0;
939 @ An integer number can be preceded by any number of spaces and `\.+' or
940 `\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
941 octal constant (i.e., radix 8, preceded by~'), a hexadecimal constant
942 (radix 16, preceded by~"), an alphabetic constant (preceded by~`), or
943 an internal variable. After scanning is complete,
944 |cur_val| will contain the answer, which must be at most
945 $2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
946 10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
947 otherwise |radix| is set to zero. An optional space follows a constant.
950 int radix; /* |scan_int| sets this to 8, 10, 16, or zero */
953 @ The |scan_int| routine is used also to scan the integer part of a
954 fraction; for example, the `\.3' in `\.{3.14159}' will be found by
955 |scan_int|. The |scan_dimen| routine assumes that |cur_tok=point_token|
956 after the integer part of such a fraction has been scanned by |scan_int|,
957 and that the decimal point has been backed up to be scanned again.
960 void scan_int(void)
961 { /* sets |cur_val| to an integer */
962 boolean negative; /* should the answer be negated? */
963 int m; /* |$2^{31}$ / radix|, the threshold of danger */
964 int d; /* the digit just scanned */
965 boolean vacuous; /* have no digits appeared? */
966 boolean OK_so_far; /* has an error message been issued? */
967 radix = 0;
968 OK_so_far = true;
969 /* Get the next non-blank non-sign token; set |negative| appropriately */
970 negative = false;
971 do {
972 /* Get the next non-blank non-call token */
973 do {
974 get_x_token();
975 } while (cur_cmd == spacer_cmd);
976 if (cur_tok == other_token + '-') {
977 negative = !negative;
978 cur_tok = other_token + '+';
980 } while (cur_tok == other_token + '+');
982 RESTART:
983 if (cur_tok == alpha_token) {
984 /* Scan an alphabetic character code into |cur_val| */
985 /* A space is ignored after an alphabetic character constant, so that
986 such constants behave like numeric ones. */
987 get_token(); /* suppress macro expansion */
988 if (cur_tok < cs_token_flag) {
989 cur_val = cur_chr;
990 if (cur_cmd <= right_brace_cmd) {
991 if (cur_cmd == right_brace_cmd)
992 incr(align_state);
993 else
994 decr(align_state);
996 } else { /* the value of a csname in this context is its name */
997 str_number txt = cs_text(cur_tok - cs_token_flag);
998 if (is_active_cs(txt))
999 cur_val = active_cs_value(txt);
1000 else if (single_letter(txt))
1001 cur_val = pool_to_unichar(str_string(txt));
1002 else
1003 cur_val = (biggest_char + 1);
1005 if (cur_val > biggest_char) {
1006 print_err("Improper alphabetic constant");
1007 help2("A one-character control sequence belongs after a ` mark.",
1008 "So I'm essentially inserting \\0 here.");
1009 cur_val = '0';
1010 back_error();
1011 } else {
1012 /* Scan an optional space */
1013 get_x_token();
1014 if (cur_cmd != spacer_cmd)
1015 back_input();
1018 } else if (cur_tok == cs_token_flag + frozen_primitive) {
1019 /* Reset |cur_tok| for unexpandable primitives, goto restart */
1020 /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
1021 an integer or an internal values should have been found. It fetches the
1022 next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
1023 primitive value of that token. No expansion takes place, because the
1024 next token may be all sorts of things. This could trigger further
1025 expansion creating new errors.
1027 get_token();
1028 cur_cs = prim_lookup(cs_text(cur_cs));
1029 if (cur_cs != undefined_primitive) {
1030 cur_cmd = get_prim_eq_type(cur_cs);
1031 cur_chr = get_prim_equiv(cur_cs);
1032 cur_tok = token_val(cur_cmd, cur_chr);
1033 } else {
1034 cur_cmd = relax_cmd;
1035 cur_chr = 0;
1036 cur_tok = cs_token_flag + frozen_relax;
1037 cur_cs = frozen_relax;
1039 goto RESTART;
1040 } else if (cur_cmd == math_style_cmd) {
1041 cur_val = cur_chr;
1042 } else if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1043 scan_something_internal(int_val_level, false);
1044 } else {
1045 /* Scan a numeric constant */
1046 radix = 10;
1047 m = 214748364;
1048 if (cur_tok == octal_token) {
1049 radix = 8;
1050 m = 02000000000;
1051 get_x_token();
1052 } else if (cur_tok == hex_token) {
1053 radix = 16;
1054 m = 01000000000;
1055 get_x_token();
1057 vacuous = true;
1058 cur_val = 0;
1059 /* Accumulate the constant until |cur_tok| is not a suitable digit */
1060 while (1) {
1061 if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token)
1062 && (cur_tok <= zero_token + 9)) {
1063 d = cur_tok - zero_token;
1064 } else if (radix == 16) {
1065 if ((cur_tok <= A_token + 5) && (cur_tok >= A_token)) {
1066 d = cur_tok - A_token + 10;
1067 } else if ((cur_tok <= other_A_token + 5)
1068 && (cur_tok >= other_A_token)) {
1069 d = cur_tok - other_A_token + 10;
1070 } else {
1071 break;
1073 } else {
1074 break;
1076 vacuous = false;
1077 if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10))) {
1078 if (OK_so_far) {
1079 print_err("Number too big");
1080 help2
1081 ("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
1082 "so I'm using that number instead of yours.");
1083 error();
1084 cur_val = infinity;
1085 OK_so_far = false;
1087 } else {
1088 cur_val = cur_val * radix + d;
1090 get_x_token();
1092 if (vacuous) {
1093 /* Express astonishment that no number was here */
1094 print_err("Missing number, treated as zero");
1095 help3("A number should have been here; I inserted `0'.",
1096 "(If you can't figure out why I needed to see a number,",
1097 "look up `weird error' in the index to The TeXbook.)");
1098 back_error();
1099 } else if (cur_cmd != spacer_cmd) {
1100 back_input();
1103 if (negative)
1104 negate(cur_val);
1108 @ The following code is executed when |scan_something_internal| was
1109 called asking for |mu_val|, when we really wanted a ``mudimen'' instead
1110 of ``muglue.''
1113 static void coerce_glue(void)
1115 int v;
1116 if (cur_val_level >= glue_val_level) {
1117 v = width(cur_val);
1118 delete_glue_ref(cur_val);
1119 cur_val = v;
1125 @ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
1126 a |scaled| value, i.e., an integral number of sp. One of its main tasks
1127 is therefore to interpret the abbreviations for various kinds of units and
1128 to convert measurements to scaled points.
1130 There are three parameters: |mu| is |true| if the finite units must be
1131 `\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
1132 |inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
1133 are permitted; and |shortcut| is |true| if |cur_val| already contains
1134 an integer and only the units need to be considered.
1136 The order of infinity that was found in the case of infinite glue is returned
1137 in the global variable |cur_order|.
1140 int cur_order; /* order of infinity found by |scan_dimen| */
1143 @ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
1144 may begin with |scan_int|. This explains why it is convenient to use
1145 |scan_int| also for the integer part of a decimal fraction.
1147 Several branches of |scan_dimen| work with |cur_val| as an integer and
1148 with an auxiliary fraction |f|, so that the actual quantity of interest is
1149 $|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
1150 representation is put into the single word |cur_val|, which suddenly
1151 switches significance from |integer| to |scaled|.
1154 void scan_dimen(boolean mu, boolean inf, boolean shortcut)
1155 /* sets |cur_val| to a dimension */
1157 boolean negative; /* should the answer be negated? */
1158 int f; /* numerator of a fraction whose denominator is $2^{16}$ */
1159 /* Local variables for dimension calculations */
1160 int num, denom; /* conversion ratio for the scanned units */
1161 int k, kk; /* number of digits in a decimal fraction */
1162 halfword p, q; /* top of decimal digit stack */
1163 scaled v; /* an internal dimension */
1164 int save_cur_val; /* temporary storage of |cur_val| */
1166 f = 0;
1167 arith_error = false;
1168 cur_order = normal;
1169 negative = false;
1170 if (!shortcut) {
1171 /* Get the next non-blank non-sign... */
1172 negative = false;
1173 do {
1174 /* Get the next non-blank non-call token */
1175 do {
1176 get_x_token();
1177 } while (cur_cmd == spacer_cmd);
1178 if (cur_tok == other_token + '-') {
1179 negative = !negative;
1180 cur_tok = other_token + '+';
1182 } while (cur_tok == other_token + '+');
1184 if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1185 /* Fetch an internal dimension and |goto attach_sign|,
1186 or fetch an internal integer */
1187 if (mu) {
1188 scan_something_internal(mu_val_level, false);
1189 coerce_glue();
1190 if (cur_val_level == mu_val_level)
1191 goto ATTACH_SIGN;
1192 if (cur_val_level != int_val_level)
1193 mu_error();
1194 } else {
1195 scan_something_internal(dimen_val_level, false);
1196 if (cur_val_level == dimen_val_level)
1197 goto ATTACH_SIGN;
1200 } else {
1201 back_input();
1202 if (cur_tok == continental_point_token) {
1203 cur_tok = point_token;
1205 if (cur_tok != point_token) {
1206 scan_int();
1207 } else {
1208 radix = 10;
1209 cur_val = 0;
1211 if (cur_tok == continental_point_token)
1212 cur_tok = point_token;
1213 if ((radix == 10) && (cur_tok == point_token)) {
1214 /* Scan decimal fraction */
1215 /* When the following code is executed, we have |cur_tok=point_token|, but this
1216 token has been backed up using |back_input|; we must first discard it.
1218 It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
1219 Let's hope people don't use that fact. */
1221 k = 0;
1222 p = null;
1223 get_token(); /* |point_token| is being re-scanned */
1224 while (1) {
1225 get_x_token();
1226 if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
1227 break;
1228 if (k < 17) { /* digits for |k>=17| cannot affect the result */
1229 q = get_avail();
1230 set_token_link(q, p);
1231 set_token_info(q, cur_tok - zero_token);
1232 p = q;
1233 incr(k);
1236 for (kk = k; kk >= 1; kk--) {
1237 dig[kk - 1] = token_info(p);
1238 q = p;
1239 p = token_link(p);
1240 free_avail(q);
1242 f = round_decimals(k);
1243 if (cur_cmd != spacer_cmd)
1244 back_input();
1248 if (cur_val < 0) { /* in this case |f=0| */
1249 negative = !negative;
1250 negate(cur_val);
1252 /* Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
1253 are |x| sp per unit; |goto attach_sign| if the units are internal */
1254 /* Now comes the harder part: At this point in the program, |cur_val| is a
1255 nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
1256 we want to multiply the sum of these two quantities by the appropriate
1257 factor, based on the specified units, in order to produce a |scaled|
1258 result, and we want to do the calculation with fixed point arithmetic that
1259 does not overflow.
1262 if (inf) {
1263 /* Scan for (f)\.{fil} units; |goto attach_fraction| if found */
1264 /* In traditional TeX, a specification like `\.{filllll}' or `\.{fill L L
1265 L}' will lead to two error messages (one for each additional keyword
1266 \.{"l"}).
1267 Not so for luatex, it just parses the construct in reverse. */
1268 if (scan_keyword("filll")) {
1269 cur_order = filll;
1270 goto ATTACH_FRACTION;
1271 } else if (scan_keyword("fill")) {
1272 cur_order = fill;
1273 goto ATTACH_FRACTION;
1274 } else if (scan_keyword("fil")) {
1275 cur_order = fil;
1276 goto ATTACH_FRACTION;
1277 } else if (scan_keyword("fi")) {
1278 cur_order = sfi;
1279 goto ATTACH_FRACTION;
1283 /* Scan for (u)units that are internal dimensions;
1284 |goto attach_sign| with |cur_val| set if found */
1285 save_cur_val = cur_val;
1286 /* Get the next non-blank non-call... */
1287 do {
1288 get_x_token();
1289 } while (cur_cmd == spacer_cmd);
1291 if ((cur_cmd < min_internal_cmd) || (cur_cmd > max_internal_cmd)) {
1292 back_input();
1293 } else {
1294 if (mu) {
1295 scan_something_internal(mu_val_level, false);
1296 coerce_glue();
1297 if (cur_val_level != mu_val_level)
1298 mu_error();
1299 } else {
1300 scan_something_internal(dimen_val_level, false);
1302 v = cur_val;
1303 goto FOUND;
1305 if (mu)
1306 goto NOT_FOUND;
1307 if (scan_keyword("em")) {
1308 v = (quad(get_cur_font()));
1309 } else if (scan_keyword("ex")) {
1310 v = (x_height(get_cur_font()));
1311 } else if (scan_keyword("px")) {
1312 v = dimen_par(pdf_px_dimen_code);
1313 } else {
1314 goto NOT_FOUND;
1316 /* Scan an optional space */
1317 get_x_token();
1318 if (cur_cmd != spacer_cmd)
1319 back_input();
1321 FOUND:
1322 cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
1323 goto ATTACH_SIGN;
1324 NOT_FOUND:
1326 if (mu) {
1327 /* Scan for (m)\.{mu} units and |goto attach_fraction| */
1328 if (scan_keyword("mu")) {
1329 goto ATTACH_FRACTION;
1330 } else {
1331 print_err("Illegal unit of measure (mu inserted)");
1332 help4("The unit of measurement in math glue must be mu.",
1333 "To recover gracefully from this error, it's best to",
1334 "delete the erroneous units; e.g., type `2' to delete",
1335 "two letters. (See Chapter 27 of The TeXbook.)");
1336 error();
1337 goto ATTACH_FRACTION;
1340 if (scan_keyword("true")) {
1341 /* Adjust (f)for the magnification ratio */
1342 prepare_mag();
1343 if (int_par(mag_code) != 1000) {
1344 cur_val = xn_over_d(cur_val, 1000, int_par(mag_code));
1345 f = (1000 * f + 0200000 * tex_remainder) / int_par(mag_code);
1346 cur_val = cur_val + (f / 0200000);
1347 f = f % 0200000;
1350 if (scan_keyword("pt"))
1351 goto ATTACH_FRACTION; /* the easy case */
1352 /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
1353 |goto done| in the case of scaled points */
1355 /* The necessary conversion factors can all be specified exactly as
1356 fractions whose numerator and denominator add to 32768 or less.
1357 According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
1358 this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
1359 \^{Bosshard, Hans Rudolf}
1360 in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
1361 The Didot point has been newly standardized in 1978;
1362 it's now exactly $\rm 1\,nd=0.375\,mm$.
1363 Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$.
1364 The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$.
1365 These would lead to the ratios $21681/20320$ and $65043/5080$,
1366 respectively.
1367 The closest approximations supported by the algorithm would be
1368 $11183/10481$ and $1370/107$. In order to maintain the
1369 relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for
1370 $\rm nd$, however.
1373 #define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
1375 if (scan_keyword("in")) {
1376 set_conversion(7227, 100);
1377 } else if (scan_keyword("pc")) {
1378 set_conversion(12, 1);
1379 } else if (scan_keyword("cm")) {
1380 set_conversion(7227, 254);
1381 } else if (scan_keyword("mm")) {
1382 set_conversion(7227, 2540);
1383 } else if (scan_keyword("bp")) {
1384 set_conversion(7227, 7200);
1385 } else if (scan_keyword("dd")) {
1386 set_conversion(1238, 1157);
1387 } else if (scan_keyword("cc")) {
1388 set_conversion(14856, 1157);
1389 } else if (scan_keyword("nd")) {
1390 set_conversion(685, 642);
1391 } else if (scan_keyword("nc")) {
1392 set_conversion(1370, 107);
1393 } else if (scan_keyword("sp")) {
1394 goto DONE;
1395 } else {
1396 /* Complain about unknown unit and |goto done2| */
1397 print_err("Illegal unit of measure (pt inserted)");
1398 help6("Dimensions can be in units of em, ex, in, pt, pc,",
1399 "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
1400 "I'll assume that you meant to say pt, for printer's points.",
1401 "To recover gracefully from this error, it's best to",
1402 "delete the erroneous units; e.g., type `2' to delete",
1403 "two letters. (See Chapter 27 of The TeXbook.)");
1404 error();
1405 goto DONE2;
1407 cur_val = xn_over_d(cur_val, num, denom);
1408 f = (num * f + 0200000 * tex_remainder) / denom;
1409 cur_val = cur_val + (f / 0200000);
1410 f = f % 0200000;
1411 DONE2:
1412 ATTACH_FRACTION:
1413 if (cur_val >= 040000)
1414 arith_error = true;
1415 else
1416 cur_val = cur_val * unity + f;
1417 DONE:
1418 /* Scan an optional space */
1419 get_x_token();
1420 if (cur_cmd != spacer_cmd)
1421 back_input();
1422 ATTACH_SIGN:
1423 if (arith_error || (abs(cur_val) >= 010000000000)) {
1424 /* Report that this dimension is out of range */
1425 print_err("Dimension too large");
1426 help2("I can't work with sizes bigger than about 19 feet.",
1427 "Continue and I'll use the largest value I can.");
1428 error();
1429 cur_val = max_dimen;
1430 arith_error = false;
1432 if (negative)
1433 negate(cur_val);
1437 @ The final member of \TeX's value-scanning trio is |scan_glue|, which
1438 makes |cur_val| point to a glue specification. The reference count of that
1439 glue spec will take account of the fact that |cur_val| is pointing to~it.
1441 The |level| parameter should be either |glue_val| or |mu_val|.
1443 Since |scan_dimen| was so much more complex than |scan_int|, we might expect
1444 |scan_glue| to be even worse. But fortunately, it is very simple, since
1445 most of the work has already been done.
1448 void scan_glue(int level)
1449 { /* sets |cur_val| to a glue spec pointer */
1450 boolean negative; /* should the answer be negated? */
1451 halfword q; /* new glue specification */
1452 boolean mu; /* does |level=mu_val|? */
1453 mu = (level == mu_val_level);
1454 /* Get the next non-blank non-sign... */
1455 negative = false;
1456 do {
1457 /* Get the next non-blank non-call token */
1458 do {
1459 get_x_token();
1460 } while (cur_cmd == spacer_cmd);
1461 if (cur_tok == other_token + '-') {
1462 negative = !negative;
1463 cur_tok = other_token + '+';
1465 } while (cur_tok == other_token + '+');
1467 if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
1468 scan_something_internal(level, negative);
1469 if (cur_val_level >= glue_val_level) {
1470 if (cur_val_level != level)
1471 mu_error();
1472 return;
1474 if (cur_val_level == int_val_level)
1475 scan_dimen(mu, false, true);
1476 else if (level == mu_val_level)
1477 mu_error();
1478 } else {
1479 back_input();
1480 scan_dimen(mu, false, false);
1481 if (negative)
1482 negate(cur_val);
1484 /* Create a new glue specification whose width is |cur_val|; scan for its
1485 stretch and shrink components */
1486 q = new_spec(zero_glue);
1487 width(q) = cur_val;
1488 if (scan_keyword("plus")) {
1489 scan_dimen(mu, true, false);
1490 stretch(q) = cur_val;
1491 stretch_order(q) = (quarterword) cur_order;
1493 if (scan_keyword("minus")) {
1494 scan_dimen(mu, true, false);
1495 shrink(q) = cur_val;
1496 shrink_order(q) = (quarterword) cur_order;
1498 cur_val = q;
1501 @ This is an omega routine
1503 void scan_scaled(void)
1504 { /* sets |cur_val| to a scaled value */
1505 boolean negative; /* should the answer be negated? */
1506 int f; /* numerator of a fraction whose denominator is $2^{16}$ */
1507 int k, kk; /* number of digits in a decimal fraction */
1508 halfword p, q; /* top of decimal digit stack */
1509 f = 0;
1510 arith_error = false;
1511 negative = false;
1512 /* Get the next non-blank non-sign... */
1513 do {
1514 /* Get the next non-blank non-call token */
1515 do {
1516 get_x_token();
1517 } while (cur_cmd == spacer_cmd);
1518 if (cur_tok == other_token + '-') {
1519 negative = !negative;
1520 cur_tok = other_token + '+';
1522 } while (cur_tok == other_token + '+');
1524 back_input();
1525 if (cur_tok == continental_point_token)
1526 cur_tok = point_token;
1527 if (cur_tok != point_token) {
1528 scan_int();
1529 } else {
1530 radix = 10;
1531 cur_val = 0;
1533 if (cur_tok == continental_point_token)
1534 cur_tok = point_token;
1535 if ((radix == 10) && (cur_tok == point_token)) {
1536 /* Scan decimal fraction */
1537 /* TODO: merge this with the same block in |scan_dimen| */
1538 /* When the following code is executed, we have |cur_tok=point_token|, but this
1539 token has been backed up using |back_input|; we must first discard it.
1541 It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
1542 Let's hope people don't use that fact. */
1544 k = 0;
1545 p = null;
1546 get_token(); /* |point_token| is being re-scanned */
1547 while (1) {
1548 get_x_token();
1549 if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
1550 break;
1551 if (k < 17) { /* digits for |k>=17| cannot affect the result */
1552 q = get_avail();
1553 set_token_link(q, p);
1554 set_token_info(q, cur_tok - zero_token);
1555 p = q;
1556 incr(k);
1559 for (kk = k; kk >= 1; kk--) {
1560 dig[kk - 1] = token_info(p);
1561 q = p;
1562 p = token_link(p);
1563 free_avail(q);
1565 f = round_decimals(k);
1566 if (cur_cmd != spacer_cmd)
1567 back_input();
1570 if (cur_val < 0) { /* in this case |f=0| */
1571 negative = !negative;
1572 negate(cur_val);
1574 if (cur_val > 040000)
1575 arith_error = true;
1576 else
1577 cur_val = cur_val * unity + f;
1578 if (arith_error || (abs(cur_val) >= 010000000000)) {
1579 print_err("Stack number too large");
1580 error();
1582 if (negative)
1583 negate(cur_val);
1587 @ This procedure is supposed to scan something like `\.{\\skip\\count12}',
1588 i.e., whatever can follow `\.{\\the}', and it constructs a token list
1589 containing something like `\.{-3.0pt minus 0.5fill}'.
1592 halfword the_toks(void)
1594 int old_setting; /* holds |selector| setting */
1595 halfword p, q, r; /* used for copying a token list */
1596 int c; /* value of |cur_chr| */
1597 str_number s;
1598 halfword retval;
1599 /* Handle \.{\\unexpanded} or \.{\\detokenize} and |return| */
1600 if (odd(cur_chr)) {
1601 c = cur_chr;
1602 scan_general_text();
1603 if (c == 1) {
1604 return cur_val;
1605 } else {
1606 old_setting = selector;
1607 selector = new_string;
1608 p = get_avail();
1609 set_token_link(p, token_link(temp_token_head));
1610 token_show(p);
1611 flush_list(p);
1612 selector = old_setting;
1613 s = make_string();
1614 retval = str_toks(str_lstring(s));
1615 flush_str(s);
1616 return retval;
1619 get_x_token();
1620 scan_something_internal(tok_val_level, false);
1621 if (cur_val_level >= ident_val_level) {
1622 /* Copy the token list */
1623 p = temp_token_head;
1624 set_token_link(p, null);
1625 if (cur_val_level == ident_val_level) {
1626 store_new_token(cs_token_flag + cur_val);
1627 } else if (cur_val != null) {
1628 r = token_link(cur_val); /* do not copy the reference count */
1629 while (r != null) {
1630 fast_store_new_token(token_info(r));
1631 r = token_link(r);
1634 return p;
1635 } else {
1636 old_setting = selector;
1637 selector = new_string;
1638 switch (cur_val_level) {
1639 case int_val_level:
1640 print_int(cur_val);
1641 break;
1642 case attr_val_level:
1643 print_int(cur_val);
1644 break;
1645 case dir_val_level:
1646 print_dir(cur_val);
1647 break;
1648 case dimen_val_level:
1649 print_scaled(cur_val);
1650 tprint("pt");
1651 break;
1652 case glue_val_level:
1653 print_spec(cur_val, "pt");
1654 delete_glue_ref(cur_val);
1655 break;
1656 case mu_val_level:
1657 print_spec(cur_val, "mu");
1658 delete_glue_ref(cur_val);
1659 break;
1660 } /* there are no other cases */
1661 selector = old_setting;
1662 s = make_string();
1663 retval = str_toks(str_lstring(s));
1664 flush_str(s);
1665 return retval;
1669 @ @c
1670 str_number the_scanned_result(void)
1672 int old_setting; /* holds |selector| setting */
1673 str_number r; /* return value * */
1674 old_setting = selector;
1675 selector = new_string;
1676 if (cur_val_level >= ident_val_level) {
1677 if (cur_val != null) {
1678 show_token_list(token_link(cur_val), null, -1);
1679 r = make_string();
1680 } else {
1681 r = get_nullstr();
1683 } else {
1684 switch (cur_val_level) {
1685 case int_val_level:
1686 print_int(cur_val);
1687 break;
1688 case attr_val_level:
1689 print_int(cur_val);
1690 break;
1691 case dir_val_level:
1692 print_dir(cur_val);
1693 break;
1694 case dimen_val_level:
1695 print_scaled(cur_val);
1696 tprint("pt");
1697 break;
1698 case glue_val_level:
1699 print_spec(cur_val, "pt");
1700 delete_glue_ref(cur_val);
1701 break;
1702 case mu_val_level:
1703 print_spec(cur_val, "mu");
1704 delete_glue_ref(cur_val);
1705 break;
1706 } /* there are no other cases */
1707 r = make_string();
1709 selector = old_setting;
1710 return r;
1715 @ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
1716 The boolean parameter |writing| is set |true| if the calling program
1717 intends to change the parameter value.
1720 static void font_param_error(int f)
1722 print_err("Font ");
1723 print_esc(font_id_text(f));
1724 tprint(" has only ");
1725 print_int(font_params(f));
1726 tprint(" fontdimen parameters");
1727 help2("To increase the number of font parameters, you must",
1728 "use \\fontdimen immediately after the \\font is loaded.");
1729 error();
1732 void set_font_dimen(void)
1734 internal_font_number f;
1735 int n; /* the parameter number */
1736 scan_int();
1737 n = cur_val;
1738 scan_font_ident();
1739 f = cur_val;
1740 if (n <= 0) {
1741 font_param_error(f);
1742 } else {
1743 if (n > font_params(f)) {
1744 if (font_used(f)) {
1745 font_param_error(f);
1746 } else {
1747 /* Increase the number of parameters in the font */
1748 do {
1749 set_font_param(f, (font_params(f) + 1), 0);
1750 } while (n != font_params(f));
1754 scan_optional_equals();
1755 scan_normal_dimen();
1756 set_font_param(f, n, cur_val);
1759 void get_font_dimen(void)
1761 internal_font_number f;
1762 int n; /* the parameter number */
1763 scan_int();
1764 n = cur_val;
1765 scan_font_ident();
1766 f = cur_val;
1767 cur_val = 0; /* initialize return value */
1768 if (n <= 0) {
1769 font_param_error(f);
1770 goto EXIT;
1771 } else {
1772 if (n > font_params(f)) {
1773 if (font_used(f)) {
1774 font_param_error(f);
1775 goto EXIT;
1776 } else {
1777 /* Increase the number of parameters in the font */
1778 do {
1779 set_font_param(f, (font_params(f) + 1), 0);
1780 } while (n != font_params(f));
1785 cur_val = font_param(f, n);
1786 EXIT:
1787 scanned_result(cur_val, dimen_val_level);
1791 @ Here's a similar procedure that returns a pointer to a rule node. This
1792 routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
1793 therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
1794 the default rule dimensions in the node, then to override them if
1795 `\.{height}' or `\.{width}' or `\.{depth}' specifications are
1796 found (in any order).
1799 halfword scan_rule_spec(void)
1801 halfword q; /* the rule node being created */
1802 q = new_rule(); /* |width|, |depth|, and |height| all equal |null_flag| now */
1803 if (cur_cmd == vrule_cmd) {
1804 width(q) = default_rule;
1805 rule_dir(q) = body_direction;
1806 } else {
1807 height(q) = default_rule;
1808 depth(q) = 0;
1809 rule_dir(q) = text_direction;
1811 RESWITCH:
1812 if (scan_keyword("width")) {
1813 scan_normal_dimen();
1814 width(q) = cur_val;
1815 goto RESWITCH;
1817 if (scan_keyword("height")) {
1818 scan_normal_dimen();
1819 height(q) = cur_val;
1820 goto RESWITCH;
1822 if (scan_keyword("depth")) {
1823 scan_normal_dimen();
1824 depth(q) = cur_val;
1825 goto RESWITCH;
1827 return q;
1831 @ Declare procedures that scan font-related stuff
1834 void scan_font_ident(void)
1836 internal_font_number f;
1837 halfword m;
1838 /* Get the next non-blank non-call... */
1839 do {
1840 get_x_token();
1841 } while (cur_cmd == spacer_cmd);
1843 if ((cur_cmd == def_font_cmd) || (cur_cmd == letterspace_font_cmd)
1844 || (cur_cmd == pdf_copy_font_cmd)) {
1845 f = get_cur_font();
1846 } else if (cur_cmd == set_font_cmd) {
1847 f = cur_chr;
1848 set_font_touched(f, 1);
1849 } else if (cur_cmd == def_family_cmd) {
1850 m = cur_chr;
1851 scan_math_family_int();
1852 f = fam_fnt(cur_val, m);
1853 set_font_touched(f, 1);
1854 } else {
1855 print_err("Missing font identifier");
1856 help2("I was looking for a control sequence whose",
1857 "current meaning has been defined by \\font.");
1858 back_error();
1859 f = null_font;
1861 cur_val = f;
1864 @ The |scan_general_text| procedure is much like |scan_toks(false,false)|,
1865 but will be invoked via |expand|, i.e., recursively.
1867 The token list (balanced text) created by |scan_general_text| begins
1868 at |link(temp_token_head)| and ends at |cur_val|. (If |cur_val=temp_token_head|,
1869 the list is empty.)
1872 void scan_general_text(void)
1874 int s; /* to save |scanner_status| */
1875 halfword w; /* to save |warning_index| */
1876 halfword d; /* to save |def_ref| */
1877 halfword p; /* tail of the token list being built */
1878 halfword q; /* new node being added to the token list via |store_new_token| */
1879 halfword unbalance; /* number of unmatched left braces */
1880 s = scanner_status;
1881 w = warning_index;
1882 d = def_ref;
1883 scanner_status = absorbing;
1884 warning_index = cur_cs;
1885 p = get_avail();
1886 def_ref = p;
1887 set_token_ref_count(def_ref, 0);
1888 p = def_ref;
1889 scan_left_brace(); /* remove the compulsory left brace */
1890 unbalance = 1;
1891 while (1) {
1892 get_token();
1893 if (cur_tok < right_brace_limit) {
1894 if (cur_cmd < right_brace_cmd) {
1895 incr(unbalance);
1896 } else {
1897 decr(unbalance);
1898 if (unbalance == 0)
1899 break;
1902 store_new_token(cur_tok);
1904 q = token_link(def_ref);
1905 free_avail(def_ref); /* discard reference count */
1906 if (q == null)
1907 cur_val = temp_token_head;
1908 else
1909 cur_val = p;
1910 set_token_link(temp_token_head, q);
1911 scanner_status = s;
1912 warning_index = w;
1913 def_ref = d;
1917 @ The |get_x_or_protected| procedure is like |get_x_token| except that
1918 protected macros are not expanded.
1921 void get_x_or_protected(void)
1922 { /* sets |cur_cmd|, |cur_chr|, |cur_tok|,
1923 and expands non-protected macros */
1924 while (1) {
1925 get_token();
1926 if (cur_cmd <= max_command_cmd)
1927 return;
1928 if ((cur_cmd >= call_cmd) && (cur_cmd < end_template_cmd)) {
1929 if (token_info(token_link(cur_chr)) == protected_token)
1930 return;
1932 expand();
1937 @ |scan_toks|. This function returns a pointer to the tail of a new token
1938 list, and it also makes |def_ref| point to the reference count at the
1939 head of that list.
1941 There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
1942 is true, the goal is to create the token list for a macro definition;
1943 otherwise the goal is to create the token list for some other \TeX\
1944 primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
1945 \.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
1946 \.{\\special}. In the latter cases a left brace must be scanned next; this
1947 left brace will not be part of the token list, nor will the matching right
1948 brace that comes at the end. If |xpand| is false, the token list will
1949 simply be copied from the input using |get_token|. Otherwise all expandable
1950 tokens will be expanded until unexpandable tokens are left, except that
1951 the results of expanding `\.{\\the}' are not expanded further.
1952 If both |macro_def| and |xpand| are true, the expansion applies
1953 only to the macro body (i.e., to the material following the first
1954 |left_brace| character).
1956 The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
1957 address of the control sequence to display in ``runaway'' error
1958 messages.
1961 halfword scan_toks(boolean macro_def, boolean xpand)
1963 halfword t; /* token representing the highest parameter number */
1964 halfword s; /* saved token */
1965 halfword p; /* tail of the token list being built */
1966 halfword q; /* new node being added to the token list via |store_new_token| */
1967 halfword unbalance; /* number of unmatched left braces */
1968 halfword hash_brace; /* possible `\.{\#\{}' token */
1969 if (macro_def)
1970 scanner_status = defining;
1971 else
1972 scanner_status = absorbing;
1973 warning_index = cur_cs;
1974 p = get_avail();
1975 def_ref = p;
1976 set_token_ref_count(def_ref, 0);
1977 p = def_ref;
1978 hash_brace = 0;
1979 t = zero_token;
1980 if (macro_def) {
1981 /* Scan and build the parameter part of the macro definition */
1982 while (1) {
1983 get_token(); /* set |cur_cmd|, |cur_chr|, |cur_tok| */
1984 if (cur_tok < right_brace_limit)
1985 break;
1986 if (cur_cmd == mac_param_cmd) {
1987 /* If the next character is a parameter number, make |cur_tok|
1988 a |match| token; but if it is a left brace, store
1989 `|left_brace|, |end_match|', set |hash_brace|, and |goto done|;
1991 s = match_token + cur_chr;
1992 get_token();
1993 if (cur_cmd == left_brace_cmd) {
1994 hash_brace = cur_tok;
1995 store_new_token(cur_tok);
1996 store_new_token(end_match_token);
1997 goto DONE;
1999 if (t == zero_token + 9) {
2000 print_err("You already have nine parameters");
2001 help1("I'm going to ignore the # sign you just used.");
2002 error();
2003 } else {
2004 incr(t);
2005 if (cur_tok != t) {
2006 print_err("Parameters must be numbered consecutively");
2007 help2
2008 ("I've inserted the digit you should have used after the #.",
2009 "Type `1' to delete what you did use.");
2010 back_error();
2012 cur_tok = s;
2015 store_new_token(cur_tok);
2017 store_new_token(end_match_token);
2018 if (cur_cmd == right_brace_cmd) {
2019 /* Express shock at the missing left brace; |goto found| */
2020 print_err("Missing { inserted");
2021 incr(align_state);
2022 help2
2023 ("Where was the left brace? You said something like `\\def\\a}',",
2024 "which I'm going to interpret as `\\def\\a{}'.");
2025 error();
2026 goto FOUND;
2029 } else {
2030 scan_left_brace(); /* remove the compulsory left brace */
2032 DONE:
2033 /* Scan and build the body of the token list; |goto found| when finished */
2034 unbalance = 1;
2035 while (1) {
2036 if (xpand) {
2037 /* Expand the next part of the input */
2038 /* Here we insert an entire token list created by |the_toks| without
2039 expanding it further. */
2040 while (1) {
2041 get_token_lua();
2042 if (cur_cmd >= call_cmd) {
2043 if (token_info(token_link(cur_chr)) == protected_token) {
2044 cur_cmd = relax_cmd;
2045 cur_chr = no_expand_flag;
2048 if (cur_cmd <= max_command_cmd)
2049 break;
2050 if (cur_cmd != the_cmd) {
2051 expand();
2052 } else {
2053 q = the_toks();
2054 if (token_link(temp_token_head) != null) {
2055 set_token_link(p, token_link(temp_token_head));
2056 p = q;
2060 x_token();
2062 } else {
2063 get_token();
2065 if (cur_tok < right_brace_limit) {
2066 if (cur_cmd < right_brace_cmd) {
2067 incr(unbalance);
2068 } else {
2069 decr(unbalance);
2070 if (unbalance == 0)
2071 goto FOUND;
2073 } else if (cur_cmd == mac_param_cmd) {
2074 if (macro_def) {
2075 /* Look for parameter number or \.{\#\#} */
2076 s = cur_tok;
2077 if (xpand)
2078 get_x_token();
2079 else
2080 get_token();
2081 if (cur_cmd != mac_param_cmd) {
2082 if ((cur_tok <= zero_token) || (cur_tok > t)) {
2083 print_err("Illegal parameter number in definition of ");
2084 sprint_cs(warning_index);
2085 help3("You meant to type ## instead of #, right?",
2086 "Or maybe a } was forgotten somewhere earlier, and things",
2087 "are all screwed up? I'm going to assume that you meant ##.");
2088 back_error();
2089 cur_tok = s;
2090 } else {
2091 cur_tok = out_param_token - '0' + cur_chr;
2096 store_new_token(cur_tok);
2098 FOUND:
2099 scanner_status = normal;
2100 if (hash_brace != 0)
2101 store_new_token(hash_brace);
2102 return p;
2106 @ Here we declare two trivial procedures in order to avoid mutually
2107 recursive procedures with parameters.
2110 void scan_normal_glue(void)
2112 scan_glue(glue_val_level);
2115 void scan_mu_glue(void)
2117 scan_glue(mu_val_level);
2120 @ The |scan_expr| procedure scans and evaluates an expression.
2122 @ Evaluating an expression is a recursive process: When the left
2123 parenthesis of a subexpression is scanned we descend to the next level
2124 of recursion; the previous level is resumed with the matching right
2125 parenthesis.
2128 typedef enum {
2129 expr_none = 0, /* \.( seen, or \.( $\langle\it expr\rangle$ \.) seen */
2130 expr_add = 1, /* \.( $\langle\it expr\rangle$ \.+ seen */
2131 expr_sub = 2, /* \.( $\langle\it expr\rangle$ \.- seen */
2132 expr_mult = 3, /* $\langle\it term\rangle$ \.* seen */
2133 expr_div = 4, /* $\langle\it term\rangle$ \./ seen */
2134 expr_scale = 5, /* $\langle\it term\rangle$ \.* $\langle\it factor\rangle$ \./ seen */
2135 } expression_states;
2138 @ We want to make sure that each term and (intermediate) result is in
2139 the proper range. Integer values must not exceed |infinity|
2140 ($2^{31}-1$) in absolute value, dimensions must not exceed |max_dimen|
2141 ($2^{30}-1$). We avoid the absolute value of an integer, because this
2142 might fail for the value $-2^{31}$ using 32-bit arithmetic.
2144 @ clear a number or dimension and set |arith_error|
2147 #define num_error(A) do { \
2148 arith_error=true; \
2149 A=0; \
2150 } while (0)
2153 @ clear a glue spec and set |arith_error|
2156 #define glue_error(A) do { \
2157 arith_error=true; \
2158 delete_glue_ref(A); \
2159 A=new_spec(zero_glue); \
2160 } while (0)
2163 #define normalize_glue(A) do { \
2164 if (stretch(A)==0) stretch_order(A)=normal; \
2165 if (shrink(A)==0) shrink_order(A)=normal; \
2166 } while (0)
2169 @ Parenthesized subexpressions can be inside expressions, and this
2170 nesting has a stack. Seven local variables represent the top of the
2171 expression stack: |p| points to pushed-down entries, if any; |l|
2172 specifies the type of expression currently beeing evaluated; |e| is the
2173 expression so far and |r| is the state of its evaluation; |t| is the
2174 term so far and |s| is the state of its evaluation; finally |n| is the
2175 numerator for a combined multiplication and division, if any.
2178 #define expr_type(A) type((A)+1)
2179 #define expr_state(A) subtype((A)+1)
2180 #define expr_e_field(A) vlink((A)+1) /* saved expression so far */
2181 #define expr_t_field(A) vlink((A)+2) /* saved term so far */
2182 #define expr_n_field(A) vinfo((A)+2) /* saved numerator */
2185 #define expr_add_sub(A,B,C) add_or_sub((A),(B),(C),(r==expr_sub))
2186 #define expr_a(A,B) expr_add_sub((A),(B),max_dimen)
2189 The function |add_or_sub(x,y,max_answer,negative)| computes the sum
2190 (for |negative=false|) or difference (for |negative=true|) of |x| and
2191 |y|, provided the absolute value of the result does not exceed
2192 |max_answer|.
2195 int add_or_sub(int x, int y, int max_answer, boolean negative)
2197 int a; /* the answer */
2198 if (negative)
2199 negate(y);
2200 if (x >= 0) {
2201 if (y <= max_answer - x)
2202 a = x + y;
2203 else
2204 num_error(a);
2205 } else if (y >= -max_answer - x) {
2206 a = x + y;
2207 } else {
2208 num_error(a);
2210 return a;
2214 #define expr_m(A) A = nx_plus_y((A),f,0)
2216 #define expr_d(A) A=quotient((A),f)
2219 @ The function |quotient(n,d)| computes the rounded quotient
2220 $q=\lfloor n/d+{1\over2}\rfloor$, when $n$ and $d$ are positive.
2223 int quotient(int n, int d)
2225 boolean negative; /* should the answer be negated? */
2226 int a; /* the answer */
2227 if (d == 0) {
2228 num_error(a);
2229 } else {
2230 if (d > 0) {
2231 negative = false;
2232 } else {
2233 negate(d);
2234 negative = true;
2236 if (n < 0) {
2237 negate(n);
2238 negative = !negative;
2240 a = n / d;
2241 n = n - a * d;
2242 d = n - d; /* avoid certain compiler optimizations! */
2243 if (d + n >= 0)
2244 incr(a);
2245 if (negative)
2246 negate(a);
2248 return a;
2251 #define expr_s(A) A=fract((A),n,f,max_dimen)
2254 @ Finally, the function |fract(x,n,d,max_answer)| computes the integer
2255 $q=\lfloor xn/d+{1\over2}\rfloor$, when $x$, $n$, and $d$ are positive
2256 and the result does not exceed |max_answer|. We can't use floating
2257 point arithmetic since the routine must produce identical results in all
2258 cases; and it would be too dangerous to multiply by~|n| and then divide
2259 by~|d|, in separate operations, since overflow might well occur. Hence
2260 this subroutine simulates double precision arithmetic, somewhat
2261 analogous to Metafont's |make_fraction| and |take_fraction| routines.
2264 int fract(int x, int n, int d, int max_answer)
2266 boolean negative; /* should the answer be negated? */
2267 int a; /* the answer */
2268 int f; /* a proper fraction */
2269 int h; /* smallest integer such that |2*h>=d| */
2270 int r; /* intermediate remainder */
2271 int t; /* temp variable */
2272 if (d == 0)
2273 goto TOO_BIG;
2274 a = 0;
2275 if (d > 0) {
2276 negative = false;
2277 } else {
2278 negate(d);
2279 negative = true;
2281 if (x < 0) {
2282 negate(x);
2283 negative = !negative;
2284 } else if (x == 0) {
2285 goto DONE;
2287 if (n < 0) {
2288 negate(n);
2289 negative = !negative;
2291 t = n / d;
2292 if (t > max_answer / x)
2293 goto TOO_BIG;
2294 a = t * x;
2295 n = n - t * d;
2296 if (n == 0)
2297 goto FOUND;
2298 t = x / d;
2299 if (t > (max_answer - a) / n)
2300 goto TOO_BIG;
2301 a = a + t * n;
2302 x = x - t * d;
2303 if (x == 0)
2304 goto FOUND;
2305 if (x < n) {
2306 t = x;
2307 x = n;
2308 n = t;
2312 /* now |0<n<=x<d| */
2313 /* Compute $f=\lfloor xn/d+{1\over2}\rfloor$; */
2314 /* The loop here preserves the following invariant relations
2315 between |f|, |x|, |n|, and~|r|:
2316 (i)~$f+\lfloor(xn+(r+d))/d\rfloor=\lfloor x_0n_0/d+{1\over2}\rfloor$;
2317 (ii)~|-d<=r<0<n<=x<d|, where $x_0$, $n_0$ are the original values of~$x$
2318 and $n$. */
2319 /* Notice that the computation specifies |(x-d)+x| instead of |(x+x)-d|,
2320 because the latter could overflow. */
2321 f = 0;
2322 r = (d / 2) - d;
2323 h = -r;
2324 while (1) {
2325 if (odd(n)) {
2326 r = r + x;
2327 if (r >= 0) {
2328 r = r - d;
2329 incr(f);
2332 n = n / 2;
2333 if (n == 0)
2334 break;
2335 if (x < h) {
2336 x = x + x;
2337 } else {
2338 t = x - d;
2339 x = t + x;
2340 f = f + n;
2341 if (x < n) {
2342 if (x == 0)
2343 break;
2344 t = x;
2345 x = n;
2346 n = t;
2351 if (f > (max_answer - a))
2352 goto TOO_BIG;
2353 a = a + f;
2354 FOUND:
2355 if (negative)
2356 negate(a);
2357 goto DONE;
2358 TOO_BIG:
2359 num_error(a);
2360 DONE:
2361 return a;
2364 @ @c
2365 void scan_expr(void)
2366 { /* scans and evaluates an expression */
2367 boolean a, b; /* saved values of |arith_error| */
2368 int l; /* type of expression */
2369 int r; /* state of expression so far */
2370 int s; /* state of term so far */
2371 int o; /* next operation or type of next factor */
2372 int e; /* expression so far */
2373 int t; /* term so far */
2374 int f; /* current factor */
2375 int n; /* numerator of combined multiplication and division */
2376 halfword p; /* top of expression stack */
2377 halfword q; /* for stack manipulations */
2378 l = cur_val_level;
2379 a = arith_error;
2380 b = false;
2381 p = null;
2382 /* Scan and evaluate an expression |e| of type |l| */
2383 RESTART:
2384 r = expr_none;
2385 e = 0;
2386 s = expr_none;
2387 t = 0;
2388 n = 0;
2389 CONTINUE:
2390 if (s == expr_none)
2391 o = l;
2392 else
2393 o = int_val_level;
2394 /* Scan a factor |f| of type |o| or start a subexpression */
2395 /* Get the next non-blank non-call token */
2396 do {
2397 get_x_token();
2398 } while (cur_cmd == spacer_cmd);
2400 if (cur_tok == other_token + '(') {
2401 /* Push the expression stack and |goto restart| */
2402 q = new_node(expr_node, 0);
2403 vlink(q) = p;
2404 expr_type(q) = (quarterword) l;
2405 expr_state(q) = (quarterword) (4 * s + r);
2406 expr_e_field(q) = e;
2407 expr_t_field(q) = t;
2408 expr_n_field(q) = n;
2409 p = q;
2410 l = o;
2411 goto RESTART;
2413 back_input();
2414 if ((o == int_val_level) || (o == attr_val_level))
2415 scan_int();
2416 else if (o == dimen_val_level)
2417 scan_normal_dimen();
2418 else if (o == glue_val_level)
2419 scan_normal_glue();
2420 else
2421 scan_mu_glue();
2422 f = cur_val;
2424 FOUND:
2425 /* Scan the next operator and set |o| */
2426 /* Get the next non-blank non-call token */
2427 do {
2428 get_x_token();
2429 } while (cur_cmd == spacer_cmd);
2431 if (cur_tok == other_token + '+') {
2432 o = expr_add;
2433 } else if (cur_tok == other_token + '-') {
2434 o = expr_sub;
2435 } else if (cur_tok == other_token + '*') {
2436 o = expr_mult;
2437 } else if (cur_tok == other_token + '/') {
2438 o = expr_div;
2439 } else {
2440 o = expr_none;
2441 if (p == null) {
2442 if (cur_cmd != relax_cmd)
2443 back_input();
2444 } else if (cur_tok != other_token + ')') {
2445 print_err("Missing ) inserted for expression");
2446 help1("I was expecting to see `+', `-', `*', `/', or `)'. Didn't.");
2447 back_error();
2451 arith_error = b;
2452 /* Make sure that |f| is in the proper range */
2453 if (((l == int_val_level) || (l == attr_val_level)) || (s > expr_sub)) {
2454 if ((f > infinity) || (f < -infinity))
2455 num_error(f);
2456 } else if (l == dimen_val_level) {
2457 if (abs(f) > max_dimen)
2458 num_error(f);
2459 } else {
2460 if ((abs(width(f)) > max_dimen) ||
2461 (abs(stretch(f)) > max_dimen) || (abs(shrink(f)) > max_dimen))
2462 glue_error(f);
2465 switch (s) {
2466 /* Cases for evaluation of the current term */
2467 case expr_none:
2469 Applying the factor |f| to the partial term |t| (with the operator
2470 |s|) is delayed until the next operator |o| has been scanned. Here we
2471 handle the first factor of a partial term. A glue spec has to be copied
2472 unless the next operator is a right parenthesis; this allows us later on
2473 to simply modify the glue components.
2475 if ((l >= glue_val_level) && (o != expr_none)) {
2476 t = new_spec(f);
2477 delete_glue_ref(f);
2478 normalize_glue(t);
2479 } else {
2480 t = f;
2482 break;
2483 case expr_mult:
2484 /* If a multiplication is followed by a division, the two operations are
2485 combined into a `scaling' operation. Otherwise the term |t| is
2486 multiplied by the factor |f|. */
2487 if (o == expr_div) {
2488 n = f;
2489 o = expr_scale;
2490 } else if ((l == int_val_level) || (l == attr_val_level)) {
2491 t = mult_integers(t, f);
2492 } else if (l == dimen_val_level) {
2493 expr_m(t);
2494 } else {
2495 expr_m(width(t));
2496 expr_m(stretch(t));
2497 expr_m(shrink(t));
2499 break;
2500 case expr_div:
2501 /* Here we divide the term |t| by the factor |f| */
2502 if (l < glue_val_level) {
2503 expr_d(t);
2504 } else {
2505 expr_d(width(t));
2506 expr_d(stretch(t));
2507 expr_d(shrink(t));
2509 break;
2510 case expr_scale:
2511 /* Here the term |t| is multiplied by the quotient $n/f$. */
2512 if ((l == int_val_level) || (l == attr_val_level)) {
2513 t = fract(t, n, f, infinity);
2514 } else if (l == dimen_val_level) {
2515 expr_s(t);
2516 } else {
2517 expr_s(width(t));
2518 expr_s(stretch(t));
2519 expr_s(shrink(t));
2521 break;
2523 } /* there are no other cases */
2524 if (o > expr_sub) {
2525 s = o;
2526 } else {
2527 /* Evaluate the current expression */
2528 /* When a term |t| has been completed it is copied to, added to, or
2529 subtracted from the expression |e|. */
2530 s = expr_none;
2531 if (r == expr_none) {
2532 e = t;
2533 } else if ((l == int_val_level) || (l == attr_val_level)) {
2534 e = expr_add_sub(e, t, infinity);
2535 } else if (l == dimen_val_level) {
2536 e = expr_a(e, t);
2537 } else {
2538 /* Compute the sum or difference of two glue specs */
2539 /* We know that |stretch_order(e)>normal| implies |stretch(e)<>0| and
2540 |shrink_order(e)>normal| implies |shrink(e)<>0|. */
2541 width(e) = expr_a(width(e), width(t));
2542 if (stretch_order(e) == stretch_order(t)) {
2543 stretch(e) = expr_a(stretch(e), stretch(t));
2544 } else if ((stretch_order(e) < stretch_order(t))
2545 && (stretch(t) != 0)) {
2546 stretch(e) = stretch(t);
2547 stretch_order(e) = stretch_order(t);
2549 if (shrink_order(e) == shrink_order(t)) {
2550 shrink(e) = expr_a(shrink(e), shrink(t));
2551 } else if ((shrink_order(e) < shrink_order(t)) && (shrink(t) != 0)) {
2552 shrink(e) = shrink(t);
2553 shrink_order(e) = shrink_order(t);
2555 delete_glue_ref(t);
2556 normalize_glue(e);
2558 r = o;
2560 b = arith_error;
2561 if (o != expr_none)
2562 goto CONTINUE;
2563 if (p != null) {
2564 /* Pop the expression stack and |goto found| */
2565 f = e;
2566 q = p;
2567 e = expr_e_field(q);
2568 t = expr_t_field(q);
2569 n = expr_n_field(q);
2570 s = expr_state(q) / 4;
2571 r = expr_state(q) % 4;
2572 l = expr_type(q);
2573 p = vlink(q);
2574 flush_node(q);
2575 goto FOUND;
2578 if (b) {
2579 print_err("Arithmetic overflow");
2580 help2("I can't evaluate this expression,",
2581 "since the result is out of range.");
2582 error();
2583 if (l >= glue_val_level) {
2584 delete_glue_ref(e);
2585 e = zero_glue;
2586 add_glue_ref(e);
2587 } else {
2588 e = 0;
2591 arith_error = a;
2592 cur_val = e;
2593 cur_val_level = l;